Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: Source/core/rendering/FastTextAutosizer.cpp

Issue 101543009: Make cluster creation independent of fingerprinting. Keep track of current (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@pdr-multiplier
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 20 matching lines...) Expand all
31 #include "config.h" 31 #include "config.h"
32 #include "core/rendering/FastTextAutosizer.h" 32 #include "core/rendering/FastTextAutosizer.h"
33 33
34 #include "core/dom/Document.h" 34 #include "core/dom/Document.h"
35 #include "core/frame/Frame.h" 35 #include "core/frame/Frame.h"
36 #include "core/frame/FrameView.h" 36 #include "core/frame/FrameView.h"
37 #include "core/frame/Settings.h" 37 #include "core/frame/Settings.h"
38 #include "core/page/Page.h" 38 #include "core/page/Page.h"
39 #include "core/rendering/InlineIterator.h" 39 #include "core/rendering/InlineIterator.h"
40 #include "core/rendering/RenderBlock.h" 40 #include "core/rendering/RenderBlock.h"
41 #include "core/rendering/RenderView.h"
41 #include "core/rendering/TextAutosizer.h" 42 #include "core/rendering/TextAutosizer.h"
42 43
43 using namespace std; 44 using namespace std;
44 45
45 namespace WebCore { 46 namespace WebCore {
46 47
47 FastTextAutosizer::FastTextAutosizer(Document* document) 48 FastTextAutosizer::FastTextAutosizer(Document* document)
48 : m_document(document) 49 : m_document(document)
49 { 50 {
50 } 51 }
51 52
52 void FastTextAutosizer::prepareForLayout() 53 void FastTextAutosizer::record(RenderBlock* block)
53 { 54 {
54 if (!m_document->settings() 55 if (!enabled())
55 || !m_document->settings()->textAutosizingEnabled()
56 || m_document->printing()
57 || !m_document->page())
58 return; 56 return;
59 bool windowWidthChanged = updateWindowWidth();
60 57
61 // If needed, set existing clusters as needing their multiplier recalculated . 58 if (!shouldBeClusterRoot(block))
62 for (FingerprintToClusterMap::iterator it = m_clusterForFingerprint.begin(), end = m_clusterForFingerprint.end(); it != end; ++it) { 59 return;
63 Cluster* cluster = it->value.get();
64 ASSERT(cluster);
65 WTF::HashSet<RenderBlock*>& blocks = cluster->m_blocks;
66 60
67 if (windowWidthChanged) { 61 AtomicString fingerprint = computeFingerprint(block);
68 // Clusters depend on the window width. Changes to the width should cause all clusters to recalc. 62 if (fingerprint.isNull())
69 cluster->setNeedsClusterRecalc(); 63 return;
70 } else {
71 // If any of the cluster's blocks need a layout, mark the entire clu ster as needing a recalc.
72 for (WTF::HashSet<RenderBlock*>::iterator block = blocks.begin(); bl ock != blocks.end(); ++block) {
73 if ((*block)->needsLayout()) {
74 cluster->setNeedsClusterRecalc();
75 break;
76 }
77 }
78 }
79 64
80 // If the cluster needs a recalc, mark all blocks as needing a layout so they pick up the new cluster info. 65 m_fingerprints.set(block, fingerprint);
81 if (cluster->needsClusterRecalc()) { 66
82 for (WTF::HashSet<RenderBlock*>::iterator block = blocks.begin(); bl ock != blocks.end(); ++block) 67 ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fing erprint, PassOwnPtr<BlockSet>());
83 (*block)->setNeedsLayout(); 68 if (addResult.isNewEntry)
84 } 69 addResult.iterator->value = adoptPtr(new BlockSet);
70 addResult.iterator->value->add(block);
71 }
72
73 void FastTextAutosizer::destroy(RenderBlock* block)
74 {
75 AtomicString fingerprint = m_fingerprints.take(block);
76 if (fingerprint.isNull())
77 return;
78
79 ReverseFingerprintMap::iterator blocksIter = m_blocksForFingerprint.find(fin gerprint);
80 WTF::HashSet<RenderBlock*>& blocks = *blocksIter->value;
81 blocks.remove(block);
82 if (blocks.isEmpty())
83 m_blocksForFingerprint.remove(blocksIter);
84 }
85
86 void FastTextAutosizer::beginLayout(RenderBlock* block)
87 {
88 if (!enabled())
89 return;
90
91 if (block->isRenderView())
92 prepareWindowInfo(toRenderView(block));
93
94 if (shouldBeClusterRoot(block))
95 m_clusterStack.append(getCluster(block));
96 }
97
98 void FastTextAutosizer::inflate(RenderBlock* block)
99 {
100 if (m_clusterStack.isEmpty())
101 return;
102 Cluster* cluster = m_clusterStack.last();
103
104 applyMultiplier(block, cluster->m_multiplier);
105
106 // FIXME: Add an optimization to not do this walk if it's not needed.
107 for (InlineWalker walker(block); !walker.atEnd(); walker.advance()) {
108 RenderObject* inlineObj = walker.current();
109 if (inlineObj->isText())
110 applyMultiplier(inlineObj, cluster->m_multiplier);
85 } 111 }
86 } 112 }
87 113
88 bool FastTextAutosizer::updateWindowWidth() 114 void FastTextAutosizer::endLayout(RenderBlock* block)
89 { 115 {
pdr. 2013/12/21 01:46:57 Could you add a preventative if(!enabled) check he
skobes 2014/01/07 03:12:37 Done.
90 int originalWindowWidth = m_windowWidth; 116 if (!m_clusterStack.isEmpty() && m_clusterStack.last()->m_root == block)
117 m_clusterStack.removeLast();
118 }
119
120 bool FastTextAutosizer::enabled()
121 {
122 return m_document->settings()
123 && m_document->settings()->textAutosizingEnabled()
124 && !m_document->printing()
125 && m_document->page();
126 }
127
128 void FastTextAutosizer::prepareWindowInfo(RenderView* renderView)
129 {
130 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode());
91 131
92 Frame* mainFrame = m_document->page()->mainFrame(); 132 Frame* mainFrame = m_document->page()->mainFrame();
93 IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverrid e(); 133 IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverrid e();
94 if (windowSize.isEmpty()) 134 if (windowSize.isEmpty())
95 windowSize = mainFrame->view()->unscaledVisibleContentSize(ScrollableAre a::IncludeScrollbars); 135 windowSize = mainFrame->view()->unscaledVisibleContentSize(ScrollableAre a::IncludeScrollbars);
96 m_windowWidth = windowSize.width(); 136 m_windowWidth = horizontalWritingMode ? windowSize.width() : windowSize.heig ht();
97 137
98 return m_windowWidth != originalWindowWidth; 138 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize();
139 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht();
99 } 140 }
100 141
101 void FastTextAutosizer::record(RenderBlock* block) 142 bool FastTextAutosizer::shouldBeClusterRoot(RenderBlock* block)
102 { 143 {
103 if (!m_document->settings() 144 // FIXME: move the logic out of TextAutosizer.cpp into this class.
104 || !m_document->settings()->textAutosizingEnabled() 145 // FIXME: why does isIndependentDescendant hang here?
105 || m_document->printing() 146 return block->isRenderView()
106 || !m_document->page()) 147 || (TextAutosizer::isAutosizingContainer(block)
107 return; 148 /* && TextAutosizer::isIndependentDescendant(block) */);
108
109 if (!TextAutosizer::isAutosizingContainer(block))
110 return;
111
112 AtomicString blockFingerprint = fingerprint(block);
113 HashMap<AtomicString, OwnPtr<Cluster> >::AddResult result =
114 m_clusterForFingerprint.add(blockFingerprint, PassOwnPtr<Cluster>());
115
116 if (result.isNewEntry)
117 result.iterator->value = adoptPtr(new Cluster(blockFingerprint));
118
119 Cluster* cluster = result.iterator->value.get();
120 cluster->addBlock(block);
121
122 m_clusterForBlock.set(block, cluster);
123 } 149 }
124 150
125 void FastTextAutosizer::destroy(RenderBlock* block) 151 bool FastTextAutosizer::clusterWantsAutosizing(RenderBlock* root)
126 { 152 {
127 Cluster* cluster = m_clusterForBlock.take(block); 153 // FIXME: this should be slightly different.
128 if (!cluster) 154 return TextAutosizer::containerShouldBeAutosized(root);
129 return;
130 cluster->m_blocks.remove(block);
131 if (cluster->m_blocks.isEmpty()) {
132 // This deletes the Cluster.
133 m_clusterForFingerprint.remove(cluster->m_fingerprint);
134 return;
135 }
136 cluster->setNeedsClusterRecalc();
137 } 155 }
138 156
139 static void applyMultiplier(RenderObject* renderer, float multiplier) 157 AtomicString FastTextAutosizer::computeFingerprint(RenderBlock* block)
140 { 158 {
141 RenderStyle* currentStyle = renderer->style(); 159 // FIXME(crbug.com/322340): Implement a fingerprinting algorithm.
160 return nullAtom;
161 }
162
163 FastTextAutosizer::Cluster* FastTextAutosizer::getCluster(RenderBlock* block)
pdr. 2013/12/21 01:46:57 I was surprised to learn clusters are created in g
skobes 2014/01/07 03:12:37 Done.
164 {
165 ClusterMap::AddResult addResult = m_clusters.add(block, PassOwnPtr<Cluster>( ));
166 if (!addResult.isNewEntry)
167 return addResult.iterator->value.get();
168
169 AtomicString fingerprint = m_fingerprints.get(block);
170 if (fingerprint.isNull()) {
171 addResult.iterator->value = adoptPtr(createCluster(block));
172 return addResult.iterator->value.get();
173 }
174 return addSupercluster(*m_blocksForFingerprint.find(fingerprint)->value, blo ck);
175 }
176
177 FastTextAutosizer::Cluster* FastTextAutosizer::createCluster(RenderBlock* block)
178 {
179 float multiplier = clusterWantsAutosizing(block) ? computeMultiplier(block) : 1.0f;
180 return new Cluster(block, multiplier);
181 }
182
183 FastTextAutosizer::Cluster* FastTextAutosizer::addSupercluster(WTF::HashSet<Rend erBlock*>& roots, RenderBlock* returnFor)
184 {
185 RenderBlock* superRoot = deepestCommonAncestor(roots);
186
187 bool shouldAutosize = false;
188 for (WTF::HashSet<RenderBlock*>::iterator it = roots.begin(); it != roots.en d(); ++it)
189 shouldAutosize |= clusterWantsAutosizing(*it);
190
191 float multiplier = shouldAutosize ? computeMultiplier(superRoot) : 1.0f;
192
193 Cluster* result = 0;
194 for (WTF::HashSet<RenderBlock*>::iterator it = roots.begin(); it != roots.en d(); ++it) {
195 Cluster* cluster = new Cluster(*it, multiplier);
196 m_clusters.set(*it, adoptPtr(cluster));
197
198 if (*it == returnFor)
199 result = cluster;
200 }
201 return result;
202 }
203
204 RenderBlock* FastTextAutosizer::deepestCommonAncestor(WTF::HashSet<RenderBlock*> & blocks)
205 {
206 // Find the lowest common ancestor of blocks.
207 // Note: this could be improved to not be O(b*h) for b blocks and tree heigh t h.
208 HashCountedSet<RenderObject*> ancestors;
209 for (WTF::HashSet<RenderBlock*>::iterator it = blocks.begin(); it != blocks. end(); ++it) {
210 for (RenderBlock* block = (*it); block; block = block->containingBlock() ) {
211 ancestors.add(block);
212 // The first ancestor that has all of the blocks as children wins.
213 if (ancestors.count(block) == blocks.size())
214 return block;
215 }
216 }
217 ASSERT_NOT_REACHED();
218 return 0;
219 }
220
221 float FastTextAutosizer::computeMultiplier(RenderBlock* block)
222 {
223 // Block width, in CSS pixels.
224 float blockWidth = block->contentLogicalWidth();
225
226 // FIXME: incorporate font scale factor.
227 // FIXME: incorporate device scale adjustment.
228 return max(min(blockWidth, (float) m_layoutWidth) / m_windowWidth, 1.0f);
229 }
230
231 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier )
232 {
233 RenderStyle* currentStyle = renderer->style();
142 if (currentStyle->textAutosizingMultiplier() == multiplier) 234 if (currentStyle->textAutosizingMultiplier() == multiplier)
143 return; 235 return;
144 236
145 // We need to clone the render style to avoid breaking style sharing. 237 // We need to clone the render style to avoid breaking style sharing.
146 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); 238 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle);
147 style->setTextAutosizingMultiplier(multiplier); 239 style->setTextAutosizingMultiplier(multiplier);
148 style->setUnique(); 240 style->setUnique();
149 renderer->setStyleInternal(style.release()); 241 renderer->setStyleInternal(style.release());
150 } 242 }
151 243
152 void FastTextAutosizer::inflate(RenderBlock* block)
153 {
154 Cluster* cluster = 0;
155 for (const RenderObject* clusterBlock = block; clusterBlock && !cluster; clu sterBlock = clusterBlock->parent()) {
156 if (clusterBlock->isRenderBlock())
157 cluster = m_clusterForBlock.get(toRenderBlock(clusterBlock));
158 }
159 if (!cluster)
160 return;
161
162 recalcClusterIfNeeded(cluster);
163
164 applyMultiplier(block, cluster->m_multiplier);
165
166 // FIXME: Add an optimization to not do this walk if it's not needed.
167 for (InlineWalker walker(block); !walker.atEnd(); walker.advance()) {
168 RenderObject* inlineObj = walker.current();
169 if (inlineObj->isRenderBlock() && m_clusterForBlock.contains(toRenderBlo ck(inlineObj)))
170 continue;
171
172 applyMultiplier(inlineObj, cluster->m_multiplier);
173 }
174 }
175
176 AtomicString FastTextAutosizer::fingerprint(const RenderBlock* block)
177 {
178 // FIXME(crbug.com/322340): Implement a better fingerprinting algorithm.
179 return String::number((unsigned long long) block);
180 }
181
182 void FastTextAutosizer::recalcClusterIfNeeded(FastTextAutosizer::Cluster* cluste r)
183 {
184 ASSERT(m_windowWidth > 0);
185 if (!cluster->needsClusterRecalc())
186 return;
187
188 WTF::HashSet<RenderBlock*>& blocks = cluster->m_blocks;
189
190 bool shouldAutosize = false;
191 for (WTF::HashSet<RenderBlock*>::iterator it = blocks.begin(); it != blocks. end(); ++it)
192 shouldAutosize |= TextAutosizer::containerShouldBeAutosized(*it);
193
194 if (!shouldAutosize) {
195 cluster->m_multiplier = 1.0f;
196 return;
197 }
198
199 // Find the lowest common ancestor of blocks.
200 // Note: this could be improved to not be O(b*h) for b blocks and tree heigh t h.
201 cluster->m_clusterRoot = 0;
202 HashCountedSet<const RenderObject*> ancestors;
203 for (WTF::HashSet<RenderBlock*>::iterator it = blocks.begin(); !cluster->m_c lusterRoot && it != blocks.end(); ++it) {
204 const RenderObject* renderer = (*it);
205 while (renderer && (renderer = renderer->parent())) {
206 ancestors.add(renderer);
207 // The first ancestor that has all of the blocks as children wins an d is crowned the cluster root.
208 if (ancestors.count(renderer) == blocks.size()) {
209 cluster->m_clusterRoot = renderer->isRenderBlock() ? renderer : renderer->containingBlock();
210 break;
211 }
212 }
213 }
214
215 ASSERT(cluster->m_clusterRoot);
216 bool horizontalWritingMode = isHorizontalWritingMode(cluster->m_clusterRoot- >style()->writingMode());
217
218 // Largest area of block that can be visible at once (assuming the main
219 // frame doesn't get scaled to less than overview scale), in CSS pixels.
220 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize();
221 float layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize. height();
222
223 // Cluster root layout width, in CSS pixels.
224 float rootWidth = toRenderBlock(cluster->m_clusterRoot)->contentLogicalWidth ();
225
226 // FIXME: incorporate font scale factor.
227 float multiplier = min(rootWidth, layoutWidth) / m_windowWidth;
228 cluster->m_multiplier = max(multiplier, 1.0f);
229 }
230
231 } // namespace WebCore 244 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698