Chromium Code Reviews| 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 |