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

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

Issue 197883013: [FastTextAutosizer] Refactor for understandability (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 #include "core/rendering/RenderView.h" 44 #include "core/rendering/RenderView.h"
45 45
46 using namespace std; 46 using namespace std;
47 47
48 namespace WebCore { 48 namespace WebCore {
49 49
50 static const RenderObject* parentElementRenderer(const RenderObject* renderer) 50 static const RenderObject* parentElementRenderer(const RenderObject* renderer)
51 { 51 {
52 // At style recalc, the renderer's parent may not be attached, 52 // At style recalc, the renderer's parent may not be attached,
53 // so we need to obtain this from the DOM tree. 53 // so we need to obtain this from the DOM tree.
54
55 const Node* node = renderer->node(); 54 const Node* node = renderer->node();
56 if (!node) 55 if (!node)
57 return 0; 56 return 0;
58 57
59 while ((node = node->parentNode())) { 58 while ((node = node->parentNode())) {
60 if (node->isElementNode()) 59 if (node->isElementNode())
61 return node->renderer(); 60 return node->renderer();
62 } 61 }
63 return 0; 62 return 0;
64 } 63 }
65 64
66 static const Vector<QualifiedName>& formInputTags() 65 static bool isFormInput(const Element* element)
67 { 66 {
68 // Returns the tags for the form input elements.
69 DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ()); 67 DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ());
70 if (formInputTags.isEmpty()) { 68 if (formInputTags.isEmpty()) {
71 formInputTags.append(HTMLNames::inputTag); 69 formInputTags.append(HTMLNames::inputTag);
72 formInputTags.append(HTMLNames::buttonTag); 70 formInputTags.append(HTMLNames::buttonTag);
73 formInputTags.append(HTMLNames::selectTag); 71 formInputTags.append(HTMLNames::selectTag);
74 } 72 }
75 return formInputTags; 73 return formInputTags.contains(element->tagQName());
76 } 74 }
77 75
78 static bool isAutosizingContainer(const RenderObject* renderer) 76 static bool isExemptFromAutosizer(const RenderObject* renderer)
skobes 2014/03/17 19:20:44 If this returns false, it doesn't mean the block i
pdr. 2014/03/18 21:55:00 This took me a while to grok but you're definitely
79 { 77 {
78 // FIXME: update this doc.
80 // "Autosizing containers" are the smallest unit for which we can 79 // "Autosizing containers" are the smallest unit for which we can
81 // enable/disable Text Autosizing. 80 // enable/disable Text Autosizing.
82 // - Must not be inline, as different multipliers on one line looks terrible . 81 // - Must not be inline, as different multipliers on one line looks terrible .
83 // Exceptions are inline-block and alike elements (inline-table, -webkit-i nline-*), 82 // Exceptions are inline-block and alike elements (inline-table, -webkit-i nline-*),
84 // as they often contain entire multi-line columns of text. 83 // as they often contain entire multi-line columns of text.
85 // - Must not be list items, as items in the same list should look consisten t (*). 84 // - Must not be list items, as items in the same list should look consisten t (*).
86 // - Must not be normal list items, as items in the same list should look 85 // - Must not be normal list items, as items in the same list should look
87 // consistent, unless they are floating or position:absolute/fixed. 86 // consistent, unless they are floating or position:absolute/fixed.
88 Node* node = renderer->generatingNode(); 87 Node* node = renderer->generatingNode();
89 if ((node && !node->hasChildren()) 88 if (node && !node->hasChildren())
90 || !renderer->isRenderBlock() 89 return true;
91 || (renderer->isInline() && !renderer->style()->isDisplayReplacedType()) ) 90 if (!renderer->isRenderBlock())
92 return false; 91 return true;
92 if (renderer->isInline() && !renderer->style()->isDisplayReplacedType())
93 return true;
93 if (renderer->isListItem()) 94 if (renderer->isListItem())
94 return renderer->isFloating() || renderer->isOutOfFlowPositioned(); 95 return (!renderer->isFloating() && !renderer->isOutOfFlowPositioned());
95 // Avoid creating containers for text within text controls, buttons, or <sel ect> buttons. 96 // Avoid creating containers for text within text controls, buttons, or <sel ect> buttons.
96 Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0; 97 Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0;
97 if (parentNode && parentNode->isElementNode() && formInputTags().contains(to Element(parentNode)->tagQName())) 98 if (parentNode && parentNode->isElementNode() && isFormInput(toElement(paren tNode)))
98 return false; 99 return true;
99 100
100 return true; 101 return false;
101 }
102
103 static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderO bject* current, const RenderObject* stayWithin)
104 {
105 if (current == stayWithin || !isAutosizingContainer(current))
106 return current->nextInPreOrder(stayWithin);
107 return current->nextInPreOrderAfterChildren(stayWithin);
108 } 102 }
109 103
110 static bool isIndependentDescendant(const RenderBlock* renderer) 104 static bool isIndependentDescendant(const RenderBlock* renderer)
111 { 105 {
112 ASSERT(isAutosizingContainer(renderer)); 106 ASSERT(!isExemptFromAutosizer(renderer));
113 107
114 // "Autosizing clusters" are special autosizing containers within which we 108 // "Autosizing clusters" are special autosizing containers within which we
115 // want to enforce a uniform text size multiplier, in the hopes of making 109 // want to enforce a uniform text size multiplier, in the hopes of making
116 // the major sections of the page look internally consistent. 110 // the major sections of the page look internally consistent.
117 // All their descendants (including other autosizing containers) must share 111 // All their descendants (including other autosizing containers) must share
118 // the same multiplier, except for subtrees which are themselves clusters, 112 // the same multiplier, except for subtrees which are themselves clusters,
119 // and some of their descendant containers might not be autosized at all 113 // and some of their descendant containers might not be autosized at all
120 // (for example if their height is constrained). 114 // (for example if their height is constrained).
121 // Additionally, clusterShouldBeAutosized requires each cluster to contain a 115 // Additionally, clusterShouldBeAutosized requires each cluster to contain a
122 // minimum amount of text, without which it won't be autosized. 116 // minimum amount of text, without which it won't be autosized.
(...skipping 17 matching lines...) Expand all
140 || renderer->hasColumns() 134 || renderer->hasColumns()
141 || (containingBlock && containingBlock->isHorizontalWritingMode() != ren derer->isHorizontalWritingMode()) 135 || (containingBlock && containingBlock->isHorizontalWritingMode() != ren derer->isHorizontalWritingMode())
142 || renderer->style()->isDisplayReplacedType() 136 || renderer->style()->isDisplayReplacedType()
143 || renderer->isTextArea() 137 || renderer->isTextArea()
144 || renderer->style()->userModify() != READ_ONLY; 138 || renderer->style()->userModify() != READ_ONLY;
145 // FIXME: Tables need special handling to multiply all their columns by 139 // FIXME: Tables need special handling to multiply all their columns by
146 // the same amount even if they're different widths; so do hasColumns() 140 // the same amount even if they're different widths; so do hasColumns()
147 // containers, and probably flexboxes... 141 // containers, and probably flexboxes...
148 } 142 }
149 143
150 static bool containerIsRowOfLinks(const RenderObject* container) 144 static bool blockContainsRowOfLinks(const RenderBlock* block)
skobes 2014/03/17 19:20:44 blockIsRowOfLinks (since if it contains links and
pdr. 2014/03/18 21:55:00 Done.
151 { 145 {
152 // A "row of links" is a container for which holds: 146 // A "row of links" is a block for which holds:
153 // 1. it should not contain non-link text elements longer than 3 characters 147 // 1. it should not contain non-link text elements longer than 3 characters
154 // 2. it should contain min. 3 inline links and all links should 148 // 2. it should contain min. 3 inline links and all links should
155 // have the same specified font size 149 // have the same specified font size
156 // 3. it should not contain <br> elements 150 // 3. it should not contain <br> elements
157 // 4. it should contain only inline elements unless they are containers, 151 // 4. it should contain only inline elements unless they are containers,
158 // children of link elements or children of sub-containers. 152 // children of link elements or children of sub-containers.
159 int linkCount = 0; 153 int linkCount = 0;
160 RenderObject* renderer = container->nextInPreOrder(container); 154 RenderObject* renderer = block->nextInPreOrder(block);
161 float matchingFontSize = -1; 155 float matchingFontSize = -1;
162 156
163 while (renderer) { 157 while (renderer) {
164 if (!isAutosizingContainer(renderer)) { 158 if (isExemptFromAutosizer(renderer)) {
165 if (renderer->isText() && toRenderText(renderer)->text().impl()->str ipWhiteSpace()->length() > 3) 159 if (renderer->isText() && toRenderText(renderer)->text().impl()->str ipWhiteSpace()->length() > 3)
166 return false; 160 return false;
167 if (!renderer->isInline()) 161 if (!renderer->isInline() || renderer->isBR())
168 return false;
169 if (renderer->isBR())
170 return false; 162 return false;
171 } 163 }
172 if (renderer->style()->isLink()) { 164 if (renderer->style()->isLink()) {
173 if (matchingFontSize < 0) { 165 linkCount++;
166 if (matchingFontSize < 0)
174 matchingFontSize = renderer->style()->specifiedFontSize(); 167 matchingFontSize = renderer->style()->specifiedFontSize();
175 } else { 168 else if (matchingFontSize != renderer->style()->specifiedFontSize())
176 if (matchingFontSize != renderer->style()->specifiedFontSize()) 169 return false;
177 return false;
178 }
179 170
180 linkCount++;
181 // Skip traversing descendants of the link. 171 // Skip traversing descendants of the link.
182 renderer = renderer->nextInPreOrderAfterChildren(container); 172 renderer = renderer->nextInPreOrderAfterChildren(block);
183 } else { 173 continue;
184 renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, c ontainer);
185 } 174 }
175 renderer = renderer->nextInPreOrder(block);
186 } 176 }
187 177
188 return (linkCount >= 3); 178 return (linkCount >= 3);
189 } 179 }
190 180
191 static bool contentHeightIsConstrained(const RenderBlock* container) 181 static bool blockHeightConstrained(const RenderBlock* block)
192 { 182 {
193 // FIXME: Propagate constrainedness down the tree, to avoid inefficiently wa lking back up from each box. 183 // FIXME: Propagate constrainedness down the tree, to avoid inefficiently wa lking back up from each box.
194 // FIXME: This code needs to take into account vertical writing modes. 184 // FIXME: This code needs to take into account vertical writing modes.
195 // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in. 185 // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in.
196 for (; container; container = container->containingBlock()) { 186 for (; block; block = block->containingBlock()) {
197 RenderStyle* style = container->style(); 187 RenderStyle* style = block->style();
198 if (style->overflowY() >= OSCROLL) 188 if (style->overflowY() >= OSCROLL)
199 return false; 189 return false;
200 if (style->height().isSpecified() || style->maxHeight().isSpecified() || container->isOutOfFlowPositioned()) { 190 if (style->height().isSpecified() || style->maxHeight().isSpecified() || block->isOutOfFlowPositioned()) {
201 // Some sites (e.g. wikipedia) set their html and/or body elements t o height:100%, 191 // Some sites (e.g. wikipedia) set their html and/or body elements t o height:100%,
202 // without intending to constrain the height of the content within t hem. 192 // without intending to constrain the height of the content within t hem.
203 return !container->isRoot() && !container->isBody(); 193 return !block->isRoot() && !block->isBody();
204 } 194 }
205 if (container->isFloating()) 195 if (block->isFloating())
206 return false; 196 return false;
207 } 197 }
208 return false; 198 return false;
209 } 199 }
210 200
211 static bool containerContainsOneOfTags(const RenderBlock* container, const Vecto r<QualifiedName>& tags) 201 static bool blockContainsFormInput(const RenderBlock* block)
212 { 202 {
213 const RenderObject* renderer = container; 203 const RenderObject* renderer = block;
214 while (renderer) { 204 while (renderer) {
215 const Node* rendererNode = renderer->node(); 205 const Node* node = renderer->node();
216 if (rendererNode && rendererNode->isElementNode()) { 206 if (node && node->isElementNode() && isFormInput(toElement(node)))
217 if (tags.contains(toElement(rendererNode)->tagQName())) 207 return true;
218 return true; 208 if (renderer == block)
219 } 209 renderer = renderer->nextInPreOrder(block);
220 renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, conta iner); 210 else
211 renderer = renderer->nextInPreOrderAfterChildren(block);
221 } 212 }
222 213
223 return false; 214 return false;
224 } 215 }
225 216
226 static bool containerShouldBeAutosized(const RenderBlock* container) 217 // Some blocks are not autosized even if their parent cluster wants them to.
218 static bool blockPreventedFromAutosizing(const RenderBlock* block)
skobes 2014/03/17 19:20:44 blockSuppressesAutosizing (since autosizing is dis
pdr. 2014/03/18 21:55:00 Done.
227 { 219 {
228 if (containerContainsOneOfTags(container, formInputTags())) 220 if (blockContainsFormInput(block))
229 return false; 221 return true;
230 222
231 if (containerIsRowOfLinks(container)) 223 if (blockContainsRowOfLinks(block))
232 return false; 224 return true;
233 225
234 // Don't autosize block-level text that can't wrap (as it's likely to 226 // Don't autosize block-level text that can't wrap (as it's likely to
235 // expand sideways and break the page's layout). 227 // expand sideways and break the page's layout).
236 if (!container->style()->autoWrap()) 228 if (!block->style()->autoWrap())
237 return false; 229 return true;
238 230
239 return !contentHeightIsConstrained(container); 231 if (blockHeightConstrained(block))
232 return true;
233
234 return false;
235 }
236
237 static bool mightBeWiderOrNarrowerDescendant(const RenderBlock* block)
238 {
239 // FIXME: This heuristic may need to be expanded to other ways a block can b e wider or narrower
240 // than its parent containing block.
241 return block->style() && block->style()->width().isSpecified();
242 }
243
244 // Before a block enters layout we don't know for sure if it will become a
245 // cluster. Note: clusters are also created for blocks that do not autosize!
246 static bool blockMightBecomeAutosizingCluster(const RenderBlock* block)
247 {
248 ASSERT(!isExemptFromAutosizer(block));
249 return isIndependentDescendant(block) || mightBeWiderOrNarrowerDescendant(bl ock) || block->isTable();
240 } 250 }
241 251
242 FastTextAutosizer::FastTextAutosizer(const Document* document) 252 FastTextAutosizer::FastTextAutosizer(const Document* document)
243 : m_document(document) 253 : m_document(document)
244 , m_frameWidth(0) 254 , m_frameWidth(0)
245 , m_layoutWidth(0) 255 , m_layoutWidth(0)
246 , m_baseMultiplier(0) 256 , m_baseMultiplier(0)
247 , m_pageAutosizingStatus(PageAutosizingStatusUnknown) 257 , m_pageAutosizingStatus(PageAutosizingStatusUnknown)
248 , m_firstBlock(0) 258 , m_firstBlock(0)
249 #ifndef NDEBUG 259 #ifndef NDEBUG
250 , m_renderViewInfoPrepared(false) 260 , m_renderViewInfoPrepared(false)
251 , m_blocksThatHaveBegunLayout() 261 , m_blocksThatHaveBegunLayout()
252 #endif 262 #endif
253 , m_superclusters() 263 , m_superclusters()
254 , m_clusterStack() 264 , m_clusterStack()
255 , m_fingerprintMapper() 265 , m_fingerprintMapper()
256 { 266 {
257 } 267 }
258 268
259 void FastTextAutosizer::record(const RenderBlock* block) 269 void FastTextAutosizer::record(const RenderBlock* block)
260 { 270 {
261 if (!enabled()) 271 if (!enabled())
262 return; 272 return;
263 273
264 ASSERT(!m_blocksThatHaveBegunLayout.contains(block)); 274 ASSERT(!m_blocksThatHaveBegunLayout.contains(block));
265 275
266 if (!isFingerprintingCandidate(block)) 276 if (isExemptFromAutosizer(block))
277 return;
278
279 if (!block->isRenderView() && !blockMightBecomeAutosizingCluster(block))
267 return; 280 return;
268 281
269 if (Fingerprint fingerprint = computeFingerprint(block)) 282 if (Fingerprint fingerprint = computeFingerprint(block))
270 m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint); 283 m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint);
271 } 284 }
272 285
273 void FastTextAutosizer::destroy(const RenderBlock* block) 286 void FastTextAutosizer::destroy(const RenderBlock* block)
274 { 287 {
275 if (!enabled()) 288 if (!enabled())
276 return; 289 return;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 continue; 370 continue;
358 for (RenderObject* row = section->firstChild(); row; row = row->nextSibl ing()) { 371 for (RenderObject* row = section->firstChild(); row; row = row->nextSibl ing()) {
359 if (!row->isTableRow()) 372 if (!row->isTableRow())
360 continue; 373 continue;
361 for (RenderObject* cell = row->firstChild(); cell; cell = cell->next Sibling()) { 374 for (RenderObject* cell = row->firstChild(); cell; cell = cell->next Sibling()) {
362 if (!cell->isTableCell()) 375 if (!cell->isTableCell())
363 continue; 376 continue;
364 RenderTableCell* renderTableCell = toRenderTableCell(cell); 377 RenderTableCell* renderTableCell = toRenderTableCell(cell);
365 378
366 bool shouldAutosize; 379 bool shouldAutosize;
367 if (!containerShouldBeAutosized(renderTableCell)) 380 if (blockPreventedFromAutosizing(renderTableCell))
368 shouldAutosize = false; 381 shouldAutosize = false;
369 else if (Supercluster* supercluster = getSupercluster(renderTabl eCell)) 382 else if (Supercluster* supercluster = getSupercluster(renderTabl eCell))
370 shouldAutosize = anyClusterHasEnoughTextToAutosize(superclus ter->m_roots, table); 383 shouldAutosize = anyClusterHasEnoughTextToAutosize(superclus ter->m_roots, table);
371 else 384 else
372 shouldAutosize = clusterWouldHaveEnoughTextToAutosize(render TableCell, table); 385 shouldAutosize = clusterWouldHaveEnoughTextToAutosize(render TableCell, table);
373 386
374 if (shouldAutosize) { 387 if (shouldAutosize) {
375 for (RenderObject* child = cell; child; child = child->nextI nPreOrder(cell)) { 388 for (RenderObject* child = cell; child; child = child->nextI nPreOrder(cell)) {
376 if (child->isText()) { 389 if (child->isText()) {
377 applyMultiplier(child, multiplier); 390 applyMultiplier(child, multiplier);
(...skipping 20 matching lines...) Expand all
398 #endif 411 #endif
399 } else if (currentCluster()->m_root == block) { 412 } else if (currentCluster()->m_root == block) {
400 m_clusterStack.removeLast(); 413 m_clusterStack.removeLast();
401 } 414 }
402 } 415 }
403 416
404 void FastTextAutosizer::inflate(RenderBlock* block) 417 void FastTextAutosizer::inflate(RenderBlock* block)
405 { 418 {
406 Cluster* cluster = currentCluster(); 419 Cluster* cluster = currentCluster();
407 float multiplier = 0; 420 float multiplier = 0;
408 for (RenderObject* descendant = nextChildSkippingChildrenOfBlocks(block, blo ck); descendant; descendant = nextChildSkippingChildrenOfBlocks(descendant, bloc k)) { 421 RenderObject* descendant = block->nextInPreOrder();
skobes 2014/03/17 19:20:44 I'm not sure what the changes in inflate() are doi
pdr. 2014/03/18 21:55:00 This is mostly removing "nextChildSkippingChildren
422 while (descendant) {
423 // Skip block descendants because they will be inflate()'d on their own.
424 if (descendant->isRenderBlock()) {
425 descendant = descendant->nextInPreOrderAfterChildren(block);
426 continue;
427 }
409 if (descendant->isText()) { 428 if (descendant->isText()) {
410 // We only calculate this multiplier on-demand to ensure the parent block of this text 429 // We only calculate this multiplier on-demand to ensure the parent block of this text
411 // has entered layout. 430 // has entered layout.
412 if (!multiplier) 431 if (!multiplier)
413 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f; 432 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f;
414 applyMultiplier(descendant, multiplier); 433 applyMultiplier(descendant, multiplier);
415 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing. 434 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing.
416 } 435 }
436 descendant = descendant->nextInPreOrder(block);
417 } 437 }
418 } 438 }
419 439
420 bool FastTextAutosizer::enabled() 440 bool FastTextAutosizer::enabled()
421 { 441 {
422 if (!m_document->settings() || !m_document->page() || m_document->printing() ) 442 if (!m_document->settings() || !m_document->page() || m_document->printing() )
423 return false; 443 return false;
424 444
425 return m_document->settings()->textAutosizingEnabled(); 445 return m_document->settings()->textAutosizingEnabled();
426 } 446 }
(...skipping 22 matching lines...) Expand all
449 } 469 }
450 470
451 m_pageAutosizingStatus = m_frameWidth && (m_baseMultiplier * (static_cast<fl oat>(m_layoutWidth) / m_frameWidth) > 1.0f) 471 m_pageAutosizingStatus = m_frameWidth && (m_baseMultiplier * (static_cast<fl oat>(m_layoutWidth) / m_frameWidth) > 1.0f)
452 ? PageNeedsAutosizing : PageDoesNotNeedAutosizing; 472 ? PageNeedsAutosizing : PageDoesNotNeedAutosizing;
453 473
454 #ifndef NDEBUG 474 #ifndef NDEBUG
455 m_renderViewInfoPrepared = true; 475 m_renderViewInfoPrepared = true;
456 #endif 476 #endif
457 } 477 }
458 478
459 bool FastTextAutosizer::isFingerprintingCandidate(const RenderBlock* block)
460 {
461 // FIXME: move the logic out of TextAutosizer.cpp into this class.
462 return block->isRenderView()
463 || (isAutosizingContainer(block)
464 && (isIndependentDescendant(block)
465 || mightBeWiderOrNarrowerDescendant(block)));
466 }
467
468 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider) 479 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider)
469 { 480 {
470 Cluster hypotheticalCluster(root, true, 0); 481 Cluster hypotheticalCluster(root, true, 0);
471 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); 482 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider);
472 } 483 }
473 484
474 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) 485 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider)
475 { 486 {
476 if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText) 487 if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText)
477 return cluster->m_hasEnoughTextToAutosize == HasEnoughText; 488 return cluster->m_hasEnoughTextToAutosize == HasEnoughText;
478 489
479 const RenderBlock* root = cluster->m_root; 490 const RenderBlock* root = cluster->m_root;
480 if (!widthProvider) 491 if (!widthProvider)
481 widthProvider = clusterWidthProvider(root); 492 widthProvider = clusterWidthProvider(root);
482 493
483 // TextAreas and user-modifiable areas get a free pass to autosize regardles s of text content. 494 // TextAreas and user-modifiable areas get a free pass to autosize regardles s of text content.
484 if (root->isTextArea() || (root->style() && root->style()->userModify() != R EAD_ONLY)) { 495 if (root->isTextArea() || (root->style() && root->style()->userModify() != R EAD_ONLY)) {
485 cluster->m_hasEnoughTextToAutosize = HasEnoughText; 496 cluster->m_hasEnoughTextToAutosize = HasEnoughText;
486 return true; 497 return true;
487 } 498 }
488 499
489 if (!containerShouldBeAutosized(root)) { 500 if (blockPreventedFromAutosizing(root)) {
490 cluster->m_hasEnoughTextToAutosize = NotEnoughText; 501 cluster->m_hasEnoughTextToAutosize = NotEnoughText;
491 return false; 502 return false;
492 } 503 }
493 504
494 // 4 lines of text is considered enough to autosize. 505 // 4 lines of text is considered enough to autosize.
495 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4; 506 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4;
496 507
497 float length = 0; 508 float length = 0;
498 RenderObject* descendant = root->nextInPreOrder(root); 509 RenderObject* descendant = root->nextInPreOrder(root);
499 while (descendant) { 510 while (descendant) {
500 if (descendant->isRenderBlock()) { 511 if (descendant->isRenderBlock()) {
501 RenderBlock* block = toRenderBlock(descendant); 512 RenderBlock* block = toRenderBlock(descendant);
502 if (isAutosizingContainer(block)) { 513
503 // Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that 514 // FIXME: These checks do not seem right but our tests are particula rly
skobes 2014/03/17 19:20:44 Clarify what specifically seems wrong?
pdr. 2014/03/18 21:55:00 I updated this comment. In general I think this re
504 // after the block has entered layout, which may not be th e case. 515 // sensitive to them. We should refactor this and the tests.
516 if (!isExemptFromAutosizer(block)) {
505 bool isAutosizingClusterRoot = isIndependentDescendant(block) || block->isTable(); 517 bool isAutosizingClusterRoot = isIndependentDescendant(block) || block->isTable();
506 if ((isAutosizingClusterRoot && !block->isTableCell()) 518 if ((isAutosizingClusterRoot && !block->isTableCell()) || blockP reventedFromAutosizing(block)) {
507 || !containerShouldBeAutosized(block)) {
508 descendant = descendant->nextInPreOrderAfterChildren(root); 519 descendant = descendant->nextInPreOrderAfterChildren(root);
509 continue; 520 continue;
510 } 521 }
511 } 522 }
512 } else if (descendant->isText()) { 523 } else if (descendant->isText()) {
513 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because 524 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because
514 // the lineboxes will not be built until layout. These values can be different. 525 // the lineboxes will not be built until layout. These values can be different.
515 // Note: This is an approximation assuming each character is 1em wid e. 526 // Note: This is an approximation assuming each character is 1em wid e.
516 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); 527 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize();
517 528
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 if (renderer->isTableCell()) 584 if (renderer->isTableCell())
574 data.m_column = renderer->node()->nodeIndex(); 585 data.m_column = renderer->node()->nodeIndex();
575 586
576 return StringHasher::computeHash<UChar>( 587 return StringHasher::computeHash<UChar>(
577 static_cast<const UChar*>(static_cast<const void*>(&data)), 588 static_cast<const UChar*>(static_cast<const void*>(&data)),
578 sizeof data / sizeof(UChar)); 589 sizeof data / sizeof(UChar));
579 } 590 }
580 591
581 FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBl ock* block) 592 FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBl ock* block)
582 { 593 {
583 if (!isAutosizingContainer(block)) 594 if (isExemptFromAutosizer(block))
584 return 0; 595 return 0;
585 596
586 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster(); 597 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster();
587 ASSERT(parentCluster || block->isRenderView()); 598 ASSERT(parentCluster || block->isRenderView());
588 599
589 // Create clusters to suppress / unsuppress autosizing based on containerSho uldBeAutosized. 600 bool mightAutosize = block->isRenderView() || blockMightBecomeAutosizingClus ter(block);
590 bool containerCanAutosize = containerShouldBeAutosized(block); 601 bool preventsAutosizing = blockPreventedFromAutosizing(block);
591 bool parentClusterCanAutosize = parentCluster && parentCluster->m_autosize;
592 bool createClusterThatMightAutosize = block->isRenderView()
593 || mightBeWiderOrNarrowerDescendant(block)
594 || isIndependentDescendant(block)
595 || block->isTable();
596 602
597 // If the container would not alter the m_autosize bit, it doesn't need to b e a cluster. 603 // If the block would not alter the m_autosize bit, it doesn't need to be a cluster.
598 if (!createClusterThatMightAutosize && containerCanAutosize == parentCluster CanAutosize) 604 bool parentPreventsAutosizing = parentCluster && !parentCluster->m_autosize;
605 if (!mightAutosize && preventsAutosizing == parentPreventsAutosizing)
599 return 0; 606 return 0;
600 607
601 return new Cluster(block, containerCanAutosize, parentCluster, getSuperclust er(block)); 608 return new Cluster(block, !preventsAutosizing, parentCluster, getSupercluste r(block));
602 } 609 }
603 610
604 FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const Render Block* block) 611 FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const Render Block* block)
605 { 612 {
606 Fingerprint fingerprint = m_fingerprintMapper.get(block); 613 Fingerprint fingerprint = m_fingerprintMapper.get(block);
607 if (!fingerprint) 614 if (!fingerprint)
608 return 0; 615 return 0;
609 616
610 BlockSet* roots = &m_fingerprintMapper.getTentativeClusterRoots(fingerprint) ; 617 BlockSet* roots = &m_fingerprintMapper.getTentativeClusterRoots(fingerprint) ;
611 if (!roots || roots->size() < 2 || !roots->contains(block)) 618 if (!roots || roots->size() < 2 || !roots->contains(block))
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 return parent; 796 return parent;
790 797
791 if (parent->isEmpty()) 798 if (parent->isEmpty())
792 return parent->isText() ? parent : 0; 799 return parent->isText() ? parent : 0;
793 800
794 ++depth; 801 ++depth;
795 const RenderObject* child = (firstOrLast == First) ? parent->firstChild() : parent->lastChild(); 802 const RenderObject* child = (firstOrLast == First) ? parent->firstChild() : parent->lastChild();
796 while (child) { 803 while (child) {
797 // Note: At this point clusters may not have been created for these bloc ks so we cannot rely 804 // Note: At this point clusters may not have been created for these bloc ks so we cannot rely
798 // on m_clusters. Instead, we use a best-guess about whether the b lock will become a cluster. 805 // on m_clusters. Instead, we use a best-guess about whether the b lock will become a cluster.
799 if (!isAutosizingContainer(child) || !isIndependentDescendant(toRenderBl ock(child))) { 806 if (isExemptFromAutosizer(child) || !isIndependentDescendant(toRenderBlo ck(child))) {
800 const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast); 807 const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast);
801 if (leaf) 808 if (leaf)
802 return leaf; 809 return leaf;
803 } 810 }
804 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling(); 811 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling();
805 } 812 }
806 --depth; 813 --depth;
807 814
808 return 0; 815 return 0;
809 } 816 }
810 817
811 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier ) 818 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier )
812 { 819 {
813 ASSERT(renderer); 820 ASSERT(renderer);
814 RenderStyle* currentStyle = renderer->style(); 821 RenderStyle* currentStyle = renderer->style();
815 if (currentStyle->textAutosizingMultiplier() == multiplier) 822 if (currentStyle->textAutosizingMultiplier() == multiplier)
816 return; 823 return;
817 824
818 // We need to clone the render style to avoid breaking style sharing. 825 // We need to clone the render style to avoid breaking style sharing.
819 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); 826 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle);
820 style->setTextAutosizingMultiplier(multiplier); 827 style->setTextAutosizingMultiplier(multiplier);
821 style->setUnique(); 828 style->setUnique();
822 renderer->setStyleInternal(style.release()); 829 renderer->setStyleInternal(style.release());
823 } 830 }
824 831
825 bool FastTextAutosizer::mightBeWiderOrNarrowerDescendant(const RenderBlock* bloc k)
826 {
827 // FIXME: This heuristic may need to be expanded to other ways a block can b e wider or narrower
828 // than its parent containing block.
829 return block->style() && block->style()->width().isSpecified();
830 }
831
832 bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster) 832 bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster)
833 { 833 {
834 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) ) 834 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) )
835 return true; 835 return true;
836 836
837 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent); 837 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent);
838 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root)); 838 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root));
839 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext)); 839 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext));
840 840
841 float contentWidth = cluster->m_root->contentLogicalWidth().toFloat(); 841 float contentWidth = cluster->m_root->contentLogicalWidth().toFloat();
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 FastTextAutosizer::Fingerprint FastTextAutosizer::FingerprintMapper::get(const R enderObject* renderer) 923 FastTextAutosizer::Fingerprint FastTextAutosizer::FingerprintMapper::get(const R enderObject* renderer)
924 { 924 {
925 return m_fingerprints.get(renderer); 925 return m_fingerprints.get(renderer);
926 } 926 }
927 927
928 FastTextAutosizer::BlockSet& FastTextAutosizer::FingerprintMapper::getTentativeC lusterRoots(Fingerprint fingerprint) 928 FastTextAutosizer::BlockSet& FastTextAutosizer::FingerprintMapper::getTentativeC lusterRoots(Fingerprint fingerprint)
929 { 929 {
930 return *m_blocksForFingerprint.get(fingerprint); 930 return *m_blocksForFingerprint.get(fingerprint);
931 } 931 }
932 932
933 RenderObject* FastTextAutosizer::nextChildSkippingChildrenOfBlocks(const RenderO bject* current, const RenderObject* stayWithin)
934 {
935 if (current == stayWithin || !current->isRenderBlock())
936 return current->nextInPreOrder(stayWithin);
937 return current->nextInPreOrderAfterChildren(stayWithin);
938 }
939
940 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block) 933 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block)
941 : m_textAutosizer(block->document().fastTextAutosizer()) 934 : m_textAutosizer(block->document().fastTextAutosizer())
942 , m_block(block) 935 , m_block(block)
943 { 936 {
944 if (!m_textAutosizer) 937 if (!m_textAutosizer)
945 return; 938 return;
946 939
947 if (!m_textAutosizer->enabled()) { 940 if (!m_textAutosizer->enabled()) {
948 m_textAutosizer = 0; 941 m_textAutosizer = 0;
949 return; 942 return;
950 } 943 }
951 944
952 if (m_textAutosizer->m_pageAutosizingStatus == PageAutosizingStatusUnknown) 945 if (m_textAutosizer->m_pageAutosizingStatus == PageAutosizingStatusUnknown)
953 m_textAutosizer->updateRenderViewInfo(); 946 m_textAutosizer->updateRenderViewInfo();
954 947
955 if (m_textAutosizer->m_pageAutosizingStatus == PageNeedsAutosizing) 948 if (m_textAutosizer->m_pageAutosizingStatus == PageNeedsAutosizing)
956 m_textAutosizer->beginLayout(m_block); 949 m_textAutosizer->beginLayout(m_block);
957 else 950 else
958 m_textAutosizer = 0; 951 m_textAutosizer = 0;
959 } 952 }
960 953
961 FastTextAutosizer::LayoutScope::~LayoutScope() 954 FastTextAutosizer::LayoutScope::~LayoutScope()
962 { 955 {
963 if (m_textAutosizer) 956 if (m_textAutosizer)
964 m_textAutosizer->endLayout(m_block); 957 m_textAutosizer->endLayout(m_block);
965 } 958 }
966 959
967 } // namespace WebCore 960 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698