]> git.saurik.com Git - wxWidgets.git/blobdiff - src/html/htmlcell.cpp
Crash fix under VC++
[wxWidgets.git] / src / html / htmlcell.cpp
index 7d38d30994b3a66cc87ae533d67508a918c39028..8ea2197716ad12b3b459ca0c2de4f5c1bfd6e009 100644 (file)
@@ -4,7 +4,7 @@
 // Author:      Vaclav Slavik
 // RCS-ID:      $Id$
 // Copyright:   (c) 1999 Vaclav Slavik
 // Author:      Vaclav Slavik
 // RCS-ID:      $Id$
 // Copyright:   (c) 1999 Vaclav Slavik
-// Licence:     wxWindows Licence
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 /////////////////////////////////////////////////////////////////////////////
 
 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
@@ -94,7 +94,7 @@ wxHtmlCell::wxHtmlCell() : wxObject()
     m_Next = NULL;
     m_Parent = NULL;
     m_Width = m_Height = m_Descent = 0;
     m_Next = NULL;
     m_Parent = NULL;
     m_Width = m_Height = m_Descent = 0;
-    m_CanLiveOnPagebreak = TRUE;
+    m_CanLiveOnPagebreak = true;
     m_Link = NULL;
 }
 
     m_Link = NULL;
 }
 
@@ -139,10 +139,10 @@ bool wxHtmlCell::AdjustPagebreak(int *pagebreak, int* WXUNUSED(known_pagebreaks)
                 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak)
     {
         *pagebreak = m_PosY;
                 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak)
     {
         *pagebreak = m_PosY;
-        return TRUE;
+        return true;
     }
 
     }
 
-    return FALSE;
+    return false;
 }
 
 
 }
 
 
@@ -260,7 +260,7 @@ wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell()
 {
     m_Word = word;
     dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent);
 {
     m_Word = word;
     dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent);
-    SetCanLiveOnPagebreak(FALSE);
+    SetCanLiveOnPagebreak(false);
     m_allowLinebreak = true;
 }
 
     m_allowLinebreak = true;
 }
 
@@ -283,7 +283,7 @@ void wxHtmlWordCell::Split(wxDC& dc,
     wxPoint pt1 = (selFrom == wxDefaultPosition) ?
                    wxDefaultPosition : selFrom - GetAbsPos();
     wxPoint pt2 = (selTo == wxDefaultPosition) ?
     wxPoint pt1 = (selFrom == wxDefaultPosition) ?
                    wxDefaultPosition : selFrom - GetAbsPos();
     wxPoint pt2 = (selTo == wxDefaultPosition) ?
-                   wxPoint(m_Width, -1) : selTo - GetAbsPos();
+                   wxPoint(m_Width, wxDefaultCoord) : selTo - GetAbsPos();
 
     wxCoord charW, charH;
     unsigned len = m_Word.length();
 
     wxCoord charW, charH;
     unsigned len = m_Word.length();
@@ -381,11 +381,11 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
 {
 #if 0 // useful for debugging
     dc.SetPen(*wxBLACK_PEN);
 {
 #if 0 // useful for debugging
     dc.SetPen(*wxBLACK_PEN);
-    dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
+    dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width /* VZ: +1? */ ,m_Height);
 #endif
 
     bool drawSelectionAfterCell = false;
 #endif
 
     bool drawSelectionAfterCell = false;
-    
+
     if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
     {
         // Selection changing, we must draw the word piecewise:
     if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
     {
         // Selection changing, we must draw the word piecewise:
@@ -529,13 +529,14 @@ wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCe
 {
     m_Cells = m_LastCell = NULL;
     m_Parent = parent;
 {
     m_Cells = m_LastCell = NULL;
     m_Parent = parent;
+    m_MaxTotalWidth = 0;
     if (m_Parent) m_Parent->InsertCell(this);
     m_AlignHor = wxHTML_ALIGN_LEFT;
     m_AlignVer = wxHTML_ALIGN_BOTTOM;
     m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
     m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
     if (m_Parent) m_Parent->InsertCell(this);
     m_AlignHor = wxHTML_ALIGN_LEFT;
     m_AlignVer = wxHTML_ALIGN_BOTTOM;
     m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
     m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
-    m_UseBkColour = FALSE;
-    m_UseBorder = FALSE;
+    m_UseBkColour = false;
+    m_UseBorder = false;
     m_MinHeight = 0;
     m_MinHeightAlign = wxHTML_ALIGN_TOP;
     m_LastLayout = -1;
     m_MinHeight = 0;
     m_MinHeightAlign = wxHTML_ALIGN_TOP;
     m_LastLayout = -1;
@@ -580,7 +581,7 @@ int wxHtmlContainerCell::GetIndent(int ind) const
 
 int wxHtmlContainerCell::GetIndentUnits(int ind) const
 {
 
 int wxHtmlContainerCell::GetIndentUnits(int ind) const
 {
-    bool p = FALSE;
+    bool p = false;
     if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
     else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
     else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
     if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
     else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
     else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
@@ -599,13 +600,13 @@ bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks,
     else
     {
         wxHtmlCell *c = GetFirstChild();
     else
     {
         wxHtmlCell *c = GetFirstChild();
-        bool rt = FALSE;
+        bool rt = false;
         int pbrk = *pagebreak - m_PosY;
 
         while (c)
         {
             if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages))
         int pbrk = *pagebreak - m_PosY;
 
         while (c)
         {
             if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages))
-                rt = TRUE;
+                rt = true;
             c = c->GetNext();
         }
         if (rt)
             c = c->GetNext();
         }
         if (rt)
@@ -636,14 +637,16 @@ void wxHtmlContainerCell::Layout(int w)
        return;
     }
 
        return;
     }
 
-    wxHtmlCell *cell = m_Cells, *line = m_Cells;
+    wxHtmlCell *cell = m_Cells,
+               *line = m_Cells;
     wxHtmlCell *nextCell;
     long xpos = 0, ypos = m_IndentTop;
     int xdelta = 0, ybasicpos = 0, ydiff;
     int s_width, nextWordWidth, s_indent;
     int ysizeup = 0, ysizedown = 0;
     int MaxLineWidth = 0;
     wxHtmlCell *nextCell;
     long xpos = 0, ypos = m_IndentTop;
     int xdelta = 0, ybasicpos = 0, ydiff;
     int s_width, nextWordWidth, s_indent;
     int ysizeup = 0, ysizedown = 0;
     int MaxLineWidth = 0;
-    int xcnt = 0;
+    int curLineWidth = 0;
+    m_MaxTotalWidth = 0;
 
 
     /*
 
 
     /*
@@ -698,9 +701,22 @@ void wxHtmlContainerCell::Layout(int w)
         // layout nonbreakable run of cells:
         cell->SetPos(xpos, ybasicpos + cell->GetDescent());
         xpos += cell->GetWidth();
         // layout nonbreakable run of cells:
         cell->SetPos(xpos, ybasicpos + cell->GetDescent());
         xpos += cell->GetWidth();
+        if (!cell->IsTerminalCell())
+        {
+            // Container cell indicates new line
+            if (curLineWidth > m_MaxTotalWidth)
+                m_MaxTotalWidth = curLineWidth;
+
+            if (wxMax(cell->GetWidth(), cell->GetMaxTotalWidth()) > m_MaxTotalWidth)
+                m_MaxTotalWidth = cell->GetMaxTotalWidth();
+            curLineWidth = 0;
+        }
+        else
+            // Normal cell, add maximum cell width to line width
+            curLineWidth += cell->GetMaxTotalWidth();
+
         cell = cell->GetNext();
         cell = cell->GetNext();
-        xcnt++;
-            
+
         // compute length of the next word that would be added:
         nextWordWidth = 0;
         if (cell)
         // compute length of the next word that would be added:
         nextWordWidth = 0;
         if (cell)
@@ -712,9 +728,9 @@ void wxHtmlContainerCell::Layout(int w)
                 nextCell = nextCell->GetNext();
             } while (nextCell && !nextCell->IsLinebreakAllowed());
         }
                 nextCell = nextCell->GetNext();
             } while (nextCell && !nextCell->IsLinebreakAllowed());
         }
-        
+
         // force new line if occured:
         // force new line if occured:
-        if ((cell == NULL) || 
+        if ((cell == NULL) ||
             (xpos + nextWordWidth > s_width && cell->IsLinebreakAllowed()))
         {
             if (xpos > MaxLineWidth) MaxLineWidth = xpos;
             (xpos + nextWordWidth > s_width && cell->IsLinebreakAllowed()))
         {
             if (xpos > MaxLineWidth) MaxLineWidth = xpos;
@@ -738,29 +754,88 @@ void wxHtmlContainerCell::Layout(int w)
             ypos += ysizeup;
 
             if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
             ypos += ysizeup;
 
             if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
+            {
                 while (line != cell)
                 {
                     line->SetPos(line->GetPosX() + xdelta,
                                    ypos + line->GetPosY());
                     line = line->GetNext();
                 }
                 while (line != cell)
                 {
                     line->SetPos(line->GetPosX() + xdelta,
                                    ypos + line->GetPosY());
                     line = line->GetNext();
                 }
-            else
+            }
+            else // align == justify
             {
             {
-                int counter = 0;
-                int step = (s_width - xpos);
-                if (step < 0) step = 0;
-                xcnt--;
-                if (xcnt > 0) while (line != cell)
+                // we have to distribute the extra horz space between the cells
+                // on this line
+
+                // an added complication is that some cells have fixed size and
+                // shouldn't get any increment (it so happens that these cells
+                // also don't allow line break on them which provides with an
+                // easy way to test for this) -- and neither should the cells
+                // adjacent to them as this could result in a visible space
+                // between two cells separated by, e.g. font change, cell which
+                // is wrong
+
+                int step = s_width - xpos;
+                if ( step > 0 )
                 {
                 {
-                    line->SetPos(line->GetPosX() + s_indent +
-                                   (counter++ * step / xcnt),
-                                   ypos + line->GetPosY());
-                    line = line->GetNext();
+                    // first count the cells which will get extra space
+                    int total = 0;
+
+                    const wxHtmlCell *c;
+                    if ( line != cell )
+                    {
+                        for ( c = line->GetNext(); c != cell; c = c->GetNext() )
+                        {
+                            if ( c->IsLinebreakAllowed() )
+                            {
+                                total++;
+                            }
+                        }
+                    }
+
+                    // and now extra space to those cells which merit it
+                    if ( total )
+                    {
+                        // first cell on line is not moved:
+                        line->SetPos(line->GetPosX() + s_indent,
+                                     line->GetPosY() + ypos);
+
+                        line = line->GetNext();
+                        for ( int n = 0; line != cell; line = line->GetNext() )
+                        {
+                            if ( line->IsLinebreakAllowed() )
+                            {
+                                // offset the next cell relative to this one
+                                // thus increasing our size
+                                n++;
+                            }
+
+                            line->SetPos(line->GetPosX() + s_indent +
+                                           ((n * step) / total),
+                                           line->GetPosY() + ypos);
+                        }
+                    }
+                    else
+                    {
+                        // this will cause the code to enter "else branch" below:
+                        step = 0;
+                    }
+                }
+                // else branch:
+                if ( step <= 0 ) // no extra space to distribute
+                {
+                    // just set the indent properly
+                    while (line != cell)
+                    {
+                        line->SetPos(line->GetPosX() + s_indent,
+                                     line->GetPosY() + ypos);
+                        line = line->GetNext();
+                    }
                 }
             }
 
             ypos += ysizedown;
                 }
             }
 
             ypos += ysizedown;
-            xpos = xcnt = 0;
+            xpos = 0;
             ysizeup = ysizedown = 0;
             line = cell;
         }
             ysizeup = ysizedown = 0;
             line = cell;
         }
@@ -785,6 +860,10 @@ void wxHtmlContainerCell::Layout(int w)
         m_Height = m_MinHeight;
     }
 
         m_Height = m_MinHeight;
     }
 
+    if (curLineWidth > m_MaxTotalWidth)
+        m_MaxTotalWidth = curLineWidth;
+
+    m_MaxTotalWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
     MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
     if (m_Width < MaxLineWidth) m_Width = MaxLineWidth;
 
     MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
     if (m_Width < MaxLineWidth) m_Width = MaxLineWidth;
 
@@ -823,52 +902,60 @@ void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
     dc.SetPen(*wxRED_PEN);
     dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
 #endif
     dc.SetPen(*wxRED_PEN);
     dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
 #endif
-    // container visible, draw it:
-    if ((y + m_PosY <= view_y2) && (y + m_PosY + m_Height > view_y1))
+            
+    int xlocal = x + m_PosX;
+    int ylocal = y + m_PosY;
+
+    if (m_UseBkColour)
     {
     {
-        if (m_UseBkColour)
-        {
-            wxBrush myb = wxBrush(m_BkColour, wxSOLID);
+        wxBrush myb = wxBrush(m_BkColour, wxSOLID);
 
 
-            int real_y1 = mMax(y + m_PosY, view_y1);
-            int real_y2 = mMin(y + m_PosY + m_Height - 1, view_y2);
+        int real_y1 = mMax(ylocal, view_y1);
+        int real_y2 = mMin(ylocal + m_Height - 1, view_y2);
 
 
-            dc.SetBrush(myb);
-            dc.SetPen(*wxTRANSPARENT_PEN);
-            dc.DrawRectangle(x + m_PosX, real_y1, m_Width, real_y2 - real_y1 + 1);
-        }
+        dc.SetBrush(myb);
+        dc.SetPen(*wxTRANSPARENT_PEN);
+        dc.DrawRectangle(xlocal, real_y1, m_Width, real_y2 - real_y1 + 1);
+    }
 
 
-        if (m_UseBorder)
-        {
-            wxPen mypen1(m_BorderColour1, 1, wxSOLID);
-            wxPen mypen2(m_BorderColour2, 1, wxSOLID);
-
-            dc.SetPen(mypen1);
-            dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX, y + m_PosY + m_Height - 1);
-            dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX + m_Width, y + m_PosY);
-            dc.SetPen(mypen2);
-            dc.DrawLine(x + m_PosX + m_Width - 1, y + m_PosY, x + m_PosX +  m_Width - 1, y + m_PosY + m_Height - 1);
-            dc.DrawLine(x + m_PosX, y + m_PosY + m_Height - 1, x + m_PosX + m_Width, y + m_PosY + m_Height - 1);
-        }
+    if (m_UseBorder)
+    {
+        wxPen mypen1(m_BorderColour1, 1, wxSOLID);
+        wxPen mypen2(m_BorderColour2, 1, wxSOLID);
+
+        dc.SetPen(mypen1);
+        dc.DrawLine(xlocal, ylocal, xlocal, ylocal + m_Height - 1);
+        dc.DrawLine(xlocal, ylocal, xlocal + m_Width, ylocal);
+        dc.SetPen(mypen2);
+        dc.DrawLine(xlocal + m_Width - 1, ylocal, xlocal +  m_Width - 1, ylocal + m_Height - 1);
+        dc.DrawLine(xlocal, ylocal + m_Height - 1, xlocal + m_Width, ylocal + m_Height - 1);
+    }
 
 
-        if (m_Cells)
+    if (m_Cells)
+    {
+        // draw container's contents:
+        for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
         {
         {
-            // draw container's contents:
-            for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
+            
+            // optimize drawing: don't render off-screen content:
+            if ((ylocal + cell->GetPosY() <= view_y2) &&
+                (ylocal + cell->GetPosY() + cell->GetHeight() > view_y1))
             {
             {
+                // the cell is visible, draw it:
                 UpdateRenderingStatePre(info, cell);
                 cell->Draw(dc,
                 UpdateRenderingStatePre(info, cell);
                 cell->Draw(dc,
-                           x + m_PosX, y + m_PosY, view_y1, view_y2,
+                           xlocal, ylocal, view_y1, view_y2,
                            info);
                 UpdateRenderingStatePost(info, cell);
             }
                            info);
                 UpdateRenderingStatePost(info, cell);
             }
+            else
+            {
+                // the cell is off-screen, proceed with font+color+etc.
+                // changes only:
+                cell->DrawInvisible(dc, xlocal, ylocal, info);
+            }
         }
     }
         }
     }
-    // container invisible, just proceed font+color changing:
-    else
-    {
-        DrawInvisible(dc, x, y, info);
-    }
 }
 
 
 }
 
 
@@ -1007,10 +1094,10 @@ wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
             if ( cell->IsFormattingCell() )
                 continue;
             int cellY = cell->GetPosY();
             if ( cell->IsFormattingCell() )
                 continue;
             int cellY = cell->GetPosY();
-            if (!( y < cellY || (y < cellY + cell->GetHeight() && 
+            if (!( y < cellY || (y < cellY + cell->GetHeight() &&
                                  x < cell->GetPosX() + cell->GetWidth()) ))
                 continue;
                                  x < cell->GetPosX() + cell->GetWidth()) ))
                 continue;
-            
+
             c = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
             if (c) return c;
         }
             c = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
             if (c) return c;
         }
@@ -1096,7 +1183,7 @@ static bool IsEmptyContainer(wxHtmlContainerCell *cell)
 }
 
 void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
 }
 
 void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
-{   
+{
     if ( top )
         SetIndent(0, wxHTML_INDENT_TOP);
     if ( bottom )
     if ( top )
         SetIndent(0, wxHTML_INDENT_TOP);
     if ( bottom )
@@ -1130,13 +1217,13 @@ void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
                 }
             }
         }
                 }
             }
         }
-        
+
         if ( bottom )
         {
             wxArrayPtrVoid arr;
             for ( c = m_Cells; c; c = c->GetNext() )
                 arr.Add((void*)c);
         if ( bottom )
         {
             wxArrayPtrVoid arr;
             for ( c = m_Cells; c; c = c->GetNext() )
                 arr.Add((void*)c);
-           
+
             for ( int i = arr.GetCount() - 1; i >= 0; i--)
             {
                 c = (wxHtmlCell*)arr[i];
             for ( int i = arr.GetCount() - 1; i >= 0; i--)
             {
                 c = (wxHtmlCell*)arr[i];