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 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |