[Text Autosizing] Provide an API for influencing the font scale factor
[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     multiplier *= m_document->settings()->textAutosizingFontScaleFactor();
72
73     if (multiplier < 1)
74         return;
75     for (RenderObject* descendant = traverseNext(block, block, treatAsInline); descendant; descendant = traverseNext(descendant, block, treatAsInline)) {
76         if (descendant->isText())
77             processText(toRenderText(descendant), multiplier);
78     }
79 }
80
81 void TextAutosizer::processText(RenderText* text, float multiplier)
82 {
83     float specifiedSize = text->style()->fontDescription().specifiedSize();
84     float newSize = specifiedSize * multiplier; // FIXME: This is overly simplistic.
85
86     RefPtr<RenderStyle> style = RenderStyle::clone(text->style());
87     FontDescription fontDescription(style->fontDescription());
88     fontDescription.setComputedSize(newSize);
89     style->setFontDescription(fontDescription);
90     style->font().update(style->font().fontSelector());
91     text->setStyle(style.release());
92
93     // FIXME: Increase computed line height proportionately.
94     // FIXME: Increase list marker size proportionately.
95 }
96
97 bool TextAutosizer::treatAsInline(const RenderObject* renderer)
98 {
99     return !renderer->isRenderBlock() || renderer->isListItem() || renderer->isInlineBlockOrInlineTable();
100 }
101
102 // FIXME: Consider making this a method on RenderObject if it remains this generic.
103 RenderObject* TextAutosizer::traverseNext(RenderObject* current, const RenderObject* stayWithin, RenderObjectFilter filter)
104 {
105     for (RenderObject* child = current->firstChild(); child; child = child->nextSibling()) {
106         if (!filter || filter(child)) {
107             ASSERT(!stayWithin || child->isDescendantOf(stayWithin));
108             return child;
109         }
110     }
111
112     for (RenderObject* ancestor = current; ancestor; ancestor = ancestor->parent()) {
113         if (ancestor == stayWithin)
114             return 0;
115         for (RenderObject* sibling = ancestor->nextSibling(); sibling; sibling = sibling->nextSibling()) {
116             if (!filter || filter(sibling)) {
117                 ASSERT(!stayWithin || sibling->isDescendantOf(stayWithin));
118                 return sibling;
119             }
120         }
121     }
122
123     return 0;
124 }
125
126 } // namespace WebCore
127
128 #endif // ENABLE(TEXT_AUTOSIZING)