OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |