0824aa336bec31e7a4ca91e4b3b718b4d3dbccad
[WebKit-https.git] / Source / WebCore / rendering / TextAutosizer.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2012 Apple Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
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
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(TEXT_AUTOSIZING)
24
25 #include "TextAutosizer.h"
26
27 #include "Document.h"
28 #include "InspectorInstrumentation.h"
29 #include "RenderObject.h"
30 #include "RenderText.h"
31 #include "RenderView.h"
32 #include "Settings.h"
33
34 namespace WebCore {
35
36 TextAutosizer::TextAutosizer(Document* document)
37     : m_document(document)
38 {
39 }
40
41 TextAutosizer::~TextAutosizer()
42 {
43 }
44
45 bool TextAutosizer::processSubtree(RenderObject* layoutRoot)
46 {
47     // FIXME: Text Autosizing should only be enabled when m_document->page()->mainFrame()->view()->useFixedLayout()
48     // is true, but for now it's useful to ignore this so that it can be tested on desktop.
49     if (!m_document->settings() || !m_document->settings()->textAutosizingEnabled() || layoutRoot->view()->printing() || !m_document->page())
50         return false;
51
52     IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverride();
53     if (windowSize.isEmpty()) {
54         Frame* mainFrame = m_document->page()->mainFrame();
55         bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(mainFrame);
56         windowSize = mainFrame->view()->visibleContentRect(includeScrollbars).size(); // FIXME: Check that this is always in logical (density-independent) pixels (see wkbug.com/87440).
57     }
58
59     for (RenderObject* descendant = traverseNext(layoutRoot, layoutRoot); descendant; descendant = traverseNext(descendant, layoutRoot)) {
60         if (!treatAsInline(descendant))
61             processBlock(toRenderBlock(descendant), windowSize);
62     }
63
64     return true;
65 }
66
67 void TextAutosizer::processBlock(RenderBlock* block, const IntSize& windowSize)
68 {
69     int windowLogicalWidth = block->isHorizontalWritingMode() ? windowSize.width() : windowSize.height();
70     float multiplier = static_cast<float>(block->logicalWidth()) / windowLogicalWidth; // FIXME: This is overly simplistic.
71     if (multiplier < 1)
72         return;
73     for (RenderObject* descendant = traverseNext(block, block, treatAsInline); descendant; descendant = traverseNext(descendant, block, treatAsInline)) {
74         if (descendant->isText())
75             processText(toRenderText(descendant), multiplier);
76     }
77 }
78
79 void TextAutosizer::processText(RenderText* text, float multiplier)
80 {
81     float specifiedSize = text->style()->fontDescription().specifiedSize();
82     float newSize = specifiedSize * multiplier; // FIXME: This is overly simplistic.
83
84     RefPtr<RenderStyle> style = RenderStyle::clone(text->style());
85     FontDescription fontDescription(style->fontDescription());
86     fontDescription.setComputedSize(newSize);
87     style->setFontDescription(fontDescription);
88     style->font().update(style->font().fontSelector());
89     text->setStyle(style.release());
90
91     // FIXME: Increase computed line height proportionately.
92     // FIXME: Increase list marker size proportionately.
93 }
94
95 bool TextAutosizer::treatAsInline(const RenderObject* renderer)
96 {
97     return !renderer->isRenderBlock() || renderer->isListItem() || renderer->isInlineBlockOrInlineTable();
98 }
99
100 // FIXME: Consider making this a method on RenderObject if it remains this generic.
101 RenderObject* TextAutosizer::traverseNext(RenderObject* current, const RenderObject* stayWithin, RenderObjectFilter filter)
102 {
103     for (RenderObject* child = current->firstChild(); child; child = child->nextSibling()) {
104         if (!filter || filter(child)) {
105             ASSERT(!stayWithin || child->isDescendantOf(stayWithin));
106             return child;
107         }
108     }
109
110     for (RenderObject* ancestor = current; ancestor; ancestor = ancestor->parent()) {
111         if (ancestor == stayWithin)
112             return 0;
113         for (RenderObject* sibling = ancestor->nextSibling(); sibling; sibling = sibling->nextSibling()) {
114             if (!filter || filter(sibling)) {
115                 ASSERT(!stayWithin || sibling->isDescendantOf(stayWithin));
116                 return sibling;
117             }
118         }
119     }
120
121     return 0;
122 }
123
124 } // namespace WebCore
125
126 #endif // ENABLE(TEXT_AUTOSIZING)