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 |