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

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: Address reviewer comments 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 isPotentialClusterRoot(const RenderObject* renderer)
79 { 77 {
80 // "Autosizing containers" are the smallest unit for which we can 78 // "Potential cluster roots" are the smallest unit for which we can
81 // enable/disable Text Autosizing. 79 // enable/disable text autosizing.
82 // - Must not be inline, as different multipliers on one line looks terrible . 80 // - 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-*), 81 // Exceptions are inline-block and alike elements (inline-table, -webkit-i nline-*),
84 // as they often contain entire multi-line columns of text. 82 // 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 (*). 83 // - 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 84 // - Must not be normal list items, as items in the same list should look
87 // consistent, unless they are floating or position:absolute/fixed. 85 // consistent, unless they are floating or position:absolute/fixed.
88 Node* node = renderer->generatingNode(); 86 Node* node = renderer->generatingNode();
89 if ((node && !node->hasChildren()) 87 if (node && !node->hasChildren())
90 || !renderer->isRenderBlock() 88 return false;
91 || (renderer->isInline() && !renderer->style()->isDisplayReplacedType()) ) 89 if (!renderer->isRenderBlock())
90 return false;
91 if (renderer->isInline() && !renderer->style()->isDisplayReplacedType())
92 return false; 92 return false;
93 if (renderer->isListItem()) 93 if (renderer->isListItem())
94 return renderer->isFloating() || renderer->isOutOfFlowPositioned(); 94 return (renderer->isFloating() || renderer->isOutOfFlowPositioned());
95 // Avoid creating containers for text within text controls, buttons, or <sel ect> buttons. 95 // Avoid creating containers for text within text controls, buttons, or <sel ect> buttons.
96 Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0; 96 Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode() : 0;
97 if (parentNode && parentNode->isElementNode() && formInputTags().contains(to Element(parentNode)->tagQName())) 97 if (parentNode && parentNode->isElementNode() && isFormInput(toElement(paren tNode)))
98 return false; 98 return false;
99 99
100 return true; 100 return true;
101 } 101 }
102 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 }
109
110 static bool isIndependentDescendant(const RenderBlock* renderer) 103 static bool isIndependentDescendant(const RenderBlock* renderer)
111 { 104 {
112 ASSERT(isAutosizingContainer(renderer)); 105 ASSERT(isPotentialClusterRoot(renderer));
113 106
114 // "Autosizing clusters" are special autosizing containers within which we
115 // want to enforce a uniform text size multiplier, in the hopes of making
116 // the major sections of the page look internally consistent.
117 // All their descendants (including other autosizing containers) must share
118 // the same multiplier, except for subtrees which are themselves clusters,
119 // and some of their descendant containers might not be autosized at all
120 // (for example if their height is constrained).
121 // Additionally, clusterShouldBeAutosized requires each cluster to contain a
122 // minimum amount of text, without which it won't be autosized.
123 //
124 // Clusters are chosen using very similar criteria to CSS flow roots, aka
125 // block formatting contexts (http://w3.org/TR/css3-box/#flow-root), since
126 // flow roots correspond to box containers that behave somewhat
127 // independently from their parent (for example they don't overlap floats).
128 // The definition of a flow root also conveniently includes most of the
129 // ways that a box and its children can have significantly different width
130 // from the box's parent (we want to avoid having significantly different
131 // width blocks within a cluster, since the narrower blocks would end up
132 // larger than would otherwise be necessary).
133 RenderBlock* containingBlock = renderer->containingBlock(); 107 RenderBlock* containingBlock = renderer->containingBlock();
134 return renderer->isRenderView() 108 return renderer->isRenderView()
135 || renderer->isFloating() 109 || renderer->isFloating()
136 || renderer->isOutOfFlowPositioned() 110 || renderer->isOutOfFlowPositioned()
137 || renderer->isTableCell() 111 || renderer->isTableCell()
138 || renderer->isTableCaption() 112 || renderer->isTableCaption()
139 || renderer->isFlexibleBoxIncludingDeprecated() 113 || renderer->isFlexibleBoxIncludingDeprecated()
140 || renderer->hasColumns() 114 || renderer->hasColumns()
141 || (containingBlock && containingBlock->isHorizontalWritingMode() != ren derer->isHorizontalWritingMode()) 115 || (containingBlock && containingBlock->isHorizontalWritingMode() != ren derer->isHorizontalWritingMode())
142 || renderer->style()->isDisplayReplacedType() 116 || renderer->style()->isDisplayReplacedType()
143 || renderer->isTextArea() 117 || renderer->isTextArea()
144 || renderer->style()->userModify() != READ_ONLY; 118 || renderer->style()->userModify() != READ_ONLY;
145 // FIXME: Tables need special handling to multiply all their columns by 119 // FIXME: Tables need special handling to multiply all their columns by
146 // the same amount even if they're different widths; so do hasColumns() 120 // the same amount even if they're different widths; so do hasColumns()
147 // containers, and probably flexboxes... 121 // containers, and probably flexboxes...
148 } 122 }
149 123
150 static bool containerIsRowOfLinks(const RenderObject* container) 124 static bool blockIsRowOfLinks(const RenderBlock* block)
151 { 125 {
152 // A "row of links" is a container for which holds: 126 // A "row of links" is a block for which:
153 // 1. it should not contain non-link text elements longer than 3 characters 127 // 1. It does not contain non-link text elements longer than 3 characters
154 // 2. it should contain min. 3 inline links and all links should 128 // 2. It contains a minimum of 3 inline links and all links should
155 // have the same specified font size 129 // have the same specified font size.
156 // 3. it should not contain <br> elements 130 // 3. It should not contain <br> elements.
157 // 4. it should contain only inline elements unless they are containers, 131 // 4. It should contain only inline elements unless they are containers,
158 // children of link elements or children of sub-containers. 132 // children of link elements or children of sub-containers.
159 int linkCount = 0; 133 int linkCount = 0;
160 RenderObject* renderer = container->nextInPreOrder(container); 134 RenderObject* renderer = block->nextInPreOrder(block);
161 float matchingFontSize = -1; 135 float matchingFontSize = -1;
162 136
163 while (renderer) { 137 while (renderer) {
164 if (!isAutosizingContainer(renderer)) { 138 if (!isPotentialClusterRoot(renderer)) {
165 if (renderer->isText() && toRenderText(renderer)->text().impl()->str ipWhiteSpace()->length() > 3) 139 if (renderer->isText() && toRenderText(renderer)->text().impl()->str ipWhiteSpace()->length() > 3)
166 return false; 140 return false;
167 if (!renderer->isInline()) 141 if (!renderer->isInline() || renderer->isBR())
168 return false;
169 if (renderer->isBR())
170 return false; 142 return false;
171 } 143 }
172 if (renderer->style()->isLink()) { 144 if (renderer->style()->isLink()) {
173 if (matchingFontSize < 0) { 145 linkCount++;
146 if (matchingFontSize < 0)
174 matchingFontSize = renderer->style()->specifiedFontSize(); 147 matchingFontSize = renderer->style()->specifiedFontSize();
175 } else { 148 else if (matchingFontSize != renderer->style()->specifiedFontSize())
176 if (matchingFontSize != renderer->style()->specifiedFontSize()) 149 return false;
177 return false;
178 }
179 150
180 linkCount++;
181 // Skip traversing descendants of the link. 151 // Skip traversing descendants of the link.
182 renderer = renderer->nextInPreOrderAfterChildren(container); 152 renderer = renderer->nextInPreOrderAfterChildren(block);
183 } else { 153 continue;
184 renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, c ontainer);
185 } 154 }
155 renderer = renderer->nextInPreOrder(block);
186 } 156 }
187 157
188 return (linkCount >= 3); 158 return (linkCount >= 3);
189 } 159 }
190 160
191 static bool contentHeightIsConstrained(const RenderBlock* container) 161 static bool blockHeightConstrained(const RenderBlock* block)
192 { 162 {
193 // FIXME: Propagate constrainedness down the tree, to avoid inefficiently wa lking back up from each box. 163 // 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. 164 // 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. 165 // 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()) { 166 for (; block; block = block->containingBlock()) {
197 RenderStyle* style = container->style(); 167 RenderStyle* style = block->style();
198 if (style->overflowY() >= OSCROLL) 168 if (style->overflowY() >= OSCROLL)
199 return false; 169 return false;
200 if (style->height().isSpecified() || style->maxHeight().isSpecified() || container->isOutOfFlowPositioned()) { 170 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%, 171 // 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. 172 // without intending to constrain the height of the content within t hem.
203 return !container->isRoot() && !container->isBody(); 173 return !block->isRoot() && !block->isBody();
204 } 174 }
205 if (container->isFloating()) 175 if (block->isFloating())
206 return false; 176 return false;
207 } 177 }
208 return false; 178 return false;
209 } 179 }
210 180
211 static bool containerContainsOneOfTags(const RenderBlock* container, const Vecto r<QualifiedName>& tags) 181 static bool blockContainsFormInput(const RenderBlock* block)
212 { 182 {
213 const RenderObject* renderer = container; 183 const RenderObject* renderer = block;
214 while (renderer) { 184 while (renderer) {
215 const Node* rendererNode = renderer->node(); 185 const Node* node = renderer->node();
216 if (rendererNode && rendererNode->isElementNode()) { 186 if (node && node->isElementNode() && isFormInput(toElement(node)))
217 if (tags.contains(toElement(rendererNode)->tagQName())) 187 return true;
218 return true; 188 if (renderer == block)
219 } 189 renderer = renderer->nextInPreOrder(block);
220 renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, conta iner); 190 else
191 renderer = renderer->nextInPreOrderAfterChildren(block);
221 } 192 }
222 193
223 return false; 194 return false;
224 } 195 }
225 196
226 static bool containerShouldBeAutosized(const RenderBlock* container) 197 // Some blocks are not autosized even if their parent cluster wants them to.
198 static bool blockSuppressesAutosizing(const RenderBlock* block)
227 { 199 {
228 if (containerContainsOneOfTags(container, formInputTags())) 200 if (blockContainsFormInput(block))
229 return false; 201 return true;
230 202
231 if (containerIsRowOfLinks(container)) 203 if (blockIsRowOfLinks(block))
232 return false; 204 return true;
233 205
234 // Don't autosize block-level text that can't wrap (as it's likely to 206 // Don't autosize block-level text that can't wrap (as it's likely to
235 // expand sideways and break the page's layout). 207 // expand sideways and break the page's layout).
236 if (!container->style()->autoWrap()) 208 if (!block->style()->autoWrap())
237 return false; 209 return true;
238 210
239 return !contentHeightIsConstrained(container); 211 if (blockHeightConstrained(block))
212 return true;
213
214 return false;
215 }
216
217 static bool mightBeWiderOrNarrowerDescendant(const RenderBlock* block)
218 {
219 // FIXME: This heuristic may need to be expanded to other ways a block can b e wider or narrower
220 // than its parent containing block.
221 return block->style() && block->style()->width().isSpecified();
222 }
223
224 // Before a block enters layout we don't know for sure if it will become a clust er.
225 // Note: clusters are also created for blocks that do become autosizing clusters !
226 static bool blockMightBecomeAutosizingCluster(const RenderBlock* block)
227 {
228 ASSERT(isPotentialClusterRoot(block));
229 return isIndependentDescendant(block) || mightBeWiderOrNarrowerDescendant(bl ock) || block->isTable();
240 } 230 }
241 231
242 FastTextAutosizer::FastTextAutosizer(const Document* document) 232 FastTextAutosizer::FastTextAutosizer(const Document* document)
243 : m_document(document) 233 : m_document(document)
244 , m_frameWidth(0) 234 , m_frameWidth(0)
245 , m_layoutWidth(0) 235 , m_layoutWidth(0)
246 , m_baseMultiplier(0) 236 , m_baseMultiplier(0)
247 , m_pageAutosizingStatus(PageAutosizingStatusUnknown) 237 , m_pageAutosizingStatus(PageAutosizingStatusUnknown)
248 , m_firstBlock(0) 238 , m_firstBlock(0)
249 #ifndef NDEBUG 239 #ifndef NDEBUG
250 , m_renderViewInfoPrepared(false) 240 , m_renderViewInfoPrepared(false)
251 , m_blocksThatHaveBegunLayout() 241 , m_blocksThatHaveBegunLayout()
252 #endif 242 #endif
253 , m_superclusters() 243 , m_superclusters()
254 , m_clusterStack() 244 , m_clusterStack()
255 , m_fingerprintMapper() 245 , m_fingerprintMapper()
256 { 246 {
257 } 247 }
258 248
259 void FastTextAutosizer::record(const RenderBlock* block) 249 void FastTextAutosizer::record(const RenderBlock* block)
260 { 250 {
261 if (!enabled()) 251 if (!enabled())
262 return; 252 return;
263 253
264 ASSERT(!m_blocksThatHaveBegunLayout.contains(block)); 254 ASSERT(!m_blocksThatHaveBegunLayout.contains(block));
265 255
266 if (!isFingerprintingCandidate(block)) 256 if (!isPotentialClusterRoot(block))
257 return;
258
259 if (!blockMightBecomeAutosizingCluster(block))
267 return; 260 return;
268 261
269 if (Fingerprint fingerprint = computeFingerprint(block)) 262 if (Fingerprint fingerprint = computeFingerprint(block))
270 m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint); 263 m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint);
271 } 264 }
272 265
273 void FastTextAutosizer::destroy(const RenderBlock* block) 266 void FastTextAutosizer::destroy(const RenderBlock* block)
274 { 267 {
275 if (!enabled()) 268 if (!enabled())
276 return; 269 return;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 continue; 350 continue;
358 for (RenderObject* row = section->firstChild(); row; row = row->nextSibl ing()) { 351 for (RenderObject* row = section->firstChild(); row; row = row->nextSibl ing()) {
359 if (!row->isTableRow()) 352 if (!row->isTableRow())
360 continue; 353 continue;
361 for (RenderObject* cell = row->firstChild(); cell; cell = cell->next Sibling()) { 354 for (RenderObject* cell = row->firstChild(); cell; cell = cell->next Sibling()) {
362 if (!cell->isTableCell()) 355 if (!cell->isTableCell())
363 continue; 356 continue;
364 RenderTableCell* renderTableCell = toRenderTableCell(cell); 357 RenderTableCell* renderTableCell = toRenderTableCell(cell);
365 358
366 bool shouldAutosize; 359 bool shouldAutosize;
367 if (!containerShouldBeAutosized(renderTableCell)) 360 if (blockSuppressesAutosizing(renderTableCell))
368 shouldAutosize = false; 361 shouldAutosize = false;
369 else if (Supercluster* supercluster = getSupercluster(renderTabl eCell)) 362 else if (Supercluster* supercluster = getSupercluster(renderTabl eCell))
370 shouldAutosize = anyClusterHasEnoughTextToAutosize(superclus ter->m_roots, table); 363 shouldAutosize = anyClusterHasEnoughTextToAutosize(superclus ter->m_roots, table);
371 else 364 else
372 shouldAutosize = clusterWouldHaveEnoughTextToAutosize(render TableCell, table); 365 shouldAutosize = clusterWouldHaveEnoughTextToAutosize(render TableCell, table);
373 366
374 if (shouldAutosize) { 367 if (shouldAutosize) {
375 for (RenderObject* child = cell; child; child = child->nextI nPreOrder(cell)) { 368 for (RenderObject* child = cell; child; child = child->nextI nPreOrder(cell)) {
376 if (child->isText()) { 369 if (child->isText()) {
377 applyMultiplier(child, multiplier); 370 applyMultiplier(child, multiplier);
(...skipping 20 matching lines...) Expand all
398 #endif 391 #endif
399 } else if (currentCluster()->m_root == block) { 392 } else if (currentCluster()->m_root == block) {
400 m_clusterStack.removeLast(); 393 m_clusterStack.removeLast();
401 } 394 }
402 } 395 }
403 396
404 void FastTextAutosizer::inflate(RenderBlock* block) 397 void FastTextAutosizer::inflate(RenderBlock* block)
405 { 398 {
406 Cluster* cluster = currentCluster(); 399 Cluster* cluster = currentCluster();
407 float multiplier = 0; 400 float multiplier = 0;
408 for (RenderObject* descendant = nextChildSkippingChildrenOfBlocks(block, blo ck); descendant; descendant = nextChildSkippingChildrenOfBlocks(descendant, bloc k)) { 401 RenderObject* descendant = block->nextInPreOrder();
402 while (descendant) {
403 // Skip block descendants because they will be inflate()'d on their own.
404 if (descendant->isRenderBlock()) {
405 descendant = descendant->nextInPreOrderAfterChildren(block);
406 continue;
407 }
409 if (descendant->isText()) { 408 if (descendant->isText()) {
410 // We only calculate this multiplier on-demand to ensure the parent block of this text 409 // We only calculate this multiplier on-demand to ensure the parent block of this text
411 // has entered layout. 410 // has entered layout.
412 if (!multiplier) 411 if (!multiplier)
413 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f; 412 multiplier = cluster->m_autosize ? clusterMultiplier(cluster) : 1.0f;
414 applyMultiplier(descendant, multiplier); 413 applyMultiplier(descendant, multiplier);
415 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing. 414 applyMultiplier(descendant->parent(), multiplier); // Parent handles line spacing.
416 } 415 }
416 descendant = descendant->nextInPreOrder(block);
417 } 417 }
418 } 418 }
419 419
420 bool FastTextAutosizer::enabled() 420 bool FastTextAutosizer::enabled()
421 { 421 {
422 if (!m_document->settings() || !m_document->page() || m_document->printing() ) 422 if (!m_document->settings() || !m_document->page() || m_document->printing() )
423 return false; 423 return false;
424 424
425 return m_document->settings()->textAutosizingEnabled(); 425 return m_document->settings()->textAutosizingEnabled();
426 } 426 }
(...skipping 22 matching lines...) Expand all
449 } 449 }
450 450
451 m_pageAutosizingStatus = m_frameWidth && (m_baseMultiplier * (static_cast<fl oat>(m_layoutWidth) / m_frameWidth) > 1.0f) 451 m_pageAutosizingStatus = m_frameWidth && (m_baseMultiplier * (static_cast<fl oat>(m_layoutWidth) / m_frameWidth) > 1.0f)
452 ? PageNeedsAutosizing : PageDoesNotNeedAutosizing; 452 ? PageNeedsAutosizing : PageDoesNotNeedAutosizing;
453 453
454 #ifndef NDEBUG 454 #ifndef NDEBUG
455 m_renderViewInfoPrepared = true; 455 m_renderViewInfoPrepared = true;
456 #endif 456 #endif
457 } 457 }
458 458
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) 459 bool FastTextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider)
469 { 460 {
470 Cluster hypotheticalCluster(root, true, 0); 461 Cluster hypotheticalCluster(root, true, 0);
471 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider); 462 return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider);
472 } 463 }
473 464
474 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider) 465 bool FastTextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const R enderBlock* widthProvider)
475 { 466 {
476 if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText) 467 if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText)
477 return cluster->m_hasEnoughTextToAutosize == HasEnoughText; 468 return cluster->m_hasEnoughTextToAutosize == HasEnoughText;
478 469
479 const RenderBlock* root = cluster->m_root; 470 const RenderBlock* root = cluster->m_root;
480 if (!widthProvider) 471 if (!widthProvider)
481 widthProvider = clusterWidthProvider(root); 472 widthProvider = clusterWidthProvider(root);
482 473
483 // TextAreas and user-modifiable areas get a free pass to autosize regardles s of text content. 474 // 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)) { 475 if (root->isTextArea() || (root->style() && root->style()->userModify() != R EAD_ONLY)) {
485 cluster->m_hasEnoughTextToAutosize = HasEnoughText; 476 cluster->m_hasEnoughTextToAutosize = HasEnoughText;
486 return true; 477 return true;
487 } 478 }
488 479
489 if (!containerShouldBeAutosized(root)) { 480 if (blockSuppressesAutosizing(root)) {
490 cluster->m_hasEnoughTextToAutosize = NotEnoughText; 481 cluster->m_hasEnoughTextToAutosize = NotEnoughText;
491 return false; 482 return false;
492 } 483 }
493 484
494 // 4 lines of text is considered enough to autosize. 485 // 4 lines of text is considered enough to autosize.
495 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4; 486 float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4;
496 487
497 float length = 0; 488 float length = 0;
498 RenderObject* descendant = root->nextInPreOrder(root); 489 RenderObject* descendant = root->nextInPreOrder(root);
499 while (descendant) { 490 while (descendant) {
500 if (descendant->isRenderBlock()) { 491 if (descendant->isRenderBlock()) {
501 RenderBlock* block = toRenderBlock(descendant); 492 RenderBlock* block = toRenderBlock(descendant);
502 if (isAutosizingContainer(block)) { 493
503 // Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that 494 // Note: Ideally we would check isWiderOrNarrowerDescendant here but we only know that
504 // after the block has entered layout, which may not be th e case. 495 // after the block has entered layout, which may not be the ca se.
496 if (isPotentialClusterRoot(block)) {
505 bool isAutosizingClusterRoot = isIndependentDescendant(block) || block->isTable(); 497 bool isAutosizingClusterRoot = isIndependentDescendant(block) || block->isTable();
506 if ((isAutosizingClusterRoot && !block->isTableCell()) 498 if ((isAutosizingClusterRoot && !block->isTableCell()) || blockS uppressesAutosizing(block)) {
507 || !containerShouldBeAutosized(block)) {
508 descendant = descendant->nextInPreOrderAfterChildren(root); 499 descendant = descendant->nextInPreOrderAfterChildren(root);
509 continue; 500 continue;
510 } 501 }
511 } 502 }
512 } else if (descendant->isText()) { 503 } else if (descendant->isText()) {
513 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because 504 // Note: Using text().stripWhiteSpace().length() instead of rendered TextLength() because
514 // the lineboxes will not be built until layout. These values can be different. 505 // 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. 506 // Note: This is an approximation assuming each character is 1em wid e.
516 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize(); 507 length += toRenderText(descendant)->text().stripWhiteSpace().length( ) * descendant->style()->specifiedFontSize();
517 508
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 if (renderer->isTableCell()) 564 if (renderer->isTableCell())
574 data.m_column = renderer->node()->nodeIndex(); 565 data.m_column = renderer->node()->nodeIndex();
575 566
576 return StringHasher::computeHash<UChar>( 567 return StringHasher::computeHash<UChar>(
577 static_cast<const UChar*>(static_cast<const void*>(&data)), 568 static_cast<const UChar*>(static_cast<const void*>(&data)),
578 sizeof data / sizeof(UChar)); 569 sizeof data / sizeof(UChar));
579 } 570 }
580 571
581 FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBl ock* block) 572 FastTextAutosizer::Cluster* FastTextAutosizer::maybeCreateCluster(const RenderBl ock* block)
582 { 573 {
583 if (!isAutosizingContainer(block)) 574 if (!isPotentialClusterRoot(block))
584 return 0; 575 return 0;
585 576
586 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster(); 577 Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster();
587 ASSERT(parentCluster || block->isRenderView()); 578 ASSERT(parentCluster || block->isRenderView());
588 579
589 // Create clusters to suppress / unsuppress autosizing based on containerSho uldBeAutosized. 580 bool mightAutosize = blockMightBecomeAutosizingCluster(block);
590 bool containerCanAutosize = containerShouldBeAutosized(block); 581 bool suppressesAutosizing = blockSuppressesAutosizing(block);
591 bool parentClusterCanAutosize = parentCluster && parentCluster->m_autosize;
592 bool createClusterThatMightAutosize = block->isRenderView()
593 || mightBeWiderOrNarrowerDescendant(block)
594 || isIndependentDescendant(block)
595 || block->isTable();
596 582
597 // If the container would not alter the m_autosize bit, it doesn't need to b e a cluster. 583 // If the block would not alter the m_autosize bit, it doesn't need to be a cluster.
598 if (!createClusterThatMightAutosize && containerCanAutosize == parentCluster CanAutosize) 584 bool parentSuppressesAutosizing = parentCluster && !parentCluster->m_autosiz e;
585 if (!mightAutosize && suppressesAutosizing == parentSuppressesAutosizing)
599 return 0; 586 return 0;
600 587
601 return new Cluster(block, containerCanAutosize, parentCluster, getSuperclust er(block)); 588 return new Cluster(block, !suppressesAutosizing, parentCluster, getSuperclus ter(block));
602 } 589 }
603 590
604 FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const Render Block* block) 591 FastTextAutosizer::Supercluster* FastTextAutosizer::getSupercluster(const Render Block* block)
605 { 592 {
606 Fingerprint fingerprint = m_fingerprintMapper.get(block); 593 Fingerprint fingerprint = m_fingerprintMapper.get(block);
607 if (!fingerprint) 594 if (!fingerprint)
608 return 0; 595 return 0;
609 596
610 BlockSet* roots = &m_fingerprintMapper.getTentativeClusterRoots(fingerprint) ; 597 BlockSet* roots = &m_fingerprintMapper.getTentativeClusterRoots(fingerprint) ;
611 if (!roots || roots->size() < 2 || !roots->contains(block)) 598 if (!roots || roots->size() < 2 || !roots->contains(block))
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 return parent; 776 return parent;
790 777
791 if (parent->isEmpty()) 778 if (parent->isEmpty())
792 return parent->isText() ? parent : 0; 779 return parent->isText() ? parent : 0;
793 780
794 ++depth; 781 ++depth;
795 const RenderObject* child = (firstOrLast == First) ? parent->firstChild() : parent->lastChild(); 782 const RenderObject* child = (firstOrLast == First) ? parent->firstChild() : parent->lastChild();
796 while (child) { 783 while (child) {
797 // Note: At this point clusters may not have been created for these bloc ks so we cannot rely 784 // 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. 785 // 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))) { 786 if (!isPotentialClusterRoot(child) || !isIndependentDescendant(toRenderB lock(child))) {
800 const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast); 787 const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast);
801 if (leaf) 788 if (leaf)
802 return leaf; 789 return leaf;
803 } 790 }
804 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling(); 791 child = (firstOrLast == First) ? child->nextSibling() : child->previousS ibling();
805 } 792 }
806 --depth; 793 --depth;
807 794
808 return 0; 795 return 0;
809 } 796 }
810 797
811 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier ) 798 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier )
812 { 799 {
813 ASSERT(renderer); 800 ASSERT(renderer);
814 RenderStyle* currentStyle = renderer->style(); 801 RenderStyle* currentStyle = renderer->style();
815 if (currentStyle->textAutosizingMultiplier() == multiplier) 802 if (currentStyle->textAutosizingMultiplier() == multiplier)
816 return; 803 return;
817 804
818 // We need to clone the render style to avoid breaking style sharing. 805 // We need to clone the render style to avoid breaking style sharing.
819 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); 806 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle);
820 style->setTextAutosizingMultiplier(multiplier); 807 style->setTextAutosizingMultiplier(multiplier);
821 style->setUnique(); 808 style->setUnique();
822 renderer->setStyleInternal(style.release()); 809 renderer->setStyleInternal(style.release());
823 } 810 }
824 811
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) 812 bool FastTextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster)
833 { 813 {
834 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) ) 814 if (!cluster->m_parent || !mightBeWiderOrNarrowerDescendant(cluster->m_root) )
835 return true; 815 return true;
836 816
837 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent); 817 const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContain ingAllText(cluster->m_parent);
838 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root)); 818 ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root));
839 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext)); 819 ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllT ext));
840 820
841 float contentWidth = cluster->m_root->contentLogicalWidth().toFloat(); 821 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) 903 FastTextAutosizer::Fingerprint FastTextAutosizer::FingerprintMapper::get(const R enderObject* renderer)
924 { 904 {
925 return m_fingerprints.get(renderer); 905 return m_fingerprints.get(renderer);
926 } 906 }
927 907
928 FastTextAutosizer::BlockSet& FastTextAutosizer::FingerprintMapper::getTentativeC lusterRoots(Fingerprint fingerprint) 908 FastTextAutosizer::BlockSet& FastTextAutosizer::FingerprintMapper::getTentativeC lusterRoots(Fingerprint fingerprint)
929 { 909 {
930 return *m_blocksForFingerprint.get(fingerprint); 910 return *m_blocksForFingerprint.get(fingerprint);
931 } 911 }
932 912
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) 913 FastTextAutosizer::LayoutScope::LayoutScope(RenderBlock* block)
941 : m_textAutosizer(block->document().fastTextAutosizer()) 914 : m_textAutosizer(block->document().fastTextAutosizer())
942 , m_block(block) 915 , m_block(block)
943 { 916 {
944 if (!m_textAutosizer) 917 if (!m_textAutosizer)
945 return; 918 return;
946 919
947 if (!m_textAutosizer->enabled()) { 920 if (!m_textAutosizer->enabled()) {
948 m_textAutosizer = 0; 921 m_textAutosizer = 0;
949 return; 922 return;
950 } 923 }
951 924
952 if (m_textAutosizer->m_pageAutosizingStatus == PageAutosizingStatusUnknown) 925 if (m_textAutosizer->m_pageAutosizingStatus == PageAutosizingStatusUnknown)
953 m_textAutosizer->updateRenderViewInfo(); 926 m_textAutosizer->updateRenderViewInfo();
954 927
955 if (m_textAutosizer->m_pageAutosizingStatus == PageNeedsAutosizing) 928 if (m_textAutosizer->m_pageAutosizingStatus == PageNeedsAutosizing)
956 m_textAutosizer->beginLayout(m_block); 929 m_textAutosizer->beginLayout(m_block);
957 else 930 else
958 m_textAutosizer = 0; 931 m_textAutosizer = 0;
959 } 932 }
960 933
961 FastTextAutosizer::LayoutScope::~LayoutScope() 934 FastTextAutosizer::LayoutScope::~LayoutScope()
962 { 935 {
963 if (m_textAutosizer) 936 if (m_textAutosizer)
964 m_textAutosizer->endLayout(m_block); 937 m_textAutosizer->endLayout(m_block);
965 } 938 }
966 939
967 } // namespace WebCore 940 } // 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