| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2012 Apple Inc. All rights reserved. | 3 * Copyright (C) 2012 Apple Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
| 6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
| 7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
| 8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
| 9 * | 9 * |
| 10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 * Library General Public License for more details. | 13 * Library General Public License for more details. |
| 14 * | 14 * |
| 15 * You should have received a copy of the GNU Library General Public License | 15 * You should have received a copy of the GNU Library General Public License |
| 16 * along with this library; see the file COPYING.LIB. If not, write to | 16 * along with this library; see the file COPYING.LIB. If not, write to |
| 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 18 * Boston, MA 02110-1301, USA. | 18 * Boston, MA 02110-1301, USA. |
| 19 */ | 19 */ |
| 20 | 20 |
| 21 #include "config.h" | 21 #include "config.h" |
| 22 | 22 |
| 23 #if ENABLE(TEXT_AUTOSIZING) | 23 #if ENABLE(TEXT_AUTOSIZING) |
| 24 | 24 |
| 25 #include "TextAutosizer.h" | 25 #include "TextAutosizer.h" |
| 26 | 26 |
| 27 #include "Document.h" | 27 #include "Document.h" |
| 28 #include "HTMLElement.h" |
| 28 #include "InspectorInstrumentation.h" | 29 #include "InspectorInstrumentation.h" |
| 29 #include "IntSize.h" | 30 #include "IntSize.h" |
| 30 #include "RenderObject.h" | 31 #include "RenderObject.h" |
| 31 #include "RenderStyle.h" | 32 #include "RenderStyle.h" |
| 32 #include "RenderText.h" | 33 #include "RenderText.h" |
| 33 #include "RenderView.h" | 34 #include "RenderView.h" |
| 34 #include "Settings.h" | 35 #include "Settings.h" |
| 35 #include "StyleInheritedData.h" | 36 #include "StyleInheritedData.h" |
| 36 | 37 |
| 37 #include <algorithm> | 38 #include <algorithm> |
| 39 #include <wtf/StdLibExtras.h> |
| 38 | 40 |
| 39 namespace WebCore { | 41 namespace WebCore { |
| 40 | 42 |
| 43 using namespace HTMLNames; |
| 44 |
| 41 struct TextAutosizingWindowInfo { | 45 struct TextAutosizingWindowInfo { |
| 42 IntSize windowSize; | 46 IntSize windowSize; |
| 43 IntSize minLayoutSize; | 47 IntSize minLayoutSize; |
| 44 }; | 48 }; |
| 45 | 49 |
| 50 |
| 51 static const Vector<QualifiedName>& formInputTags() |
| 52 { |
| 53 // Returns the tags for the form input elements. |
| 54 DEFINE_STATIC_LOCAL(Vector<QualifiedName>, formInputTags, ()); |
| 55 if (formInputTags.isEmpty()) { |
| 56 formInputTags.append(inputTag); |
| 57 formInputTags.append(buttonTag); |
| 58 formInputTags.append(selectTag); |
| 59 } |
| 60 return formInputTags; |
| 61 } |
| 62 |
| 46 TextAutosizer::TextAutosizer(Document* document) | 63 TextAutosizer::TextAutosizer(Document* document) |
| 47 : m_document(document) | 64 : m_document(document) |
| 48 { | 65 { |
| 49 } | 66 } |
| 50 | 67 |
| 51 TextAutosizer::~TextAutosizer() | 68 TextAutosizer::~TextAutosizer() |
| 52 { | 69 { |
| 53 } | 70 } |
| 54 | 71 |
| 55 bool TextAutosizer::processSubtree(RenderObject* layoutRoot) | 72 bool TextAutosizer::processSubtree(RenderObject* layoutRoot) |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 // - Must not be inline, as different multipliers on one line looks terrible
. | 202 // - Must not be inline, as different multipliers on one line looks terrible
. |
| 186 // Exceptions are inline-block and alike elements (inline-table, -webkit-i
nline-*), | 203 // Exceptions are inline-block and alike elements (inline-table, -webkit-i
nline-*), |
| 187 // as they often contain entire multi-line columns of text. | 204 // as they often contain entire multi-line columns of text. |
| 188 // - Must not be list items, as items in the same list should look consisten
t (*). | 205 // - Must not be list items, as items in the same list should look consisten
t (*). |
| 189 // - Must not be normal list items, as items in the same list should look | 206 // - Must not be normal list items, as items in the same list should look |
| 190 // consistent, unless they are floating or position:absolute/fixed. | 207 // consistent, unless they are floating or position:absolute/fixed. |
| 191 if (!renderer->isRenderBlock() || (renderer->isInline() && !renderer->style(
)->isDisplayReplacedType())) | 208 if (!renderer->isRenderBlock() || (renderer->isInline() && !renderer->style(
)->isDisplayReplacedType())) |
| 192 return false; | 209 return false; |
| 193 if (renderer->isListItem()) | 210 if (renderer->isListItem()) |
| 194 return renderer->isFloating() || renderer->isOutOfFlowPositioned(); | 211 return renderer->isFloating() || renderer->isOutOfFlowPositioned(); |
| 212 // Avoid creating containers for text within text controls, buttons, or <sel
ect> buttons. |
| 213 Node* parentNode = renderer->parent() ? renderer->parent()->generatingNode()
: 0; |
| 214 if (parentNode && parentNode->isElementNode() && formInputTags().contains(to
Element(parentNode)->tagQName())) |
| 215 return false; |
| 216 |
| 195 return true; | 217 return true; |
| 196 } | 218 } |
| 197 | 219 |
| 198 bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer, const Rende
rBlock* parentBlockContainingAllText) | 220 bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer, const Rende
rBlock* parentBlockContainingAllText) |
| 199 { | 221 { |
| 200 // "Autosizing clusters" are special autosizing containers within which we | 222 // "Autosizing clusters" are special autosizing containers within which we |
| 201 // want to enforce a uniform text size multiplier, in the hopes of making | 223 // want to enforce a uniform text size multiplier, in the hopes of making |
| 202 // the major sections of the page look internally consistent. | 224 // the major sections of the page look internally consistent. |
| 203 // All their descendants (including other autosizing containers) must share | 225 // All their descendants (including other autosizing containers) must share |
| 204 // the same multiplier, except for subtrees which are themselves clusters, | 226 // the same multiplier, except for subtrees which are themselves clusters, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 // FIXME: Tables need special handling to multiply all their columns by | 266 // FIXME: Tables need special handling to multiply all their columns by |
| 245 // the same amount even if they're different widths; so do hasColumns() | 267 // the same amount even if they're different widths; so do hasColumns() |
| 246 // containers, and probably flexboxes... | 268 // containers, and probably flexboxes... |
| 247 } | 269 } |
| 248 | 270 |
| 249 bool TextAutosizer::isAutosizingCluster(const RenderObject* object) | 271 bool TextAutosizer::isAutosizingCluster(const RenderObject* object) |
| 250 { | 272 { |
| 251 return isAutosizingContainer(object) && isAutosizingCluster(toRenderBlock(ob
ject), 0); | 273 return isAutosizingContainer(object) && isAutosizingCluster(toRenderBlock(ob
ject), 0); |
| 252 } | 274 } |
| 253 | 275 |
| 254 static bool contentHeightIsConstrained(const RenderBlock* container) | 276 bool TextAutosizer::containerShouldBeAutosized(const RenderBlock* container) |
| 277 { |
| 278 if (containerContainsOneOfTags(container, formInputTags())) |
| 279 return false; |
| 280 |
| 281 // Don't autosize block-level text that can't wrap (as it's likely to |
| 282 // expand sideways and break the page's layout). |
| 283 if (!container->style()->autoWrap()) |
| 284 return false; |
| 285 |
| 286 return !contentHeightIsConstrained(container); |
| 287 } |
| 288 |
| 289 bool TextAutosizer::containerContainsOneOfTags(const RenderBlock* container, con
st Vector<QualifiedName>& tags) |
| 290 { |
| 291 const RenderObject* renderer = container; |
| 292 while (renderer) { |
| 293 const Node* rendererNode = renderer->node(); |
| 294 if (rendererNode && rendererNode->isElementNode()) { |
| 295 if (tags.contains(toElement(rendererNode)->tagQName())) |
| 296 return true; |
| 297 } |
| 298 renderer = nextInPreOrderSkippingDescendantsOfContainers(renderer, conta
iner); |
| 299 } |
| 300 |
| 301 return false; |
| 302 } |
| 303 |
| 304 bool TextAutosizer::contentHeightIsConstrained(const RenderBlock* container) |
| 255 { | 305 { |
| 256 // FIXME: Propagate constrainedness down the tree, to avoid inefficiently wa
lking back up from each box. | 306 // FIXME: Propagate constrainedness down the tree, to avoid inefficiently wa
lking back up from each box. |
| 257 // FIXME: This code needs to take into account vertical writing modes. | 307 // FIXME: This code needs to take into account vertical writing modes. |
| 258 // FIXME: Consider additional heuristics, such as ignoring fixed heights if
the content is already overflowing before autosizing kicks in. | 308 // FIXME: Consider additional heuristics, such as ignoring fixed heights if
the content is already overflowing before autosizing kicks in. |
| 259 for (; container; container = container->containingBlock()) { | 309 for (; container; container = container->containingBlock()) { |
| 260 RenderStyle* style = container->style(); | 310 RenderStyle* style = container->style(); |
| 261 if (style->overflowY() >= OSCROLL) | 311 if (style->overflowY() >= OSCROLL) |
| 262 return false; | 312 return false; |
| 263 if (style->height().isSpecified() || style->maxHeight().isSpecified()) { | 313 if (style->height().isSpecified() || style->maxHeight().isSpecified()) { |
| 264 // Some sites (e.g. wikipedia) set their html and/or body elements t
o height:100%, | 314 // Some sites (e.g. wikipedia) set their html and/or body elements t
o height:100%, |
| 265 // without intending to constrain the height of the content within t
hem. | 315 // without intending to constrain the height of the content within t
hem. |
| 266 return !container->isRoot() && !container->isBody(); | 316 return !container->isRoot() && !container->isBody(); |
| 267 } | 317 } |
| 268 if (container->isFloatingOrOutOfFlowPositioned()) | 318 if (container->isFloatingOrOutOfFlowPositioned()) |
| 269 return false; | 319 return false; |
| 270 } | 320 } |
| 271 return false; | 321 return false; |
| 272 } | 322 } |
| 273 | 323 |
| 274 bool TextAutosizer::containerShouldBeAutosized(const RenderBlock* container) | |
| 275 { | |
| 276 // Don't autosize block-level text that can't wrap (as it's likely to | |
| 277 // expand sideways and break the page's layout). | |
| 278 if (!container->style()->autoWrap()) | |
| 279 return false; | |
| 280 | |
| 281 return !contentHeightIsConstrained(container); | |
| 282 } | |
| 283 | |
| 284 bool TextAutosizer::clusterShouldBeAutosized(const RenderBlock* blockContainingA
llText, float blockWidth) | 324 bool TextAutosizer::clusterShouldBeAutosized(const RenderBlock* blockContainingA
llText, float blockWidth) |
| 285 { | 325 { |
| 286 // Don't autosize clusters that contain less than 4 lines of text (in | 326 // Don't autosize clusters that contain less than 4 lines of text (in |
| 287 // practice less lines are required, since measureDescendantTextWidth | 327 // practice less lines are required, since measureDescendantTextWidth |
| 288 // assumes that characters are 1em wide, but most characters are narrower | 328 // assumes that characters are 1em wide, but most characters are narrower |
| 289 // than that, so we're overestimating their contribution to the linecount). | 329 // than that, so we're overestimating their contribution to the linecount). |
| 290 // | 330 // |
| 291 // This is to reduce the likelihood of autosizing things like headers and | 331 // This is to reduce the likelihood of autosizing things like headers and |
| 292 // footers, which can be quite visually distracting. The rationale is that | 332 // footers, which can be quite visually distracting. The rationale is that |
| 293 // if a cluster contains very few lines of text then it's ok to have to zoom | 333 // if a cluster contains very few lines of text then it's ok to have to zoom |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 child = (direction == FirstToLast) ? child->nextSibling() : child->previ
ousSibling(); | 435 child = (direction == FirstToLast) ? child->nextSibling() : child->previ
ousSibling(); |
| 396 } | 436 } |
| 397 --depth; | 437 --depth; |
| 398 | 438 |
| 399 return 0; | 439 return 0; |
| 400 } | 440 } |
| 401 | 441 |
| 402 } // namespace WebCore | 442 } // namespace WebCore |
| 403 | 443 |
| 404 #endif // ENABLE(TEXT_AUTOSIZING) | 444 #endif // ENABLE(TEXT_AUTOSIZING) |
| OLD | NEW |