]> git.saurik.com Git - wxWidgets.git/blobdiff - src/html/htmlcell.cpp
increase worst case to *4 for UTF8, switch a memcpy for wxMemcpy
[wxWidgets.git] / src / html / htmlcell.cpp
index cda05a607abe5f5ac8f2e104dbb1b7057428962e..5ea2d4b802b1a2aa721d619f9e28e1473e36317c 100644 (file)
@@ -4,7 +4,7 @@
 // Author:      Vaclav Slavik
 // RCS-ID:      $Id$
 // Copyright:   (c) 1999 Vaclav Slavik
-// Licence:     wxWindows Licence
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
@@ -87,12 +87,14 @@ GetSelectedTextBgColour(const wxColour& WXUNUSED(clr))
 // wxHtmlCell
 //-----------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlCell, wxObject)
+
 wxHtmlCell::wxHtmlCell() : wxObject()
 {
     m_Next = NULL;
     m_Parent = NULL;
     m_Width = m_Height = m_Descent = 0;
-    m_CanLiveOnPagebreak = TRUE;
+    m_CanLiveOnPagebreak = true;
     m_Link = NULL;
 }
 
@@ -137,10 +139,10 @@ bool wxHtmlCell::AdjustPagebreak(int *pagebreak, int* WXUNUSED(known_pagebreaks)
                 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak)
     {
         *pagebreak = m_PosY;
-        return TRUE;
+        return true;
     }
 
-    return FALSE;
+    return false;
 }
 
 
@@ -252,11 +254,13 @@ bool wxHtmlCell::IsBefore(wxHtmlCell *cell) const
 // wxHtmlWordCell
 //-----------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlWordCell, wxHtmlCell)
+
 wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell()
 {
     m_Word = word;
     dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent);
-    SetCanLiveOnPagebreak(FALSE);
+    SetCanLiveOnPagebreak(false);
     m_allowLinebreak = true;
 }
 
@@ -279,7 +283,7 @@ void wxHtmlWordCell::Split(wxDC& dc,
     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();
@@ -377,11 +381,11 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
 {
 #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;
-    
+
     if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
     {
         // Selection changing, we must draw the word piecewise:
@@ -519,18 +523,20 @@ wxCursor wxHtmlWordCell::GetCursor() const
 // wxHtmlContainerCell
 //-----------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlContainerCell, wxHtmlCell)
 
 wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell()
 {
     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;
-    m_UseBkColour = FALSE;
-    m_UseBorder = FALSE;
+    m_UseBkColour = false;
+    m_UseBorder = false;
     m_MinHeight = 0;
     m_MinHeightAlign = wxHTML_ALIGN_TOP;
     m_LastLayout = -1;
@@ -575,7 +581,7 @@ int wxHtmlContainerCell::GetIndent(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;
@@ -594,13 +600,13 @@ bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks,
     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))
-                rt = TRUE;
+                rt = true;
             c = c->GetNext();
         }
         if (rt)
@@ -631,14 +637,16 @@ void wxHtmlContainerCell::Layout(int w)
        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;
-    int xcnt = 0;
+    int curLineWidth = 0;
+    m_MaxTotalWidth = 0;
 
 
     /*
@@ -693,9 +701,22 @@ void wxHtmlContainerCell::Layout(int w)
         // 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();
-        xcnt++;
-            
+
         // compute length of the next word that would be added:
         nextWordWidth = 0;
         if (cell)
@@ -707,9 +728,9 @@ void wxHtmlContainerCell::Layout(int w)
                 nextCell = nextCell->GetNext();
             } while (nextCell && !nextCell->IsLinebreakAllowed());
         }
-        
+
         // force new line if occured:
-        if ((cell == NULL) || 
+        if ((cell == NULL) ||
             (xpos + nextWordWidth > s_width && cell->IsLinebreakAllowed()))
         {
             if (xpos > MaxLineWidth) MaxLineWidth = xpos;
@@ -733,30 +754,88 @@ void wxHtmlContainerCell::Layout(int w)
             ypos += ysizeup;
 
             if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
+            {
                 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();
+                    }
                 }
-                xcnt++;
             }
 
             ypos += ysizedown;
-            xpos = xcnt = 0;
+            xpos = 0;
             ysizeup = ysizedown = 0;
             line = cell;
         }
@@ -781,6 +860,10 @@ void wxHtmlContainerCell::Layout(int w)
         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;
 
@@ -968,11 +1051,9 @@ const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) co
 {
     if (m_Cells)
     {
-        const wxHtmlCell *r = NULL;
-
         for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
         {
-            r = cell->Find(condition, param);
+            const wxHtmlCell *r = cell->Find(condition, param);
             if (r) return r;
         }
     }
@@ -1005,10 +1086,10 @@ wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
             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;
-            
+
             c = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
             if (c) return c;
         }
@@ -1094,7 +1175,7 @@ static bool IsEmptyContainer(wxHtmlContainerCell *cell)
 }
 
 void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
-{   
+{
     if ( top )
         SetIndent(0, wxHTML_INDENT_TOP);
     if ( bottom )
@@ -1128,13 +1209,13 @@ void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
                 }
             }
         }
-        
+
         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];
@@ -1167,6 +1248,8 @@ void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
 // wxHtmlColourCell
 // --------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlColourCell, wxHtmlCell)
+
 void wxHtmlColourCell::Draw(wxDC& dc,
                             int x, int y,
                             int WXUNUSED(view_y1), int WXUNUSED(view_y2),
@@ -1213,6 +1296,8 @@ void wxHtmlColourCell::DrawInvisible(wxDC& dc,
 // wxHtmlFontCell
 // ---------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlFontCell, wxHtmlCell)
+
 void wxHtmlFontCell::Draw(wxDC& dc,
                           int WXUNUSED(x), int WXUNUSED(y),
                           int WXUNUSED(view_y1), int WXUNUSED(view_y2),
@@ -1238,6 +1323,8 @@ void wxHtmlFontCell::DrawInvisible(wxDC& dc, int WXUNUSED(x), int WXUNUSED(y),
 // wxHtmlWidgetCell
 // ---------------------------------------------------------------------------
 
+IMPLEMENT_ABSTRACT_CLASS(wxHtmlWidgetCell, wxHtmlCell)
+
 wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w)
 {
     int sx, sy;