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

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: Address review comments. Created 6 years, 11 months 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
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | Source/core/rendering/RenderBlockFlow.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 return;
56 || m_document->printing() 57
57 || !m_document->page()) 58 if (!shouldBeClusterRoot(block))
58 return; 59 return;
59 bool windowWidthChanged = updateWindowWidth(); 60
60 61 AtomicString fingerprint = computeFingerprint(block);
61 // If needed, set existing clusters as needing their multiplier recalculated . 62 if (fingerprint.isNull())
62 for (FingerprintToClusterMap::iterator it = m_clusterForFingerprint.begin(), end = m_clusterForFingerprint.end(); it != end; ++it) { 63 return;
63 Cluster* cluster = it->value.get(); 64
64 ASSERT(cluster); 65 m_fingerprintMapper.add(block, fingerprint);
65 WTF::HashSet<RenderBlock*>& blocks = cluster->m_blocks; 66 }
66 67
67 if (windowWidthChanged) { 68 void FastTextAutosizer::destroy(RenderBlock* block)
68 // Clusters depend on the window width. Changes to the width should cause all clusters to recalc. 69 {
69 cluster->setNeedsClusterRecalc(); 70 m_fingerprintMapper.remove(block);
70 } else { 71 }
71 // If any of the cluster's blocks need a layout, mark the entire clu ster as needing a recalc. 72
72 for (WTF::HashSet<RenderBlock*>::iterator block = blocks.begin(); bl ock != blocks.end(); ++block) { 73 void FastTextAutosizer::beginLayout(RenderBlock* block)
73 if ((*block)->needsLayout()) { 74 {
74 cluster->setNeedsClusterRecalc(); 75 if (!enabled())
75 break; 76 return;
76 } 77
77 } 78 if (block->isRenderView())
78 } 79 prepareWindowInfo(toRenderView(block));
79 80
80 // If the cluster needs a recalc, mark all blocks as needing a layout so they pick up the new cluster info. 81 if (shouldBeClusterRoot(block))
81 if (cluster->needsClusterRecalc()) { 82 m_clusterStack.append(getOrCreateCluster(block));
82 for (WTF::HashSet<RenderBlock*>::iterator block = blocks.begin(); bl ock != blocks.end(); ++block) 83 }
83 (*block)->setNeedsLayout(); 84
84 } 85 void FastTextAutosizer::inflate(RenderBlock* block)
85 } 86 {
86 } 87 if (m_clusterStack.isEmpty())
87 88 return;
88 bool FastTextAutosizer::updateWindowWidth() 89 Cluster* cluster = m_clusterStack.last();
89 { 90
90 int originalWindowWidth = m_windowWidth; 91 applyMultiplier(block, cluster->m_multiplier);
92
93 // FIXME: Add an optimization to not do this walk if it's not needed.
94 for (InlineWalker walker(block); !walker.atEnd(); walker.advance()) {
95 RenderObject* inlineObj = walker.current();
96 if (inlineObj->isText())
97 applyMultiplier(inlineObj, cluster->m_multiplier);
98 }
99 }
100
101 void FastTextAutosizer::endLayout(RenderBlock* block)
102 {
103 if (!enabled())
104 return;
105
106 if (!m_clusterStack.isEmpty() && m_clusterStack.last()->m_root == block)
107 m_clusterStack.removeLast();
108 }
109
110 bool FastTextAutosizer::enabled()
111 {
112 return m_document->settings()
113 && m_document->settings()->textAutosizingEnabled()
114 && !m_document->printing()
115 && m_document->page();
116 }
117
118 void FastTextAutosizer::prepareWindowInfo(RenderView* renderView)
119 {
120 bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->wr itingMode());
91 121
92 Frame* mainFrame = m_document->page()->mainFrame(); 122 Frame* mainFrame = m_document->page()->mainFrame();
93 IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverrid e(); 123 IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverrid e();
94 if (windowSize.isEmpty()) 124 if (windowSize.isEmpty())
95 windowSize = mainFrame->view()->unscaledVisibleContentSize(ScrollableAre a::IncludeScrollbars); 125 windowSize = mainFrame->view()->unscaledVisibleContentSize(ScrollableAre a::IncludeScrollbars);
96 m_windowWidth = windowSize.width(); 126 m_windowWidth = horizontalWritingMode ? windowSize.width() : windowSize.heig ht();
97 127
98 return m_windowWidth != originalWindowWidth; 128 IntSize layoutSize = m_document->page()->mainFrame()->view()->layoutSize();
99 } 129 m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.heig ht();
100 130 }
101 void FastTextAutosizer::record(RenderBlock* block) 131
102 { 132 bool FastTextAutosizer::shouldBeClusterRoot(RenderBlock* block)
103 if (!m_document->settings() 133 {
104 || !m_document->settings()->textAutosizingEnabled() 134 // FIXME: move the logic out of TextAutosizer.cpp into this class.
105 || m_document->printing() 135 return block->isRenderView()
106 || !m_document->page()) 136 || (TextAutosizer::isAutosizingContainer(block)
107 return; 137 && TextAutosizer::isIndependentDescendant(block));
108 138 }
109 if (!TextAutosizer::isAutosizingContainer(block)) 139
110 return; 140 bool FastTextAutosizer::clusterWantsAutosizing(RenderBlock* root)
111 141 {
112 AtomicString blockFingerprint = fingerprint(block); 142 // FIXME: this should be slightly different.
113 HashMap<AtomicString, OwnPtr<Cluster> >::AddResult result = 143 return TextAutosizer::containerShouldBeAutosized(root);
114 m_clusterForFingerprint.add(blockFingerprint, PassOwnPtr<Cluster>()); 144 }
115 145
116 if (result.isNewEntry) 146 AtomicString FastTextAutosizer::computeFingerprint(RenderBlock* block)
117 result.iterator->value = adoptPtr(new Cluster(blockFingerprint)); 147 {
118 148 // FIXME(crbug.com/322340): Implement a fingerprinting algorithm.
119 Cluster* cluster = result.iterator->value.get(); 149 return nullAtom;
120 cluster->addBlock(block); 150 }
121 151
122 m_clusterForBlock.set(block, cluster); 152 FastTextAutosizer::Cluster* FastTextAutosizer::getOrCreateCluster(RenderBlock* b lock)
123 } 153 {
124 154 ClusterMap::AddResult addResult = m_clusters.add(block, PassOwnPtr<Cluster>( ));
125 void FastTextAutosizer::destroy(RenderBlock* block) 155 if (!addResult.isNewEntry)
126 { 156 return addResult.iterator->value.get();
127 Cluster* cluster = m_clusterForBlock.take(block); 157
128 if (!cluster) 158 AtomicString fingerprint = m_fingerprintMapper.get(block);
129 return; 159 if (fingerprint.isNull()) {
130 cluster->m_blocks.remove(block); 160 addResult.iterator->value = adoptPtr(createCluster(block));
131 if (cluster->m_blocks.isEmpty()) { 161 return addResult.iterator->value.get();
132 // This deletes the Cluster. 162 }
133 m_clusterForFingerprint.remove(cluster->m_fingerprint); 163 return addSupercluster(m_fingerprintMapper.getBlocks(fingerprint), block);
134 return; 164 }
135 } 165
136 cluster->setNeedsClusterRecalc(); 166 FastTextAutosizer::Cluster* FastTextAutosizer::createCluster(RenderBlock* block)
137 } 167 {
138 168 float multiplier = clusterWantsAutosizing(block) ? computeMultiplier(block) : 1.0f;
139 static void applyMultiplier(RenderObject* renderer, float multiplier) 169 return new Cluster(block, multiplier);
140 { 170 }
141 RenderStyle* currentStyle = renderer->style(); 171
172 FastTextAutosizer::Cluster* FastTextAutosizer::addSupercluster(WTF::HashSet<Rend erBlock*>& roots, RenderBlock* returnFor)
pdr. 2014/01/07 19:50:27 Would it be cleaner to change this to: FastTextAut
skobes 2014/01/07 20:10:53 How about passing the fingerprint in, and having i
173 {
174 RenderBlock* superRoot = deepestCommonAncestor(roots);
175
176 bool shouldAutosize = false;
177 for (WTF::HashSet<RenderBlock*>::iterator it = roots.begin(); it != roots.en d(); ++it)
178 shouldAutosize |= clusterWantsAutosizing(*it);
179
180 float multiplier = shouldAutosize ? computeMultiplier(superRoot) : 1.0f;
181
182 Cluster* result = 0;
183 for (WTF::HashSet<RenderBlock*>::iterator it = roots.begin(); it != roots.en d(); ++it) {
184 Cluster* cluster = new Cluster(*it, multiplier);
185 m_clusters.set(*it, adoptPtr(cluster));
186
187 if (*it == returnFor)
188 result = cluster;
189 }
190 return result;
191 }
192
193 RenderBlock* FastTextAutosizer::deepestCommonAncestor(WTF::HashSet<RenderBlock*> & blocks)
pdr. 2014/01/07 19:50:27 It may be clean to pull out the typedef for BlockS
skobes 2014/01/07 20:10:53 This is a great idea :)
194 {
195 // Find the lowest common ancestor of blocks.
196 // Note: this could be improved to not be O(b*h) for b blocks and tree heigh t h.
197 HashCountedSet<RenderObject*> ancestors;
198 for (WTF::HashSet<RenderBlock*>::iterator it = blocks.begin(); it != blocks. end(); ++it) {
199 for (RenderBlock* block = (*it); block; block = block->containingBlock() ) {
200 ancestors.add(block);
201 // The first ancestor that has all of the blocks as children wins.
202 if (ancestors.count(block) == blocks.size())
203 return block;
204 }
205 }
206 ASSERT_NOT_REACHED();
207 return 0;
208 }
209
210 float FastTextAutosizer::computeMultiplier(RenderBlock* block)
211 {
212 // Block width, in CSS pixels.
213 float blockWidth = block->contentLogicalWidth();
214
215 // FIXME: incorporate font scale factor.
216 // FIXME: incorporate device scale adjustment.
217 return max(min(blockWidth, (float) m_layoutWidth) / m_windowWidth, 1.0f);
218 }
219
220 void FastTextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier )
221 {
222 RenderStyle* currentStyle = renderer->style();
142 if (currentStyle->textAutosizingMultiplier() == multiplier) 223 if (currentStyle->textAutosizingMultiplier() == multiplier)
143 return; 224 return;
144 225
145 // We need to clone the render style to avoid breaking style sharing. 226 // We need to clone the render style to avoid breaking style sharing.
146 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle); 227 RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle);
147 style->setTextAutosizingMultiplier(multiplier); 228 style->setTextAutosizingMultiplier(multiplier);
148 style->setUnique(); 229 style->setUnique();
149 renderer->setStyleInternal(style.release()); 230 renderer->setStyleInternal(style.release());
150 } 231 }
151 232
152 void FastTextAutosizer::inflate(RenderBlock* block) 233 void FastTextAutosizer::FingerprintMapper::add(RenderBlock* block, AtomicString fingerprint)
153 { 234 {
154 Cluster* cluster = 0; 235 m_fingerprints.set(block, fingerprint);
155 for (const RenderObject* clusterBlock = block; clusterBlock && !cluster; clu sterBlock = clusterBlock->parent()) { 236
156 if (clusterBlock->isRenderBlock()) 237 ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fing erprint, PassOwnPtr<BlockSet>());
157 cluster = m_clusterForBlock.get(toRenderBlock(clusterBlock)); 238 if (addResult.isNewEntry)
158 } 239 addResult.iterator->value = adoptPtr(new BlockSet);
159 if (!cluster) 240 addResult.iterator->value->add(block);
160 return; 241 }
161 242
162 recalcClusterIfNeeded(cluster); 243 void FastTextAutosizer::FingerprintMapper::remove(RenderBlock* block)
163 244 {
164 applyMultiplier(block, cluster->m_multiplier); 245 AtomicString fingerprint = m_fingerprints.take(block);
165 246 if (fingerprint.isNull())
166 // FIXME: Add an optimization to not do this walk if it's not needed. 247 return;
167 for (InlineWalker walker(block); !walker.atEnd(); walker.advance()) { 248
168 RenderObject* inlineObj = walker.current(); 249 ReverseFingerprintMap::iterator blocksIter = m_blocksForFingerprint.find(fin gerprint);
169 if (inlineObj->isRenderBlock() && m_clusterForBlock.contains(toRenderBlo ck(inlineObj))) 250 WTF::HashSet<RenderBlock*>& blocks = *blocksIter->value;
170 continue; 251 blocks.remove(block);
171 252 if (blocks.isEmpty())
172 applyMultiplier(inlineObj, cluster->m_multiplier); 253 m_blocksForFingerprint.remove(blocksIter);
173 } 254 }
174 } 255
175 256 AtomicString FastTextAutosizer::FingerprintMapper::get(RenderBlock* block)
176 AtomicString FastTextAutosizer::fingerprint(const RenderBlock* block) 257 {
177 { 258 return m_fingerprints.get(block);
178 // FIXME(crbug.com/322340): Implement a better fingerprinting algorithm. 259 }
179 return AtomicString::number((unsigned long long) block); 260
180 } 261 WTF::HashSet<RenderBlock*>& FastTextAutosizer::FingerprintMapper::getBlocks(Atom icString fingerprint)
181 262 {
182 void FastTextAutosizer::recalcClusterIfNeeded(FastTextAutosizer::Cluster* cluste r) 263 return *m_blocksForFingerprint.get(fingerprint);
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 } 264 }
230 265
231 } // namespace WebCore 266 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/rendering/FastTextAutosizer.h ('k') | Source/core/rendering/RenderBlockFlow.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698