Changeset 158196 in webkit
- Timestamp:
- Oct 29, 2013 10:00:42 AM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r158195 r158196 1 2013-10-29 Antti Koivisto <antti@apple.com> 2 3 Multiple runs per line on simple line path 4 https://bugs.webkit.org/show_bug.cgi?id=123446 5 6 Reviewed by Andreas Kling. 7 8 By allowing multiple runs per line we can support text flows with consecutive whitespaces in the middle. 9 10 * rendering/SimpleLineLayout.cpp: 11 (WebCore::SimpleLineLayout::canUseFor): 12 13 Remove space test. 14 The improved test coverage found a few more cases that we need to disallow. 15 16 (WebCore::SimpleLineLayout::adjustRunOffsets): 17 18 Round the run positions and widths so they match line boxes. 19 Adjust for text-align. 20 21 (WebCore::SimpleLineLayout::create): 22 23 Split lines with consecutive spaces into runs. 24 25 * rendering/SimpleLineLayout.h: 26 (WebCore::SimpleLineLayout::Run::Run): 27 * rendering/SimpleLineLayoutFunctions.cpp: 28 (WebCore::SimpleLineLayout::hitTestFlow): 29 (WebCore::SimpleLineLayout::collectFlowOverflow): 30 (WebCore::SimpleLineLayout::computeTextBoundingBox): 31 * rendering/SimpleLineLayoutResolver.h: 32 (WebCore::SimpleLineLayout::RunResolver::Iterator::resolver): 33 (WebCore::SimpleLineLayout::RunResolver::Iterator::lineIndex): 34 (WebCore::SimpleLineLayout::RunResolver::Run::Run): 35 (WebCore::SimpleLineLayout::RunResolver::Run::rect): 36 (WebCore::SimpleLineLayout::RunResolver::Run::baseline): 37 (WebCore::SimpleLineLayout::RunResolver::Run::text): 38 (WebCore::SimpleLineLayout::RunResolver::Run::lineIndex): 39 (WebCore::SimpleLineLayout::RunResolver::Iterator::Iterator): 40 (WebCore::SimpleLineLayout::RunResolver::Iterator::operator++): 41 42 Removed unnecessary operators. 43 44 (WebCore::SimpleLineLayout::RunResolver::Iterator::operator==): 45 (WebCore::SimpleLineLayout::RunResolver::Iterator::operator!=): 46 (WebCore::SimpleLineLayout::RunResolver::Iterator::operator*): 47 (WebCore::SimpleLineLayout::RunResolver::Iterator::simpleRun): 48 (WebCore::SimpleLineLayout::RunResolver::RunResolver): 49 (WebCore::SimpleLineLayout::RunResolver::begin): 50 (WebCore::SimpleLineLayout::RunResolver::end): 51 52 Resolver -> RunResolver 53 54 (WebCore::SimpleLineLayout::LineResolver::Iterator::Iterator): 55 (WebCore::SimpleLineLayout::LineResolver::Iterator::operator++): 56 (WebCore::SimpleLineLayout::LineResolver::Iterator::operator==): 57 (WebCore::SimpleLineLayout::LineResolver::Iterator::operator!=): 58 (WebCore::SimpleLineLayout::LineResolver::Iterator::operator*): 59 (WebCore::SimpleLineLayout::LineResolver::LineResolver): 60 (WebCore::SimpleLineLayout::LineResolver::begin): 61 (WebCore::SimpleLineLayout::LineResolver::end): 62 63 Add LineResolver around RunResolver. It resolves the line rectangles. 64 65 (WebCore::SimpleLineLayout::runResolver): 66 (WebCore::SimpleLineLayout::lineResolver): 67 1 68 2013-10-29 Chris Fleizach <cfleizach@apple.com> 2 69 -
trunk/Source/WebCore/rendering/SimpleLineLayout.cpp
r158188 r158196 79 79 if (flow.isRubyText() || flow.isRubyBase()) 80 80 return false; 81 if (flow.parent()->isDeprecatedFlexibleBox()) 82 return false; 81 83 // These tests only works during layout. Outside layout this function may give false positives. 82 84 if (flow.view().layoutState()) { … … 155 157 156 158 unsigned length = textRenderer.textLength(); 157 unsigned consecutiveSpaceCount = 0;158 159 for (unsigned i = 0; i < length; ++i) { 159 // This rejects anything with more than one consecutive whitespace, except at the beginning or end.160 // This is because we don't currently do subruns within lines. Fixing this would improve coverage significantly.161 160 UChar character = textRenderer.characterAt(i); 162 if (isWhitespace(character)) { 163 ++consecutiveSpaceCount; 161 if (character == ' ') 164 162 continue; 165 }166 if (consecutiveSpaceCount != i && consecutiveSpaceCount > 1)167 return false;168 consecutiveSpaceCount = 0;169 163 170 164 // These would be easy to support. … … 174 168 return false; 175 169 176 static const UChar lowestRTLCharacter = 0x590; 177 if (character >= lowestRTLCharacter) { 178 UCharDirection direction = u_charDirection(character); 179 if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC 180 || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE 181 || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE) 182 return false; 183 } 170 UCharDirection direction = u_charDirection(character); 171 if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC 172 || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE 173 || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE 174 || direction == U_POP_DIRECTIONAL_FORMAT || direction == U_BOUNDARY_NEUTRAL) 175 return false; 184 176 185 177 if (!primaryFontData.glyphForCharacter(character)) … … 232 224 } 233 225 226 static void adjustRunOffsets(Vector<Run, 4>& lineRuns, ETextAlign textAlign, float lineWidth, float availableWidth) 227 { 228 float lineLeft = computeLineLeft(textAlign, availableWidth - lineWidth); 229 for (unsigned i = 0; i < lineRuns.size(); ++i) { 230 float adjustedLeft = floor(lineLeft + lineRuns[i].left); 231 float adjustedRight = ceil(lineLeft + lineRuns[i].left + lineRuns[i].width); 232 lineRuns[i].left = adjustedLeft; 233 lineRuns[i].width = adjustedRight - adjustedLeft; 234 } 235 } 236 234 237 std::unique_ptr<Layout> create(RenderBlockFlow& flow) 235 238 { … … 252 255 lineEndOffset = skipWhitespaces(textRenderer, lineEndOffset, textLength); 253 256 unsigned lineStartOffset = lineEndOffset; 254 unsigned runEndOffset = lineEndOffset;257 unsigned wordEndOffset = lineEndOffset; 255 258 LineWidth lineWidth(flow, false, DoNotIndentText); 256 while (runEndOffset < textLength) { 257 ASSERT(!isWhitespace(textRenderer.characterAt(runEndOffset))); 258 259 bool previousWasSpaceBetweenRuns = runEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(runEndOffset - 1)); 260 unsigned runStartOffset = previousWasSpaceBetweenRuns ? runEndOffset - 1 : runEndOffset; 261 262 ++runEndOffset; 263 while (runEndOffset < textLength) { 264 if (runEndOffset > lineStartOffset && isBreakable(lineBreakIterator, runEndOffset, nextBreakable, false)) 259 260 Vector<Run, 4> lineRuns; 261 lineRuns.uncheckedAppend(Run(lineStartOffset, 0)); 262 263 while (wordEndOffset < textLength) { 264 ASSERT(!isWhitespace(textRenderer.characterAt(wordEndOffset))); 265 266 bool previousWasSpaceBetweenWords = wordEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(wordEndOffset - 1)); 267 unsigned wordStartOffset = previousWasSpaceBetweenWords ? wordEndOffset - 1 : wordEndOffset; 268 269 ++wordEndOffset; 270 while (wordEndOffset < textLength) { 271 if (wordEndOffset > lineStartOffset && isBreakable(lineBreakIterator, wordEndOffset, nextBreakable, false)) 265 272 break; 266 ++ runEndOffset;273 ++wordEndOffset; 267 274 } 268 275 269 unsigned runLength = runEndOffset - runStartOffset;270 bool includeEndSpace = runEndOffset < textLength && textRenderer.characterAt(runEndOffset) == ' ';276 unsigned wordLength = wordEndOffset - wordStartOffset; 277 bool includeEndSpace = wordEndOffset < textLength && textRenderer.characterAt(wordEndOffset) == ' '; 271 278 float wordWidth; 272 279 if (includeEndSpace) 273 wordWidth = textWidth(textRenderer, runStartOffset, runLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth;280 wordWidth = textWidth(textRenderer, wordStartOffset, wordLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth; 274 281 else 275 wordWidth = textWidth(textRenderer, runStartOffset, runLength, lineWidth.committedWidth(), style);282 wordWidth = textWidth(textRenderer, wordStartOffset, wordLength, lineWidth.committedWidth(), style); 276 283 277 284 lineWidth.addUncommittedWidth(wordWidth); 285 286 // Move to the next line if the current one is full and we have something on it. 287 if (!lineWidth.fitsOnLine() && lineWidth.committedWidth()) 288 break; 289 290 if (wordStartOffset > lineEndOffset) { 291 // There were more than one consecutive whitespace. 292 ASSERT(previousWasSpaceBetweenWords); 293 // Include space to the end of the previous run. 294 lineRuns.last().textLength++; 295 lineRuns.last().width += wordTrailingSpaceWidth; 296 // Start a new run on the same line. 297 float previousRight = lineRuns.last().left + lineRuns.last().width; 298 lineRuns.append(Run(wordStartOffset + 1, previousRight)); 299 } 300 301 lineWidth.commit(); 302 303 lineRuns.last().width = lineWidth.committedWidth() - lineRuns.last().left; 304 lineRuns.last().textLength = wordEndOffset - lineRuns.last().textOffset; 305 306 lineEndOffset = wordEndOffset; 307 wordEndOffset = skipWhitespaces(textRenderer, wordEndOffset, textLength); 308 278 309 if (!lineWidth.fitsOnLine()) { 279 if (!lineWidth.committedWidth()) { 280 lineWidth.commit(); 281 lineEndOffset = runEndOffset; 282 } 310 // The first run on the line overflows. 311 ASSERT(lineRuns.size() == 1); 283 312 break; 284 313 } 285 lineWidth.commit();286 lineEndOffset = runEndOffset;287 runEndOffset = skipWhitespaces(textRenderer, runEndOffset, textLength);288 314 } 289 315 if (lineStartOffset == lineEndOffset) 290 316 continue; 291 317 292 float alignedLeft = computeLineLeft(textAlign, lineWidth.availableWidth() - lineWidth.committedWidth()); 293 float alignedRight = alignedLeft + lineWidth.committedWidth(); 294 295 Run run; 296 run.textOffset = lineStartOffset; 297 run.textLength = lineEndOffset - lineStartOffset; 298 run.left = floor(alignedLeft); 299 run.width = ceil(alignedRight) - run.left; 300 301 layout->runs.append(run); 318 adjustRunOffsets(lineRuns, textAlign, lineWidth.committedWidth(), lineWidth.availableWidth()); 319 320 for (unsigned i = 0; i < lineRuns.size(); ++i) 321 layout->runs.append(lineRuns[i]); 322 323 layout->runs.last().isEndOfLine = true; 302 324 layout->lineCount++; 303 325 } -
trunk/Source/WebCore/rendering/SimpleLineLayout.h
r158107 r158196 39 39 40 40 struct Run { 41 Run(unsigned textOffset, float left) 42 : textOffset(textOffset) 43 , textLength(0) 44 , isEndOfLine(false) 45 , left(left) 46 , width(0) 47 { } 48 41 49 unsigned textOffset; 42 unsigned textLength; 50 unsigned textLength : 31; 51 unsigned isEndOfLine : 1; 43 52 float left; 44 53 float width; -
trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp
r158163 r158196 86 86 auto resolver = lineResolver(flow, layout); 87 87 for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { 88 auto line = *it; 89 auto lineRect = line.rect(); 88 auto lineRect = *it; 90 89 lineRect.moveBy(accumulatedOffset); 91 90 if (!locationInContainer.intersects(lineRect)) … … 103 102 auto resolver = lineResolver(flow, layout); 104 103 for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { 105 auto line = *it; 106 auto rect = line.rect(); 104 auto rect = *it; 107 105 flow.addLayoutOverflow(rect); 108 106 flow.addVisualOverflow(rect); … … 117 115 if (it == end) 118 116 return IntRect(); 119 auto firstLineRect = (*it).rect();117 auto firstLineRect = *it; 120 118 float left = firstLineRect.x(); 121 119 float right = firstLineRect.maxX(); 120 float bottom = firstLineRect.maxY(); 122 121 for (++it; it != end; ++it) { 123 auto line = *it; 124 auto rect = line.rect(); 122 auto rect = *it; 125 123 if (rect.x() < left) 126 124 left = rect.x(); 127 125 if (rect.maxX() > right) 128 126 right = rect.maxX(); 127 if (rect.maxY() > bottom) 128 bottom = rect.maxY(); 129 129 } 130 130 float x = firstLineRect.x(); 131 131 float y = firstLineRect.y(); 132 132 float width = right - left; 133 float height = (*resolver.last()).rect().maxY()- y;133 float height = bottom - y; 134 134 return enclosingIntRect(FloatRect(x, y, width, height)); 135 135 } -
trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h
r158163 r158196 37 37 namespace SimpleLineLayout { 38 38 39 class R esolver {39 class RunResolver { 40 40 public: 41 41 class Iterator; … … 43 43 class Run { 44 44 public: 45 Run(const Resolver&, unsigned lineIndex);45 explicit Run(const Iterator&); 46 46 47 47 LayoutRect rect() const; … … 49 49 String text() const; 50 50 51 unsigned lineIndex() const; 52 51 53 private: 52 const Resolver& m_resolver; 54 const Iterator& m_iterator; 55 }; 56 57 class Iterator { 58 public: 59 Iterator(const RunResolver&, unsigned lineIndex); 60 61 Iterator& operator++(); 62 bool operator==(const Iterator&) const; 63 bool operator!=(const Iterator&) const; 64 65 Run operator*() const; 66 67 const RunResolver& resolver() const { return m_resolver; } 68 const SimpleLineLayout::Run& simpleRun() const; 69 unsigned lineIndex() const { return m_lineIndex; } 70 71 private: 72 const RunResolver& m_resolver; 73 unsigned m_runIndex; 53 74 unsigned m_lineIndex; 54 75 }; 55 76 56 class Iterator { 57 public: 58 Iterator(const Resolver&, unsigned lineIndex); 59 60 Iterator& operator++(); 61 Iterator& operator--(); 62 bool operator==(const Iterator&) const; 63 bool operator!=(const Iterator&) const; 64 65 Run operator*() const; 66 67 private: 68 const Resolver& m_resolver; 69 unsigned m_lineIndex; 70 }; 71 72 Resolver(const RenderBlockFlow&, const Layout&); 73 74 unsigned size() const; 77 RunResolver(const RenderBlockFlow&, const Layout&); 75 78 76 79 Iterator begin() const; 77 80 Iterator end() const; 78 Iterator last() const;79 Iterator operator[](unsigned) const;80 81 81 82 private: … … 89 90 }; 90 91 91 Resolver runResolver(const RenderBlockFlow&, const Layout&); 92 Resolver lineResolver(const RenderBlockFlow&, const Layout&); 93 94 inline Resolver::Run::Run(const Resolver& resolver, unsigned lineIndex) 92 class LineResolver { 93 public: 94 class Iterator; 95 96 class Iterator { 97 public: 98 explicit Iterator(RunResolver::Iterator); 99 100 Iterator& operator++(); 101 bool operator==(const Iterator&) const; 102 bool operator!=(const Iterator&) const; 103 104 const LayoutRect operator*() const; 105 106 private: 107 RunResolver::Iterator m_runIterator; 108 LayoutRect m_rect; 109 }; 110 111 LineResolver(const RenderBlockFlow&, const Layout&); 112 113 Iterator begin() const; 114 Iterator end() const; 115 116 private: 117 RunResolver m_runResolver; 118 }; 119 120 RunResolver runResolver(const RenderBlockFlow&, const Layout&); 121 LineResolver lineResolver(const RenderBlockFlow&, const Layout&); 122 123 inline RunResolver::Run::Run(const Iterator& iterator) 124 : m_iterator(iterator) 125 { 126 } 127 128 inline LayoutRect RunResolver::Run::rect() const 129 { 130 auto& resolver = m_iterator.resolver(); 131 auto& run = m_iterator.simpleRun(); 132 133 LayoutPoint linePosition(run.left, resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline - resolver.m_ascent); 134 LayoutSize lineSize(run.width, resolver.m_ascent + resolver.m_descent); 135 return LayoutRect(linePosition + resolver.m_contentOffset, lineSize); 136 } 137 138 inline LayoutPoint RunResolver::Run::baseline() const 139 { 140 auto& resolver = m_iterator.resolver(); 141 auto& run = m_iterator.simpleRun(); 142 143 float baselineY = resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline; 144 return LayoutPoint(run.left, baselineY) + resolver.m_contentOffset; 145 } 146 147 inline String RunResolver::Run::text() const 148 { 149 auto& resolver = m_iterator.resolver(); 150 auto& run = m_iterator.simpleRun(); 151 return resolver.m_string.substringSharingImpl(run.textOffset, run.textLength); 152 } 153 154 inline unsigned RunResolver::Run::lineIndex() const 155 { 156 return m_iterator.lineIndex(); 157 } 158 159 inline RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex) 95 160 : m_resolver(resolver) 96 , m_lineIndex(lineIndex) 97 { 98 } 99 100 inline LayoutRect Resolver::Run::rect() const 101 { 102 auto& run = m_resolver.m_layout.runs[m_lineIndex]; 103 104 LayoutPoint linePosition(run.left, m_resolver.m_lineHeight * m_lineIndex + m_resolver.m_baseline - m_resolver.m_ascent); 105 LayoutSize lineSize(run.width, m_resolver.m_ascent + m_resolver.m_descent); 106 return LayoutRect(linePosition + m_resolver.m_contentOffset, lineSize); 107 } 108 109 inline LayoutPoint Resolver::Run::baseline() const 110 { 111 auto& run = m_resolver.m_layout.runs[m_lineIndex]; 112 113 float baselineY = m_resolver.m_lineHeight * m_lineIndex + m_resolver.m_baseline; 114 return LayoutPoint(run.left, baselineY) + m_resolver.m_contentOffset; 115 } 116 117 inline String Resolver::Run::text() const 118 { 119 auto& run = m_resolver.m_layout.runs[m_lineIndex]; 120 return m_resolver.m_string.substringSharingImpl(run.textOffset, run.textLength); 121 } 122 123 inline Resolver::Iterator::Iterator(const Resolver& resolver, unsigned lineIndex) 124 : m_resolver(resolver) 125 , m_lineIndex(lineIndex) 126 { 127 } 128 129 inline Resolver::Iterator& Resolver::Iterator::operator++() 130 { 131 ++m_lineIndex; 161 , m_runIndex(runIndex) 162 , m_lineIndex(0) 163 { 164 } 165 166 inline RunResolver::Iterator& RunResolver::Iterator::operator++() 167 { 168 if (simpleRun().isEndOfLine) 169 ++m_lineIndex; 170 ++m_runIndex; 132 171 return *this; 133 172 } 134 173 135 inline Resolver::Iterator& Resolver::Iterator::operator--() 136 { 137 --m_lineIndex; 138 return *this; 139 } 140 141 inline bool Resolver::Iterator::operator==(const Iterator& other) const 174 inline bool RunResolver::Iterator::operator==(const Iterator& other) const 142 175 { 143 176 ASSERT(&m_resolver == &other.m_resolver); 144 return m_ lineIndex == other.m_lineIndex;145 } 146 147 inline bool R esolver::Iterator::operator!=(const Iterator& other) const177 return m_runIndex == other.m_runIndex; 178 } 179 180 inline bool RunResolver::Iterator::operator!=(const Iterator& other) const 148 181 { 149 182 return !(*this == other); 150 183 } 151 184 152 inline Resolver::Run Resolver::Iterator::operator*() const 153 { 154 return Run(m_resolver, m_lineIndex); 155 } 156 157 inline Resolver::Resolver(const RenderBlockFlow& flow, const Layout& layout) 185 inline RunResolver::Run RunResolver::Iterator::operator*() const 186 { 187 return Run(*this); 188 } 189 190 inline const SimpleLineLayout::Run& RunResolver::Iterator::simpleRun() const 191 { 192 return m_resolver.m_layout.runs[m_runIndex]; 193 } 194 195 inline RunResolver::RunResolver(const RenderBlockFlow& flow, const Layout& layout) 158 196 : m_layout(layout) 159 197 , m_string(toRenderText(*flow.firstChild()).text()) … … 166 204 } 167 205 168 inline unsigned Resolver::size() const 169 { 170 return m_layout.runs.size(); 171 } 172 173 inline Resolver::Iterator Resolver::begin() const 206 inline RunResolver::Iterator RunResolver::begin() const 174 207 { 175 208 return Iterator(*this, 0); 176 209 } 177 210 178 inline Resolver::Iterator Resolver::end() const 179 { 180 return Iterator(*this, size()); 181 } 182 183 inline Resolver::Iterator Resolver::last() const 184 { 185 ASSERT(size()); 186 return Iterator(*this, size() - 1); 187 } 188 189 inline Resolver::Iterator Resolver::operator[](unsigned index) const 190 { 191 ASSERT(index < size()); 192 return Iterator(*this, index); 193 } 194 195 inline Resolver runResolver(const RenderBlockFlow& flow, const Layout& layout) 196 { 197 return Resolver(flow, layout); 198 } 199 200 inline Resolver lineResolver(const RenderBlockFlow& flow, const Layout& layout) 201 { 202 return Resolver(flow, layout); 211 inline RunResolver::Iterator RunResolver::end() const 212 { 213 return Iterator(*this, m_layout.runs.size()); 214 } 215 216 inline LineResolver::Iterator::Iterator(RunResolver::Iterator runIterator) 217 : m_runIterator(runIterator) 218 { 219 } 220 221 inline LineResolver::Iterator& LineResolver::Iterator::operator++() 222 { 223 unsigned previousLine = m_runIterator.lineIndex(); 224 while ((++m_runIterator).lineIndex() == previousLine) { } 225 226 return *this; 227 } 228 229 inline bool LineResolver::Iterator::operator==(const Iterator& other) const 230 { 231 return m_runIterator == other.m_runIterator; 232 } 233 234 inline bool LineResolver::Iterator::operator!=(const Iterator& other) const 235 { 236 return m_runIterator != other.m_runIterator; 237 } 238 239 inline const LayoutRect LineResolver::Iterator::operator*() const 240 { 241 unsigned currentLine = m_runIterator.lineIndex(); 242 auto it = m_runIterator; 243 LayoutRect rect = (*it).rect(); 244 while ((++it).lineIndex() == currentLine) 245 rect.unite((*it).rect()); 246 247 return rect; 248 } 249 250 inline LineResolver::LineResolver(const RenderBlockFlow& flow, const Layout& layout) 251 : m_runResolver(flow, layout) 252 { 253 } 254 255 inline LineResolver::Iterator LineResolver::begin() const 256 { 257 return Iterator(m_runResolver.begin()); 258 } 259 260 inline LineResolver::Iterator LineResolver::end() const 261 { 262 return Iterator(m_runResolver.end()); 263 } 264 265 inline RunResolver runResolver(const RenderBlockFlow& flow, const Layout& layout) 266 { 267 return RunResolver(flow, layout); 268 } 269 270 inline LineResolver lineResolver(const RenderBlockFlow& flow, const Layout& layout) 271 { 272 return LineResolver(flow, layout); 203 273 } 204 274
Note: See TracChangeset
for help on using the changeset viewer.