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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
90 ASSERT(m_clusterStack.isEmpty() == block->isRenderView()); | 90 ASSERT(m_clusterStack.isEmpty() == block->isRenderView()); |
91 | 91 |
92 if (block->isRenderView()) { | 92 if (block->isRenderView()) { |
93 prepareRenderViewInfo(toRenderView(block)); | 93 prepareRenderViewInfo(toRenderView(block)); |
94 } else if (block == currentCluster()->m_root) { | 94 } else if (block == currentCluster()->m_root) { |
95 // Ignore beginLayout on the same block twice. | 95 // Ignore beginLayout on the same block twice. |
96 // This can happen with paginated overflow. | 96 // This can happen with paginated overflow. |
97 return; | 97 return; |
98 } | 98 } |
99 | 99 |
100 if (Cluster* cluster = maybeGetOrCreateCluster(block)) | 100 if (Cluster* cluster = maybeCreateCluster(block)) |
101 m_clusterStack.append(cluster); | 101 m_clusterStack.append(adoptPtr(cluster)); |
102 | 102 |
103 if (block->childrenInline()) | 103 if (block->childrenInline()) |
104 inflate(block); | 104 inflate(block); |
105 } | 105 } |
106 | 106 |
107 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) | 107 void FastTextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMark er* listItemMarker) |
108 { | 108 { |
109 if (!enabled()) | 109 if (!enabled()) |
110 return; | 110 return; |
111 #ifndef NDEBUG | 111 #ifndef NDEBUG |
112 m_blocksThatHaveBegunLayout.add(listItem); | 112 m_blocksThatHaveBegunLayout.add(listItem); |
113 #endif | 113 #endif |
114 // Force the LI to be inside the DBCAT when computing the multiplier. | 114 // Force the LI to be inside the DBCAT when computing the multiplier. |
115 // This guarantees that the DBCAT has entered layout, so we can ask for its width. | 115 // This guarantees that the DBCAT has entered layout, so we can ask for its width. |
116 // It also makes sense because the list marker is autosized like a text node . | 116 // It also makes sense because the list marker is autosized like a text node . |
117 float multiplier = clusterMultiplier(currentCluster()); | 117 float multiplier = clusterMultiplier(currentCluster()); |
118 | 118 |
119 applyMultiplier(listItem, multiplier); | 119 applyMultiplier(listItem, multiplier); |
120 applyMultiplier(listItemMarker, multiplier); | 120 applyMultiplier(listItemMarker, multiplier); |
121 } | 121 } |
122 | 122 |
123 void FastTextAutosizer::endLayout(RenderBlock* block) | 123 void FastTextAutosizer::endLayout(RenderBlock* block) |
124 { | 124 { |
125 if (!enabled()) | 125 if (!enabled()) |
126 return; | 126 return; |
127 | |
128 if (block->isRenderView()) { | |
129 m_superclusters.clear(); | |
127 #ifndef NDEBUG | 130 #ifndef NDEBUG |
128 if (block->isRenderView()) | |
129 m_blocksThatHaveBegunLayout.clear(); | 131 m_blocksThatHaveBegunLayout.clear(); |
130 #endif | 132 #endif |
133 } | |
131 | 134 |
132 if (currentCluster()->m_root == block) | 135 if (currentCluster()->m_root == block) |
133 m_clusterStack.removeLast(); | 136 m_clusterStack.removeLast(); |
134 | 137 |
135 ASSERT(m_clusterStack.isEmpty() == block->isRenderView()); | 138 ASSERT(m_clusterStack.isEmpty() == block->isRenderView()); |
136 } | 139 } |
137 | 140 |
138 void FastTextAutosizer::inflate(RenderBlock* block) | 141 void FastTextAutosizer::inflate(RenderBlock* block) |
139 { | 142 { |
140 Cluster* cluster = currentCluster(); | 143 Cluster* cluster = currentCluster(); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
215 | 218 |
216 float length = 0; | 219 float length = 0; |
217 const RenderBlock* root = cluster->m_root; | 220 const RenderBlock* root = cluster->m_root; |
218 bool measureLocalText = TextAutosizer::containerShouldBeAutosized(root); | 221 bool measureLocalText = TextAutosizer::containerShouldBeAutosized(root); |
219 RenderObject* descendant = root->nextInPreOrder(root); | 222 RenderObject* descendant = root->nextInPreOrder(root); |
220 while (descendant) { | 223 while (descendant) { |
221 // FIXME: We should skip over text from descendant clusters (see: | 224 // FIXME: We should skip over text from descendant clusters (see: |
222 // clusters-sufficient-text-except-in-root.html). This currently includes text | 225 // clusters-sufficient-text-except-in-root.html). This currently includes text |
223 // from descendant clusters. | 226 // from descendant clusters. |
224 | 227 |
225 if (descendant->isRenderBlock() && m_clusters.contains(toRenderBlock(des cendant))) { | |
226 length += textLength(m_clusters.get(toRenderBlock(descendant))); | |
227 descendant = descendant->nextInPreOrderAfterChildren(root); | |
228 continue; | |
229 } | |
230 | |
231 if (measureLocalText && descendant->isText()) { | 228 if (measureLocalText && descendant->isText()) { |
232 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because | 229 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because |
233 // the lineboxes will not be built until layout. These values can be different. | 230 // the lineboxes will not be built until layout. These values can be different. |
234 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); | 231 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); |
235 } | 232 } |
236 descendant = descendant->nextInPreOrder(root); | 233 descendant = descendant->nextInPreOrder(root); |
237 } | 234 } |
238 | 235 |
239 return cluster->m_textLength = length; | 236 return cluster->m_textLength = length; |
240 } | 237 } |
241 | 238 |
242 AtomicString FastTextAutosizer::computeFingerprint(const RenderBlock* block) | 239 AtomicString FastTextAutosizer::computeFingerprint(const RenderBlock* block) |
243 { | 240 { |
244 // FIXME(crbug.com/322340): Implement a fingerprinting algorithm. | 241 // FIXME(crbug.com/322340): Implement a fingerprinting algorithm. |
245 return nullAtom; | 242 return nullAtom; |
246 } | 243 } |
247 | 244 |
248 FastTextAutosizer::Cluster* FastTextAutosizer::maybeGetOrCreateCluster(const Ren derBlock* block) | 245 FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBl ock* block) |
249 { | 246 { |
250 if (!TextAutosizer::isAutosizingContainer(block)) | 247 if (!TextAutosizer::isAutosizingContainer(block)) |
251 return 0; | 248 return 0; |
252 | 249 |
253 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster(); | 250 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster(); |
254 ASSERT(parentCluster || block->isRenderView()); | 251 ASSERT(parentCluster || block->isRenderView()); |
255 | 252 |
256 // Create clusters to suppress / unsuppress autosizing based on containerSho uldBeAutosized. | 253 // Create clusters to suppress / unsuppress autosizing based on containerSho uldBeAutosized. |
257 bool containerCanAutosize = TextAutosizer::containerShouldBeAutosized(block) ; | 254 bool containerCanAutosize = TextAutosizer::containerShouldBeAutosized(block) ; |
258 bool parentClusterCanAutosize = parentCluster && parentCluster->m_autosize; | 255 bool parentClusterCanAutosize = parentCluster && parentCluster->m_autosize; |
259 bool createClusterThatMightAutosize = mightBeWiderOrNarrowerDescendant(block ) || TextAutosizer::isIndependentDescendant(block); | 256 bool createClusterThatMightAutosize = mightBeWiderOrNarrowerDescendant(block ) || TextAutosizer::isIndependentDescendant(block); |
260 | 257 |
261 // If the container would not alter the m_autosize bit, it doesn't need to b e a cluster. | 258 // If the container would not alter the m_autosize bit, it doesn't need to b e a cluster. |
262 if (!createClusterThatMightAutosize && containerCanAutosize == parentCluster CanAutosize) | 259 if (!createClusterThatMightAutosize && containerCanAutosize == parentCluster CanAutosize) |
263 return 0; | 260 return 0; |
264 | 261 |
265 ClusterMap::AddResult addResult = m_clusters.add(block, PassOwnPtr<Cluster>( )); | 262 return new Cluster(block, containerCanAutosize, parentCluster, getSuperclust er(block)); |
263 } | |
264 | |
265 FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const Render Block* block) | |
266 { | |
267 AtomicString fingerprint = m_fingerprintMapper.get(block); | |
268 if (fingerprint.isNull()) | |
269 return 0; | |
270 | |
271 BlockSet* roots = &m_fingerprintMapper.getBlocks(fingerprint); | |
272 if (roots->size() < 2) | |
273 return 0; | |
274 | |
275 SuperclusterMap::AddResult addResult = m_superclusters.add(fingerprint, Pass OwnPtr<Supercluster>()); | |
266 if (!addResult.isNewEntry) | 276 if (!addResult.isNewEntry) |
267 return addResult.iterator->value.get(); | 277 return addResult.iterator->value.get(); |
268 | 278 |
269 AtomicString fingerprint = m_fingerprintMapper.get(block); | 279 Supercluster* supercluster = new Supercluster(roots); |
270 if (fingerprint.isNull()) { | 280 addResult.iterator->value = adoptPtr(supercluster); |
271 addResult.iterator->value = adoptPtr(new Cluster(block, containerCanAuto size, parentCluster)); | 281 return supercluster; |
272 return addResult.iterator->value.get(); | |
273 } | |
274 return addSupercluster(fingerprint, block); | |
275 } | |
276 | |
277 // FIXME: The supercluster logic does not work yet. | |
278 FastTextAutosizer::Cluster* FastTextAutosizer::addSupercluster(AtomicString fing erprint, const RenderBlock* returnFor) | |
279 { | |
280 BlockSet& roots = m_fingerprintMapper.getBlocks(fingerprint); | |
281 | |
282 Cluster* result = 0; | |
283 for (BlockSet::iterator it = roots.begin(); it != roots.end(); ++it) { | |
284 Cluster* cluster = new Cluster(*it, TextAutosizer::containerShouldBeAuto sized(*it), currentCluster()); | |
285 m_clusters.set(*it, adoptPtr(cluster)); | |
286 | |
287 if (*it == returnFor) | |
288 result = cluster; | |
289 } | |
290 return result; | |
291 } | 282 } |
292 | 283 |
293 const RenderBlock* FastTextAutosizer::deepestCommonAncestor(BlockSet& blocks) | 284 const RenderBlock* FastTextAutosizer::deepestCommonAncestor(BlockSet& blocks) |
294 { | 285 { |
295 // Find the lowest common ancestor of blocks. | 286 // Find the lowest common ancestor of blocks. |
296 // Note: this could be improved to not be O(b*h) for b blocks and tree heigh t h. | 287 // Note: this could be improved to not be O(b*h) for b blocks and tree heigh t h. |
297 HashCountedSet<const RenderBlock*> ancestors; | 288 HashCountedSet<const RenderBlock*> ancestors; |
298 for (BlockSet::iterator it = blocks.begin(); it != blocks.end(); ++it) { | 289 for (BlockSet::iterator it = blocks.begin(); it != blocks.end(); ++it) { |
299 for (const RenderBlock* block = (*it); block; block = block->containingB lock()) { | 290 for (const RenderBlock* block = (*it); block; block = block->containingB lock()) { |
300 ancestors.add(block); | 291 ancestors.add(block); |
301 // The first ancestor that has all of the blocks as children wins. | 292 // The first ancestor that has all of the blocks as children wins. |
302 if (ancestors.count(block) == blocks.size()) | 293 if (ancestors.count(block) == blocks.size()) |
303 return block; | 294 return block; |
304 } | 295 } |
305 } | 296 } |
306 ASSERT_NOT_REACHED(); | 297 ASSERT_NOT_REACHED(); |
307 return 0; | 298 return 0; |
308 } | 299 } |
309 | 300 |
310 float FastTextAutosizer::clusterMultiplier(Cluster* cluster) | 301 float FastTextAutosizer::clusterMultiplier(Cluster* cluster) |
311 { | 302 { |
312 ASSERT(m_renderViewInfoPrepared); | 303 ASSERT(m_renderViewInfoPrepared); |
313 if (!cluster->m_multiplier) { | 304 if (!cluster->m_multiplier) { |
314 if (TextAutosizer::isIndependentDescendant(cluster->m_root) || isWiderDe scendant(cluster) || isNarrowerDescendant(cluster)) { | 305 if (TextAutosizer::isIndependentDescendant(cluster->m_root) || isWiderDe scendant(cluster) || isNarrowerDescendant(cluster)) { |
315 if (clusterHasEnoughTextToAutosize(cluster)) { | 306 if (cluster->m_supercluster) { |
316 const RenderBlock* deepestBlockWithAllText = deepestBlockContain ingAllText(cluster); | 307 cluster->m_multiplier = superclusterMultiplier(cluster->m_superc luster); |
317 | 308 } else if (clusterHasEnoughTextToAutosize(cluster)) { |
318 // Ensure the deepest block containing all text has a valid cont entLogicalWidth. | 309 cluster->m_multiplier = multiplierFromBlock(deepestBlockContaini ngAllText(cluster)); |
319 ASSERT(m_blocksThatHaveBegunLayout.contains(deepestBlockWithAllT ext)); | |
320 | |
321 // Block width, in CSS pixels. | |
322 float textBlockWidth = deepestBlockWithAllText->contentLogicalWi dth(); | |
323 float multiplier = min(textBlockWidth, static_cast<float>(m_layo utWidth)) / m_frameWidth; | |
324 cluster->m_multiplier = max(m_baseMultiplier * multiplier, 1.0f) ; | |
325 } else { | 310 } else { |
326 cluster->m_multiplier = 1.0f; | 311 cluster->m_multiplier = 1.0f; |
327 } | 312 } |
328 } else { | 313 } else { |
329 cluster->m_multiplier = cluster->m_parent ? clusterMultiplier(cluste r->m_parent) : 1.0f; | 314 cluster->m_multiplier = cluster->m_parent ? clusterMultiplier(cluste r->m_parent) : 1.0f; |
330 } | 315 } |
331 } | 316 } |
332 ASSERT(cluster->m_multiplier); | 317 ASSERT(cluster->m_multiplier); |
333 return cluster->m_multiplier; | 318 return cluster->m_multiplier; |
334 } | 319 } |
335 | 320 |
321 float FastTextAutosizer::superclusterMultiplier(Supercluster* supercluster) | |
322 { | |
323 if (!supercluster->m_multiplier) { | |
324 const BlockSet* roots = supercluster->m_roots; | |
325 BlockSet dbcats; | |
pdr.
2014/02/06 22:03:27
Please add a comment explaining what a dbcat is, o
skobes
2014/02/06 23:55:50
Done.
| |
326 for (BlockSet::iterator it = roots->begin(); it != roots->end(); ++it) { | |
327 // This is a bit of a hack to let us compute dbcat and text length f or | |
pdr.
2014/02/06 22:03:27
The old autosizer used this hacky pattern quite a
skobes
2014/02/06 23:55:50
Done.
| |
328 // clusters that don't technically exist yet. | |
329 Cluster pseudocluster(*it, true, 0, supercluster); | |
330 dbcats.add(deepestBlockContainingAllText(&pseudocluster)); | |
331 supercluster->m_anyClusterHasEnoughText |= clusterHasEnoughTextToAut osize(&pseudocluster); | |
332 } | |
333 supercluster->m_multiplier = supercluster->m_anyClusterHasEnoughText | |
334 ? multiplierFromBlock(deepestCommonAncestor(dbcats)) : 1.0f; | |
335 } | |
336 ASSERT(supercluster->m_multiplier); | |
337 return supercluster->m_multiplier; | |
338 } | |
339 | |
340 float FastTextAutosizer::multiplierFromBlock(const RenderBlock* block) | |
341 { | |
342 ASSERT(m_blocksThatHaveBegunLayout.contains(block)); | |
343 | |
344 // Block width, in CSS pixels. | |
345 float textBlockWidth = block->contentLogicalWidth(); | |
346 float multiplier = min(textBlockWidth, static_cast<float>(m_layoutWidth)) / m_frameWidth; | |
347 | |
348 return max(m_baseMultiplier * multiplier, 1.0f); | |
349 } | |
350 | |
336 // FIXME: Refactor this to look more like FastTextAutosizer::deepestCommonAncest or. This is copied | 351 // FIXME: Refactor this to look more like FastTextAutosizer::deepestCommonAncest or. This is copied |
337 // from TextAutosizer::findDeepestBlockContainingAllText. | 352 // from TextAutosizer::findDeepestBlockContainingAllText. |
338 const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* clu ster) | 353 const RenderBlock* FastTextAutosizer::deepestBlockContainingAllText(Cluster* clu ster) |
339 { | 354 { |
340 if (cluster->m_deepestBlockContainingAllText) | 355 if (cluster->m_deepestBlockContainingAllText) |
341 return cluster->m_deepestBlockContainingAllText; | 356 return cluster->m_deepestBlockContainingAllText; |
342 | 357 |
343 size_t firstDepth = 0; | 358 size_t firstDepth = 0; |
344 const RenderObject* firstTextLeaf = findTextLeaf(cluster->m_root, firstDepth , First); | 359 const RenderObject* firstTextLeaf = findTextLeaf(cluster->m_root, firstDepth , First); |
345 if (!firstTextLeaf) | 360 if (!firstTextLeaf) |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 float contentWidth = cluster->m_root->contentLogicalWidth(); | 474 float contentWidth = cluster->m_root->contentLogicalWidth(); |
460 float clusterTextWidth = parentDeepestBlockContainingAllText->contentLogical Width(); | 475 float clusterTextWidth = parentDeepestBlockContainingAllText->contentLogical Width(); |
461 float widthDifference = clusterTextWidth - contentWidth; | 476 float widthDifference = clusterTextWidth - contentWidth; |
462 | 477 |
463 return widthDifference > narrowWidthDifference; | 478 return widthDifference > narrowWidthDifference; |
464 } | 479 } |
465 | 480 |
466 FastTextAutosizer::Cluster* FastTextAutosizer::currentCluster() const | 481 FastTextAutosizer::Cluster* FastTextAutosizer::currentCluster() const |
467 { | 482 { |
468 ASSERT(!m_clusterStack.isEmpty()); | 483 ASSERT(!m_clusterStack.isEmpty()); |
469 return m_clusterStack.last(); | 484 return m_clusterStack.last().get(); |
470 } | 485 } |
471 | 486 |
472 void FastTextAutosizer::FingerprintMapper::add(const RenderBlock* block, AtomicS tring fingerprint) | 487 void FastTextAutosizer::FingerprintMapper::add(const RenderBlock* block, AtomicS tring fingerprint) |
473 { | 488 { |
474 m_fingerprints.set(block, fingerprint); | 489 m_fingerprints.set(block, fingerprint); |
475 | 490 |
476 ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fing erprint, PassOwnPtr<BlockSet>()); | 491 ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fing erprint, PassOwnPtr<BlockSet>()); |
477 if (addResult.isNewEntry) | 492 if (addResult.isNewEntry) |
478 addResult.iterator->value = adoptPtr(new BlockSet); | 493 addResult.iterator->value = adoptPtr(new BlockSet); |
479 addResult.iterator->value->add(block); | 494 addResult.iterator->value->add(block); |
(...skipping 23 matching lines...) Expand all Loading... | |
503 } | 518 } |
504 | 519 |
505 RenderObject* FastTextAutosizer::nextChildSkippingChildrenOfBlocks(const RenderO bject* current, const RenderObject* stayWithin) | 520 RenderObject* FastTextAutosizer::nextChildSkippingChildrenOfBlocks(const RenderO bject* current, const RenderObject* stayWithin) |
506 { | 521 { |
507 if (current == stayWithin || !current->isRenderBlock()) | 522 if (current == stayWithin || !current->isRenderBlock()) |
508 return current->nextInPreOrder(stayWithin); | 523 return current->nextInPreOrder(stayWithin); |
509 return current->nextInPreOrderAfterChildren(stayWithin); | 524 return current->nextInPreOrderAfterChildren(stayWithin); |
510 } | 525 } |
511 | 526 |
512 } // namespace WebCore | 527 } // namespace WebCore |
OLD | NEW |