Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(464)

Side by Side Diff: Source/core/rendering/FastTextAutosizer.cpp

Issue 145123010: Fix supercluster logic. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW
« Source/core/rendering/FastTextAutosizer.h ('K') | « Source/core/rendering/FastTextAutosizer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698