OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 return parent; | 56 return parent; |
57 } | 57 } |
58 return 0; | 58 return 0; |
59 } | 59 } |
60 | 60 |
61 FastTextAutosizer::FastTextAutosizer(const Document* document) | 61 FastTextAutosizer::FastTextAutosizer(const Document* document) |
62 : m_document(document) | 62 : m_document(document) |
63 , m_frameWidth(0) | 63 , m_frameWidth(0) |
64 , m_layoutWidth(0) | 64 , m_layoutWidth(0) |
65 , m_baseMultiplier(0) | 65 , m_baseMultiplier(0) |
66 , m_pageNeedsAutosizing(PageNeedsAutosizing_Unknown) | |
66 , m_firstBlock(0) | 67 , m_firstBlock(0) |
67 #ifndef NDEBUG | 68 #ifndef NDEBUG |
68 , m_renderViewInfoPrepared(false) | 69 , m_renderViewInfoPrepared(false) |
69 , m_blocksThatHaveBegunLayout() | 70 , m_blocksThatHaveBegunLayout() |
70 #endif | 71 #endif |
71 , m_superclusters() | 72 , m_superclusters() |
72 , m_clusterStack() | 73 , m_clusterStack() |
73 , m_fingerprintMapper() | 74 , m_fingerprintMapper() |
74 { | 75 { |
75 } | 76 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 } | 115 } |
115 | 116 |
116 void FastTextAutosizer::beginLayout(RenderBlock* block) | 117 void FastTextAutosizer::beginLayout(RenderBlock* block) |
117 { | 118 { |
118 ASSERT(enabled()); | 119 ASSERT(enabled()); |
119 #ifndef NDEBUG | 120 #ifndef NDEBUG |
120 m_blocksThatHaveBegunLayout.add(block); | 121 m_blocksThatHaveBegunLayout.add(block); |
121 #endif | 122 #endif |
122 | 123 |
123 if (!m_firstBlock) { | 124 if (!m_firstBlock) { |
124 prepareRenderViewInfo(); | 125 m_firstBlock = block; |
125 prepareClusterStack(block->parent()); | 126 prepareClusterStack(block->parent()); |
126 m_firstBlock = block; | |
127 } else if (block == currentCluster()->m_root) { | 127 } else if (block == currentCluster()->m_root) { |
128 // Ignore beginLayout on the same block twice. | 128 // Ignore beginLayout on the same block twice. |
129 // This can happen with paginated overflow. | 129 // This can happen with paginated overflow. |
130 return; | 130 return; |
131 } | 131 } |
132 | 132 |
133 if (Cluster* cluster = maybeCreateCluster(block)) { | 133 if (Cluster* cluster = maybeCreateCluster(block)) { |
134 m_clusterStack.append(adoptPtr(cluster)); | 134 m_clusterStack.append(adoptPtr(cluster)); |
135 if (block->isTable()) | 135 if (block->isTable()) |
136 inflateTable(toRenderTable(block)); | 136 inflateTable(toRenderTable(block)); |
137 } | 137 } |
138 | 138 |
139 if (block->childrenInline()) | 139 if (block->childrenInline()) |
140 inflate(block); | 140 inflate(block); |
141 } | 141 } |
142 | 142 |
143 bool FastTextAutosizer::isInLayout() const | |
144 { | |
145 return !!m_firstBlock; | |
146 } | |
147 | |
143 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) | 148 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) |
144 { | 149 { |
145 if (!enabled()) | 150 if (!enabled()) |
146 return; | 151 return; |
147 ASSERT(listItem && listItemMarker); | 152 ASSERT(listItem && listItemMarker); |
148 #ifndef NDEBUG | 153 #ifndef NDEBUG |
149 m_blocksThatHaveBegunLayout.add(listItem); | 154 m_blocksThatHaveBegunLayout.add(listItem); |
150 #endif | 155 #endif |
151 // Force the LI to be inside the DBCAT when computing the multiplier. | 156 // Force the LI to be inside the DBCAT when computing the multiplier. |
152 // This guarantees that the DBCAT has entered layout, so we can ask for its width. | 157 // This guarantees that the DBCAT has entered layout, so we can ask for its width. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
195 } | 200 } |
196 | 201 |
197 void FastTextAutosizer::endLayout(RenderBlock* block) | 202 void FastTextAutosizer::endLayout(RenderBlock* block) |
198 { | 203 { |
199 ASSERT(enabled()); | 204 ASSERT(enabled()); |
200 | 205 |
201 if (currentCluster()->m_root == block) | 206 if (currentCluster()->m_root == block) |
202 m_clusterStack.removeLast(); | 207 m_clusterStack.removeLast(); |
203 | 208 |
204 if (block == m_firstBlock) { | 209 if (block == m_firstBlock) { |
205 m_firstBlock = 0; | 210 m_firstBlock = 0; |
pdr.
2014/03/01 05:16:43
Should we reset m_pageNeedsAutosizing here?
| |
206 m_clusterStack.clear(); | 211 m_clusterStack.clear(); |
207 m_superclusters.clear(); | 212 m_superclusters.clear(); |
208 #ifndef NDEBUG | 213 #ifndef NDEBUG |
209 m_blocksThatHaveBegunLayout.clear(); | 214 m_blocksThatHaveBegunLayout.clear(); |
210 #endif | 215 #endif |
211 } | 216 } |
212 } | 217 } |
213 | 218 |
214 void FastTextAutosizer::inflate(RenderBlock* block) | 219 void FastTextAutosizer::inflate(RenderBlock* block) |
215 { | 220 { |
216 Cluster* cluster = currentCluster(); | 221 Cluster* cluster = currentCluster(); |
217 float multiplier = 0; | 222 float multiplier = 0; |
218 for (RenderObject* descendant = nextChildSkippingChildrenOfBlocks(block, blo ck); descendant; descendant = nextChildSkippingChildrenOfBlocks(descendant, bloc k)) { | 223 for (RenderObject* descendant = nextChildSkippingChildrenOfBlocks(block, blo ck); descendant; descendant = nextChildSkippingChildrenOfBlocks(descendant, bloc k)) { |
219 if (descendant->isText()) { | 224 if (descendant->isText()) { |
220 // We only calculate this multiplier on-demand to ensure the parent block of this text | 225 // We only calculate this multiplier on-demand to ensure the parent block of this text |
221 // has entered layout. | 226 // has entered layout. |
222 if (!multiplier) | 227 if (!multiplier) |
223 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f; | 228 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f; |
224 applyMultiplier(descendant, multiplier); | 229 applyMultiplier(descendant, multiplier); |
225 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing. | 230 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing. |
226 } | 231 } |
227 } | 232 } |
228 } | 233 } |
229 | 234 |
230 bool FastTextAutosizer::enabled() | 235 bool FastTextAutosizer::enabled() |
231 { | 236 { |
232 if (!m_document->settings() || !m_document->page() || m_document->printing() ) | 237 if (!m_document->settings() |
238 || !m_document->page() | |
239 || m_document->printing() | |
240 || !m_document->settings()->textAutosizingEnabled()) | |
233 return false; | 241 return false; |
234 | 242 |
235 return m_document->settings()->textAutosizingEnabled(); | 243 if (m_pageNeedsAutosizing == PageNeedsAutosizing_Unknown) |
244 updateRenderViewInfo(); | |
245 | |
246 if (m_pageNeedsAutosizing == PageNeedsAutosizing_No) | |
247 return false; | |
248 | |
249 return true; | |
236 } | 250 } |
237 | 251 |
238 void FastTextAutosizer::prepareRenderViewInfo() | 252 void FastTextAutosizer::updateRenderViewInfo() |
239 { | 253 { |
254 if (!m_document->settings() | |
pdr.
2014/03/01 05:16:43
Having these checks in two places doesn't seem rig
| |
255 || !m_document->page() | |
256 || m_document->printing() | |
257 || !m_document->settings()->textAutosizingEnabled()) | |
258 return; | |
259 | |
240 RenderView* renderView = toRenderView(m_document->renderer()); | 260 RenderView* renderView = toRenderView(m_document->renderer()); |
241 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode()); | 261 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode()); |
242 | 262 |
243 LocalFrame* mainFrame = m_document->page()->mainFrame(); | 263 LocalFrame* mainFrame = m_document->page()->mainFrame(); |
244 IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride (); | 264 IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride (); |
245 if (frameSize.isEmpty()) | 265 if (frameSize.isEmpty()) |
246 frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollb ars); | 266 frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollb ars); |
247 m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height( ); | 267 m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height( ); |
248 | 268 |
249 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize(); | 269 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize(); |
250 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht(); | 270 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht(); |
251 | 271 |
252 // Compute the base font scale multiplier based on device and accessibility settings. | 272 // Compute the base font scale multiplier based on device and accessibility settings. |
253 m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor(); | 273 m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor(); |
254 // If the page has a meta viewport or @viewport, don't apply the device scal e adjustment. | 274 // If the page has a meta viewport or @viewport, don't apply the device scal e adjustment. |
255 const ViewportDescription& viewportDescription = m_document->page()->mainFra me()->document()->viewportDescription(); | 275 const ViewportDescription& viewportDescription = m_document->page()->mainFra me()->document()->viewportDescription(); |
256 if (!viewportDescription.isSpecifiedByAuthor()) { | 276 if (!viewportDescription.isSpecifiedByAuthor()) { |
257 float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustm ent(); | 277 float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustm ent(); |
258 m_baseMultiplier *= deviceScaleAdjustment; | 278 m_baseMultiplier *= deviceScaleAdjustment; |
259 } | 279 } |
280 | |
281 if (m_frameWidth) { | |
282 m_pageNeedsAutosizing = (m_baseMultiplier * (static_cast<float>(m_layout Width) / m_frameWidth) > 1.0f) | |
283 ? PageNeedsAutosizing_Yes : PageNeedsAutosizing_No; | |
284 } else { | |
285 m_pageNeedsAutosizing = PageNeedsAutosizing_Unknown; | |
286 } | |
287 | |
260 #ifndef NDEBUG | 288 #ifndef NDEBUG |
261 m_renderViewInfoPrepared = true; | 289 m_renderViewInfoPrepared = true; |
262 #endif | 290 #endif |
263 } | 291 } |
264 | 292 |
265 bool FastTextAutosizer::isFingerprintingCandidate(const RenderBlock* block) | 293 bool FastTextAutosizer::isFingerprintingCandidate(const RenderBlock* block) |
266 { | 294 { |
267 // FIXME: move the logic out of TextAutosizer.cpp into this class. | 295 // FIXME: move the logic out of TextAutosizer.cpp into this class. |
268 return block->isRenderView() | 296 return block->isRenderView() |
269 || (TextAutosizer::isAutosizingContainer(block) | 297 || (TextAutosizer::isAutosizingContainer(block) |
270 && (TextAutosizer::isIndependentDescendant(block) | 298 && (TextAutosizer::isIndependentDescendant(block) |
271 || mightBeWiderOrNarrowerDescendant(block))); | 299 || mightBeWiderOrNarrowerDescendant(block))); |
272 } | 300 } |
273 | 301 |
274 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) | 302 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) |
275 { | 303 { |
276 Cluster hypotheticalCluster(root, true, 0); | 304 Cluster hypotheticalCluster(root, true, 0); |
277 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); | 305 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); |
278 } | 306 } |
279 | 307 |
280 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) | 308 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) |
281 { | 309 { |
282 if (cluster->m_hasEnoughTextToAutosize != Unknown) | 310 if (cluster->m_hasEnoughTextToAutosize != HasEnoughTextToAutosize_Unknown) |
283 return cluster->m_hasEnoughTextToAutosize == Yes; | 311 return cluster->m_hasEnoughTextToAutosize == HasEnoughTextToAutosize_Yes ; |
284 | 312 |
285 const RenderBlock* root = cluster->m_root; | 313 const RenderBlock* root = cluster->m_root; |
286 if (!widthProvider) | 314 if (!widthProvider) |
287 widthProvider = clusterWidthProvider(root); | 315 widthProvider = clusterWidthProvider(root); |
288 | 316 |
289 // TextAreas and user-modifiable areas get a free pass to autosize regardles s of text content. | 317 // TextAreas and user-modifiable areas get a free pass to autosize regardles s of text content. |
290 if (root->isTextArea() || (root->style() && root->style()->userModify() != R EAD_ONLY)) { | 318 if (root->isTextArea() || (root->style() && root->style()->userModify() != R EAD_ONLY)) { |
291 cluster->m_hasEnoughTextToAutosize = Yes; | 319 cluster->m_hasEnoughTextToAutosize = HasEnoughTextToAutosize_Yes; |
292 return true; | 320 return true; |
293 } | 321 } |
294 | 322 |
295 if (!TextAutosizer::containerShouldBeAutosized(root)) { | 323 if (!TextAutosizer::containerShouldBeAutosized(root)) { |
296 cluster->m_hasEnoughTextToAutosize = No; | 324 cluster->m_hasEnoughTextToAutosize = HasEnoughTextToAutosize_No; |
297 return false; | 325 return false; |
298 } | 326 } |
299 | 327 |
300 // 4 lines of text is considered enough to autosize. | 328 // 4 lines of text is considered enough to autosize. |
301 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4; | 329 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4; |
302 | 330 |
303 float length = 0; | 331 float length = 0; |
304 RenderObject* descendant = root->nextInPreOrder(root); | 332 RenderObject* descendant = root->nextInPreOrder(root); |
305 while (descendant) { | 333 while (descendant) { |
306 if (descendant->isRenderBlock()) { | 334 if (descendant->isRenderBlock()) { |
307 RenderBlock* block = toRenderBlock(descendant); | 335 RenderBlock* block = toRenderBlock(descendant); |
308 if (TextAutosizer::isAutosizingContainer(block)) { | 336 if (TextAutosizer::isAutosizingContainer(block)) { |
309 // Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that | 337 // Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that |
310 // after the block has entered layout, which may not be th e case. | 338 // after the block has entered layout, which may not be th e case. |
311 bool isAutosizingClusterRoot = TextAutosizer::isIndependentDesce ndant(block); | 339 bool isAutosizingClusterRoot = TextAutosizer::isIndependentDesce ndant(block); |
312 if (isAutosizingClusterRoot || !TextAutosizer::containerShouldBe Autosized(block)) { | 340 if (isAutosizingClusterRoot || !TextAutosizer::containerShouldBe Autosized(block)) { |
313 descendant = descendant->nextInPreOrderAfterChildren(root); | 341 descendant = descendant->nextInPreOrderAfterChildren(root); |
314 continue; | 342 continue; |
315 } | 343 } |
316 } | 344 } |
317 } else if (descendant->isText()) { | 345 } else if (descendant->isText()) { |
318 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because | 346 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because |
319 // the lineboxes will not be built until layout. These values can be different. | 347 // the lineboxes will not be built until layout. These values can be different. |
320 // Note: This is an approximation assuming each character is 1em wid e. | 348 // Note: This is an approximation assuming each character is 1em wid e. |
321 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); | 349 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); |
322 | 350 |
323 if (length >= minimumTextLengthToAutosize) { | 351 if (length >= minimumTextLengthToAutosize) { |
324 cluster->m_hasEnoughTextToAutosize = Yes; | 352 cluster->m_hasEnoughTextToAutosize = HasEnoughTextToAutosize_Yes ; |
325 return true; | 353 return true; |
326 } | 354 } |
327 } | 355 } |
328 descendant = descendant->nextInPreOrder(root); | 356 descendant = descendant->nextInPreOrder(root); |
329 } | 357 } |
330 | 358 |
331 cluster->m_hasEnoughTextToAutosize = No; | 359 cluster->m_hasEnoughTextToAutosize = HasEnoughTextToAutosize_No; |
332 return false; | 360 return false; |
333 } | 361 } |
334 | 362 |
335 FastTextAutosizer::Fingerprint FastTextAutosizer::getFingerprint(const RenderObj ect* renderer) | 363 FastTextAutosizer::Fingerprint FastTextAutosizer::getFingerprint(const RenderObj ect* renderer) |
336 { | 364 { |
337 Fingerprint result = m_fingerprintMapper.get(renderer); | 365 Fingerprint result = m_fingerprintMapper.get(renderer); |
338 if (!result) { | 366 if (!result) { |
339 result = computeFingerprint(renderer); | 367 result = computeFingerprint(renderer); |
340 m_fingerprintMapper.add(renderer, result); | 368 m_fingerprintMapper.add(renderer, result); |
341 } | 369 } |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
511 | 539 |
512 float FastTextAutosizer::multiplierFromBlock(const RenderBlock* block) | 540 float FastTextAutosizer::multiplierFromBlock(const RenderBlock* block) |
513 { | 541 { |
514 // If block->needsLayout() is false, it does not need to be in m_blocksThatH aveBegunLayout. | 542 // If block->needsLayout() is false, it does not need to be in m_blocksThatH aveBegunLayout. |
515 // This can happen during layout of a positioned object if the cluster's DBC AT is deeper | 543 // This can happen during layout of a positioned object if the cluster's DBC AT is deeper |
516 // than the positioned object's containing block, and wasn't marked as needi ng layout. | 544 // than the positioned object's containing block, and wasn't marked as needi ng layout. |
517 ASSERT(m_blocksThatHaveBegunLayout.contains(block) || !block->needsLayout()) ; | 545 ASSERT(m_blocksThatHaveBegunLayout.contains(block) || !block->needsLayout()) ; |
518 | 546 |
519 // Block width, in CSS pixels. | 547 // Block width, in CSS pixels. |
520 float blockWidth = widthFromBlock(block); | 548 float blockWidth = widthFromBlock(block); |
521 float multiplier = min(blockWidth, static_cast<float>(m_layoutWidth)) / m_fr ameWidth; | 549 float multiplier = m_frameWidth ? min(blockWidth, static_cast<float>(m_layou tWidth)) / m_frameWidth : 1.0f; |
522 | 550 |
523 return max(m_baseMultiplier * multiplier, 1.0f); | 551 return max(m_baseMultiplier * multiplier, 1.0f); |
524 } | 552 } |
525 | 553 |
526 const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* clu ster) | 554 const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* clu ster) |
527 { | 555 { |
528 if (!cluster->m_deepestBlockContainingAllText) | 556 if (!cluster->m_deepestBlockContainingAllText) |
529 cluster->m_deepestBlockContainingAllText = deepestBlockContainingAllText (cluster->m_root); | 557 cluster->m_deepestBlockContainingAllText = deepestBlockContainingAllText (cluster->m_root); |
530 | 558 |
531 return cluster->m_deepestBlockContainingAllText; | 559 return cluster->m_deepestBlockContainingAllText; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
696 return *m_blocksForFingerprint.get(fingerprint); | 724 return *m_blocksForFingerprint.get(fingerprint); |
697 } | 725 } |
698 | 726 |
699 RenderObject* FastTextAutosizer::nextChildSkippingChildrenOfBlocks(const RenderO bject* current, const RenderObject* stayWithin) | 727 RenderObject* FastTextAutosizer::nextChildSkippingChildrenOfBlocks(const RenderO bject* current, const RenderObject* stayWithin) |
700 { | 728 { |
701 if (current == stayWithin || !current->isRenderBlock()) | 729 if (current == stayWithin || !current->isRenderBlock()) |
702 return current->nextInPreOrder(stayWithin); | 730 return current->nextInPreOrder(stayWithin); |
703 return current->nextInPreOrderAfterChildren(stayWithin); | 731 return current->nextInPreOrderAfterChildren(stayWithin); |
704 } | 732 } |
705 | 733 |
734 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block) | |
735 : m_textAutosizer(block->document().fastTextAutosizer()) | |
736 , m_block(block) | |
737 { | |
738 if (m_textAutosizer) { | |
739 if (!m_textAutosizer->isInLayout()) | |
740 m_textAutosizer->updateRenderViewInfo(); | |
pdr.
2014/03/01 05:16:43
Won't the enabled check below handle calling updat
| |
741 | |
742 if (m_textAutosizer->enabled()) | |
743 m_textAutosizer->beginLayout(m_block); | |
744 else | |
745 m_textAutosizer = 0; | |
746 } | |
747 } | |
748 | |
749 FastTextAutosizer::LayoutScope::~LayoutScope() | |
750 { | |
751 if (m_textAutosizer) | |
752 m_textAutosizer->endLayout(m_block); | |
753 } | |
754 | |
706 } // namespace WebCore | 755 } // namespace WebCore |
OLD | NEW |