Changeset 85668 in webkit
- Timestamp:
- May 3, 2011 3:11:39 PM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r85661 r85668 1 2011-05-03 Eric Seidel <eric@webkit.org> 2 3 Reviewed by Ryosuke Niwa. 4 5 Split out layoutRunsAndFloats from layoutInlineChildren 6 https://bugs.webkit.org/show_bug.cgi?id=60052 7 8 No new tests, just moving code here. There should be 9 no change in behavior. 10 11 * rendering/RenderBlock.h: 12 * rendering/RenderBlockLineLayout.cpp: 13 (WebCore::RenderBlock::layoutRunsAndFloats): 14 (WebCore::RenderBlock::layoutInlineChildren): 15 1 16 2011-05-03 James Robinson <jamesr@chromium.org> 2 17 -
trunk/Source/WebCore/rendering/RenderBlock.h
r85652 r85668 702 702 // End helper functions and structs used by layoutBlockChildren. 703 703 704 // Helper function for layoutInlineChildren() 705 void layoutRunsAndFloats(bool fullLayout, bool hasInlineChild, Vector<FloatWithRect>&, int& repaintLogicalTop, int& repaintLogicalBottom); 706 704 707 // Pagination routines. 705 708 int nextPageLogicalTop(int logicalOffset) const; // Returns the top of the next page following logicalOffset. -
trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp
r85652 r85668 60 60 // We don't let our line box tree for a single line get any deeper than this. 61 61 const unsigned cMaxLineDepth = 200; 62 62 63 63 class LineInfo { 64 64 public: … … 132 132 endpoint.m_pos--; 133 133 } 134 } 134 } 135 135 } 136 136 … … 163 163 if (!(haveNextMidpoint && nextMidpoint.m_obj == obj)) 164 164 return; 165 // This is a new start point. Stop ignoring objects and 165 // This is a new start point. Stop ignoring objects and 166 166 // adjust our start. 167 167 lineMidpointState.betweenMidpoints = false; … … 195 195 if (isRootLineBox) 196 196 return toRenderBlock(obj)->createAndAppendRootInlineBox(); 197 197 198 198 if (obj->isText()) { 199 199 InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); … … 204 204 return textBox; 205 205 } 206 206 207 207 if (obj->isBox()) 208 208 return toRenderBox(obj)->createInlineBox(); 209 209 210 210 return toRenderInline(obj)->createAndAppendInlineFlowBox(); 211 211 } … … 241 241 do { 242 242 ASSERT(obj->isRenderInline() || obj == this); 243 243 244 244 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0; 245 245 … … 281 281 break; 282 282 283 childBox = parentBox; 283 childBox = parentBox; 284 284 } 285 285 … … 477 477 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) 478 478 totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().wordSpacing(); 479 needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length; 479 needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length; 480 480 } 481 481 HashSet<const SimpleFontData*> fallbackFonts; 482 482 GlyphOverflow glyphOverflow; 483 483 484 484 // Always compute glyph overflow if the block's line-box-contain value is "glyphs". 485 485 if (lineBox->fitsToGlyphs()) { … … 493 493 int boxDescent = rt->style(lineInfo.isFirstLine())->font().fontMetrics().descent() + baselineShift; 494 494 if (boxAscent > rootDescent || boxDescent > rootAscent) 495 glyphOverflow.computeBounds = true; 495 glyphOverflow.computeBounds = true; 496 496 } 497 497 … … 752 752 } 753 753 754 void RenderBlock::layoutRunsAndFloats(bool fullLayout, bool hasInlineChild, Vector<FloatWithRect>& floats, int& repaintLogicalTop, int& repaintLogicalBottom) 755 { 756 // We want to skip ahead to the first dirty line 757 InlineBidiResolver resolver; 758 unsigned floatIndex; 759 LineInfo lineInfo; 760 bool useRepaintBounds = false; 761 762 RootInlineBox* startLine = determineStartPosition(lineInfo, fullLayout, resolver, floats, floatIndex, 763 useRepaintBounds, repaintLogicalTop, repaintLogicalBottom); 764 765 // FIXME: This would make more sense outside of this function, but since 766 // determineStartPosition can change the fullLayout flag we have to do this here. Failure to call 767 // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html. 768 if (fullLayout && hasInlineChild && !selfNeedsLayout()) { 769 setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like 770 // we're supposed to. 771 RenderView* v = view(); 772 if (v && !v->doingFullRepaint() && hasLayer()) { 773 // Because we waited until we were already inside layout to discover 774 // that the block really needed a full layout, we missed our chance to repaint the layer 775 // before layout started. Luckily the layer has cached the repaint rect for its original 776 // position and size, and so we can use that to make a repaint happen now. 777 repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); 778 } 779 } 780 781 FloatingObject* lastFloat = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; 782 783 LineMidpointState& lineMidpointState = resolver.midpointState(); 784 785 // We also find the first clean line and extract these lines. We will add them back 786 // if we determine that we're able to synchronize after handling all our dirty lines. 787 InlineIterator cleanLineStart; 788 BidiStatus cleanLineBidiStatus; 789 int endLineLogicalTop = 0; 790 RootInlineBox* endLine = (fullLayout || !startLine) ? 791 0 : determineEndPosition(startLine, floats, floatIndex, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop); 792 793 if (startLine) { 794 if (!useRepaintBounds) { 795 useRepaintBounds = true; 796 repaintLogicalTop = logicalHeight(); 797 repaintLogicalBottom = logicalHeight(); 798 } 799 RenderArena* arena = renderArena(); 800 RootInlineBox* box = startLine; 801 while (box) { 802 repaintLogicalTop = min(repaintLogicalTop, box->logicalTopVisualOverflow()); 803 repaintLogicalBottom = max(repaintLogicalBottom, box->logicalBottomVisualOverflow()); 804 RootInlineBox* next = box->nextRootBox(); 805 box->deleteLine(arena); 806 box = next; 807 } 808 } 809 810 InlineIterator end = resolver.position(); 811 812 if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) { 813 // If the last line before the start line ends with a line break that clear floats, 814 // adjust the height accordingly. 815 // A line break can be either the first or the last object on a line, depending on its direction. 816 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { 817 RenderObject* lastObject = lastLeafChild->renderer(); 818 if (!lastObject->isBR()) 819 lastObject = lastRootBox()->firstLeafChild()->renderer(); 820 if (lastObject->isBR()) { 821 EClear clear = lastObject->style()->clear(); 822 if (clear != CNONE) 823 newLine(clear); 824 } 825 } 826 } 827 828 bool endLineMatched = false; 829 bool checkForEndLineMatch = endLine; 830 bool checkForFloatsFromLastLine = false; 831 832 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 833 834 LineBreakIteratorInfo lineBreakIteratorInfo; 835 VerticalPositionCache verticalPositionCache; 836 837 while (!end.atEnd()) { 838 // FIXME: Is this check necessary before the first iteration or can it be moved to the end? 839 if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop))) 840 break; 841 842 lineMidpointState.reset(); 843 844 lineInfo.setEmpty(true); 845 846 EClear clear = CNONE; 847 bool hyphenated; 848 Vector<RenderBox*> positionedObjects; 849 850 InlineIterator oldEnd = end; 851 FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; 852 end = findNextLineBreak(resolver, lineInfo, lineBreakIteratorInfo, hyphenated, &clear, lastFloatFromPreviousLine, positionedObjects); 853 if (resolver.position().atEnd()) { 854 // FIXME: We shouldn't be creating any runs in findNextLineBreak to begin with! 855 // Once BidiRunList is separated from BidiResolver this will not be needed. 856 resolver.runs().deleteRuns(); 857 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 858 checkForFloatsFromLastLine = true; 859 break; 860 } 861 ASSERT(end != resolver.position()); 862 863 if (lineInfo.isEmpty()) { 864 if (lastRootBox()) 865 lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); 866 } else { 867 VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); 868 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine. 869 BidiRunList<BidiRun>& bidiRuns = resolver.runs(); 870 resolver.createBidiRunsForLine(end, override, lineInfo.previousLineBrokeCleanly()); 871 ASSERT(resolver.position() == end); 872 873 BidiRun* trailingSpaceRun = !lineInfo.previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0; 874 875 // Now that the runs have been ordered, we create the line boxes. 876 // At the same time we figure out where border/padding/margin should be applied for 877 // inline flow boxes. 878 879 RootInlineBox* lineBox = 0; 880 int oldLogicalHeight = logicalHeight(); 881 if (bidiRuns.runCount()) { 882 if (hyphenated) 883 bidiRuns.logicallyLastRun()->m_hasHyphen = true; 884 lineInfo.setLastLine(!end.m_obj); 885 lineBox = constructLine(bidiRuns, lineInfo); 886 if (lineBox) { 887 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly()); 888 889 #if ENABLE(SVG) 890 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox(); 891 #else 892 bool isSVGRootInlineBox = false; 893 #endif 894 895 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 896 897 // Now we position all of our text runs horizontally. 898 if (!isSVGRootInlineBox) 899 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache); 900 901 // Now position our text runs vertically. 902 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache); 903 904 #if ENABLE(SVG) 905 // SVG text layout code computes vertical & horizontal positions on its own. 906 // Note that we still need to execute computeVerticalPositionsForLine() as 907 // it calls InlineTextBox::positionLineBox(), which tracks whether the box 908 // contains reversed text or not. If we wouldn't do that editing and thus 909 // text selection in RTL boxes would not work as expected. 910 if (isSVGRootInlineBox) { 911 ASSERT(isSVGText()); 912 static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation(); 913 } 914 #endif 915 916 // Compute our overflow now. 917 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap); 918 919 #if PLATFORM(MAC) 920 // Highlight acts as an overflow inflation. 921 if (style()->highlight() != nullAtom) 922 lineBox->addHighlightOverflow(); 923 #endif 924 } 925 } 926 927 bidiRuns.deleteRuns(); 928 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 929 930 if (lineBox) { 931 lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); 932 if (useRepaintBounds) { 933 repaintLogicalTop = min(repaintLogicalTop, lineBox->logicalTopVisualOverflow()); 934 repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); 935 } 936 937 if (paginated) { 938 int adjustment = 0; 939 adjustLinePositionForPagination(lineBox, adjustment); 940 if (adjustment) { 941 int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, lineInfo.isFirstLine()); 942 lineBox->adjustBlockDirectionPosition(adjustment); 943 if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop. 944 repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); 945 946 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, lineInfo.isFirstLine()) != oldLineWidth) { 947 // We have to delete this line, remove all floats that got added, and let line layout re-run. 948 lineBox->deleteLine(renderArena()); 949 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight); 950 setLogicalHeight(oldLogicalHeight + adjustment); 951 resolver.setPosition(oldEnd); 952 end = oldEnd; 953 continue; 954 } 955 956 setLogicalHeight(lineBox->blockLogicalHeight()); 957 } 958 } 959 } 960 961 for (size_t i = 0; i < positionedObjects.size(); ++i) 962 setStaticPositions(this, positionedObjects[i]); 963 964 lineInfo.setFirstLine(false); 965 newLine(clear); 966 } 967 968 if (m_floatingObjects && lastRootBox()) { 969 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 970 FloatingObjectSetIterator it = floatingObjectSet.begin(); 971 FloatingObjectSetIterator end = floatingObjectSet.end(); 972 if (lastFloat) { 973 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); 974 ASSERT(lastFloatIterator != end); 975 ++lastFloatIterator; 976 it = lastFloatIterator; 977 } 978 for (; it != end; ++it) { 979 FloatingObject* f = *it; 980 appendFloatingObjectToLastLine(f); 981 ASSERT(f->m_renderer == floats[floatIndex].object); 982 // If a float's geometry has changed, give up on syncing with clean lines. 983 if (floats[floatIndex].rect != f->frameRect()) 984 checkForEndLineMatch = false; 985 floatIndex++; 986 } 987 lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; 988 } 989 990 lineMidpointState.reset(); 991 resolver.setPosition(end); 992 } 993 994 if (endLine) { 995 if (endLineMatched) { 996 // Attach all the remaining lines, and then adjust their y-positions as needed. 997 int delta = logicalHeight() - endLineLogicalTop; 998 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) { 999 line->attachLine(); 1000 if (paginated) { 1001 delta -= line->paginationStrut(); 1002 adjustLinePositionForPagination(line, delta); 1003 } 1004 if (delta) { 1005 repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow() + min(delta, 0)); 1006 repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow() + max(delta, 0)); 1007 line->adjustBlockDirectionPosition(delta); 1008 } 1009 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { 1010 Vector<RenderBox*>::iterator end = cleanLineFloats->end(); 1011 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { 1012 insertFloatingObject(*f); 1013 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta); 1014 positionNewFloats(); 1015 } 1016 } 1017 } 1018 setLogicalHeight(lastRootBox()->blockLogicalHeight()); 1019 } else { 1020 // Delete all the remaining lines. 1021 RootInlineBox* line = endLine; 1022 RenderArena* arena = renderArena(); 1023 while (line) { 1024 repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow()); 1025 repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow()); 1026 RootInlineBox* next = line->nextRootBox(); 1027 line->deleteLine(arena); 1028 line = next; 1029 } 1030 } 1031 } 1032 if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) { 1033 // In case we have a float on the last line, it might not be positioned up to now. 1034 // This has to be done before adding in the bottom border/padding, or the float will 1035 // include the padding incorrectly. -dwh 1036 if (checkForFloatsFromLastLine) { 1037 int bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); 1038 int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); 1039 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); 1040 m_lineBoxes.appendLineBox(trailingFloatsLineBox); 1041 trailingFloatsLineBox->setConstructed(); 1042 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 1043 VerticalPositionCache verticalPositionCache; 1044 trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache); 1045 int blockLogicalHeight = logicalHeight(); 1046 IntRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); 1047 IntRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); 1048 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); 1049 trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight()); 1050 } 1051 1052 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1053 FloatingObjectSetIterator it = floatingObjectSet.begin(); 1054 FloatingObjectSetIterator end = floatingObjectSet.end(); 1055 if (lastFloat) { 1056 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); 1057 ASSERT(lastFloatIterator != end); 1058 ++lastFloatIterator; 1059 it = lastFloatIterator; 1060 } 1061 for (; it != end; ++it) 1062 appendFloatingObjectToLastLine(*it); 1063 lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; 1064 } 1065 size_t floatCount = floats.size(); 1066 // Floats that did not have layout did not repaint when we laid them out. They would have 1067 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be 1068 // painted. 1069 for (size_t i = 0; i < floatCount; ++i) { 1070 if (!floats[i].everHadLayout) { 1071 RenderBox* f = floats[i].object; 1072 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout()) 1073 f->repaint(); 1074 } 1075 } 1076 } 1077 754 1078 void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom) 755 1079 { 756 bool useRepaintBounds = false;757 758 1080 m_overflow.clear(); 759 1081 760 1082 setLogicalHeight(borderBefore() + paddingBefore()); 761 1083 … … 789 1111 if (o->isReplaced() || o->isFloating() || o->isPositioned()) { 790 1112 RenderBox* box = toRenderBox(o); 791 1113 792 1114 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) 793 1115 o->setChildNeedsLayout(true, false); 794 1116 795 1117 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 796 1118 if (relayoutChildren && (o->style()->paddingStart().isPercent() || o->style()->paddingEnd().isPercent())) 797 1119 o->setPreferredLogicalWidthsDirty(true, false); 798 1120 799 1121 if (o->isPositioned()) 800 1122 o->containingBlock()->insertPositionedObject(box); … … 816 1138 } 817 1139 818 // We want to skip ahead to the first dirty line 819 InlineBidiResolver resolver; 820 unsigned floatIndex; 821 LineInfo lineInfo; 822 RootInlineBox* startLine = determineStartPosition(lineInfo, fullLayout, resolver, floats, floatIndex, 823 useRepaintBounds, repaintLogicalTop, repaintLogicalBottom); 824 825 if (fullLayout && hasInlineChild && !selfNeedsLayout()) { 826 setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like 827 // we're supposed to. 828 RenderView* v = view(); 829 if (v && !v->doingFullRepaint() && hasLayer()) { 830 // Because we waited until we were already inside layout to discover 831 // that the block really needed a full layout, we missed our chance to repaint the layer 832 // before layout started. Luckily the layer has cached the repaint rect for its original 833 // position and size, and so we can use that to make a repaint happen now. 834 repaintUsingContainer(containerForRepaint(), layer()->repaintRect()); 835 } 836 } 837 838 FloatingObject* lastFloat = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; 839 840 LineMidpointState& lineMidpointState = resolver.midpointState(); 841 842 // We also find the first clean line and extract these lines. We will add them back 843 // if we determine that we're able to synchronize after handling all our dirty lines. 844 InlineIterator cleanLineStart; 845 BidiStatus cleanLineBidiStatus; 846 int endLineLogicalTop = 0; 847 RootInlineBox* endLine = (fullLayout || !startLine) ? 848 0 : determineEndPosition(startLine, floats, floatIndex, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop); 849 850 if (startLine) { 851 if (!useRepaintBounds) { 852 useRepaintBounds = true; 853 repaintLogicalTop = logicalHeight(); 854 repaintLogicalBottom = logicalHeight(); 855 } 856 RenderArena* arena = renderArena(); 857 RootInlineBox* box = startLine; 858 while (box) { 859 repaintLogicalTop = min(repaintLogicalTop, box->logicalTopVisualOverflow()); 860 repaintLogicalBottom = max(repaintLogicalBottom, box->logicalBottomVisualOverflow()); 861 RootInlineBox* next = box->nextRootBox(); 862 box->deleteLine(arena); 863 box = next; 864 } 865 } 866 867 InlineIterator end = resolver.position(); 868 869 if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) { 870 // If the last line before the start line ends with a line break that clear floats, 871 // adjust the height accordingly. 872 // A line break can be either the first or the last object on a line, depending on its direction. 873 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) { 874 RenderObject* lastObject = lastLeafChild->renderer(); 875 if (!lastObject->isBR()) 876 lastObject = lastRootBox()->firstLeafChild()->renderer(); 877 if (lastObject->isBR()) { 878 EClear clear = lastObject->style()->clear(); 879 if (clear != CNONE) 880 newLine(clear); 881 } 882 } 883 } 884 885 bool endLineMatched = false; 886 bool checkForEndLineMatch = endLine; 887 bool checkForFloatsFromLastLine = false; 888 889 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); 890 891 LineBreakIteratorInfo lineBreakIteratorInfo; 892 VerticalPositionCache verticalPositionCache; 893 894 while (!end.atEnd()) { 895 // FIXME: Is this check necessary before the first iteration or can it be moved to the end? 896 if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop))) 897 break; 898 899 lineMidpointState.reset(); 900 901 lineInfo.setEmpty(true); 902 903 EClear clear = CNONE; 904 bool hyphenated; 905 Vector<RenderBox*> positionedObjects; 906 907 InlineIterator oldEnd = end; 908 FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; 909 end = findNextLineBreak(resolver, lineInfo, lineBreakIteratorInfo, hyphenated, &clear, lastFloatFromPreviousLine, positionedObjects); 910 if (resolver.position().atEnd()) { 911 // FIXME: We shouldn't be creating any runs in findNextLineBreak to begin with! 912 // Once BidiRunList is separated from BidiResolver this will not be needed. 913 resolver.runs().deleteRuns(); 914 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 915 checkForFloatsFromLastLine = true; 916 break; 917 } 918 ASSERT(end != resolver.position()); 919 920 if (lineInfo.isEmpty()) { 921 if (lastRootBox()) 922 lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); 923 } else { 924 VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); 925 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine. 926 BidiRunList<BidiRun>& bidiRuns = resolver.runs(); 927 resolver.createBidiRunsForLine(end, override, lineInfo.previousLineBrokeCleanly()); 928 ASSERT(resolver.position() == end); 929 930 BidiRun* trailingSpaceRun = !lineInfo.previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0; 931 932 // Now that the runs have been ordered, we create the line boxes. 933 // At the same time we figure out where border/padding/margin should be applied for 934 // inline flow boxes. 935 936 RootInlineBox* lineBox = 0; 937 int oldLogicalHeight = logicalHeight(); 938 if (bidiRuns.runCount()) { 939 if (hyphenated) 940 bidiRuns.logicallyLastRun()->m_hasHyphen = true; 941 lineInfo.setLastLine(!end.m_obj); 942 lineBox = constructLine(bidiRuns, lineInfo); 943 if (lineBox) { 944 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly()); 945 946 #if ENABLE(SVG) 947 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox(); 948 #else 949 bool isSVGRootInlineBox = false; 950 #endif 951 952 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 953 954 // Now we position all of our text runs horizontally. 955 if (!isSVGRootInlineBox) 956 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache); 957 958 // Now position our text runs vertically. 959 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache); 960 961 #if ENABLE(SVG) 962 // SVG text layout code computes vertical & horizontal positions on its own. 963 // Note that we still need to execute computeVerticalPositionsForLine() as 964 // it calls InlineTextBox::positionLineBox(), which tracks whether the box 965 // contains reversed text or not. If we wouldn't do that editing and thus 966 // text selection in RTL boxes would not work as expected. 967 if (isSVGRootInlineBox) { 968 ASSERT(isSVGText()); 969 static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation(); 970 } 971 #endif 972 973 // Compute our overflow now. 974 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap); 975 976 #if PLATFORM(MAC) 977 // Highlight acts as an overflow inflation. 978 if (style()->highlight() != nullAtom) 979 lineBox->addHighlightOverflow(); 980 #endif 981 } 982 } 983 984 bidiRuns.deleteRuns(); 985 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). 986 987 if (lineBox) { 988 lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); 989 if (useRepaintBounds) { 990 repaintLogicalTop = min(repaintLogicalTop, lineBox->logicalTopVisualOverflow()); 991 repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); 992 } 993 994 if (paginated) { 995 int adjustment = 0; 996 adjustLinePositionForPagination(lineBox, adjustment); 997 if (adjustment) { 998 int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, lineInfo.isFirstLine()); 999 lineBox->adjustBlockDirectionPosition(adjustment); 1000 if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop. 1001 repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); 1002 1003 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, lineInfo.isFirstLine()) != oldLineWidth) { 1004 // We have to delete this line, remove all floats that got added, and let line layout re-run. 1005 lineBox->deleteLine(renderArena()); 1006 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight); 1007 setLogicalHeight(oldLogicalHeight + adjustment); 1008 resolver.setPosition(oldEnd); 1009 end = oldEnd; 1010 continue; 1011 } 1012 1013 setLogicalHeight(lineBox->blockLogicalHeight()); 1014 } 1015 } 1016 } 1017 1018 for (size_t i = 0; i < positionedObjects.size(); ++i) 1019 setStaticPositions(this, positionedObjects[i]); 1020 1021 lineInfo.setFirstLine(false); 1022 newLine(clear); 1023 } 1024 1025 if (m_floatingObjects && lastRootBox()) { 1026 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1027 FloatingObjectSetIterator it = floatingObjectSet.begin(); 1028 FloatingObjectSetIterator end = floatingObjectSet.end(); 1029 if (lastFloat) { 1030 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); 1031 ASSERT(lastFloatIterator != end); 1032 ++lastFloatIterator; 1033 it = lastFloatIterator; 1034 } 1035 for (; it != end; ++it) { 1036 FloatingObject* f = *it; 1037 appendFloatingObjectToLastLine(f); 1038 ASSERT(f->m_renderer == floats[floatIndex].object); 1039 // If a float's geometry has changed, give up on syncing with clean lines. 1040 if (floats[floatIndex].rect != f->frameRect()) 1041 checkForEndLineMatch = false; 1042 floatIndex++; 1043 } 1044 lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; 1045 } 1046 1047 lineMidpointState.reset(); 1048 resolver.setPosition(end); 1049 } 1050 1051 if (endLine) { 1052 if (endLineMatched) { 1053 // Attach all the remaining lines, and then adjust their y-positions as needed. 1054 int delta = logicalHeight() - endLineLogicalTop; 1055 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) { 1056 line->attachLine(); 1057 if (paginated) { 1058 delta -= line->paginationStrut(); 1059 adjustLinePositionForPagination(line, delta); 1060 } 1061 if (delta) { 1062 repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow() + min(delta, 0)); 1063 repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow() + max(delta, 0)); 1064 line->adjustBlockDirectionPosition(delta); 1065 } 1066 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { 1067 Vector<RenderBox*>::iterator end = cleanLineFloats->end(); 1068 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { 1069 insertFloatingObject(*f); 1070 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta); 1071 positionNewFloats(); 1072 } 1073 } 1074 } 1075 setLogicalHeight(lastRootBox()->blockLogicalHeight()); 1076 } else { 1077 // Delete all the remaining lines. 1078 RootInlineBox* line = endLine; 1079 RenderArena* arena = renderArena(); 1080 while (line) { 1081 repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow()); 1082 repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow()); 1083 RootInlineBox* next = line->nextRootBox(); 1084 line->deleteLine(arena); 1085 line = next; 1086 } 1087 } 1088 } 1089 if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) { 1090 // In case we have a float on the last line, it might not be positioned up to now. 1091 // This has to be done before adding in the bottom border/padding, or the float will 1092 // include the padding incorrectly. -dwh 1093 if (checkForFloatsFromLastLine) { 1094 int bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); 1095 int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); 1096 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); 1097 m_lineBoxes.appendLineBox(trailingFloatsLineBox); 1098 trailingFloatsLineBox->setConstructed(); 1099 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 1100 VerticalPositionCache verticalPositionCache; 1101 trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache); 1102 int blockLogicalHeight = logicalHeight(); 1103 IntRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); 1104 IntRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); 1105 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); 1106 trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight()); 1107 } 1108 1109 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1110 FloatingObjectSetIterator it = floatingObjectSet.begin(); 1111 FloatingObjectSetIterator end = floatingObjectSet.end(); 1112 if (lastFloat) { 1113 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); 1114 ASSERT(lastFloatIterator != end); 1115 ++lastFloatIterator; 1116 it = lastFloatIterator; 1117 } 1118 for (; it != end; ++it) 1119 appendFloatingObjectToLastLine(*it); 1120 lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; 1121 } 1122 size_t floatCount = floats.size(); 1123 // Floats that did not have layout did not repaint when we laid them out. They would have 1124 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be 1125 // painted. 1126 for (size_t i = 0; i < floatCount; ++i) { 1127 if (!floats[i].everHadLayout) { 1128 RenderBox* f = floats[i].object; 1129 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout()) 1130 f->repaint(); 1131 } 1132 } 1140 layoutRunsAndFloats(fullLayout, hasInlineChild, floats, repaintLogicalTop, repaintLogicalBottom); 1133 1141 } 1134 1142 … … 1173 1181 if (floats[floatIndex].rect.size() != newSize) { 1174 1182 int floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x(); 1175 int floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) 1183 int floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) 1176 1184 : max(floats[floatIndex].rect.width(), newSize.width()); 1177 1185 floatHeight = min(floatHeight, numeric_limits<int>::max() - floatTop); … … 1204 1212 if (containsFloats() || !floats.isEmpty()) { 1205 1213 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout. 1206 fullLayout = true; 1214 fullLayout = true; 1207 1215 break; 1208 1216 } 1209 1217 1210 1218 if (!useRepaintBounds) 1211 1219 useRepaintBounds = true; 1212 1220 1213 1221 repaintLogicalTop = min(repaintLogicalTop, curr->logicalTopVisualOverflow() + min(paginationDelta, 0)); 1214 1222 repaintLogicalBottom = max(repaintLogicalBottom, curr->logicalBottomVisualOverflow() + max(paginationDelta, 0)); 1215 1223 curr->adjustBlockDirectionPosition(paginationDelta); 1216 } 1224 } 1217 1225 } 1218 1226 … … 1231 1239 if (firstRootBox()) { 1232 1240 RenderArena* arena = renderArena(); 1233 curr = firstRootBox(); 1241 curr = firstRootBox(); 1234 1242 while (curr) { 1235 1243 RootInlineBox* next = curr->nextRootBox(); … … 1440 1448 // FIXME: Right now, we only allow line boxes for inlines that are truly empty. 1441 1449 // We need to fix this, though, because at the very least, inlines containing only 1442 // ignorable whitespace should should also have line boxes. 1450 // ignorable whitespace should should also have line boxes. 1443 1451 return !flow->firstChild() && flow->hasInlineDirectionBordersPaddingOrMargin(); 1444 1452 } … … 1456 1464 1457 1465 UChar current = it.current(); 1458 return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) 1466 return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) 1459 1467 && !skipNonBreakingSpace(it, lineInfo); 1460 1468 } … … 1503 1511 } 1504 1512 1505 // This is currently just used for list markers and inline flows that have line boxes. Neither should 1506 // have an effect on whitespace at the start of the line. 1513 // This is currently just used for list markers and inline flows that have line boxes. Neither should 1514 // have an effect on whitespace at the start of the line. 1507 1515 static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState) 1508 1516 { … … 1736 1744 lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--; 1737 1745 1738 // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts 1746 // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts 1739 1747 // ignoring spaces. 1740 1748 size_t currentMidpoint = trailingSpaceMidpoint + 1; … … 1766 1774 } 1767 1775 1768 InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, LineBreakIteratorInfo& lineBreakIteratorInfo, 1776 InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, LineBreakIteratorInfo& lineBreakIteratorInfo, 1769 1777 bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedBoxes) 1770 1778 { … … 1785 1793 bool ignoringSpaces = false; 1786 1794 InlineIterator ignoreStart; 1787 1795 1788 1796 // This variable tracks whether the very last character we saw was a space. We use 1789 1797 // this to detect when we encounter a second space so we know we have to terminate … … 1810 1818 bool autoWrapWasEverTrueOnLine = false; 1811 1819 bool floatsFitOnLine = true; 1812 1820 1813 1821 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 1814 // very specific circumstances (in order to match common WinIE renderings). 1815 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 1822 // very specific circumstances (in order to match common WinIE renderings). 1823 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 1816 1824 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto(); 1817 1825 … … 1823 1831 currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace(); 1824 1832 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace(); 1825 1833 1826 1834 bool autoWrap = RenderStyle::autoWrap(currWS); 1827 1835 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap; … … 1834 1842 1835 1843 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS); 1836 1844 1837 1845 if (o->isBR()) { 1838 1846 if (width.fitsOnLine()) { … … 1884 1892 box->layer()->setStaticBlockPosition(logicalHeight()); 1885 1893 } 1886 1894 1887 1895 // If we're ignoring spaces, we have to stop and include this object and 1888 1896 // then start ignoring spaces again. … … 1901 1909 // Right now, we should only encounter empty inlines here. 1902 1910 ASSERT(!o->firstChild()); 1903 1911 1904 1912 RenderInline* flowBox = toRenderInline(o); 1905 1906 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need 1907 // to make sure that we stop to include this object and then start ignoring spaces again. 1908 // If this object is at the start of the line, we need to behave like list markers and 1913 1914 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need 1915 // to make sure that we stop to include this object and then start ignoring spaces again. 1916 // If this object is at the start of the line, we need to behave like list markers and 1909 1917 // start ignoring spaces. 1910 1918 if (inlineFlowRequiresLineBox(flowBox)) { … … 1916 1924 } else if (style()->collapseWhiteSpace() && resolver.position().m_obj == o 1917 1925 && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { 1918 // Like with list markers, we start ignoring spaces to make sure that any 1926 // Like with list markers, we start ignoring spaces to make sure that any 1919 1927 // additional spaces we see will be discarded. 1920 1928 currentCharacterIsSpace = true; … … 1948 1956 if (o->isListMarker()) { 1949 1957 if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { 1950 // Like with inline flows, we start ignoring spaces to make sure that any 1958 // Like with inline flows, we start ignoring spaces to make sure that any 1951 1959 // additional spaces we see will be discarded. 1952 1960 currentCharacterIsSpace = true; … … 2022 2030 2023 2031 bool applyWordSpacing = false; 2024 2032 2025 2033 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace); 2026 2034 … … 2067 2075 appliedStartWidth = true; 2068 2076 } 2069 2077 2070 2078 applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace; 2071 2079 … … 2080 2088 float charWidth = textWidth(t, pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); 2081 2089 // Check if line is too big even without the extra space 2082 // at the end of the line. If it is not, do nothing. 2083 // If the line needs the extra whitespace to be too long, 2084 // then move the line break to the space and skip all 2090 // at the end of the line. If it is not, do nothing. 2091 // If the line needs the extra whitespace to be too long, 2092 // then move the line break to the space and skip all 2085 2093 // additional whitespace. 2086 2094 if (!width.fitsOnLine(charWidth)) { … … 2139 2147 breakWords = false; 2140 2148 } 2141 2149 2142 2150 if (midWordBreak) { 2143 2151 // Remember this as a breakable position in case … … 2151 2159 lastSpace = pos; 2152 2160 } 2153 2161 2154 2162 if (!ignoringSpaces && o->style()->collapseWhiteSpace()) { 2155 2163 // If we encounter a newline, or if we encounter a … … 2158 2166 if (currentCharacterIsSpace && previousCharacterIsSpace) { 2159 2167 ignoringSpaces = true; 2160 2168 2161 2169 // We just entered a mode where we are ignoring 2162 2170 // spaces. Create a midpoint to terminate the run 2163 // before the second space. 2171 // before the second space. 2164 2172 addMidpoint(lineMidpointState, ignoreStart); 2165 2173 } … … 2193 2201 lBreak.moveTo(o, pos, nextBreakable); 2194 2202 } 2195 2203 2196 2204 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces) 2197 2205 trailingObjects.setTrailingWhitespace(static_cast<RenderText*>(o)); … … 2285 2293 if (!collapseWhiteSpace) 2286 2294 currentCharacterIsSpace = false; 2287 2295 2288 2296 pos = 0; 2289 2297 atStart = false; 2290 2298 } 2291 2299 2292 2300 if (width.fitsOnLine() || lastWS == NOWRAP) 2293 2301 lBreak.clear();
Note: See TracChangeset
for help on using the changeset viewer.