Changeset 20103 in webkit
- Timestamp:
- Mar 11, 2007, 4:14:34 AM (18 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r20102 r20103 1 2007-03-11 Antti Koivisto <antti@apple.com> 2 3 Reviewed by Hyatt. 4 5 Optimize linebox memory consumption: 6 - move all bitfields to baseclass compacting them 7 - make InlineTextBox::m_truncation unsigned short and make it relative to m_start 8 - remove extremely rarely used EllipsisBox pointer from RootInlineBox and instead 9 use a global hashmap to store it if needed 10 - use minimum required number of bits to store BidiStatus enum variables in RootInlineBox 11 - move overflow variables in RootInlineBox to a separate struct that is instantiated 12 only if any of the variables is set to a value that can't trivially be derived from 13 box x, y, width and height 14 15 As a result line box objects shrink: 16 InlineBox: 44 -> 44 bytes 17 InlineTextBox: 68 -> 60 bytes 18 InlineFlowBox: 68 -> 64 bytes 19 RootInlineBox: 128 -> 88 bytes 20 21 The optimizations possiblity was noticed when debugging http://bugs.webkit.org/show_bug.cgi?id=12833 22 Bug 12833: REGRESSION: Selecting text in 6.6MB txt file is sluggish as of the Feb 19th nightly 23 <rdar://problem/5028159> 24 25 On that page the patch saves 11.5MB or some 21% of linebox memory consumption. It also 26 actually improves selection performance somewhat by improving memory locality. 27 28 * rendering/InlineBox.h: 29 (WebCore::InlineBox::InlineBox): 30 * rendering/InlineFlowBox.h: 31 (WebCore::InlineFlowBox::InlineFlowBox): 32 * rendering/InlineTextBox.cpp: 33 (WebCore::InlineTextBox::placeEllipsisBox): 34 (WebCore::InlineTextBox::nodeAtPoint): 35 (WebCore::InlineTextBox::paint): 36 (WebCore::InlineTextBox::paintDecoration): 37 (WebCore::InlineTextBox::paintSpellingOrGrammarMarker): 38 (WebCore::InlineTextBox::paintMarkedTextUnderline): 39 * rendering/InlineTextBox.h: 40 (WebCore::InlineTextBox::InlineTextBox): 41 * rendering/RootInlineBox.cpp: 42 (WebCore::throw): 43 (WebCore::RootInlineBox::Overflow::operator delete): 44 (WebCore::RootInlineBox::Overflow::destroy): 45 (WebCore::RootInlineBox::destroy): 46 (WebCore::RootInlineBox::detachEllipsisBox): 47 (WebCore::RootInlineBox::clearTruncation): 48 (WebCore::RootInlineBox::placeEllipsis): 49 (WebCore::RootInlineBox::paintEllipsisBox): 50 (WebCore::RootInlineBox::addHighlightOverflow): 51 (WebCore::RootInlineBox::nodeAtPoint): 52 (WebCore::RootInlineBox::adjustPosition): 53 (WebCore::RootInlineBox::selectionTop): 54 (WebCore::RootInlineBox::setLineBreakInfo): 55 (WebCore::RootInlineBox::ellipsisBox): 56 (WebCore::RootInlineBox::setVerticalOverflowPositions): 57 (WebCore::RootInlineBox::setHorizontalOverflowPositions): 58 (WebCore::RootInlineBox::setVerticalSelectionPositions): 59 * rendering/RootInlineBox.h: 60 (WebCore::RootInlineBox::RootInlineBox): 61 (WebCore::RootInlineBox::topOverflow): 62 (WebCore::RootInlineBox::bottomOverflow): 63 (WebCore::RootInlineBox::leftOverflow): 64 (WebCore::RootInlineBox::rightOverflow): 65 (WebCore::RootInlineBox::lineBreakBidiStatus): 66 (WebCore::RootInlineBox::selectionBottom): 67 (WebCore::RootInlineBox::Overflow::Overflow): 68 1 69 2007-03-11 Alexey Proskuryakov <ap@webkit.org> 2 70 -
trunk/WebCore/rendering/InlineBox.h
r18874 r20103 44 44 , m_height(0) 45 45 , m_baseline(0) 46 , m_next(0) 47 , m_prev(0) 48 , m_parent(0) 46 49 , m_firstLine(false) 47 50 , m_constructed(false) 48 51 , m_dirty(false) 49 52 , m_extracted(false) 50 , m_next(0) 51 , m_prev(0) 52 , m_parent(0) 53 , m_includeLeftEdge(false) 54 , m_includeRightEdge(false) 55 , m_hasTextChildren(false) 56 , m_endsWithBreak(false) 57 , m_hasSelectedChildren(false) 58 , m_hasEllipsisBox(false) 59 , m_reversed(false) 60 , m_treatAsText(true) 61 , m_toAdd(0) 53 62 { 54 63 } … … 62 71 , m_height(height) 63 72 , m_baseline(baseline) 73 , m_next(next) 74 , m_prev(prev) 75 , m_parent(parent) 64 76 , m_firstLine(firstLine) 65 77 , m_constructed(constructed) 66 78 , m_dirty(dirty) 67 79 , m_extracted(extracted) 68 , m_next(next) 69 , m_prev(prev) 70 , m_parent(parent) 80 , m_includeLeftEdge(false) 81 , m_includeRightEdge(false) 82 , m_hasTextChildren(false) 83 , m_endsWithBreak(false) 84 , m_hasSelectedChildren(false) 85 , m_hasEllipsisBox(false) 86 , m_reversed(false) 87 , m_treatAsText(true) 88 , m_toAdd(0) 71 89 { 72 90 } … … 193 211 int m_baseline; 194 212 213 InlineBox* m_next; // The next element on the same line as us. 214 InlineBox* m_prev; // The previous element on the same line as us. 215 216 InlineFlowBox* m_parent; // The box that contains us. 217 218 // Some of these bits are actually for subclasses and moved here to compact the structures. 219 // for this class 195 220 bool m_firstLine : 1; 196 221 bool m_constructed : 1; 197 222 bool m_dirty : 1; 198 223 bool m_extracted : 1; 199 200 InlineBox* m_next; // The next element on the same line as us. 201 InlineBox* m_prev; // The previous element on the same line as us. 202 203 InlineFlowBox* m_parent; // The box that contains us. 224 // for InlineFlowBox 225 bool m_includeLeftEdge : 1; 226 bool m_includeRightEdge : 1; 227 bool m_hasTextChildren : 1; 228 // for RootInlineBox 229 bool m_endsWithBreak : 1; // Whether the line ends with a <br>. 230 bool m_hasSelectedChildren : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected). 231 bool m_hasEllipsisBox : 1; 232 // for InlineTextBox 233 bool m_reversed : 1; 234 bool m_dirOverride : 1; 235 bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height. 236 int m_toAdd : 13; // for justified text 204 237 }; 205 238 -
trunk/WebCore/rendering/InlineFlowBox.h
r18874 r20103 39 39 , m_lastChild(0) 40 40 , m_maxHorizontalVisualOverflow(0) 41 , m_includeLeftEdge(false)42 , m_includeRightEdge(false)43 , m_hasTextChildren(false)44 41 { 45 42 } … … 133 130 InlineBox* m_lastChild; 134 131 int m_maxHorizontalVisualOverflow; 135 bool m_includeLeftEdge : 1;136 bool m_includeRightEdge : 1;137 bool m_hasTextChildren : 1;138 132 }; 139 133 -
trunk/WebCore/rendering/InlineTextBox.cpp
r20067 r20103 187 187 188 188 // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character. 189 m_truncation = offset + m_start;189 m_truncation = offset; 190 190 return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, textPos(), m_firstLine); 191 191 } … … 415 415 int endPoint = m_len; 416 416 if (m_truncation != cNoTruncation) 417 endPoint = m_truncation - m_start;417 endPoint = m_truncation; 418 418 paintInfo.context->drawText(TextRun(textStr, m_start, endPoint), IntPoint(m_x + tx, m_y + ty + m_baseline), textStyle); 419 419 } else { … … 577 577 578 578 int width = (m_truncation == cNoTruncation) ? m_width 579 : static_cast<RenderText*>(m_object)->width(m_start, m_truncation - m_start, textPos(), m_firstLine);579 : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine); 580 580 581 581 // Get the text decoration colors. … … 624 624 } 625 625 if (m_truncation != cNoTruncation) { 626 paintEnd = min(paintEnd, (unsigned)m_ truncation);626 paintEnd = min(paintEnd, (unsigned)m_start + m_truncation); 627 627 useWholeWidth = false; 628 628 } … … 772 772 } 773 773 if (m_truncation != cNoTruncation) { 774 paintEnd = min(paintEnd, (unsigned)m_ truncation);774 paintEnd = min(paintEnd, (unsigned)m_start + m_truncation); 775 775 useWholeWidth = false; 776 776 } -
trunk/WebCore/rendering/InlineTextBox.h
r19140 r20103 32 32 namespace WebCore { 33 33 34 const int cNoTruncation = -1;35 const int cFullTruncation = -2;34 const unsigned short cNoTruncation = USHRT_MAX; 35 const unsigned short cFullTruncation = USHRT_MAX - 1; 36 36 37 37 class String; … … 48 48 , m_len(0) 49 49 , m_truncation(cNoTruncation) 50 , m_reversed(false)51 , m_treatAsText(true)52 , m_toAdd(0)53 50 { 54 51 } … … 133 130 unsigned short m_len; 134 131 135 int m_truncation; // Where to truncate when text overflow is applied. We use special constants to132 unsigned short m_truncation; // Where to truncate when text overflow is applied. We use special constants to 136 133 // denote no truncation (the whole run paints) and full truncation (nothing paints at all). 137 138 bool m_reversed : 1;139 bool m_dirOverride : 1;140 bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height.141 int m_toAdd : 13; // for justified text142 134 143 135 private: -
trunk/WebCore/rendering/RootInlineBox.cpp
r20067 r20103 28 28 #include "GraphicsContext.h" 29 29 #include "HitTestResult.h" 30 #include "RenderArena.h" 30 31 #include "RenderBlock.h" 31 32 … … 33 34 34 35 namespace WebCore { 36 37 typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap; 38 static EllipsisBoxMap* gEllipsisBoxMap = 0; 39 40 void* RootInlineBox::Overflow::operator new(size_t sz, RenderArena* renderArena) throw() 41 { 42 return renderArena->allocate(sz); 43 } 44 45 void RootInlineBox::Overflow::operator delete(void* ptr, size_t sz) 46 { 47 // Stash size where destroy can find it. 48 *(size_t *)ptr = sz; 49 } 50 51 void RootInlineBox::Overflow::destroy(RenderArena* renderArena) 52 { 53 delete this; 54 // Recover the size left there for us by operator delete and free the memory. 55 renderArena->free(*(size_t *)this, this); 56 } 35 57 36 58 void RootInlineBox::destroy(RenderArena* arena) 37 59 { 60 if (m_overflow) 61 m_overflow->destroy(arena); 38 62 detachEllipsisBox(arena); 39 63 InlineFlowBox::destroy(arena); … … 42 66 void RootInlineBox::detachEllipsisBox(RenderArena* arena) 43 67 { 44 if (m_ellipsisBox) { 45 m_ellipsisBox->destroy(arena); 46 m_ellipsisBox = 0; 68 if (m_hasEllipsisBox) { 69 EllipsisBoxMap::iterator it = gEllipsisBoxMap->find(this); 70 it->second->destroy(arena); 71 gEllipsisBoxMap->remove(it); 72 m_hasEllipsisBox = false; 47 73 } 48 74 } … … 50 76 void RootInlineBox::clearTruncation() 51 77 { 52 if (m_ ellipsisBox) {78 if (m_hasEllipsisBox) { 53 79 detachEllipsisBox(m_object->renderArena()); 54 80 InlineFlowBox::clearTruncation(); … … 72 98 { 73 99 // Create an ellipsis box. 74 m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,100 EllipsisBox* ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this, 75 101 ellipsisWidth - (markupBox ? markupBox->width() : 0), 76 102 yPos(), height(), baseline(), !prevRootBox(), 77 103 markupBox); 104 105 if (!gEllipsisBoxMap) 106 gEllipsisBoxMap = new EllipsisBoxMap(); 107 gEllipsisBoxMap->add(this, ellipsisBox); 108 m_hasEllipsisBox = true; 78 109 79 110 if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) { 80 m_ellipsisBox->m_x = xPos() + width();111 ellipsisBox->m_x = xPos() + width(); 81 112 return; 82 113 } … … 86 117 // truncated). 87 118 bool foundBox = false; 88 m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);119 ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); 89 120 } 90 121 … … 99 130 void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& paintInfo, int tx, int ty) const 100 131 { 101 if (m_ ellipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE &&132 if (m_hasEllipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE && 102 133 paintInfo.phase == PaintPhaseForeground) 103 m_ellipsisBox->paint(paintInfo, tx, ty);134 ellipsisBox()->paint(paintInfo, tx, ty); 104 135 } 105 136 … … 110 141 FloatRect rootRect(0, selectionTop(), width(), selectionHeight()); 111 142 IntRect inflatedRect = enclosingIntRect(object()->document()->frame()->customHighlightLineRect(object()->style()->highlight(), rootRect, object()->node())); 112 m_leftOverflow = min(m_leftOverflow, inflatedRect.x()); 113 m_rightOverflow = max(m_rightOverflow, inflatedRect.right()); 114 m_topOverflow = min(m_topOverflow, inflatedRect.y()); 115 m_bottomOverflow = max(m_bottomOverflow, inflatedRect.bottom()); 143 setVerticalOverflowPositions(min(leftOverflow(), inflatedRect.x()), max(rightOverflow(), inflatedRect.right())); 144 setHorizontalOverflowPositions(min(topOverflow(), inflatedRect.y()), max(bottomOverflow(), inflatedRect.bottom())); 116 145 } 117 146 … … 142 171 bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) 143 172 { 144 if (m_ ellipsisBox && object()->style()->visibility() == VISIBLE) {145 if ( m_ellipsisBox->nodeAtPoint(request, result, x, y, tx, ty)) {173 if (m_hasEllipsisBox && object()->style()->visibility() == VISIBLE) { 174 if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) { 146 175 object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); 147 176 return true; … … 154 183 { 155 184 InlineFlowBox::adjustPosition(dx, dy); 156 m_topOverflow += dy; 157 m_bottomOverflow += dy; 185 if (m_overflow) { 186 m_overflow->m_topOverflow += dy; 187 m_overflow->m_bottomOverflow += dy; 188 m_overflow->m_selectionTop += dy; 189 m_overflow->m_selectionBottom += dy; 190 } 158 191 m_blockHeight += dy; 159 m_selectionTop += dy;160 m_selectionBottom += dy;161 192 } 162 193 … … 260 291 int RootInlineBox::selectionTop() 261 292 { 293 int selectionTop = m_overflow ? m_overflow->m_selectionTop : m_y; 262 294 if (!prevRootBox()) 263 return m_selectionTop;295 return selectionTop; 264 296 265 297 int prevBottom = prevRootBox()->selectionBottom(); 266 if (prevBottom < m_selectionTop && block()->containsFloats()) {298 if (prevBottom < selectionTop && block()->containsFloats()) { 267 299 // This line has actually been moved further down, probably from a large line-height, but possibly because the 268 300 // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous … … 270 302 int prevLeft = block()->leftOffset(prevBottom); 271 303 int prevRight = block()->rightOffset(prevBottom); 272 int newLeft = block()->leftOffset( m_selectionTop);273 int newRight = block()->rightOffset( m_selectionTop);304 int newLeft = block()->leftOffset(selectionTop); 305 int newRight = block()->rightOffset(selectionTop); 274 306 if (prevLeft > newLeft || prevRight < newRight) 275 return m_selectionTop;307 return selectionTop; 276 308 } 277 309 … … 320 352 m_lineBreakPos = breakPos; 321 353 m_lineBreakContext = context; 322 if (status) 323 m_lineBreakBidiStatus = *status; 354 if (status) { 355 m_lineBreakBidiStatusEor = status->eor; 356 m_lineBreakBidiStatusLastStrong = status->lastStrong; 357 m_lineBreakBidiStatusLast = status->last; 358 } 359 } 360 361 EllipsisBox* RootInlineBox::ellipsisBox() const 362 { 363 if (!m_hasEllipsisBox) 364 return false; 365 return gEllipsisBoxMap->get(this); 366 } 367 368 void RootInlineBox::setVerticalOverflowPositions(int top, int bottom) 369 { 370 if (!m_overflow) { 371 if (top == m_y && bottom == m_y + m_height) 372 return; 373 m_overflow = new (m_object->renderArena()) Overflow(this); 374 } 375 m_overflow->m_topOverflow = top; 376 m_overflow->m_bottomOverflow = bottom; 377 } 378 379 void RootInlineBox::setHorizontalOverflowPositions(int left, int right) 380 { 381 if (!m_overflow) { 382 if (left == m_x && right == m_x + m_width) 383 return; 384 m_overflow = new (m_object->renderArena()) Overflow(this); 385 } 386 m_overflow->m_leftOverflow = left; 387 m_overflow->m_rightOverflow = right; 388 } 389 390 void RootInlineBox::setVerticalSelectionPositions(int top, int bottom) 391 { 392 if (!m_overflow) { 393 if (top == m_y && bottom == m_y + m_height) 394 return; 395 m_overflow = new (m_object->renderArena()) Overflow(this); 396 } 397 m_overflow->m_selectionTop = top; 398 m_overflow->m_selectionBottom = bottom; 324 399 } 325 400 -
trunk/WebCore/rendering/RootInlineBox.h
r18758 r20103 37 37 RootInlineBox(RenderObject* obj) 38 38 : InlineFlowBox(obj) 39 , m_topOverflow(0) 40 , m_bottomOverflow(0) 41 , m_leftOverflow(0) 42 , m_rightOverflow(0) 39 , m_overflow(0) 43 40 , m_lineBreakObj(0) 44 41 , m_lineBreakPos(0) 45 42 , m_lineBreakContext(0) 46 , m_blockHeight(0)47 , m_endsWithBreak(false)48 , m_hasSelectedChildren(false)49 , m_ellipsisBox(0)50 43 { 51 44 } … … 61 54 virtual void adjustPosition(int dx, int dy); 62 55 63 virtual int topOverflow() { return m_ topOverflow; }64 virtual int bottomOverflow() { return m_ bottomOverflow; }65 virtual int leftOverflow() { return m_ leftOverflow; }66 virtual int rightOverflow() { return m_ rightOverflow; }56 virtual int topOverflow() { return m_overflow ? m_overflow->m_topOverflow : m_y; } 57 virtual int bottomOverflow() { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_height; } 58 virtual int leftOverflow() { return m_overflow ? m_overflow->m_leftOverflow : m_x; } 59 virtual int rightOverflow() { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; } 67 60 68 virtual void setVerticalOverflowPositions(int top, int bottom) { m_topOverflow = top; m_bottomOverflow = bottom; }69 void setHorizontalOverflowPositions(int left, int right) { m_leftOverflow = left; m_rightOverflow = right; }61 virtual void setVerticalOverflowPositions(int top, int bottom); 62 void setHorizontalOverflowPositions(int left, int right); 70 63 71 virtual void setVerticalSelectionPositions(int top, int bottom) { m_selectionTop = top; m_selectionBottom = bottom; }64 virtual void setVerticalSelectionPositions(int top, int bottom); 72 65 73 66 RenderObject* lineBreakObj() const { return m_lineBreakObj; } 74 BidiStatus lineBreakBidiStatus() const { return m_lineBreakBidiStatus; } 67 BidiStatus lineBreakBidiStatus() const { 68 BidiStatus status; 69 status.eor = m_lineBreakBidiStatusEor; 70 status.lastStrong = m_lineBreakBidiStatusLastStrong; 71 status.last = m_lineBreakBidiStatusLast; 72 return status; 73 } 75 74 BidiContext* lineBreakBidiContext() const { return m_lineBreakContext.get(); } 76 75 void setLineBreakInfo(RenderObject*, unsigned breakPos, BidiStatus*, BidiContext*); … … 91 90 virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox); 92 91 93 EllipsisBox* ellipsisBox() const { return m_ellipsisBox; }92 EllipsisBox* ellipsisBox() const; 94 93 95 94 void paintEllipsisBox(RenderObject::PaintInfo&, int tx, int ty) const; … … 119 118 120 119 int selectionTop(); 121 int selectionBottom() { return m_ selectionBottom; }120 int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + m_height; } 122 121 int selectionHeight() { return max(0, selectionBottom() - selectionTop()); } 123 122 … … 128 127 // that spills out above the height of our font (e.g, a tall image), or something that extends further 129 128 // below our line (e.g., a child whose font has a huge descent). 130 int m_topOverflow; 131 int m_bottomOverflow; 132 int m_leftOverflow; 133 int m_rightOverflow; 134 135 int m_selectionTop; 136 int m_selectionBottom; 129 130 // Allocated only when some of these fields have non-default values 131 struct Overflow { 132 Overflow(RootInlineBox* box) 133 : m_topOverflow(box->m_y) 134 , m_bottomOverflow(box->m_y + box->m_height) 135 , m_leftOverflow(box->m_x) 136 , m_rightOverflow(box->m_x + box->m_width) 137 , m_selectionTop(box->m_y) 138 , m_selectionBottom(box->m_y + box->m_height) 139 { 140 } 141 void destroy(RenderArena*); 142 void* operator new(size_t, RenderArena*) throw(); 143 void operator delete(void*, size_t); 144 145 int m_topOverflow; 146 int m_bottomOverflow; 147 int m_leftOverflow; 148 int m_rightOverflow; 149 int m_selectionTop; 150 int m_selectionBottom; 151 private: 152 void* operator new(size_t) throw(); 153 }; 154 155 Overflow* m_overflow; 137 156 138 157 // Where this line ended. The exact object and the position within that object are stored so that … … 141 160 unsigned m_lineBreakPos; 142 161 143 BidiStatus m_lineBreakBidiStatus;144 162 RefPtr<BidiContext> m_lineBreakContext; 145 163 … … 147 165 int m_blockHeight; 148 166 149 // Whether the line ends with a <br>. 150 bool m_endsWithBreak : 1; 151 152 // Whether we have any children selected (this bit will also be set if the <br> that terminates our 153 // line is selected). 154 bool m_hasSelectedChildren : 1; 155 156 // An inline text box that represents our text truncation string. 157 EllipsisBox* m_ellipsisBox; 167 WTF::Unicode::Direction m_lineBreakBidiStatusEor : 5; 168 WTF::Unicode::Direction m_lineBreakBidiStatusLastStrong : 5; 169 WTF::Unicode::Direction m_lineBreakBidiStatusLast : 5; 158 170 }; 159 171
Note:
See TracChangeset
for help on using the changeset viewer.