2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef TextAutosizer_h
32 #define TextAutosizer_h
34 #include "core/rendering/RenderObject.h"
35 #include "core/rendering/RenderTable.h"
36 #include "platform/heap/Handle.h"
37 #include "wtf/HashMap.h"
38 #include "wtf/HashSet.h"
39 #include "wtf/Noncopyable.h"
40 #include "wtf/OwnPtr.h"
41 #include "wtf/PassOwnPtr.h"
48 class RenderListMarker;
50 // Single-pass text autosizer. Documentation at:
51 // http://tinyurl.com/TextAutosizer
53 class TextAutosizer FINAL : public NoBaseWillBeGarbageCollectedFinalized<TextAutosizer> {
54 WTF_MAKE_NONCOPYABLE(TextAutosizer);
56 static PassOwnPtrWillBeRawPtr<TextAutosizer> create(const Document* document)
58 return adoptPtrWillBeNoop(new TextAutosizer(document));
60 static float computeAutosizedFontSize(float specifiedSize, float multiplier);
62 void updatePageInfoInAllFrames();
63 void updatePageInfo();
64 void record(const RenderBlock*);
65 void destroy(const RenderBlock*);
66 void inflateListItem(RenderListItem*, RenderListMarker*);
72 explicit LayoutScope(RenderBlock*);
75 TextAutosizer* m_textAutosizer;
79 class TableLayoutScope : LayoutScope {
81 explicit TableLayoutScope(RenderTable*);
84 class DeferUpdatePageInfo {
87 explicit DeferUpdatePageInfo(Page*);
88 ~DeferUpdatePageInfo();
90 RefPtrWillBeMember<LocalFrame> m_mainFrame;
94 typedef HashSet<const RenderBlock*> BlockSet;
96 enum HasEnoughTextToAutosize {
102 enum RelayoutBehavior {
103 AlreadyInLayout, // The default; appropriate if we are already in layout.
104 LayoutNeeded // Use this if changing a multiplier outside of layout.
107 enum BeginLayoutBehavior {
112 enum InflateBehavior {
118 // A block that is evaluated for becoming a cluster root.
119 POTENTIAL_ROOT = 1 << 0,
120 // A cluster root that establishes an independent multiplier.
121 INDEPENDENT = 1 << 1,
122 // A cluster root with an explicit width. These are likely to be independent.
123 EXPLICIT_WIDTH = 1 << 2,
124 // A cluster that is wider or narrower than its parent. These also create an
125 // independent multiplier, but this state cannot be determined until layout.
126 WIDER_OR_NARROWER = 1 << 3,
127 // A cluster that suppresses autosizing.
131 typedef unsigned BlockFlags;
133 // A supercluster represents autosizing information about a set of two or
134 // more blocks that all have the same fingerprint. Clusters whose roots
135 // belong to a supercluster will share a common multiplier and
136 // text-length-based autosizing status.
137 struct Supercluster {
138 explicit Supercluster(const BlockSet* roots)
140 , m_hasEnoughTextToAutosize(UnknownAmountOfText)
145 const BlockSet* const m_roots;
146 HasEnoughTextToAutosize m_hasEnoughTextToAutosize;
151 explicit Cluster(const RenderBlock* root, BlockFlags flags, Cluster* parent, Supercluster* supercluster = 0)
154 , m_deepestBlockContainingAllText(0)
157 , m_hasEnoughTextToAutosize(UnknownAmountOfText)
158 , m_supercluster(supercluster)
159 , m_hasTableAncestor(root->isTableCell() || (m_parent && m_parent->m_hasTableAncestor))
163 const RenderBlock* const m_root;
165 // The deepest block containing all text is computed lazily (see:
166 // deepestBlockContainingAllText). A value of 0 indicates the value has not been computed yet.
167 const RenderBlock* m_deepestBlockContainingAllText;
169 // The multiplier is computed lazily (see: clusterMultiplier) because it must be calculated
170 // after the lowest block containing all text has entered layout (the
171 // m_blocksThatHaveBegunLayout assertions cover this). Note: the multiplier is still
172 // calculated when m_autosize is false because child clusters may depend on this multiplier.
174 HasEnoughTextToAutosize m_hasEnoughTextToAutosize;
175 // A set of blocks that are similar to this block.
176 Supercluster* m_supercluster;
177 bool m_hasTableAncestor;
180 enum TextLeafSearch {
185 struct FingerprintSourceData {
186 FingerprintSourceData()
188 , m_qualifiedNameHash(0)
189 , m_packedStyleProperties(0)
195 unsigned m_parentHash;
196 unsigned m_qualifiedNameHash;
197 // Style specific selection of signals
198 unsigned m_packedStyleProperties;
202 // Ensures efficient hashing using StringHasher.
203 COMPILE_ASSERT(!(sizeof(FingerprintSourceData) % sizeof(UChar)),
204 Sizeof_FingerprintSourceData_must_be_multiple_of_UChar);
206 typedef unsigned Fingerprint;
207 typedef HashMap<Fingerprint, OwnPtr<Supercluster> > SuperclusterMap;
208 typedef Vector<OwnPtr<Cluster> > ClusterStack;
210 // Fingerprints are computed during style recalc, for (some subset of)
211 // blocks that will become cluster roots.
212 class FingerprintMapper {
214 void add(const RenderObject*, Fingerprint);
215 void addTentativeClusterRoot(const RenderBlock*, Fingerprint);
216 // Returns true if any BlockSet was modified or freed by the removal.
217 bool remove(const RenderObject*);
218 Fingerprint get(const RenderObject*);
219 BlockSet* getTentativeClusterRoots(Fingerprint);
220 bool hasFingerprints() const { return !m_fingerprints.isEmpty(); }
222 typedef HashMap<const RenderObject*, Fingerprint> FingerprintMap;
223 typedef HashMap<Fingerprint, OwnPtr<BlockSet> > ReverseFingerprintMap;
225 FingerprintMap m_fingerprints;
226 ReverseFingerprintMap m_blocksForFingerprint;
228 void assertMapsAreConsistent();
236 , m_baseMultiplier(0)
237 , m_pageNeedsAutosizing(false)
238 , m_hasAutosized(false)
239 , m_settingEnabled(false)
243 int m_frameWidth; // LocalFrame width in density-independent pixels (DIPs).
244 int m_layoutWidth; // Layout width in CSS pixels.
245 float m_baseMultiplier; // Includes accessibility font scale factor and device scale adjustment.
246 bool m_pageNeedsAutosizing;
248 bool m_settingEnabled;
251 explicit TextAutosizer(const Document*);
253 void beginLayout(RenderBlock*);
254 void endLayout(RenderBlock*);
255 void inflateAutoTable(RenderTable*);
256 float inflate(RenderObject*, InflateBehavior = ThisBlockOnly, float multiplier = 0);
257 bool shouldHandleLayout() const;
258 void setAllTextNeedsLayout();
259 void resetMultipliers();
260 BeginLayoutBehavior prepareForLayout(const RenderBlock*);
261 void prepareClusterStack(const RenderObject*);
262 bool clusterHasEnoughTextToAutosize(Cluster*, const RenderBlock* widthProvider = 0);
263 bool superclusterHasEnoughTextToAutosize(Supercluster*, const RenderBlock* widthProvider = 0);
264 bool clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider = 0);
265 Fingerprint getFingerprint(const RenderObject*);
266 Fingerprint computeFingerprint(const RenderObject*);
267 Cluster* maybeCreateCluster(const RenderBlock*);
268 Supercluster* getSupercluster(const RenderBlock*);
269 float clusterMultiplier(Cluster*);
270 float superclusterMultiplier(Cluster*);
271 // A cluster's width provider is typically the deepest block containing all text.
272 // There are exceptions, such as tables and table cells which use the table itself for width.
273 const RenderBlock* clusterWidthProvider(const RenderBlock*) const;
274 const RenderBlock* maxClusterWidthProvider(const Supercluster*, const RenderBlock* currentRoot) const;
275 // Typically this returns a block's computed width. In the case of tables layout, this
276 // width is not yet known so the fixed width is used if it's available, or the containing
277 // block's width otherwise.
278 float widthFromBlock(const RenderBlock*) const;
279 float multiplierFromBlock(const RenderBlock*);
280 void applyMultiplier(RenderObject*, float, RelayoutBehavior = AlreadyInLayout);
281 bool isWiderOrNarrowerDescendant(Cluster*);
282 Cluster* currentCluster() const;
283 const RenderBlock* deepestBlockContainingAllText(Cluster*);
284 const RenderBlock* deepestBlockContainingAllText(const RenderBlock*) const;
285 // Returns the first text leaf that is in the current cluster. We attempt to not include text
286 // from descendant clusters but because descendant clusters may not exist, this is only an approximation.
287 // The TraversalDirection controls whether we return the first or the last text leaf.
288 const RenderObject* findTextLeaf(const RenderObject*, size_t&, TextLeafSearch) const;
289 BlockFlags classifyBlock(const RenderObject*, BlockFlags mask = UINT_MAX) const;
290 #ifdef AUTOSIZING_DOM_DEBUG_INFO
291 void writeClusterDebugInfo(Cluster*);
294 RawPtrWillBeMember<const Document> m_document;
295 const RenderBlock* m_firstBlockToBeginLayout;
297 BlockSet m_blocksThatHaveBegunLayout; // Used to ensure we don't compute properties of a block before beginLayout() is called on it.
300 // Clusters are created and destroyed during layout. The map key is the
301 // cluster root. Clusters whose roots share the same fingerprint use the
303 SuperclusterMap m_superclusters;
304 ClusterStack m_clusterStack;
305 FingerprintMapper m_fingerprintMapper;
306 Vector<RefPtr<RenderStyle> > m_stylesRetainedDuringLayout;
307 // FIXME: All frames should share the same m_pageInfo instance.
309 bool m_updatePageInfoDeferred;
314 #endif // TextAutosizer_h