Changeset 159354 in webkit
- Timestamp:
- Nov 15, 2013 1:40:59 PM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 added
- 8 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/CMakeLists.txt
r159268 r159354 77 77 "${WEBCORE_DIR}/plugins" 78 78 "${WEBCORE_DIR}/rendering" 79 "${WEBCORE_DIR}/rendering/line" 79 80 "${WEBCORE_DIR}/rendering/mathml" 80 81 "${WEBCORE_DIR}/rendering/shapes" … … 2210 2211 rendering/break_lines.cpp 2211 2212 2213 rendering/line/LineBreaker.cpp 2214 rendering/line/LineInfo.cpp 2215 2212 2216 rendering/mathml/RenderMathMLBlock.cpp 2213 2217 rendering/mathml/RenderMathMLFenced.cpp -
trunk/Source/WebCore/ChangeLog
r159353 r159354 1 2013-11-15 Zoltan Horvath <zoltan@webkit.org> 2 3 Move BreakingContext and LineBreaker into their own files 4 <https://webkit.org/b/124336> 5 6 Reviewed by David Hyatt. 7 8 In this change I introduced 'line' subdirectory inside 'rendering', this directory will contain all the classes 9 which have been refactored from RenderBlockLineLayout.cpp. This change contains the separation of BreakingContext, 10 and the separation of LineBreaker classes. Since I wanted to keep the helper functions organized, I also added a 11 new file called LineInlineHeaders.h, which contains the functions which used in LineBreaker.h and BreakingContext.h. 12 I moved LineInfo class into line directory. It was necessary this time, since I added a cpp for it. I'll move the 13 rest of the line layout related helper classes later. (I wanted to minimize merge conflicts.) 14 15 No new tests, no behavior change. 16 17 * CMakeLists.txt: 18 * GNUmakefile.am: 19 * GNUmakefile.list.am: 20 * WebCore.vcxproj/WebCore.vcxproj: 21 * WebCore.vcxproj/WebCoreCommon.props: 22 * WebCore.xcodeproj/project.pbxproj: 23 * rendering/RenderBlockLineLayout.cpp: 24 (WebCore::createRun): 25 * rendering/line/BreakingContextInlineHeaders.h: Added. 26 (WebCore::WordMeasurement::WordMeasurement): 27 (WebCore::TrailingObjects::TrailingObjects): 28 (WebCore::TrailingObjects::setTrailingWhitespace): 29 (WebCore::TrailingObjects::clear): 30 (WebCore::TrailingObjects::appendBoxIfNeeded): 31 (WebCore::deprecatedAddMidpoint): 32 (WebCore::startIgnoringSpaces): 33 (WebCore::stopIgnoringSpaces): 34 (WebCore::ensureLineBoxInsideIgnoredSpaces): 35 (WebCore::TrailingObjects::updateMidpointsForTrailingBoxes): 36 (WebCore::BreakingContext::BreakingContext): 37 (WebCore::BreakingContext::currentObject): 38 (WebCore::BreakingContext::lineBreak): 39 (WebCore::BreakingContext::lineBreakRef): 40 (WebCore::BreakingContext::lineWidth): 41 (WebCore::BreakingContext::atEnd): 42 (WebCore::BreakingContext::clearLineBreakIfFitsOnLine): 43 (WebCore::BreakingContext::commitLineBreakAtCurrentWidth): 44 (WebCore::BreakingContext::initializeForCurrentObject): 45 (WebCore::BreakingContext::increment): 46 (WebCore::BreakingContext::handleBR): 47 (WebCore::borderPaddingMarginStart): 48 (WebCore::borderPaddingMarginEnd): 49 (WebCore::shouldAddBorderPaddingMargin): 50 (WebCore::previousInFlowSibling): 51 (WebCore::inlineLogicalWidth): 52 (WebCore::BreakingContext::handleOutOfFlowPositioned): 53 (WebCore::BreakingContext::handleFloat): 54 (WebCore::shouldSkipWhitespaceAfterStartObject): 55 (WebCore::BreakingContext::handleEmptyInline): 56 (WebCore::BreakingContext::handleReplaced): 57 (WebCore::firstPositiveWidth): 58 (WebCore::updateSegmentsForShapes): 59 (WebCore::iteratorIsBeyondEndOfRenderCombineText): 60 (WebCore::nextCharacter): 61 (WebCore::updateCounterIfNeeded): 62 (WebCore::measureHyphenWidth): 63 (WebCore::textWidth): 64 (WebCore::ensureCharacterGetsLineBox): 65 (WebCore::tryHyphenating): 66 (WebCore::BreakingContext::handleText): 67 (WebCore::textBeginsWithBreakablePosition): 68 (WebCore::BreakingContext::canBreakAtThisPosition): 69 (WebCore::BreakingContext::commitAndUpdateLineBreakIfNeeded): 70 (WebCore::checkMidpoints): 71 (WebCore::BreakingContext::handleEndOfLine): 72 * rendering/line/LineBreaker.cpp: Added. 73 (WebCore::LineBreaker::reset): 74 (WebCore::LineBreaker::skipTrailingWhitespace): 75 (WebCore::LineBreaker::skipLeadingWhitespace): 76 * rendering/line/LineBreaker.h: Added. 77 (WebCore::LineBreaker::LineBreaker): 78 (WebCore::LineBreaker::lineWasHyphenated): 79 (WebCore::LineBreaker::positionedObjects): 80 (WebCore::LineBreaker::clear): 81 * rendering/line/LineInfo.cpp: Added. 82 (WebCore::LineInfo::setEmpty): 83 * rendering/line/LineInfo.h: Renamed from Source/WebCore/rendering/LineInfo.h. 84 (WebCore::LineInfo::LineInfo): 85 (WebCore::LineInfo::isFirstLine): 86 (WebCore::LineInfo::isLastLine): 87 (WebCore::LineInfo::isEmpty): 88 (WebCore::LineInfo::previousLineBrokeCleanly): 89 (WebCore::LineInfo::floatPaginationStrut): 90 (WebCore::LineInfo::runsFromLeadingWhitespace): 91 (WebCore::LineInfo::resetRunsFromLeadingWhitespace): 92 (WebCore::LineInfo::incrementRunsFromLeadingWhitespace): 93 (WebCore::LineInfo::setFirstLine): 94 (WebCore::LineInfo::setLastLine): 95 (WebCore::LineInfo::setPreviousLineBrokeCleanly): 96 (WebCore::LineInfo::setFloatPaginationStrut): 97 * rendering/line/LineInlineHeaders.h: Added. 98 (WebCore::hasInlineDirectionBordersPaddingOrMargin): 99 (WebCore::lineStyle): 100 (WebCore::requiresLineBoxForContent): 101 (WebCore::shouldCollapseWhiteSpace): 102 (WebCore::skipNonBreakingSpace): 103 (WebCore::alwaysRequiresLineBox): 104 (WebCore::requiresLineBox): 105 (WebCore::setStaticPositions): 106 1 107 2013-11-15 Brady Eidson <beidson@apple.com> 2 108 -
trunk/Source/WebCore/GNUmakefile.am
r159335 r159354 92 92 -I$(srcdir)/Source/WebCore/plugins/win \ 93 93 -I$(srcdir)/Source/WebCore/rendering \ 94 -I$(srcdir)/Source/WebCore/rendering/line \ 94 95 -I$(srcdir)/Source/WebCore/rendering/mathml \ 95 96 -I$(srcdir)/Source/WebCore/rendering/shapes \ -
trunk/Source/WebCore/GNUmakefile.list.am
r159349 r159354 4302 4302 Source/WebCore/rendering/LayoutRepainter.h \ 4303 4303 Source/WebCore/rendering/LayoutRepainter.cpp \ 4304 Source/WebCore/rendering/LineInfo.h \4305 4304 Source/WebCore/rendering/LineLayoutState.h \ 4306 4305 Source/WebCore/rendering/LineWidth.h \ … … 4507 4506 Source/WebCore/rendering/TextPaintStyle.h \ 4508 4507 Source/WebCore/rendering/VerticalPositionCache.h \ 4508 Source/WebCore/rendering/line/BreakingContextInlineHeaders.h \ 4509 Source/WebCore/rendering/line/LineInfo.h \ 4510 Source/WebCore/rendering/line/LineInfo.cpp \ 4511 Source/WebCore/rendering/line/LineBreaker.h \ 4512 Source/WebCore/rendering/line/LineBreaker.cpp \ 4513 Source/WebCore/rendering/line/LineInlineHeaders.h \ 4509 4514 Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp \ 4510 4515 Source/WebCore/rendering/mathml/RenderMathMLBlock.h \ -
trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
r159349 r159354 11051 11051 <ClCompile Include="..\rendering\SimpleLineLayoutFunctions.cpp" /> 11052 11052 <ClCompile Include="..\rendering\TextPaintStyle.cpp" /> 11053 <ClCompile Include="..\rendering\line\LineBreaker.cpp" /> 11054 <ClCompile Include="..\rendering\line\LineInfo.cpp" /> 11053 11055 <ClCompile Include="..\rendering\shapes\PolygonShape.cpp" /> 11054 11056 <ClCompile Include="..\rendering\shapes\RasterShape.cpp" /> … … 19780 19782 <ClInclude Include="..\rendering\LayoutRepainter.h" /> 19781 19783 <ClInclude Include="..\rendering\LayoutState.h" /> 19782 <ClInclude Include="..\rendering\LineInfo.h" />19783 19784 <ClInclude Include="..\rendering\LineLayoutState.h" /> 19784 19785 <ClInclude Include="..\rendering\LineWidth.h" /> … … 19855 19856 <ClInclude Include="..\rendering\RenderSlider.h" /> 19856 19857 <ClInclude Include="..\rendering\RenderSnapshottedPlugIn.h" /> 19858 <ClInclude Include="..\rendering\line\BreakingContextInlineHeaders.h" /> 19859 <ClInclude Include="..\rendering\line\LineBreaker.h" /> 19860 <ClInclude Include="..\rendering\line\LineInfo.h" /> 19861 <ClInclude Include="..\rendering\line\LineInlineHeaders.h" /> 19857 19862 <ClInclude Include="..\rendering\shapes\PolygonShape.h" /> 19858 19863 <ClInclude Include="..\rendering\shapes\RasterShape.h" /> -
trunk/Source/WebCore/WebCore.vcxproj/WebCoreCommon.props
r157432 r159354 8 8 <ItemDefinitionGroup> 9 9 <ClCompile> 10 <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\Modules\mediacontrols;$(ProjectDir)..\Modules\mediastream;$(ProjectDir)..\Modules\filesystem;$(ProjectDir)..\Modules\geolocation;$(ProjectDir)..\Modules\indexeddb;$(ProjectDir)..\Modules\mediasource;$(ProjectDir)..\Modules\navigatorcontentutils;$(ProjectDir)..\Modules\speech;$(ProjectDir)..\Modules\proximity;$(ProjectDir)..\Modules\quota;$(ProjectDir)..\Modules\notifications;$(ProjectDir)..\Modules\webdatabase;$(ProjectDir)..\Modules\websockets;$(ProjectDir)..\accessibility;$(ProjectDir)..\accessibility\win;$(ProjectDir)..\bridge;$(ProjectDir)..\bridge\c;$(ProjectDir)..\bridge\jsc;$(ProjectDir)..\css;$(ProjectDir)..\editing;$(ProjectDir)..\fileapi;$(ProjectDir)..\rendering;$(ProjectDir)..\rendering\ mathml;$(ProjectDir)..\rendering\shapes;$(ProjectDir)..\rendering\style;$(ProjectDir)..\rendering\svg;$(ProjectDir)..\bindings;$(ProjectDir)..\bindings\generic;$(ProjectDir)..\bindings\js;$(ProjectDir)..\bindings\js\specialization;$(ProjectDir)..\dom;$(ProjectDir)..\dom\default;$(ProjectDir)..\history;$(ProjectDir)..\html;$(ProjectDir)..\html\canvas;$(ProjectDir)..\html\forms;$(ProjectDir)..\html\parser;$(ProjectDir)..\html\shadow;$(ProjectDir)..\html\track;$(ProjectDir)..\inspector;$(ProjectDir)..\loader;$(ProjectDir)..\loader\appcache;$(ProjectDir)..\loader\archive;$(ProjectDir)..\loader\archive\cf;$(ProjectDir)..\loader\cache;$(ProjectDir)..\loader\icon;$(ProjectDir)..\mathml;$(ProjectDir)..\page;$(ProjectDir)..\page\animation;$(ProjectDir)..\page\scrolling;$(ProjectDir)..\page\win;$(ProjectDir)..\platform;$(ProjectDir)..\platform\animation;$(ProjectDir)..\platform\mock;$(ProjectDir)..\platform\sql;$(ProjectDir)..\platform\win;$(ProjectDir)..\platform\network;$(ProjectDir)..\platform\network\win;$(ProjectDir)..\platform\cf;$(ProjectDir)..\platform\graphics;$(ProjectDir)..\platform\graphics\ca;$(ProjectDir)..\platform\graphics\cpu\arm\filters;$(ProjectDir)..\platform\graphics\filters;$(ProjectDir)..\platform\graphics\filters\arm;$(ProjectDir)..\platform\graphics\opentype;$(ProjectDir)..\platform\graphics\transforms;$(ProjectDir)..\platform\text;$(ProjectDir)..\platform\text\transcoder;$(ProjectDir)..\platform\graphics\win;$(ProjectDir)..\xml;$(ProjectDir)..\xml\parser;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources;$(ProjectDir)..\plugins;$(ProjectDir)..\plugins\win;$(ProjectDir)..\svg\animation;$(ProjectDir)..\svg\graphics;$(ProjectDir)..\svg\properties;$(ProjectDir)..\svg\graphics\filters;$(ProjectDir)..\svg;$(ProjectDir)..\testing;$(ProjectDir)..\crypto;$(ProjectDir)..\wml;$(ProjectDir)..\storage;$(ProjectDir)..\style;$(ProjectDir)..\websockets;$(ProjectDir)..\workers;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ProjectDir)..\ForwardingHeaders;$(ProjectDir)..\platform\graphics\gpu;$(ProjectDir)..\platform\graphics\egl;$(ProjectDir)..\platform\graphics\surfaces;$(ProjectDir)..\platform\graphics\surfaces\egl;$(ProjectDir)..\platform\graphics\opengl;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;$(WebKit_Libraries)\include\private\JavaScriptCore;$(WebKit_Libraries)\include\sqlite;$(WebKit_Libraries)\include\JavaScriptCore;$(WebKit_Libraries)\include\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>10 <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\Modules\mediacontrols;$(ProjectDir)..\Modules\mediastream;$(ProjectDir)..\Modules\filesystem;$(ProjectDir)..\Modules\geolocation;$(ProjectDir)..\Modules\indexeddb;$(ProjectDir)..\Modules\mediasource;$(ProjectDir)..\Modules\navigatorcontentutils;$(ProjectDir)..\Modules\speech;$(ProjectDir)..\Modules\proximity;$(ProjectDir)..\Modules\quota;$(ProjectDir)..\Modules\notifications;$(ProjectDir)..\Modules\webdatabase;$(ProjectDir)..\Modules\websockets;$(ProjectDir)..\accessibility;$(ProjectDir)..\accessibility\win;$(ProjectDir)..\bridge;$(ProjectDir)..\bridge\c;$(ProjectDir)..\bridge\jsc;$(ProjectDir)..\css;$(ProjectDir)..\editing;$(ProjectDir)..\fileapi;$(ProjectDir)..\rendering;$(ProjectDir)..\rendering\line;$(ProjectDir)..\rendering\mathml;$(ProjectDir)..\rendering\shapes;$(ProjectDir)..\rendering\style;$(ProjectDir)..\rendering\svg;$(ProjectDir)..\bindings;$(ProjectDir)..\bindings\generic;$(ProjectDir)..\bindings\js;$(ProjectDir)..\bindings\js\specialization;$(ProjectDir)..\dom;$(ProjectDir)..\dom\default;$(ProjectDir)..\history;$(ProjectDir)..\html;$(ProjectDir)..\html\canvas;$(ProjectDir)..\html\forms;$(ProjectDir)..\html\parser;$(ProjectDir)..\html\shadow;$(ProjectDir)..\html\track;$(ProjectDir)..\inspector;$(ProjectDir)..\loader;$(ProjectDir)..\loader\appcache;$(ProjectDir)..\loader\archive;$(ProjectDir)..\loader\archive\cf;$(ProjectDir)..\loader\cache;$(ProjectDir)..\loader\icon;$(ProjectDir)..\mathml;$(ProjectDir)..\page;$(ProjectDir)..\page\animation;$(ProjectDir)..\page\scrolling;$(ProjectDir)..\page\win;$(ProjectDir)..\platform;$(ProjectDir)..\platform\animation;$(ProjectDir)..\platform\mock;$(ProjectDir)..\platform\sql;$(ProjectDir)..\platform\win;$(ProjectDir)..\platform\network;$(ProjectDir)..\platform\network\win;$(ProjectDir)..\platform\cf;$(ProjectDir)..\platform\graphics;$(ProjectDir)..\platform\graphics\ca;$(ProjectDir)..\platform\graphics\cpu\arm\filters;$(ProjectDir)..\platform\graphics\filters;$(ProjectDir)..\platform\graphics\filters\arm;$(ProjectDir)..\platform\graphics\opentype;$(ProjectDir)..\platform\graphics\transforms;$(ProjectDir)..\platform\text;$(ProjectDir)..\platform\text\transcoder;$(ProjectDir)..\platform\graphics\win;$(ProjectDir)..\xml;$(ProjectDir)..\xml\parser;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources;$(ProjectDir)..\plugins;$(ProjectDir)..\plugins\win;$(ProjectDir)..\svg\animation;$(ProjectDir)..\svg\graphics;$(ProjectDir)..\svg\properties;$(ProjectDir)..\svg\graphics\filters;$(ProjectDir)..\svg;$(ProjectDir)..\testing;$(ProjectDir)..\crypto;$(ProjectDir)..\wml;$(ProjectDir)..\storage;$(ProjectDir)..\style;$(ProjectDir)..\websockets;$(ProjectDir)..\workers;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ProjectDir)..\ForwardingHeaders;$(ProjectDir)..\platform\graphics\gpu;$(ProjectDir)..\platform\graphics\egl;$(ProjectDir)..\platform\graphics\surfaces;$(ProjectDir)..\platform\graphics\surfaces\egl;$(ProjectDir)..\platform\graphics\opengl;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;$(WebKit_Libraries)\include\private\JavaScriptCore;$(WebKit_Libraries)\include\sqlite;$(WebKit_Libraries)\include\JavaScriptCore;$(WebKit_Libraries)\include\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 11 11 <PreprocessorDefinitions>DISABLE_3D_RENDERING;WEBCORE_CONTEXT_MENUS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 12 12 <PrecompiledHeader>Use</PrecompiledHeader> -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r159353 r159354 3438 3438 A024575116CEAA27000E5671 /* EXTDrawBuffers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A024574E16CEAA27000E5671 /* EXTDrawBuffers.cpp */; }; 3439 3439 A024575216CEAA27000E5671 /* EXTDrawBuffers.h in Headers */ = {isa = PBXBuildFile; fileRef = A024574F16CEAA27000E5671 /* EXTDrawBuffers.h */; }; 3440 A06BFE2E17DFB43F008302BB /* LineInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = A06BFE2C17DFB433008302BB /* LineInfo.h */; };3441 3440 A07D3355152B630E001B6393 /* JSWebGLShaderPrecisionFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A07D3353152B630E001B6393 /* JSWebGLShaderPrecisionFormat.cpp */; }; 3442 3441 A07D3356152B630E001B6393 /* JSWebGLShaderPrecisionFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = A07D3354152B630E001B6393 /* JSWebGLShaderPrecisionFormat.h */; }; … … 6300 6299 FF945ECB161F7F3600971BC8 /* PseudoElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF945EC9161F7F3600971BC8 /* PseudoElement.cpp */; }; 6301 6300 FF945ECC161F7F3600971BC8 /* PseudoElement.h in Headers */ = {isa = PBXBuildFile; fileRef = FF945ECA161F7F3600971BC8 /* PseudoElement.h */; }; 6301 FFB698CC1833EE0D00158A31 /* LineBreaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFB698CA1833EC3800158A31 /* LineBreaker.cpp */; }; 6302 FFB698CF183402BB00158A31 /* LineInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFB698CD1833F17600158A31 /* LineInfo.cpp */; }; 6302 6303 FFD5B97A135CC97800D5E92A /* PageVisibilityState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */; }; 6303 6304 FFD5B97B135CC97800D5E92A /* PageVisibilityState.h in Headers */ = {isa = PBXBuildFile; fileRef = FFD5B978135CC97800D5E92A /* PageVisibilityState.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 10207 10208 A024574F16CEAA27000E5671 /* EXTDrawBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EXTDrawBuffers.h; path = canvas/EXTDrawBuffers.h; sourceTree = "<group>"; }; 10208 10209 A024575016CEAA27000E5671 /* EXTDrawBuffers.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = EXTDrawBuffers.idl; path = canvas/EXTDrawBuffers.idl; sourceTree = "<group>"; }; 10209 A06BFE2C17DFB433008302BB /* LineInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineInfo.h; sourceTree = "<group>"; };10210 10210 A0718BE817E26F1600F6BF44 /* LineLayoutState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineLayoutState.h; sourceTree = "<group>"; }; 10211 10211 A07D3353152B630E001B6393 /* JSWebGLShaderPrecisionFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLShaderPrecisionFormat.cpp; sourceTree = "<group>"; }; … … 13473 13473 FF945EC9161F7F3600971BC8 /* PseudoElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoElement.cpp; sourceTree = "<group>"; }; 13474 13474 FF945ECA161F7F3600971BC8 /* PseudoElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoElement.h; sourceTree = "<group>"; }; 13475 FFB698C91832F10B00158A31 /* BreakingContextInlineHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakingContextInlineHeaders.h; sourceTree = "<group>"; }; 13476 FFB698CA1833EC3800158A31 /* LineBreaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LineBreaker.cpp; sourceTree = "<group>"; }; 13477 FFB698CB1833EC3800158A31 /* LineBreaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineBreaker.h; sourceTree = "<group>"; }; 13478 FFB698CD1833F17600158A31 /* LineInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LineInfo.cpp; sourceTree = "<group>"; }; 13479 FFB698CE1833F17600158A31 /* LineInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineInfo.h; sourceTree = "<group>"; }; 13475 13480 FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageVisibilityState.cpp; sourceTree = "<group>"; }; 13476 13481 FFD5B978135CC97800D5E92A /* PageVisibilityState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageVisibilityState.h; sourceTree = "<group>"; }; … … 20902 20907 isa = PBXGroup; 20903 20908 children = ( 20909 FFB698C81832F10B00158A31 /* line */, 20904 20910 CDE7FC42181904B1002BBB77 /* OrderIterator.cpp */, 20905 20911 CDE7FC43181904B1002BBB77 /* OrderIterator.h */, … … 20950 20956 2D9066040BE141D400956998 /* LayoutState.cpp */, 20951 20957 2D9066050BE141D400956998 /* LayoutState.h */, 20952 A06BFE2C17DFB433008302BB /* LineInfo.h */,20953 20958 A0718BE817E26F1600F6BF44 /* LineLayoutState.h */, 20954 20959 A0CB002317DF81AC0017896B /* LineWidth.cpp */, … … 21888 21893 ); 21889 21894 name = WebAudio; 21895 sourceTree = "<group>"; 21896 }; 21897 FFB698C81832F10B00158A31 /* line */ = { 21898 isa = PBXGroup; 21899 children = ( 21900 FFB698CD1833F17600158A31 /* LineInfo.cpp */, 21901 FFB698CE1833F17600158A31 /* LineInfo.h */, 21902 FFB698CA1833EC3800158A31 /* LineBreaker.cpp */, 21903 FFB698CB1833EC3800158A31 /* LineBreaker.h */, 21904 FFB698C91832F10B00158A31 /* BreakingContextInlineHeaders.h */, 21905 ); 21906 path = line; 21890 21907 sourceTree = "<group>"; 21891 21908 }; … … 25183 25200 BC10D76817D8EE71005E2626 /* RenderBlockFlow.h in Headers */, 25184 25201 A0CB002517DF826C0017896B /* LineWidth.h in Headers */, 25185 A06BFE2E17DFB43F008302BB /* LineInfo.h in Headers */,25186 25202 CD3E251C18046B0600E27F56 /* GridCoordinate.h in Headers */, 25187 25203 CD3E252418046BCD00E27F56 /* CSSGridTemplateValue.h in Headers */, … … 25768 25784 A80E6D050A1989CA007FB8C5 /* CSSPrimitiveValue.cpp in Sources */, 25769 25785 A80E6CF70A1989CA007FB8C5 /* CSSProperty.cpp in Sources */, 25786 FFB698CC1833EE0D00158A31 /* LineBreaker.cpp in Sources */, 25770 25787 78D02BC5154A18DF00B62D05 /* CSSPropertyAnimation.cpp in Sources */, 25771 25788 1ABA76CA11D20E50004C201C /* CSSPropertyNames.cpp in Sources */, … … 26574 26591 9392262F10321084006E7D5D /* JSCSSRuleListCustom.cpp in Sources */, 26575 26592 142011B60A003133008303F9 /* JSCSSStyleDeclaration.cpp in Sources */, 26593 FFB698CF183402BB00158A31 /* LineInfo.cpp in Sources */, 26576 26594 BC5825F30C0B89380053F1B5 /* JSCSSStyleDeclarationCustom.cpp in Sources */, 26577 26595 BC46C2060C0DDCA10020CFC3 /* JSCSSStyleRule.cpp in Sources */, -
trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp
r159347 r159354 4 4 * Copyright (C) 2010 Google Inc. All rights reserved. 5 5 * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com> 6 * Copyright (C) 2013 Adobe Systems Inc. All right reserved. 6 7 * 7 8 * This library is free software; you can redistribute it and/or … … 26 27 #include "AXObjectCache.h" 27 28 #include "BidiResolver.h" 29 #include "BreakingContextInlineHeaders.h" 28 30 #include "FloatingObjects.h" 29 #include "Hyphenation.h"30 31 #include "InlineElementBox.h" 31 32 #include "InlineIterator.h" 32 33 #include "InlineTextBox.h" 33 #include "LineInfo.h"34 34 #include "LineLayoutState.h" 35 35 #include "Logging.h" 36 36 #include "RenderBlockFlow.h" 37 #include "RenderCombineText.h"38 #include "RenderCounter.h"39 37 #include "RenderFlowThread.h" 40 #include "RenderInline.h"41 #include "RenderLayer.h"42 38 #include "RenderLineBreak.h" 43 #include "RenderListMarker.h"44 39 #include "RenderRegion.h" 45 #include "RenderRubyRun.h"46 40 #include "RenderView.h" 47 41 #include "Settings.h" … … 49 43 #include "TrailingFloatsRootInlineBox.h" 50 44 #include "VerticalPositionCache.h" 51 #include "break_lines.h"52 45 #include <wtf/RefCountedLeakCounter.h> 53 46 #include <wtf/StdLibExtras.h> 54 #include <wtf/Vector.h>55 #include <wtf/unicode/CharacterNames.h>56 57 #if ENABLE(CSS_SHAPES)58 #include "ShapeInsideInfo.h"59 #endif60 47 61 48 #if ENABLE(SVG) 62 #include "RenderSVGInlineText.h"63 49 #include "SVGRootInlineBox.h" 64 50 #endif 65 51 66 using namespace WTF;67 using namespace Unicode;68 69 52 namespace WebCore { 70 71 // We don't let our line box tree for a single line get any deeper than this.72 const unsigned cMaxLineDepth = 200;73 74 struct RenderTextInfo {75 // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.76 RenderTextInfo();77 ~RenderTextInfo();78 79 RenderText* m_text;80 OwnPtr<TextLayout> m_layout;81 LazyLineBreakIterator m_lineBreakIterator;82 const Font* m_font;83 };84 85 class LineBreaker {86 public:87 friend class BreakingContext;88 LineBreaker(RenderBlockFlow& block)89 : m_block(block)90 {91 reset();92 }93 94 InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);95 96 bool lineWasHyphenated() { return m_hyphenated; }97 const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; }98 EClear clear() { return m_clear; }99 100 private:101 void reset();102 103 InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);104 void skipTrailingWhitespace(InlineIterator&, const LineInfo&);105 void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&);106 107 RenderBlockFlow& m_block;108 bool m_hyphenated;109 EClear m_clear;110 Vector<RenderBox*> m_positionedObjects;111 };112 113 static inline LayoutUnit borderPaddingMarginStart(const RenderInline& child)114 {115 return child.marginStart() + child.paddingStart() + child.borderStart();116 }117 118 static inline LayoutUnit borderPaddingMarginEnd(const RenderInline& child)119 {120 return child.marginEnd() + child.paddingEnd() + child.borderEnd();121 }122 123 static inline bool shouldAddBorderPaddingMargin(RenderObject* child)124 {125 // When deciding whether we're at the edge of an inline, adjacent collapsed whitespace is the same as no sibling at all.126 return !child || (child->isText() && !toRenderText(child)->textLength());127 }128 129 static RenderObject* previousInFlowSibling(RenderObject* child)130 {131 child = child->previousSibling();132 while (child && child->isOutOfFlowPositioned())133 child = child->previousSibling();134 return child;135 }136 137 static LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge = true, bool checkEndEdge = true)138 {139 unsigned lineDepth = 1;140 LayoutUnit extraWidth = 0;141 RenderElement* parent = child->parent();142 while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {143 const RenderInline& parentAsRenderInline = toRenderInline(*parent);144 if (!isEmptyInline(parentAsRenderInline)) {145 checkStartEdge = checkStartEdge && shouldAddBorderPaddingMargin(previousInFlowSibling(child));146 if (checkStartEdge)147 extraWidth += borderPaddingMarginStart(parentAsRenderInline);148 checkEndEdge = checkEndEdge && shouldAddBorderPaddingMargin(child->nextSibling());149 if (checkEndEdge)150 extraWidth += borderPaddingMarginEnd(parentAsRenderInline);151 if (!checkStartEdge && !checkEndEdge)152 return extraWidth;153 }154 child = parent;155 parent = child->parent();156 }157 return extraWidth;158 }159 53 160 54 static void determineDirectionality(TextDirection& dir, InlineIterator iter) … … 178 72 } 179 73 180 static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak) 181 { 182 // Check to see if our last midpoint is a start point beyond the line break. If so, 183 // shave it off the list, and shave off a trailing space if the previous end point doesn't 184 // preserve whitespace. 185 if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) { 186 InlineIterator* midpoints = lineMidpointState.midpoints.data(); 187 InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2]; 188 const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1]; 189 InlineIterator currpoint = endpoint; 190 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) 191 currpoint.increment(); 192 if (currpoint == lBreak) { 193 // We hit the line break before the start point. Shave off the start point. 194 lineMidpointState.numMidpoints--; 195 if (endpoint.m_obj->style().collapseWhiteSpace() && endpoint.m_obj->isText()) 196 endpoint.m_pos--; 197 } 198 } 199 } 200 201 // Don't call this directly. Use one of the descriptive helper functions below. 202 static void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) 203 { 204 if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints) 205 lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10); 206 207 InlineIterator* midpoints = lineMidpointState.midpoints.data(); 208 midpoints[lineMidpointState.numMidpoints++] = midpoint; 209 } 210 211 static inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) 212 { 213 ASSERT(!(lineMidpointState.numMidpoints % 2)); 214 deprecatedAddMidpoint(lineMidpointState, midpoint); 215 } 216 217 static inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) 218 { 219 ASSERT(lineMidpointState.numMidpoints % 2); 220 deprecatedAddMidpoint(lineMidpointState, midpoint); 221 } 222 223 // When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or 224 // hard line breaks to ensure that they're not ignored. 225 static inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer) 226 { 227 InlineIterator midpoint(0, renderer, 0); 228 stopIgnoringSpaces(lineMidpointState, midpoint); 229 startIgnoringSpaces(lineMidpointState, midpoint); 230 } 231 232 // Adding a pair of midpoints before a character will split it out into a new line box. 233 static inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator) 234 { 235 InlineIterator midpoint(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos); 236 startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos - 1)); 237 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos)); 238 } 239 240 static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) 74 inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) 241 75 { 242 76 ASSERT(obj); … … 304 138 } 305 139 306 307 140 static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) 308 141 { … … 328 161 329 162 return toRenderInline(obj)->createAndAppendInlineFlowBox(); 330 }331 332 // FIXME: Don't let counters mark themselves as needing pref width recalcs during layout333 // so we don't need this hack.334 static inline void updateCounterIfNeeded(RenderText& renderText)335 {336 if (!renderText.preferredLogicalWidthsDirty() || !renderText.isCounter())337 return;338 toRenderCounter(renderText).updateCounter();339 163 } 340 164 … … 604 428 setMarginStartForChild(renderer, -startOverhang); 605 429 setMarginEndForChild(renderer, -endOverhang); 606 }607 608 static inline float measureHyphenWidth(RenderText* renderer, const Font& font, HashSet<const SimpleFontData*>* fallbackFonts = 0)609 {610 const RenderStyle& style = renderer->style();611 return font.width(RenderBlock::constructTextRun(renderer, font, style.hyphenString().string(), style), fallbackFonts);612 }613 614 class WordMeasurement {615 public:616 WordMeasurement()617 : renderer(0)618 , width(0)619 , startOffset(0)620 , endOffset(0)621 {622 }623 624 RenderText* renderer;625 float width;626 int startOffset;627 int endOffset;628 HashSet<const SimpleFontData*> fallbackFonts;629 };630 631 static inline const RenderStyle& lineStyle(const RenderElement& renderer, const LineInfo& lineInfo)632 {633 return lineInfo.isFirstLine() ? renderer.firstLineStyle() : renderer.style();634 430 } 635 431 … … 998 794 } 999 795 1000 1001 static void setStaticPositions(RenderBlockFlow& block, RenderBox& child)1002 {1003 // FIXME: The math here is actually not really right. It's a best-guess approximation that1004 // will work for the common cases1005 RenderElement* containerBlock = child.container();1006 LayoutUnit blockHeight = block.logicalHeight();1007 if (containerBlock->isRenderInline()) {1008 // A relative positioned inline encloses us. In this case, we also have to determine our1009 // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned1010 // inline so that we can obtain the value later.1011 toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block.startAlignedOffsetForLine(blockHeight, false));1012 toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);1013 }1014 block.updateStaticInlinePositionForChild(child, blockHeight);1015 child.layer()->setStaticBlockPosition(blockHeight);1016 }1017 1018 796 template <typename CharacterType> 1019 797 static inline int findFirstTrailingSpace(const RenderText& lastText, const CharacterType* characters, int start, int stop) … … 1465 1243 if (currentRegion->isLastRegion()) 1466 1244 pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight); 1467 }1468 1469 static inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)1470 {1471 for (size_t i = 0; i < wordMeasurements.size(); ++i) {1472 if (wordMeasurements[i].width > 0)1473 return wordMeasurements[i].width;1474 }1475 return 0;1476 1245 } 1477 1246 … … 2226 1995 } 2227 1996 2228 static inline bool skipNonBreakingSpace(const InlineIterator& it, const LineInfo& lineInfo)2229 {2230 if (it.m_obj->style().nbspMode() != SPACE || it.current() != noBreakSpace)2231 return false;2232 2233 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly2234 // with m_minWidth/m_maxWidth.2235 // Do not skip a non-breaking space if it is the first character2236 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off2237 // |true|).2238 if (lineInfo.isEmpty() && lineInfo.previousLineBrokeCleanly())2239 return false;2240 2241 return true;2242 }2243 2244 enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace };2245 static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition)2246 {2247 // CSS2 16.6.12248 // If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.2249 // If a space (U+0020) at the end of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is also removed.2250 // If spaces (U+0020) or tabs (U+0009) at the end of a line have 'white-space' set to 'pre-wrap', UAs may visually collapse them.2251 return style->collapseWhiteSpace()2252 || (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));2253 }2254 2255 static bool requiresLineBoxForContent(const RenderInline& flow, const LineInfo& lineInfo)2256 {2257 RenderElement* parent = flow.parent();2258 if (flow.document().inNoQuirksMode()) {2259 const RenderStyle& flowStyle = lineStyle(flow, lineInfo);2260 const RenderStyle& parentStyle = lineStyle(*parent, lineInfo);2261 if (flowStyle.lineHeight() != parentStyle.lineHeight()2262 || flowStyle.verticalAlign() != parentStyle.verticalAlign()2263 || !parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flowStyle.font().fontMetrics()))2264 return true;2265 }2266 return false;2267 }2268 2269 static bool hasInlineDirectionBordersPaddingOrMargin(const RenderInline& flow)2270 {2271 // Where an empty inline is split across anonymous blocks we should only give lineboxes to the 'sides' of the2272 // inline that have borders, padding or margin.2273 bool shouldApplyStartBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || !flow.isInlineElementContinuation();2274 if (shouldApplyStartBorderPaddingOrMargin && (flow.borderStart() || flow.marginStart() || flow.paddingStart()))2275 return true;2276 2277 bool shouldApplyEndBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || flow.isInlineElementContinuation() || !flow.inlineElementContinuation();2278 return shouldApplyEndBorderPaddingOrMargin && (flow.borderEnd() || flow.marginEnd() || flow.paddingEnd());2279 }2280 2281 static bool alwaysRequiresLineBox(const RenderInline& flow)2282 {2283 // FIXME: Right now, we only allow line boxes for inlines that are truly empty.2284 // We need to fix this, though, because at the very least, inlines containing only2285 // ignorable whitespace should should also have line boxes.2286 return isEmptyInline(flow) && hasInlineDirectionBordersPaddingOrMargin(flow);2287 }2288 2289 static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)2290 {2291 if (it.m_obj->isFloatingOrOutOfFlowPositioned())2292 return false;2293 2294 if (it.m_obj->isBR())2295 return true;2296 2297 bool rendererIsEmptyInline = false;2298 if (it.m_obj->isRenderInline()) {2299 const RenderInline& inlineRenderer = toRenderInline(*it.m_obj);2300 if (!alwaysRequiresLineBox(inlineRenderer) && !requiresLineBoxForContent(inlineRenderer, lineInfo))2301 return false;2302 rendererIsEmptyInline = isEmptyInline(inlineRenderer);2303 }2304 2305 if (!shouldCollapseWhiteSpace(&it.m_obj->style(), lineInfo, whitespacePosition))2306 return true;2307 2308 UChar current = it.current();2309 bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, lineInfo);2310 return notJustWhitespace || rendererIsEmptyInline;2311 }2312 2313 1997 bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) 2314 1998 { … … 2321 2005 2322 2006 return !it.atEnd(); 2323 }2324 2325 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building2326 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned2327 // elements quite right. In other words, we need to build this function's work into the normal line2328 // object iteration process.2329 // NB. this function will insert any floating elements that would otherwise2330 // be skipped but it will not position them.2331 void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)2332 {2333 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {2334 RenderObject& object = *iterator.m_obj;2335 if (object.isOutOfFlowPositioned())2336 setStaticPositions(m_block, toRenderBox(object));2337 else if (object.isFloating())2338 m_block.insertFloatingObject(toRenderBox(object));2339 iterator.increment();2340 }2341 }2342 2343 void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo, FloatingObject* lastFloatFromPreviousLine, LineWidth& width)2344 {2345 while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {2346 RenderObject& object = *resolver.position().m_obj;2347 if (object.isOutOfFlowPositioned()) {2348 setStaticPositions(m_block, toRenderBox(object));2349 if (object.style().isOriginalDisplayInlineType()) {2350 resolver.runs().addRun(createRun(0, 1, &object, resolver));2351 lineInfo.incrementRunsFromLeadingWhitespace();2352 }2353 } else if (object.isFloating()) {2354 // The top margin edge of a self-collapsing block that clears a float intrudes up into it by the height of the margin,2355 // so in order to place this first child float at the top content edge of the self-collapsing block add the margin back in before placement.2356 LayoutUnit marginOffset = (!object.previousSibling() && m_block.isSelfCollapsingBlock() && m_block.style().clear() && m_block.getClearDelta(m_block, LayoutUnit())) ? m_block.collapsedMarginBeforeForChild(m_block) : LayoutUnit();2357 LayoutUnit oldLogicalHeight = m_block.logicalHeight();2358 m_block.setLogicalHeight(oldLogicalHeight + marginOffset);2359 m_block.positionNewFloatOnLine(m_block.insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width);2360 m_block.setLogicalHeight(oldLogicalHeight);2361 } else if (object.isText() && object.style().hasTextCombine() && object.isCombineText() && !toRenderCombineText(object).isCombined()) {2362 toRenderCombineText(object).combineText();2363 if (toRenderCombineText(object).isCombined())2364 continue;2365 }2366 resolver.increment();2367 }2368 resolver.commitExplicitEmbedding();2369 }2370 2371 // This is currently just used for list markers and inline flows that have line boxes. Neither should2372 // have an effect on whitespace at the start of the line.2373 static bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow& block, RenderObject* o, LineMidpointState& lineMidpointState)2374 {2375 RenderObject* next = bidiNextSkippingEmptyInlines(block, o);2376 while (next && next->isFloatingOrOutOfFlowPositioned())2377 next = bidiNextSkippingEmptyInlines(block, next);2378 2379 if (next && next->isText() && toRenderText(next)->textLength() > 0) {2380 RenderText* nextText = toRenderText(next);2381 UChar nextChar = nextText->characterAt(0);2382 if (nextText->style().isCollapsibleWhiteSpace(nextChar)) {2383 startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0));2384 return true;2385 }2386 }2387 2388 return false;2389 }2390 2391 static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>& fallbackFonts, TextLayout* layout = 0)2392 {2393 const RenderStyle& style = text->style();2394 2395 GlyphOverflow glyphOverflow;2396 if (isFixedPitch || (!from && len == text->textLength()) || style.hasTextCombine())2397 return text->width(from, len, font, xPos, &fallbackFonts, &glyphOverflow);2398 2399 if (layout)2400 return Font::width(*layout, from, len, &fallbackFonts);2401 2402 TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, style);2403 run.setCharactersLength(text->textLength() - from);2404 ASSERT(run.charactersLength() >= run.length());2405 2406 run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());2407 run.setTabSize(!collapseWhiteSpace, style.tabSize());2408 run.setXPos(xPos);2409 return font.width(run, &fallbackFonts, &glyphOverflow);2410 }2411 2412 static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, unsigned consecutiveHyphenatedLines, int consecutiveHyphenatedLinesLimit, int minimumPrefixLimit, int minimumSuffixLimit, unsigned lastSpace, unsigned pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)2413 {2414 // Map 'hyphenate-limit-{before,after}: auto;' to 2.2415 unsigned minimumPrefixLength;2416 unsigned minimumSuffixLength;2417 2418 if (minimumPrefixLimit < 0)2419 minimumPrefixLength = 2;2420 else2421 minimumPrefixLength = static_cast<unsigned>(minimumPrefixLimit);2422 2423 if (minimumSuffixLimit < 0)2424 minimumSuffixLength = 2;2425 else2426 minimumSuffixLength = static_cast<unsigned>(minimumSuffixLimit);2427 2428 if (pos - lastSpace <= minimumSuffixLength)2429 return;2430 2431 if (consecutiveHyphenatedLinesLimit >= 0 && consecutiveHyphenatedLines >= static_cast<unsigned>(consecutiveHyphenatedLinesLimit))2432 return;2433 2434 int hyphenWidth = measureHyphenWidth(text, font);2435 2436 float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;2437 // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely2438 // that an hyphenation opportunity exists, so do not bother to look for it.2439 if (maxPrefixWidth <= font.pixelSize() * 5 / 4)2440 return;2441 2442 const RenderStyle& style = text->style();2443 TextRun run = RenderBlock::constructTextRun(text, font, text, lastSpace, pos - lastSpace, style);2444 run.setCharactersLength(text->textLength() - lastSpace);2445 ASSERT(run.charactersLength() >= run.length());2446 2447 run.setTabSize(!collapseWhiteSpace, style.tabSize());2448 run.setXPos(xPos + lastSpaceWordSpacing);2449 2450 unsigned prefixLength = font.offsetForPosition(run, maxPrefixWidth, false);2451 if (prefixLength < minimumPrefixLength)2452 return;2453 2454 prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, std::min(prefixLength, pos - lastSpace - minimumSuffixLength) + 1, localeIdentifier);2455 if (!prefixLength || prefixLength < minimumPrefixLength)2456 return;2457 2458 // When lastSapce is a space, which it always is except sometimes at the beginning of a line or after collapsed2459 // space, it should not count towards hyphenate-limit-before.2460 if (prefixLength == minimumPrefixLength) {2461 UChar characterAtLastSpace = text->characterAt(lastSpace);2462 if (characterAtLastSpace == ' ' || characterAtLastSpace == '\n' || characterAtLastSpace == '\t' || characterAtLastSpace == noBreakSpace)2463 return;2464 }2465 2466 ASSERT(pos - lastSpace - prefixLength >= minimumSuffixLength);2467 2468 #if !ASSERT_DISABLED2469 HashSet<const SimpleFontData*> fallbackFonts;2470 float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace, fallbackFonts) + lastSpaceWordSpacing;2471 ASSERT(xPos + prefixWidth <= availableWidth);2472 #else2473 UNUSED_PARAM(isFixedPitch);2474 #endif2475 2476 lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);2477 hyphenated = true;2478 }2479 2480 class TrailingObjects {2481 public:2482 TrailingObjects();2483 void setTrailingWhitespace(RenderText*);2484 void clear();2485 void appendBoxIfNeeded(RenderBoxModelObject*);2486 2487 enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace };2488 2489 void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot);2490 2491 private:2492 RenderText* m_whitespace;2493 Vector<RenderBoxModelObject*, 4> m_boxes;2494 };2495 2496 TrailingObjects::TrailingObjects()2497 : m_whitespace(0)2498 {2499 }2500 2501 inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)2502 {2503 ASSERT(whitespace);2504 m_whitespace = whitespace;2505 }2506 2507 inline void TrailingObjects::clear()2508 {2509 m_whitespace = 0;2510 m_boxes.shrink(0); // Use shrink(0) instead of clear() to retain our capacity.2511 }2512 2513 inline void TrailingObjects::appendBoxIfNeeded(RenderBoxModelObject* box)2514 {2515 if (m_whitespace)2516 m_boxes.append(box);2517 }2518 2519 void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace)2520 {2521 if (!m_whitespace)2522 return;2523 2524 // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint.2525 // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline.2526 if (lineMidpointState.numMidpoints % 2) {2527 // Find the trailing space object's midpoint.2528 int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;2529 for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].m_obj != m_whitespace; --trailingSpaceMidpoint) { }2530 ASSERT(trailingSpaceMidpoint >= 0);2531 if (collapseFirstSpace == CollapseFirstSpace)2532 lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;2533 2534 // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts2535 // ignoring spaces.2536 size_t currentMidpoint = trailingSpaceMidpoint + 1;2537 for (size_t i = 0; i < m_boxes.size(); ++i) {2538 if (currentMidpoint >= lineMidpointState.numMidpoints) {2539 // We don't have a midpoint for this box yet.2540 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);2541 } else {2542 ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == m_boxes[i]);2543 ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == m_boxes[i]);2544 }2545 currentMidpoint += 2;2546 }2547 } else if (!lBreak.m_obj) {2548 ASSERT(m_whitespace->isText());2549 ASSERT(collapseFirstSpace == CollapseFirstSpace);2550 // Add a new end midpoint that stops right at the very end.2551 unsigned length = m_whitespace->textLength();2552 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;2553 InlineIterator endMid(0, m_whitespace, pos);2554 startIgnoringSpaces(lineMidpointState, endMid);2555 for (size_t i = 0; i < m_boxes.size(); ++i) {2556 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);2557 }2558 }2559 }2560 2561 void LineBreaker::reset()2562 {2563 m_positionedObjects.clear();2564 m_hyphenated = false;2565 m_clear = CNONE;2566 2007 } 2567 2008 … … 2618 2059 return end; 2619 2060 #endif 2620 }2621 2622 static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText& renderer)2623 {2624 return iter.m_obj == &renderer && iter.m_pos >= renderer.textLength();2625 }2626 2627 #if ENABLE(CSS_SHAPES)2628 static void updateSegmentsForShapes(RenderBlockFlow& block, const FloatingObject* lastFloatFromPreviousLine, const WordMeasurements& wordMeasurements, LineWidth& width, bool isFirstLine)2629 {2630 ASSERT(lastFloatFromPreviousLine);2631 2632 ShapeInsideInfo* shapeInsideInfo = block.layoutShapeInsideInfo();2633 if (!lastFloatFromPreviousLine->isPlaced() || !shapeInsideInfo)2634 return;2635 2636 bool isHorizontalWritingMode = block.isHorizontalWritingMode();2637 LayoutUnit logicalOffsetFromShapeContainer = block.logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height();2638 2639 LayoutUnit lineLogicalTop = block.logicalHeight() + logicalOffsetFromShapeContainer;2640 LayoutUnit lineLogicalHeight = block.lineHeight(isFirstLine, isHorizontalWritingMode ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);2641 LayoutUnit lineLogicalBottom = lineLogicalTop + lineLogicalHeight;2642 2643 LayoutUnit floatLogicalTop = block.logicalTopForFloat(lastFloatFromPreviousLine);2644 LayoutUnit floatLogicalBottom = block.logicalBottomForFloat(lastFloatFromPreviousLine);2645 2646 bool lineOverlapsWithFloat = (floatLogicalTop < lineLogicalBottom) && (lineLogicalTop < floatLogicalBottom);2647 if (!lineOverlapsWithFloat)2648 return;2649 2650 float minSegmentWidth = firstPositiveWidth(wordMeasurements);2651 2652 LayoutUnit floatLogicalWidth = block.logicalWidthForFloat(lastFloatFromPreviousLine);2653 LayoutUnit availableLogicalWidth = block.logicalWidth() - block.logicalRightForFloat(lastFloatFromPreviousLine);2654 if (availableLogicalWidth < minSegmentWidth)2655 block.setLogicalHeight(floatLogicalBottom);2656 2657 if (block.logicalHeight() < floatLogicalTop) {2658 shapeInsideInfo->adjustLogicalLineTop(minSegmentWidth + floatLogicalWidth);2659 block.setLogicalHeight(shapeInsideInfo->logicalLineTop() - logicalOffsetFromShapeContainer);2660 }2661 2662 lineLogicalTop = block.logicalHeight() + logicalOffsetFromShapeContainer;2663 2664 shapeInsideInfo->updateSegmentsForLine(lineLogicalTop, lineLogicalHeight);2665 width.updateCurrentShapeSegment();2666 width.updateAvailableWidth();2667 }2668 #endif2669 2670 class BreakingContext {2671 public:2672 BreakingContext(LineBreaker& lineBreaker, InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow& block)2673 : m_lineBreaker(lineBreaker)2674 , m_resolver(resolver)2675 , m_current(resolver.position())2676 , m_lineBreak(resolver.position())2677 , m_block(block)2678 , m_lastObject(m_current.m_obj)2679 , m_nextObject(0)2680 , m_currentStyle(0)2681 , m_blockStyle(block.style())2682 , m_lineInfo(inLineInfo)2683 , m_renderTextInfo(inRenderTextInfo)2684 , m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine)2685 , m_width(lineWidth)2686 , m_currWS(NORMAL)2687 , m_lastWS(NORMAL)2688 , m_preservesNewline(false)2689 , m_atStart(true)2690 , m_ignoringSpaces(false)2691 , m_currentCharacterIsSpace(false)2692 , m_currentCharacterIsWS(false)2693 , m_appliedStartWidth(appliedStartWidth)2694 , m_includeEndWidth(true)2695 , m_autoWrap(false)2696 , m_autoWrapWasEverTrueOnLine(false)2697 , m_floatsFitOnLine(true)2698 , m_collapseWhiteSpace(false)2699 , m_startingNewParagraph(m_lineInfo.previousLineBrokeCleanly())2700 , m_allowImagesToBreak(!block.document().inQuirksMode() || !block.isTableCell() || !m_blockStyle.logicalWidth().isIntrinsicOrAuto())2701 , m_atEnd(false)2702 , m_hadUncommittedWidthBeforeCurrent(false)2703 , m_lineMidpointState(resolver.midpointState())2704 {2705 m_lineInfo.setPreviousLineBrokeCleanly(false);2706 }2707 2708 RenderObject* currentObject() { return m_current.m_obj; }2709 InlineIterator lineBreak() { return m_lineBreak; }2710 InlineIterator& lineBreakRef() {return m_lineBreak; }2711 LineWidth& lineWidth() { return m_width; }2712 bool atEnd() { return m_atEnd; }2713 2714 void initializeForCurrentObject();2715 2716 void increment();2717 2718 void handleBR(EClear&);2719 void handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects);2720 void handleFloat();2721 void handleEmptyInline();2722 void handleReplaced();2723 bool handleText(WordMeasurements&, bool& hyphenated, unsigned& consecutiveHyphenatedLines);2724 bool canBreakAtThisPosition();2725 void commitAndUpdateLineBreakIfNeeded();2726 InlineIterator handleEndOfLine();2727 2728 void clearLineBreakIfFitsOnLine(bool ignoringTrailingSpace = false)2729 {2730 if (m_width.fitsOnLine(ignoringTrailingSpace) || m_lastWS == NOWRAP)2731 m_lineBreak.clear();2732 }2733 2734 void commitLineBreakAtCurrentWidth(RenderObject* object, unsigned offset = 0, int nextBreak = -1)2735 {2736 m_width.commit();2737 m_lineBreak.moveTo(object, offset, nextBreak);2738 }2739 2740 private:2741 LineBreaker& m_lineBreaker;2742 InlineBidiResolver& m_resolver;2743 2744 InlineIterator m_current;2745 InlineIterator m_lineBreak;2746 InlineIterator m_startOfIgnoredSpaces;2747 2748 RenderBlockFlow& m_block;2749 RenderObject* m_lastObject;2750 RenderObject* m_nextObject;2751 2752 RenderStyle* m_currentStyle;2753 2754 // Firefox and Opera will allow a table cell to grow to fit an image inside it under2755 // very specific circumstances (in order to match common WinIE renderings).2756 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)2757 RenderStyle& m_blockStyle;2758 2759 LineInfo& m_lineInfo;2760 2761 RenderTextInfo& m_renderTextInfo;2762 2763 FloatingObject* m_lastFloatFromPreviousLine;2764 2765 LineWidth m_width;2766 2767 EWhiteSpace m_currWS;2768 EWhiteSpace m_lastWS;2769 2770 bool m_preservesNewline;2771 bool m_atStart;2772 2773 // This variable is used only if whitespace isn't set to PRE, and it tells us whether2774 // or not we are currently ignoring whitespace.2775 bool m_ignoringSpaces;2776 2777 // This variable tracks whether the very last character we saw was a space. We use2778 // this to detect when we encounter a second space so we know we have to terminate2779 // a run.2780 bool m_currentCharacterIsSpace;2781 bool m_currentCharacterIsWS;2782 bool m_appliedStartWidth;2783 bool m_includeEndWidth;2784 bool m_autoWrap;2785 bool m_autoWrapWasEverTrueOnLine;2786 bool m_floatsFitOnLine;2787 bool m_collapseWhiteSpace;2788 bool m_startingNewParagraph;2789 bool m_allowImagesToBreak;2790 bool m_atEnd;2791 bool m_hadUncommittedWidthBeforeCurrent;2792 2793 LineMidpointState& m_lineMidpointState;2794 2795 TrailingObjects m_trailingObjects;2796 };2797 2798 inline void BreakingContext::initializeForCurrentObject()2799 {2800 m_hadUncommittedWidthBeforeCurrent = !!m_width.uncommittedWidth();2801 2802 m_currentStyle = &m_current.m_obj->style();2803 2804 ASSERT(m_currentStyle);2805 2806 m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.m_obj);2807 if (m_nextObject && m_nextObject->parent() && !m_nextObject->parent()->isDescendantOf(m_current.m_obj->parent()))2808 m_includeEndWidth = true;2809 2810 m_currWS = m_current.m_obj->isReplaced() ? m_current.m_obj->parent()->style().whiteSpace() : m_currentStyle->whiteSpace();2811 m_lastWS = m_lastObject->isReplaced() ? m_lastObject->parent()->style().whiteSpace() : m_lastObject->style().whiteSpace();2812 2813 m_autoWrap = RenderStyle::autoWrap(m_currWS);2814 m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;2815 2816 #if ENABLE(SVG)2817 m_preservesNewline = m_current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS);2818 #else2819 m_preservesNewline = RenderStyle::preserveNewline(m_currWS);2820 #endif2821 2822 m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS);2823 }2824 2825 inline void BreakingContext::increment()2826 {2827 // Clear out our character space bool, since inline <pre>s don't collapse whitespace2828 // with adjacent inline normal/nowrap spans.2829 if (!m_collapseWhiteSpace)2830 m_currentCharacterIsSpace = false;2831 2832 m_current.moveToStartOf(m_nextObject);2833 m_atStart = false;2834 }2835 2836 inline void BreakingContext::handleBR(EClear& clear)2837 {2838 if (m_width.fitsOnLine()) {2839 RenderObject* br = m_current.m_obj;2840 m_lineBreak.moveToStartOf(br);2841 m_lineBreak.increment();2842 2843 // A <br> always breaks a line, so don't let the line be collapsed2844 // away. Also, the space at the end of a line with a <br> does not2845 // get collapsed away. It only does this if the previous line broke2846 // cleanly. Otherwise the <br> has no effect on whether the line is2847 // empty or not.2848 if (m_startingNewParagraph)2849 m_lineInfo.setEmpty(false, &m_block, &m_width);2850 m_trailingObjects.clear();2851 m_lineInfo.setPreviousLineBrokeCleanly(true);2852 2853 // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and2854 // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a2855 // run for this object.2856 if (m_ignoringSpaces && m_currentStyle->clear() != CNONE)2857 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, br);2858 // If we were preceded by collapsing space and are in a right-aligned container we need to ensure the space gets2859 // collapsed away so that it doesn't push the text out from the container's right-hand edge.2860 // FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.2861 else if (m_ignoringSpaces && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT))2862 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, m_current.m_pos));2863 2864 if (!m_lineInfo.isEmpty())2865 clear = m_currentStyle->clear();2866 }2867 m_atEnd = true;2868 }2869 2870 inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects)2871 {2872 // If our original display wasn't an inline type, then we can2873 // go ahead and determine our static inline position now.2874 RenderBox* box = toRenderBox(m_current.m_obj);2875 bool isInlineType = box->style().isOriginalDisplayInlineType();2876 if (!isInlineType)2877 m_block.setStaticInlinePositionForChild(*box, m_block.logicalHeight(), m_block.startOffsetForContent(m_block.logicalHeight()));2878 else {2879 // If our original display was an INLINE type, then we can go ahead2880 // and determine our static y position now.2881 box->layer()->setStaticBlockPosition(m_block.logicalHeight());2882 }2883 2884 // If we're ignoring spaces, we have to stop and include this object and2885 // then start ignoring spaces again.2886 if (isInlineType || box->container()->isRenderInline()) {2887 if (m_ignoringSpaces)2888 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, box);2889 m_trailingObjects.appendBoxIfNeeded(box);2890 } else2891 positionedObjects.append(box);2892 2893 m_width.addUncommittedWidth(inlineLogicalWidth(box));2894 // Reset prior line break context characters.2895 m_renderTextInfo.m_lineBreakIterator.resetPriorContext();2896 }2897 2898 inline void BreakingContext::handleFloat()2899 {2900 RenderBox& floatBox = toRenderBox(*m_current.m_obj);2901 FloatingObject* floatingObject = m_block.insertFloatingObject(floatBox);2902 // check if it fits in the current line.2903 // If it does, position it now, otherwise, position2904 // it after moving to next line (in newLine() func)2905 // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.2906 if (m_floatsFitOnLine && m_width.fitsOnLineExcludingTrailingWhitespace(m_block.logicalWidthForFloat(floatingObject))) {2907 m_block.positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width);2908 if (m_lineBreak.m_obj == m_current.m_obj) {2909 ASSERT(!m_lineBreak.m_pos);2910 m_lineBreak.increment();2911 }2912 } else2913 m_floatsFitOnLine = false;2914 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.2915 m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);2916 }2917 2918 inline void BreakingContext::handleEmptyInline()2919 {2920 RenderInline& flowBox = toRenderInline(*m_current.m_obj);2921 2922 // This should only end up being called on empty inlines2923 ASSERT(isEmptyInline(flowBox));2924 2925 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need2926 // to make sure that we stop to include this object and then start ignoring spaces again.2927 // If this object is at the start of the line, we need to behave like list markers and2928 // start ignoring spaces.2929 bool requiresLineBox = alwaysRequiresLineBox(flowBox);2930 if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) {2931 // An empty inline that only has line-height, vertical-align or font-metrics will only get a2932 // line box to affect the height of the line if the rest of the line is not empty.2933 if (requiresLineBox)2934 m_lineInfo.setEmpty(false, &m_block, &m_width);2935 if (m_ignoringSpaces) {2936 m_trailingObjects.clear();2937 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, m_current.m_obj);2938 } else if (m_blockStyle.collapseWhiteSpace() && m_resolver.position().m_obj == m_current.m_obj2939 && shouldSkipWhitespaceAfterStartObject(m_block, m_current.m_obj, m_lineMidpointState)) {2940 // Like with list markers, we start ignoring spaces to make sure that any2941 // additional spaces we see will be discarded.2942 m_currentCharacterIsSpace = true;2943 m_currentCharacterIsWS = true;2944 m_ignoringSpaces = true;2945 } else2946 m_trailingObjects.appendBoxIfNeeded(&flowBox);2947 }2948 2949 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));2950 }2951 2952 inline void BreakingContext::handleReplaced()2953 {2954 RenderBox& replacedBox = toRenderBox(*m_current.m_obj);2955 2956 if (m_atStart)2957 m_width.updateAvailableWidth(replacedBox.logicalHeight());2958 2959 // Break on replaced elements if either has normal white-space.2960 if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.m_obj->isImage() || m_allowImagesToBreak)) {2961 m_width.commit();2962 m_lineBreak.moveToStartOf(m_current.m_obj);2963 }2964 2965 if (m_ignoringSpaces)2966 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, 0));2967 2968 m_lineInfo.setEmpty(false, &m_block, &m_width);2969 m_ignoringSpaces = false;2970 m_currentCharacterIsSpace = false;2971 m_currentCharacterIsWS = false;2972 m_trailingObjects.clear();2973 2974 // Optimize for a common case. If we can't find whitespace after the list2975 // item, then this is all moot.2976 LayoutUnit replacedLogicalWidth = m_block.logicalWidthForChild(replacedBox) + m_block.marginStartForChild(replacedBox) + m_block.marginEndForChild(replacedBox) + inlineLogicalWidth(m_current.m_obj);2977 if (m_current.m_obj->isListMarker()) {2978 if (m_blockStyle.collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.m_obj, m_lineMidpointState)) {2979 // Like with inline flows, we start ignoring spaces to make sure that any2980 // additional spaces we see will be discarded.2981 m_currentCharacterIsSpace = true;2982 m_currentCharacterIsWS = false;2983 m_ignoringSpaces = true;2984 }2985 if (toRenderListMarker(*m_current.m_obj).isInside())2986 m_width.addUncommittedWidth(replacedLogicalWidth);2987 } else2988 m_width.addUncommittedWidth(replacedLogicalWidth);2989 if (m_current.m_obj->isRubyRun())2990 m_width.applyOverhang(toRenderRubyRun(m_current.m_obj), m_lastObject, m_nextObject);2991 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.2992 m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);2993 }2994 2995 2996 static inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter)2997 {2998 secondToLastCharacter = lastCharacter;2999 lastCharacter = currentCharacter;3000 }3001 3002 inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated, unsigned& consecutiveHyphenatedLines)3003 {3004 if (!m_current.m_pos)3005 m_appliedStartWidth = false;3006 3007 RenderText* renderText = toRenderText(m_current.m_obj);3008 3009 #if ENABLE(SVG)3010 bool isSVGText = renderText->isSVGInlineText();3011 #endif3012 3013 // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces3014 // then we need to mark the start of the autowrap inline as a potential linebreak now.3015 if (m_autoWrap && !RenderStyle::autoWrap(m_lastWS) && m_ignoringSpaces)3016 commitLineBreakAtCurrentWidth(m_current.m_obj);3017 3018 if (renderText->style().hasTextCombine() && m_current.m_obj->isCombineText() && !toRenderCombineText(*m_current.m_obj).isCombined()) {3019 RenderCombineText& combineRenderer = toRenderCombineText(*m_current.m_obj);3020 combineRenderer.combineText();3021 // The length of the renderer's text may have changed. Increment stale iterator positions3022 if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer)) {3023 ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer));3024 m_lineBreak.increment();3025 m_resolver.increment();3026 }3027 }3028 3029 const RenderStyle& style = lineStyle(*renderText->parent(), m_lineInfo);3030 const Font& font = style.font();3031 bool isFixedPitch = font.isFixedPitch();3032 bool canHyphenate = style.hyphens() == HyphensAuto && WebCore::canHyphenate(style.locale());3033 3034 unsigned lastSpace = m_current.m_pos;3035 float wordSpacing = m_currentStyle->wordSpacing();3036 float lastSpaceWordSpacing = 0;3037 float wordSpacingForWordMeasurement = 0;3038 3039 float wrapW = m_width.uncommittedWidth() + inlineLogicalWidth(m_current.m_obj, !m_appliedStartWidth, true);3040 float charWidth = 0;3041 bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE;3042 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,3043 // which is only possible if the word is the first thing on the line, that is, if |w| is zero.3044 bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.committedWidth()) || m_currWS == PRE);3045 bool midWordBreak = false;3046 bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;3047 float hyphenWidth = 0;3048 #if ENABLE(SVG)3049 if (isSVGText) {3050 breakWords = false;3051 breakAll = false;3052 }3053 #endif3054 3055 if (m_renderTextInfo.m_text != renderText) {3056 updateCounterIfNeeded(*renderText);3057 m_renderTextInfo.m_text = renderText;3058 m_renderTextInfo.m_font = &font;3059 m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);3060 m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style.locale());3061 } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) {3062 m_renderTextInfo.m_font = &font;3063 m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);3064 }3065 3066 TextLayout* textLayout = m_renderTextInfo.m_layout.get();3067 3068 // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure3069 // words with their trailing space, then subtract its width.3070 HashSet<const SimpleFontData*> fallbackFonts;3071 float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !textLayout ? font.width(RenderBlock::constructTextRun(renderText, font, &space, 1, style), &fallbackFonts) + wordSpacing : 0;3072 3073 UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter();3074 UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter();3075 for (; m_current.m_pos < renderText->textLength(); m_current.fastIncrementInTextNode()) {3076 bool previousCharacterIsSpace = m_currentCharacterIsSpace;3077 bool previousCharacterIsWS = m_currentCharacterIsWS;3078 UChar c = m_current.current();3079 m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n'));3080 3081 if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)3082 m_lineInfo.setEmpty(false, &m_block, &m_width);3083 3084 if (c == softHyphen && m_autoWrap && !hyphenWidth && style.hyphens() != HyphensNone) {3085 hyphenWidth = measureHyphenWidth(renderText, font, &fallbackFonts);3086 m_width.addUncommittedWidth(hyphenWidth);3087 }3088 3089 bool applyWordSpacing = false;3090 3091 m_currentCharacterIsWS = m_currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);3092 3093 if ((breakAll || breakWords) && !midWordBreak && (!m_currentCharacterIsSpace || style.whiteSpace() != PRE_WRAP)) {3094 wrapW += charWidth;3095 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.m_pos + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.m_pos + 1]);3096 charWidth = textWidth(renderText, m_current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, fallbackFonts, textLayout);3097 midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth();3098 }3099 3100 bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.m_pos, m_current.m_nextBreakablePosition, breakNBSP)3101 && (style.hyphens() != HyphensNone || (m_current.previousInSameNode() != softHyphen)));3102 3103 if (betweenWords || midWordBreak) {3104 bool stoppedIgnoringSpaces = false;3105 if (m_ignoringSpaces) {3106 lastSpaceWordSpacing = 0;3107 if (!m_currentCharacterIsSpace) {3108 // Stop ignoring spaces and begin at this3109 // new point.3110 m_ignoringSpaces = false;3111 wordSpacingForWordMeasurement = 0;3112 lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.3113 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, m_current.m_pos));3114 stoppedIgnoringSpaces = true;3115 } else {3116 // Just keep ignoring these spaces.3117 nextCharacter(c, lastCharacter, secondToLastCharacter);3118 continue;3119 }3120 }3121 3122 wordMeasurements.grow(wordMeasurements.size() + 1);3123 WordMeasurement& wordMeasurement = wordMeasurements.last();3124 3125 wordMeasurement.renderer = renderText;3126 wordMeasurement.endOffset = m_current.m_pos;3127 wordMeasurement.startOffset = lastSpace;3128 3129 float additionalTempWidth;3130 if (wordTrailingSpaceWidth && c == ' ')3131 additionalTempWidth = textWidth(renderText, lastSpace, m_current.m_pos + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;3132 else3133 additionalTempWidth = textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);3134 3135 if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())3136 wordMeasurement.fallbackFonts.swap(fallbackFonts);3137 fallbackFonts.clear();3138 3139 wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;3140 additionalTempWidth += lastSpaceWordSpacing;3141 m_width.addUncommittedWidth(additionalTempWidth);3142 3143 if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharacterIsSpace && additionalTempWidth)3144 m_width.setTrailingWhitespaceWidth(additionalTempWidth);3145 3146 if (!m_appliedStartWidth) {3147 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj, true, false));3148 m_appliedStartWidth = true;3149 }3150 3151 #if ENABLE(CSS_SHAPES)3152 if (m_lastFloatFromPreviousLine)3153 updateSegmentsForShapes(m_block, m_lastFloatFromPreviousLine, wordMeasurements, m_width, m_lineInfo.isFirstLine());3154 #endif3155 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;3156 3157 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine())3158 m_width.fitBelowFloats();3159 3160 if (m_autoWrap || breakWords) {3161 // If we break only after white-space, consider the current character3162 // as candidate width for this line.3163 bool lineWasTooWide = false;3164 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {3165 float charWidth = textWidth(renderText, m_current.m_pos, 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);3166 // Check if line is too big even without the extra space3167 // at the end of the line. If it is not, do nothing.3168 // If the line needs the extra whitespace to be too long,3169 // then move the line break to the space and skip all3170 // additional whitespace.3171 if (!m_width.fitsOnLineIncludingExtraWidth(charWidth)) {3172 lineWasTooWide = true;3173 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition);3174 m_lineBreaker.skipTrailingWhitespace(m_lineBreak, m_lineInfo);3175 }3176 }3177 if (lineWasTooWide || !m_width.fitsOnLine()) {3178 if (canHyphenate && !m_width.fitsOnLine()) {3179 tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.m_pos, m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.m_nextBreakablePosition, m_lineBreaker.m_hyphenated);3180 if (m_lineBreaker.m_hyphenated) {3181 m_atEnd = true;3182 return false;3183 }3184 }3185 if (m_lineBreak.atTextParagraphSeparator()) {3186 if (!stoppedIgnoringSpaces && m_current.m_pos > 0)3187 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);3188 m_lineBreak.increment();3189 m_lineInfo.setPreviousLineBrokeCleanly(true);3190 wordMeasurement.endOffset = m_lineBreak.m_pos;3191 }3192 if (m_lineBreak.m_obj && m_lineBreak.m_pos && m_lineBreak.m_obj->isText() && toRenderText(m_lineBreak.m_obj)->textLength() && toRenderText(m_lineBreak.m_obj)->characterAt(m_lineBreak.m_pos - 1) == softHyphen && style.hyphens() != HyphensNone)3193 hyphenated = true;3194 if (m_lineBreak.m_pos && m_lineBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {3195 if (charWidth) {3196 wordMeasurement.endOffset = m_lineBreak.m_pos;3197 wordMeasurement.width = charWidth;3198 }3199 }3200 // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.3201 if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) {3202 m_atEnd = true;3203 return false;3204 }3205 } else {3206 if (!betweenWords || (midWordBreak && !m_autoWrap))3207 m_width.addUncommittedWidth(-additionalTempWidth);3208 if (hyphenWidth) {3209 // Subtract the width of the soft hyphen out since we fit on a line.3210 m_width.addUncommittedWidth(-hyphenWidth);3211 hyphenWidth = 0;3212 }3213 }3214 }3215 3216 if (c == '\n' && m_preservesNewline) {3217 if (!stoppedIgnoringSpaces && m_current.m_pos > 0)3218 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);3219 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition);3220 m_lineBreak.increment();3221 m_lineInfo.setPreviousLineBrokeCleanly(true);3222 return true;3223 }3224 3225 if (m_autoWrap && betweenWords) {3226 m_width.commit();3227 wrapW = 0;3228 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition);3229 // Auto-wrapping text should not wrap in the middle of a word once it has had an3230 // opportunity to break after a word.3231 breakWords = false;3232 }3233 3234 if (midWordBreak && !U16_IS_TRAIL(c) && !(U_GET_GC_MASK(c) & U_GC_M_MASK)) {3235 // Remember this as a breakable position in case3236 // adding the end width forces a break.3237 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition);3238 midWordBreak &= (breakWords || breakAll);3239 }3240 3241 if (betweenWords) {3242 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;3243 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;3244 lastSpace = m_current.m_pos;3245 }3246 3247 if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {3248 // If we encounter a newline, or if we encounter a3249 // second space, we need to go ahead and break up this3250 // run and enter a mode where we start collapsing spaces.3251 if (m_currentCharacterIsSpace && previousCharacterIsSpace) {3252 m_ignoringSpaces = true;3253 3254 // We just entered a mode where we are ignoring3255 // spaces. Create a midpoint to terminate the run3256 // before the second space.3257 startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpaces);3258 m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);3259 }3260 }3261 } else if (m_ignoringSpaces) {3262 // Stop ignoring spaces and begin at this3263 // new point.3264 m_ignoringSpaces = false;3265 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;3266 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;3267 lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.3268 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, m_current.m_pos));3269 }3270 #if ENABLE(SVG)3271 if (isSVGText && m_current.m_pos > 0) {3272 // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).3273 if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.m_pos))3274 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);3275 }3276 #endif3277 3278 if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {3279 m_startOfIgnoredSpaces.m_obj = m_current.m_obj;3280 m_startOfIgnoredSpaces.m_pos = m_current.m_pos;3281 // Spaces after right-aligned text and before a line-break get collapsed away completely so that the trailing3282 // space doesn't seem to push the text out from the right-hand edge.3283 // FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.3284 if (m_nextObject && m_nextObject->isBR() && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT)) {3285 m_startOfIgnoredSpaces.m_pos--;3286 // If there's just a single trailing space start ignoring it now so it collapses away.3287 if (m_current.m_pos == renderText->textLength() - 1)3288 startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpaces);3289 }3290 }3291 3292 if (!m_currentCharacterIsSpace && previousCharacterIsWS) {3293 if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())3294 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition);3295 }3296 3297 if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces)3298 m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.m_obj));3299 else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace)3300 m_trailingObjects.clear();3301 3302 m_atStart = false;3303 nextCharacter(c, lastCharacter, secondToLastCharacter);3304 }3305 3306 m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);3307 3308 wordMeasurements.grow(wordMeasurements.size() + 1);3309 WordMeasurement& wordMeasurement = wordMeasurements.last();3310 wordMeasurement.renderer = renderText;3311 3312 // IMPORTANT: current.m_pos is > length here!3313 float additionalTempWidth = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);3314 wordMeasurement.startOffset = lastSpace;3315 wordMeasurement.endOffset = m_current.m_pos;3316 wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTempWidth + wordSpacingForWordMeasurement;3317 additionalTempWidth += lastSpaceWordSpacing;3318 3319 float inlineLogicalTempWidth = inlineLogicalWidth(m_current.m_obj, !m_appliedStartWidth, m_includeEndWidth);3320 m_width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth);3321 3322 if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())3323 wordMeasurement.fallbackFonts.swap(fallbackFonts);3324 fallbackFonts.clear();3325 3326 if (m_collapseWhiteSpace && m_currentCharacterIsSpace && additionalTempWidth)3327 m_width.setTrailingWhitespaceWidth(additionalTempWidth, inlineLogicalTempWidth);3328 3329 m_includeEndWidth = false;3330 3331 if (!m_width.fitsOnLine()) {3332 if (canHyphenate)3333 tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.m_pos, m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.m_nextBreakablePosition, m_lineBreaker.m_hyphenated);3334 3335 if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen && style.hyphens() != HyphensNone) {3336 hyphenated = true;3337 m_atEnd = true;3338 }3339 }3340 return false;3341 }3342 3343 static bool textBeginsWithBreakablePosition(RenderObject* next)3344 {3345 ASSERT(next->isText());3346 RenderText* nextText = toRenderText(next);3347 if (!nextText->textLength())3348 return false;3349 UChar c = nextText->characterAt(0);3350 return c == ' ' || c == '\t' || (c == '\n' && !nextText->preservesNewline());3351 }3352 3353 inline bool BreakingContext::canBreakAtThisPosition()3354 {3355 // If we are no-wrap and have found a line-breaking opportunity already then we should take it.3356 if (m_width.committedWidth() && !m_width.fitsOnLine(m_currentCharacterIsSpace) && m_currWS == NOWRAP)3357 return true;3358 3359 // Avoid breaking before empty inlines.3360 if (m_nextObject && m_nextObject->isRenderInline() && isEmptyInline(toRenderInline(*m_nextObject)))3361 return false;3362 3363 // Return early if we autowrap and the current character is a space as we will always want to break at such a position.3364 if (m_autoWrap && m_currentCharacterIsSpace)3365 return true;3366 3367 if (m_nextObject && m_nextObject->isLineBreakOpportunity())3368 return m_autoWrap;3369 3370 bool nextIsAutoWrappingText = (m_nextObject && m_nextObject->isText() && (m_autoWrap || m_nextObject->style().autoWrap()));3371 if (!nextIsAutoWrappingText)3372 return m_autoWrap;3373 bool currentIsTextOrEmptyInline = m_current.m_obj->isText() || (m_current.m_obj->isRenderInline() && isEmptyInline(toRenderInline(*m_current.m_obj)));3374 if (!currentIsTextOrEmptyInline)3375 return m_autoWrap;3376 3377 bool canBreakHere = !m_currentCharacterIsSpace && textBeginsWithBreakablePosition(m_nextObject);3378 3379 // See if attempting to fit below floats creates more available width on the line.3380 if (!m_width.fitsOnLine() && !m_width.committedWidth())3381 m_width.fitBelowFloats();3382 3383 bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine;3384 3385 if (canPlaceOnLine && canBreakHere)3386 commitLineBreakAtCurrentWidth(m_nextObject);3387 3388 return canBreakHere;3389 }3390 3391 inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()3392 {3393 bool checkForBreak = canBreakAtThisPosition();3394 3395 if (checkForBreak && !m_width.fitsOnLine(m_ignoringSpaces)) {3396 // if we have floats, try to get below them.3397 if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->collapseWhiteSpace())3398 m_trailingObjects.clear();3399 3400 if (m_width.committedWidth()) {3401 m_atEnd = true;3402 return;3403 }3404 3405 m_width.fitBelowFloats();3406 3407 // |width| may have been adjusted because we got shoved down past a float (thus3408 // giving us more room), so we need to retest, and only jump to3409 // the end label if we still don't fit on the line. -dwh3410 if (!m_width.fitsOnLine(m_ignoringSpaces)) {3411 m_atEnd = true;3412 return;3413 }3414 } else if (m_blockStyle.autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) {3415 // If the container autowraps but the current child does not then we still need to ensure that it3416 // wraps and moves below any floats.3417 m_width.fitBelowFloats();3418 }3419 3420 if (!m_current.m_obj->isFloatingOrOutOfFlowPositioned()) {3421 m_lastObject = m_current.m_obj;3422 if (m_lastObject->isReplaced() && m_autoWrap && (!m_lastObject->isImage() || m_allowImagesToBreak) && (!m_lastObject->isListMarker() || toRenderListMarker(*m_lastObject).isInside())) {3423 m_width.commit();3424 m_lineBreak.moveToStartOf(m_nextObject);3425 }3426 }3427 }3428 3429 InlineIterator BreakingContext::handleEndOfLine()3430 {3431 #if ENABLE(CSS_SHAPES)3432 ShapeInsideInfo* shapeInfo = m_block.layoutShapeInsideInfo();3433 bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();3434 #else3435 bool segmentAllowsOverflow = true;3436 #endif3437 if (segmentAllowsOverflow) {3438 if (m_lineBreak == m_resolver.position()) {3439 if (!m_lineBreak.m_obj || !m_lineBreak.m_obj->isBR()) {3440 // we just add as much as possible3441 if (m_blockStyle.whiteSpace() == PRE && !m_current.m_pos) {3442 m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0);3443 } else if (m_lineBreak.m_obj) {3444 // Don't ever break in the middle of a word if we can help it.3445 // There's no room at all. We just have to be on this line,3446 // even though we'll spill out.3447 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos);3448 }3449 }3450 // make sure we consume at least one char/object.3451 if (m_lineBreak == m_resolver.position())3452 m_lineBreak.increment();3453 } else if (!m_current.m_pos && !m_width.committedWidth() && m_width.uncommittedWidth() && !m_hadUncommittedWidthBeforeCurrent) {3454 // Do not push the current object to the next line, when this line has some content, but it is still considered empty.3455 // Empty inline elements like <span></span> can produce such lines and now we just ignore these break opportunities3456 // at the start of a line, if no width has been committed yet.3457 // Behave as if it was actually empty and consume at least one object.3458 m_lineBreak.increment();3459 }3460 }3461 3462 // Sanity check our midpoints.3463 checkMidpoints(m_lineMidpointState, m_lineBreak);3464 3465 m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace);3466 3467 // We might have made lineBreak an iterator that points past the end3468 // of the object. Do this adjustment to make it point to the start3469 // of the next object instead to avoid confusing the rest of the3470 // code.3471 if (m_lineBreak.m_pos > 0) {3472 m_lineBreak.m_pos--;3473 m_lineBreak.increment();3474 }3475 3476 return m_lineBreak;3477 2061 } 3478 2062 -
trunk/Source/WebCore/rendering/line/LineInfo.h
r159353 r159354 35 35 namespace WebCore { 36 36 37 class RenderBlock; 38 37 39 class LineInfo { 38 40 public: … … 57 59 void setFirstLine(bool firstLine) { m_isFirstLine = firstLine; } 58 60 void setLastLine(bool lastLine) { m_isLastLine = lastLine; } 59 void setEmpty(bool empty, RenderBlock* block = 0, LineWidth* lineWidth = 0) 60 { 61 if (m_isEmpty == empty) 62 return; 63 m_isEmpty = empty; 64 if (!empty && block && floatPaginationStrut()) { 65 block->setLogicalHeight(block->logicalHeight() + floatPaginationStrut()); 66 setFloatPaginationStrut(0); 67 lineWidth->updateAvailableWidth(); 68 } 69 } 70 61 void setEmpty(bool empty, RenderBlock* block = 0, LineWidth* lineWidth = 0); 71 62 void setPreviousLineBrokeCleanly(bool previousLineBrokeCleanly) { m_previousLineBrokeCleanly = previousLineBrokeCleanly; } 72 63 void setFloatPaginationStrut(LayoutUnit strut) { m_floatPaginationStrut = strut; }
Note: See TracChangeset
for help on using the changeset viewer.