Text Autosizing: Add test framework and simple test.
[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::boostSubtree(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             boostBlock(toRenderBlock(descendant), windowSize);
62     }
63
64     return true;
65 }
66
67 void TextAutosizer::boostBlock(RenderBlock* block, LayoutSize windowSize)
68 {
69     float windowLogicalWidth = block->isHorizontalWritingMode() ? windowSize.width() : windowSize.height();
70     float multiplier = 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             boostText(toRenderText(descendant), multiplier);
76     }
77 }
78
79 void TextAutosizer::boostText(RenderText* text, float multiplier)
80 {
81     float specifiedSize = text->style()->fontDescription().specifiedSize();
82     float boostedSize = specifiedSize * multiplier; // FIXME: This is overly simplistic.
83
84     RefPtr<RenderStyle> style = RenderStyle::clone(text->style());
85     FontDescription fontDescription(style->fontDescription());
86     fontDescription.setComputedSize(boostedSize);
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: Boost list markers proportionately.
93 }
94
95 bool TextAutosizer::treatAsInline(const RenderObject* renderer)
96 {
97     return !renderer->isRenderBlock() || renderer->isListItem() || renderer->isInlineBlockOrInlineTable();
98 }
99
100 RenderObject* TextAutosizer::traverseNext(RenderObject* current, const RenderObject* stayWithin, RenderObjectFilter filter)
101 {
102     for (RenderObject* child = current->firstChild(); child; child = child->nextSibling()) {
103         if (!filter || filter(child)) {
104             ASSERT(!stayWithin || child->isDescendantOf(stayWithin));
105             return child;
106         }
107     }
108
109     for (RenderObject* ancestor = current; ancestor; ancestor = ancestor->parent()) {
110         if (ancestor == stayWithin)
111             return 0;
112         for (RenderObject* sibling = ancestor->nextSibling(); sibling; sibling = sibling->nextSibling()) {
113             if (!filter || filter(sibling)) {
114                 ASSERT(!stayWithin || sibling->isDescendantOf(stayWithin));
115                 return sibling;
116             }
117         }
118     }
119
120     return 0;
121 }
122
123 } // namespace WebCore
124
125 #endif // ENABLE(TEXT_AUTOSIZING)