Chromium Code Reviews| 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 |