Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / TextAutosizer.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32 #include "core/rendering/TextAutosizer.h"
33
34 #include "core/dom/Document.h"
35 #include "core/frame/FrameView.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/Settings.h"
38 #include "core/html/HTMLTextAreaElement.h"
39 #include "core/page/Page.h"
40 #include "core/rendering/InlineIterator.h"
41 #include "core/rendering/RenderBlock.h"
42 #include "core/rendering/RenderListItem.h"
43 #include "core/rendering/RenderListMarker.h"
44 #include "core/rendering/RenderTableCell.h"
45 #include "core/rendering/RenderView.h"
46
47 #ifdef AUTOSIZING_DOM_DEBUG_INFO
48 #include "core/dom/ExecutionContextTask.h"
49 #endif
50
51 namespace blink {
52
53 #ifdef AUTOSIZING_DOM_DEBUG_INFO
54 class WriteDebugInfoTask : public ExecutionContextTask {
55 public:
56     WriteDebugInfoTask(PassRefPtrWillBeRawPtr<Element> element, AtomicString value)
57         : m_element(element)
58         , m_value(value)
59     {
60     }
61
62     virtual void performTask(ExecutionContext*)
63     {
64         m_element->setAttribute("data-autosizing", m_value, ASSERT_NO_EXCEPTION);
65     }
66
67 private:
68     RefPtrWillBePersistent<Element> m_element;
69     AtomicString m_value;
70 };
71
72 static void writeDebugInfo(RenderObject* renderer, const AtomicString& output)
73 {
74     Node* node = renderer->node();
75     if (!node)
76         return;
77     if (node->isDocumentNode())
78         node = toDocument(node)->documentElement();
79     if (!node->isElementNode())
80         return;
81     node->document().postTask(adoptPtr(new WriteDebugInfoTask(toElement(node), output)));
82 }
83
84 void TextAutosizer::writeClusterDebugInfo(Cluster* cluster)
85 {
86     String explanation = "";
87     if (cluster->m_flags & SUPPRESSING) {
88         explanation = "[suppressed]";
89     } else if (!(cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER))) {
90         explanation = "[inherited]";
91     } else if (cluster->m_supercluster) {
92         explanation = "[supercluster]";
93     } else if (!clusterHasEnoughTextToAutosize(cluster)) {
94         explanation = "[insufficient-text]";
95     } else {
96         const RenderBlock* widthProvider = clusterWidthProvider(cluster->m_root);
97         if (cluster->m_hasTableAncestor && cluster->m_multiplier < multiplierFromBlock(widthProvider)) {
98             explanation = "[table-ancestor-limited]";
99         } else {
100             explanation = String::format("[from width %d of %s]",
101                 static_cast<int>(widthFromBlock(widthProvider)), widthProvider->debugName().utf8().data());
102         }
103     }
104     String pageInfo = "";
105     if (cluster->m_root->isRenderView()) {
106         pageInfo = String::format("; pageinfo: bm %f * (lw %d / fw %d)",
107             m_pageInfo.m_baseMultiplier, m_pageInfo.m_layoutWidth, m_pageInfo.m_frameWidth);
108     }
109     float multiplier = cluster->m_flags & SUPPRESSING ? 1.0 : cluster->m_multiplier;
110     writeDebugInfo(const_cast<RenderBlock*>(cluster->m_root),
111         AtomicString(String::format("cluster: %f %s%s", multiplier,
112             explanation.utf8().data(), pageInfo.utf8().data())));
113 }
114 #endif
115
116 static const RenderObject* parentElementRenderer(const RenderObject* renderer)
117 {
118     // At style recalc, the renderer's parent may not be attached,
119     // so we need to obtain this from the DOM tree.
120     const Node* node = renderer->node();
121     if (!node)
122         return 0;
123
124     // FIXME: This should be using NodeRenderingTraversal::parent().
125     if (Element* parent = node->parentElement())
126         return parent->renderer();
127     return 0;
128 }
129
130 static bool isNonTextAreaFormControl(const RenderObject* renderer)
131 {
132     const Node* node = renderer ? renderer->node() : 0;
133     if (!node || !node->isElementNode())
134         return false;
135     const Element* element = toElement(node);
136
137     return (element->isFormControlElement() && !isHTMLTextAreaElement(element));
138 }
139
140 static bool isPotentialClusterRoot(const RenderObject* renderer)
141 {
142     // "Potential cluster roots" are the smallest unit for which we can
143     // enable/disable text autosizing.
144     // - Must not be inline, as different multipliers on one line looks terrible.
145     //   Exceptions are inline-block and alike elements (inline-table, -webkit-inline-*),
146     //   as they often contain entire multi-line columns of text.
147     // - Must not be normal list items, as items in the same list should look
148     //   consistent, unless they are floating or position:absolute/fixed.
149     Node* node = renderer->generatingNode();
150     if (node && !node->hasChildren())
151         return false;
152     if (!renderer->isRenderBlock())
153         return false;
154     if (renderer->isInline() && !renderer->style()->isDisplayReplacedType())
155         return false;
156     if (renderer->isListItem())
157         return (renderer->isFloating() || renderer->isOutOfFlowPositioned());
158
159     return true;
160 }
161
162 static bool isIndependentDescendant(const RenderBlock* renderer)
163 {
164     ASSERT(isPotentialClusterRoot(renderer));
165
166     RenderBlock* containingBlock = renderer->containingBlock();
167     return renderer->isRenderView()
168         || renderer->isFloating()
169         || renderer->isOutOfFlowPositioned()
170         || renderer->isTableCell()
171         || renderer->isTableCaption()
172         || renderer->isFlexibleBoxIncludingDeprecated()
173         || renderer->hasColumns()
174         || (containingBlock && containingBlock->isHorizontalWritingMode() != renderer->isHorizontalWritingMode())
175         || renderer->style()->isDisplayReplacedType()
176         || renderer->isTextArea()
177         || renderer->style()->userModify() != READ_ONLY;
178 }
179
180 static bool blockIsRowOfLinks(const RenderBlock* block)
181 {
182     // A "row of links" is a block for which:
183     //  1. It does not contain non-link text elements longer than 3 characters
184     //  2. It contains a minimum of 3 inline links and all links should
185     //     have the same specified font size.
186     //  3. It should not contain <br> elements.
187     //  4. It should contain only inline elements unless they are containers,
188     //     children of link elements or children of sub-containers.
189     int linkCount = 0;
190     RenderObject* renderer = block->firstChild();
191     float matchingFontSize = -1;
192
193     while (renderer) {
194         if (!isPotentialClusterRoot(renderer)) {
195             if (renderer->isText() && toRenderText(renderer)->text().impl()->stripWhiteSpace()->length() > 3)
196                 return false;
197             if (!renderer->isInline() || renderer->isBR())
198                 return false;
199         }
200         if (renderer->style()->isLink()) {
201             linkCount++;
202             if (matchingFontSize < 0)
203                 matchingFontSize = renderer->style()->specifiedFontSize();
204             else if (matchingFontSize != renderer->style()->specifiedFontSize())
205                 return false;
206
207             // Skip traversing descendants of the link.
208             renderer = renderer->nextInPreOrderAfterChildren(block);
209             continue;
210         }
211         renderer = renderer->nextInPreOrder(block);
212     }
213
214     return (linkCount >= 3);
215 }
216
217 static bool blockHeightConstrained(const RenderBlock* block)
218 {
219     // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box.
220     // FIXME: This code needs to take into account vertical writing modes.
221     // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in.
222     for (; block; block = block->containingBlock()) {
223         RenderStyle* style = block->style();
224         if (style->overflowY() >= OSCROLL)
225             return false;
226         if (style->height().isSpecified() || style->maxHeight().isSpecified() || block->isOutOfFlowPositioned()) {
227             // Some sites (e.g. wikipedia) set their html and/or body elements to height:100%,
228             // without intending to constrain the height of the content within them.
229             return !block->isDocumentElement() && !block->isBody();
230         }
231         if (block->isFloating())
232             return false;
233     }
234     return false;
235 }
236
237 static bool blockOrImmediateChildrenAreFormControls(const RenderBlock* block)
238 {
239     if (isNonTextAreaFormControl(block))
240         return true;
241     const RenderObject* renderer = block->firstChild();
242     while (renderer) {
243         if (isNonTextAreaFormControl(renderer))
244             return true;
245         renderer = renderer->nextSibling();
246     }
247
248     return false;
249 }
250
251 // Some blocks are not autosized even if their parent cluster wants them to.
252 static bool blockSuppressesAutosizing(const RenderBlock* block)
253 {
254     if (blockOrImmediateChildrenAreFormControls(block))
255         return true;
256
257     if (blockIsRowOfLinks(block))
258         return true;
259
260     // Don't autosize block-level text that can't wrap (as it's likely to
261     // expand sideways and break the page's layout).
262     if (!block->style()->autoWrap())
263         return true;
264
265     if (blockHeightConstrained(block))
266         return true;
267
268     return false;
269 }
270
271 static bool hasExplicitWidth(const RenderBlock* block)
272 {
273     // FIXME: This heuristic may need to be expanded to other ways a block can be wider or narrower
274     //        than its parent containing block.
275     return block->style() && block->style()->width().isSpecified();
276 }
277
278 TextAutosizer::TextAutosizer(const Document* document)
279     : m_document(document)
280     , m_firstBlockToBeginLayout(0)
281 #if ENABLE(ASSERT)
282     , m_blocksThatHaveBegunLayout()
283 #endif
284     , m_superclusters()
285     , m_clusterStack()
286     , m_fingerprintMapper()
287     , m_pageInfo()
288     , m_updatePageInfoDeferred(false)
289 {
290 }
291
292 void TextAutosizer::record(const RenderBlock* block)
293 {
294     if (!m_pageInfo.m_settingEnabled)
295         return;
296
297     ASSERT(!m_blocksThatHaveBegunLayout.contains(block));
298
299     if (!classifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH))
300         return;
301
302     if (Fingerprint fingerprint = computeFingerprint(block))
303         m_fingerprintMapper.addTentativeClusterRoot(block, fingerprint);
304 }
305
306 void TextAutosizer::destroy(const RenderBlock* block)
307 {
308     if (!m_pageInfo.m_settingEnabled && !m_fingerprintMapper.hasFingerprints())
309         return;
310
311     ASSERT(!m_blocksThatHaveBegunLayout.contains(block));
312
313     if (m_fingerprintMapper.remove(block) && m_firstBlockToBeginLayout) {
314         // RenderBlock with a fingerprint was destroyed during layout.
315         // Clear the cluster stack and the supercluster map to avoid stale pointers.
316         // Speculative fix for http://crbug.com/369485.
317         m_firstBlockToBeginLayout = 0;
318         m_clusterStack.clear();
319         m_superclusters.clear();
320     }
321 }
322
323 TextAutosizer::BeginLayoutBehavior TextAutosizer::prepareForLayout(const RenderBlock* block)
324 {
325 #if ENABLE(ASSERT)
326     m_blocksThatHaveBegunLayout.add(block);
327 #endif
328
329     if (!m_firstBlockToBeginLayout) {
330         m_firstBlockToBeginLayout = block;
331         prepareClusterStack(block->parent());
332     } else if (block == currentCluster()->m_root) {
333         // Ignore beginLayout on the same block twice.
334         // This can happen with paginated overflow.
335         return StopLayout;
336     }
337
338     return ContinueLayout;
339 }
340
341 void TextAutosizer::prepareClusterStack(const RenderObject* renderer)
342 {
343     if (!renderer)
344         return;
345     prepareClusterStack(renderer->parent());
346
347     if (renderer->isRenderBlock()) {
348         const RenderBlock* block = toRenderBlock(renderer);
349 #if ENABLE(ASSERT)
350         m_blocksThatHaveBegunLayout.add(block);
351 #endif
352         if (Cluster* cluster = maybeCreateCluster(block))
353             m_clusterStack.append(adoptPtr(cluster));
354     }
355 }
356
357 void TextAutosizer::beginLayout(RenderBlock* block)
358 {
359     ASSERT(shouldHandleLayout());
360
361     if (prepareForLayout(block) == StopLayout)
362         return;
363
364     if (Cluster* cluster = maybeCreateCluster(block))
365         m_clusterStack.append(adoptPtr(cluster));
366
367     // Cells in auto-layout tables are handled separately by inflateAutoTable.
368     bool isAutoTableCell = block->isTableCell() && !toRenderTableCell(block)->table()->style()->isFixedTableLayout();
369     if (!isAutoTableCell && !m_clusterStack.isEmpty())
370         inflate(block);
371 }
372
373 void TextAutosizer::inflateListItem(RenderListItem* listItem, RenderListMarker* listItemMarker)
374 {
375     if (!shouldHandleLayout())
376         return;
377     ASSERT(listItem && listItemMarker);
378
379     if (prepareForLayout(listItem) == StopLayout)
380         return;
381
382     // Force the LI to be inside the DBCAT when computing the multiplier.
383     // This guarantees that the DBCAT has entered layout, so we can ask for its width.
384     // It also makes sense because the list marker is autosized like a text node.
385     float multiplier = clusterMultiplier(currentCluster());
386
387     applyMultiplier(listItem, multiplier);
388     applyMultiplier(listItemMarker, multiplier);
389 }
390
391 void TextAutosizer::inflateAutoTable(RenderTable* table)
392 {
393     ASSERT(table);
394     ASSERT(!table->style()->isFixedTableLayout());
395     ASSERT(table->containingBlock());
396
397     Cluster* cluster = currentCluster();
398     if (cluster->m_root != table)
399         return;
400
401     // Pre-inflate cells that have enough text so that their inflated preferred widths will be used
402     // for column sizing.
403     for (RenderObject* section = table->firstChild(); section; section = section->nextSibling()) {
404         if (!section->isTableSection())
405             continue;
406         for (RenderTableRow* row = toRenderTableSection(section)->firstRow(); row; row = row->nextRow()) {
407             for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) {
408                 if (!cell->needsLayout())
409                     continue;
410
411                 beginLayout(cell);
412                 inflate(cell, DescendToInnerBlocks);
413                 endLayout(cell);
414             }
415         }
416     }
417 }
418
419 void TextAutosizer::endLayout(RenderBlock* block)
420 {
421     ASSERT(shouldHandleLayout());
422
423     if (block == m_firstBlockToBeginLayout) {
424         m_firstBlockToBeginLayout = 0;
425         m_clusterStack.clear();
426         m_superclusters.clear();
427         m_stylesRetainedDuringLayout.clear();
428 #if ENABLE(ASSERT)
429         m_blocksThatHaveBegunLayout.clear();
430 #endif
431     // Tables can create two layout scopes for the same block so the isEmpty
432     // check below is needed to guard against endLayout being called twice.
433     } else if (!m_clusterStack.isEmpty() && currentCluster()->m_root == block) {
434         m_clusterStack.removeLast();
435     }
436 }
437
438 float TextAutosizer::inflate(RenderObject* parent, InflateBehavior behavior, float multiplier)
439 {
440     Cluster* cluster = currentCluster();
441     bool hasTextChild = false;
442
443     RenderObject* child = 0;
444     if (parent->isRenderBlock() && (parent->childrenInline() || behavior == DescendToInnerBlocks))
445         child = toRenderBlock(parent)->firstChild();
446     else if (parent->isRenderInline())
447         child = toRenderInline(parent)->firstChild();
448
449     while (child) {
450         if (child->isText()) {
451             hasTextChild = true;
452             // We only calculate this multiplier on-demand to ensure the parent block of this text
453             // has entered layout.
454             if (!multiplier)
455                 multiplier = cluster->m_flags & SUPPRESSING ? 1.0f : clusterMultiplier(cluster);
456             applyMultiplier(child, multiplier);
457             // FIXME: Investigate why MarkOnlyThis is sufficient.
458             if (parent->isRenderInline())
459                 child->setPreferredLogicalWidthsDirty(MarkOnlyThis);
460         } else if (child->isRenderInline()) {
461             multiplier = inflate(child, behavior, multiplier);
462         } else if (child->isRenderBlock() && behavior == DescendToInnerBlocks
463             && !classifyBlock(child, INDEPENDENT | EXPLICIT_WIDTH | SUPPRESSING)) {
464             multiplier = inflate(child, behavior, multiplier);
465         }
466         child = child->nextSibling();
467     }
468
469     if (hasTextChild) {
470         applyMultiplier(parent, multiplier); // Parent handles line spacing.
471     } else if (!parent->isListItem()) {
472         // For consistency, a block with no immediate text child should always have a
473         // multiplier of 1 (except for list items which are handled in inflateListItem).
474         applyMultiplier(parent, 1);
475     }
476     return multiplier;
477 }
478
479 bool TextAutosizer::shouldHandleLayout() const
480 {
481     return m_pageInfo.m_settingEnabled && m_pageInfo.m_pageNeedsAutosizing && !m_updatePageInfoDeferred;
482 }
483
484 void TextAutosizer::updatePageInfoInAllFrames()
485 {
486     ASSERT(!m_document->frame() || m_document->frame()->isMainFrame());
487
488     for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
489         if (!frame->isLocalFrame())
490             continue;
491         if (TextAutosizer* textAutosizer = toLocalFrame(frame)->document()->textAutosizer())
492             textAutosizer->updatePageInfo();
493     }
494 }
495
496 void TextAutosizer::updatePageInfo()
497 {
498     if (m_updatePageInfoDeferred || !m_document->page() || !m_document->settings())
499         return;
500
501     PageInfo previousPageInfo(m_pageInfo);
502     m_pageInfo.m_settingEnabled = m_document->settings()->textAutosizingEnabled();
503
504     if (!m_pageInfo.m_settingEnabled || m_document->printing()) {
505         m_pageInfo.m_pageNeedsAutosizing = false;
506     } else {
507         RenderView* renderView = m_document->renderView();
508         bool horizontalWritingMode = isHorizontalWritingMode(renderView->style()->writingMode());
509
510         LocalFrame* mainFrame = m_document->page()->deprecatedLocalMainFrame();
511         IntSize frameSize = m_document->settings()->textAutosizingWindowSizeOverride();
512         if (frameSize.isEmpty())
513             frameSize = mainFrame->view()->unscaledVisibleContentSize(IncludeScrollbars);
514         m_pageInfo.m_frameWidth = horizontalWritingMode ? frameSize.width() : frameSize.height();
515
516         IntSize layoutSize = mainFrame->view()->layoutSize();
517         m_pageInfo.m_layoutWidth = horizontalWritingMode ? layoutSize.width() : layoutSize.height();
518
519         // Compute the base font scale multiplier based on device and accessibility settings.
520         m_pageInfo.m_baseMultiplier = m_document->settings()->accessibilityFontScaleFactor();
521         // If the page has a meta viewport or @viewport, don't apply the device scale adjustment.
522         const ViewportDescription& viewportDescription = mainFrame->document()->viewportDescription();
523         if (!viewportDescription.isSpecifiedByAuthor()) {
524             float deviceScaleAdjustment = m_document->settings()->deviceScaleAdjustment();
525             m_pageInfo.m_baseMultiplier *= deviceScaleAdjustment;
526         }
527
528         m_pageInfo.m_pageNeedsAutosizing = !!m_pageInfo.m_frameWidth
529             && (m_pageInfo.m_baseMultiplier * (static_cast<float>(m_pageInfo.m_layoutWidth) / m_pageInfo.m_frameWidth) > 1.0f);
530     }
531
532     if (m_pageInfo.m_pageNeedsAutosizing) {
533         // If page info has changed, multipliers may have changed. Force a layout to recompute them.
534         if (m_pageInfo.m_frameWidth != previousPageInfo.m_frameWidth
535             || m_pageInfo.m_layoutWidth != previousPageInfo.m_layoutWidth
536             || m_pageInfo.m_baseMultiplier != previousPageInfo.m_baseMultiplier
537             || m_pageInfo.m_settingEnabled != previousPageInfo.m_settingEnabled)
538             setAllTextNeedsLayout();
539     } else if (previousPageInfo.m_hasAutosized) {
540         // If we are no longer autosizing the page, we won't do anything during the next layout.
541         // Set all the multipliers back to 1 now.
542         resetMultipliers();
543         m_pageInfo.m_hasAutosized = false;
544     }
545 }
546
547 void TextAutosizer::resetMultipliers()
548 {
549     RenderObject* renderer = m_document->renderView();
550     while (renderer) {
551         if (RenderStyle* style = renderer->style()) {
552             if (style->textAutosizingMultiplier() != 1)
553                 applyMultiplier(renderer, 1, LayoutNeeded);
554         }
555         renderer = renderer->nextInPreOrder();
556     }
557 }
558
559 void TextAutosizer::setAllTextNeedsLayout()
560 {
561     RenderObject* renderer = m_document->renderView();
562     while (renderer) {
563         if (renderer->isText())
564             renderer->setNeedsLayoutAndFullPaintInvalidation();
565         renderer = renderer->nextInPreOrder();
566     }
567 }
568
569 TextAutosizer::BlockFlags TextAutosizer::classifyBlock(const RenderObject* renderer, BlockFlags mask) const
570 {
571     if (!renderer->isRenderBlock())
572         return 0;
573
574     const RenderBlock* block = toRenderBlock(renderer);
575     BlockFlags flags = 0;
576
577     if (isPotentialClusterRoot(block)) {
578         if (mask & POTENTIAL_ROOT)
579             flags |= POTENTIAL_ROOT;
580
581         if ((mask & INDEPENDENT) && (isIndependentDescendant(block) || block->isTable()))
582             flags |= INDEPENDENT;
583
584         if ((mask & EXPLICIT_WIDTH) && hasExplicitWidth(block))
585             flags |= EXPLICIT_WIDTH;
586
587         if ((mask & SUPPRESSING) && blockSuppressesAutosizing(block))
588             flags |= SUPPRESSING;
589     }
590     return flags;
591 }
592
593 bool TextAutosizer::clusterWouldHaveEnoughTextToAutosize(const RenderBlock* root, const RenderBlock* widthProvider)
594 {
595     Cluster hypotheticalCluster(root, classifyBlock(root), 0);
596     return clusterHasEnoughTextToAutosize(&hypotheticalCluster, widthProvider);
597 }
598
599 bool TextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const RenderBlock* widthProvider)
600 {
601     if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText)
602         return cluster->m_hasEnoughTextToAutosize == HasEnoughText;
603
604     const RenderBlock* root = cluster->m_root;
605     if (!widthProvider)
606         widthProvider = clusterWidthProvider(root);
607
608     // TextAreas and user-modifiable areas get a free pass to autosize regardless of text content.
609     if (root->isTextArea() || (root->style() && root->style()->userModify() != READ_ONLY)) {
610         cluster->m_hasEnoughTextToAutosize = HasEnoughText;
611         return true;
612     }
613
614     if (cluster->m_flags & SUPPRESSING) {
615         cluster->m_hasEnoughTextToAutosize = NotEnoughText;
616         return false;
617     }
618
619     // 4 lines of text is considered enough to autosize.
620     float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4;
621
622     float length = 0;
623     RenderObject* descendant = root->firstChild();
624     while (descendant) {
625         if (descendant->isRenderBlock()) {
626             if (classifyBlock(descendant, INDEPENDENT | SUPPRESSING)) {
627                 descendant = descendant->nextInPreOrderAfterChildren(root);
628                 continue;
629             }
630         } else if (descendant->isText()) {
631             // Note: Using text().stripWhiteSpace().length() instead of renderedTextLength() because
632             // the lineboxes will not be built until layout. These values can be different.
633             // Note: This is an approximation assuming each character is 1em wide.
634             length += toRenderText(descendant)->text().stripWhiteSpace().length() * descendant->style()->specifiedFontSize();
635
636             if (length >= minimumTextLengthToAutosize) {
637                 cluster->m_hasEnoughTextToAutosize = HasEnoughText;
638                 return true;
639             }
640         }
641         descendant = descendant->nextInPreOrder(root);
642     }
643
644     cluster->m_hasEnoughTextToAutosize = NotEnoughText;
645     return false;
646 }
647
648 TextAutosizer::Fingerprint TextAutosizer::getFingerprint(const RenderObject* renderer)
649 {
650     Fingerprint result = m_fingerprintMapper.get(renderer);
651     if (!result) {
652         result = computeFingerprint(renderer);
653         m_fingerprintMapper.add(renderer, result);
654     }
655     return result;
656 }
657
658 TextAutosizer::Fingerprint TextAutosizer::computeFingerprint(const RenderObject* renderer)
659 {
660     Node* node = renderer->generatingNode();
661     if (!node || !node->isElementNode())
662         return 0;
663
664     FingerprintSourceData data;
665     if (const RenderObject* parent = parentElementRenderer(renderer))
666         data.m_parentHash = getFingerprint(parent);
667
668     data.m_qualifiedNameHash = QualifiedNameHash::hash(toElement(node)->tagQName());
669
670     if (RenderStyle* style = renderer->style()) {
671         data.m_packedStyleProperties = style->direction();
672         data.m_packedStyleProperties |= (style->position() << 1);
673         data.m_packedStyleProperties |= (style->floating() << 4);
674         data.m_packedStyleProperties |= (style->display() << 6);
675         data.m_packedStyleProperties |= (style->width().type() << 11);
676         // packedStyleProperties effectively using 15 bits now.
677
678         // consider for adding: writing mode, padding.
679
680         data.m_width = style->width().getFloatValue();
681     }
682
683     // Use nodeIndex as a rough approximation of column number
684     // (it's too early to call RenderTableCell::col).
685     // FIXME: account for colspan
686     if (renderer->isTableCell())
687         data.m_column = renderer->node()->nodeIndex();
688
689     return StringHasher::computeHash<UChar>(
690         static_cast<const UChar*>(static_cast<const void*>(&data)),
691         sizeof data / sizeof(UChar));
692 }
693
694 TextAutosizer::Cluster* TextAutosizer::maybeCreateCluster(const RenderBlock* block)
695 {
696     BlockFlags flags = classifyBlock(block);
697     if (!(flags & POTENTIAL_ROOT))
698         return 0;
699
700     Cluster* parentCluster = m_clusterStack.isEmpty() ? 0 : currentCluster();
701     ASSERT(parentCluster || block->isRenderView());
702
703     // If a non-independent block would not alter the SUPPRESSING flag, it doesn't need to be a cluster.
704     bool parentSuppresses = parentCluster && (parentCluster->m_flags & SUPPRESSING);
705     if (!(flags & INDEPENDENT) && !(flags & EXPLICIT_WIDTH) && !!(flags & SUPPRESSING) == parentSuppresses)
706         return 0;
707
708     Cluster* cluster = new Cluster(block, flags, parentCluster, getSupercluster(block));
709 #ifdef AUTOSIZING_DOM_DEBUG_INFO
710     // Non-SUPPRESSING clusters are annotated in clusterMultiplier.
711     if (flags & SUPPRESSING)
712         writeClusterDebugInfo(cluster);
713 #endif
714     return cluster;
715 }
716
717 TextAutosizer::Supercluster* TextAutosizer::getSupercluster(const RenderBlock* block)
718 {
719     Fingerprint fingerprint = m_fingerprintMapper.get(block);
720     if (!fingerprint)
721         return 0;
722
723     BlockSet* roots = m_fingerprintMapper.getTentativeClusterRoots(fingerprint);
724     if (!roots || roots->size() < 2 || !roots->contains(block))
725         return 0;
726
727     SuperclusterMap::AddResult addResult = m_superclusters.add(fingerprint, PassOwnPtr<Supercluster>());
728     if (!addResult.isNewEntry)
729         return addResult.storedValue->value.get();
730
731     Supercluster* supercluster = new Supercluster(roots);
732     addResult.storedValue->value = adoptPtr(supercluster);
733     return supercluster;
734 }
735
736 float TextAutosizer::clusterMultiplier(Cluster* cluster)
737 {
738     if (cluster->m_multiplier)
739         return cluster->m_multiplier;
740
741     // FIXME: why does isWiderOrNarrowerDescendant crash on independent clusters?
742     if (!(cluster->m_flags & INDEPENDENT) && isWiderOrNarrowerDescendant(cluster))
743         cluster->m_flags |= WIDER_OR_NARROWER;
744
745     if (cluster->m_flags & (INDEPENDENT | WIDER_OR_NARROWER)) {
746         if (cluster->m_supercluster)
747             cluster->m_multiplier = superclusterMultiplier(cluster);
748         else if (clusterHasEnoughTextToAutosize(cluster))
749             cluster->m_multiplier = multiplierFromBlock(clusterWidthProvider(cluster->m_root));
750         else
751             cluster->m_multiplier = 1.0f;
752     } else {
753         cluster->m_multiplier = cluster->m_parent ? clusterMultiplier(cluster->m_parent) : 1.0f;
754     }
755
756 #ifdef AUTOSIZING_DOM_DEBUG_INFO
757     writeClusterDebugInfo(cluster);
758 #endif
759
760     ASSERT(cluster->m_multiplier);
761     return cluster->m_multiplier;
762 }
763
764 bool TextAutosizer::superclusterHasEnoughTextToAutosize(Supercluster* supercluster, const RenderBlock* widthProvider)
765 {
766     if (supercluster->m_hasEnoughTextToAutosize != UnknownAmountOfText)
767         return supercluster->m_hasEnoughTextToAutosize == HasEnoughText;
768
769     BlockSet::iterator end = supercluster->m_roots->end();
770     for (BlockSet::iterator it = supercluster->m_roots->begin(); it != end; ++it) {
771         if (clusterWouldHaveEnoughTextToAutosize(*it, widthProvider)) {
772             supercluster->m_hasEnoughTextToAutosize = HasEnoughText;
773             return true;
774         }
775     }
776     supercluster->m_hasEnoughTextToAutosize = NotEnoughText;
777     return false;
778 }
779
780 float TextAutosizer::superclusterMultiplier(Cluster* cluster)
781 {
782     Supercluster* supercluster = cluster->m_supercluster;
783     if (!supercluster->m_multiplier) {
784         const RenderBlock* widthProvider = maxClusterWidthProvider(cluster->m_supercluster, cluster->m_root);
785         supercluster->m_multiplier = superclusterHasEnoughTextToAutosize(supercluster, widthProvider)
786             ? multiplierFromBlock(widthProvider) : 1.0f;
787     }
788     ASSERT(supercluster->m_multiplier);
789     return supercluster->m_multiplier;
790 }
791
792 const RenderBlock* TextAutosizer::clusterWidthProvider(const RenderBlock* root) const
793 {
794     if (root->isTable() || root->isTableCell())
795         return root;
796
797     return deepestBlockContainingAllText(root);
798 }
799
800 const RenderBlock* TextAutosizer::maxClusterWidthProvider(const Supercluster* supercluster, const RenderBlock* currentRoot) const
801 {
802     const RenderBlock* result = clusterWidthProvider(currentRoot);
803     float maxWidth = widthFromBlock(result);
804
805     const BlockSet* roots = supercluster->m_roots;
806     for (BlockSet::iterator it = roots->begin(); it != roots->end(); ++it) {
807         const RenderBlock* widthProvider = clusterWidthProvider(*it);
808         if (widthProvider->needsLayout())
809             continue;
810         float width = widthFromBlock(widthProvider);
811         if (width > maxWidth) {
812             maxWidth = width;
813             result = widthProvider;
814         }
815     }
816     RELEASE_ASSERT(result);
817     return result;
818 }
819
820 float TextAutosizer::widthFromBlock(const RenderBlock* block) const
821 {
822     RELEASE_ASSERT(block);
823     RELEASE_ASSERT(block->style());
824
825     if (!(block->isTable() || block->isTableCell() || block->isListItem()))
826         return block->contentLogicalWidth().toFloat();
827
828     if (!block->containingBlock())
829         return 0;
830
831     // Tables may be inflated before computing their preferred widths. Try several methods to
832     // obtain a width, and fall back on a containing block's width.
833     for (; block; block = block->containingBlock()) {
834         float width;
835         Length specifiedWidth = block->isTableCell()
836             ? toRenderTableCell(block)->styleOrColLogicalWidth() : block->style()->logicalWidth();
837         if (specifiedWidth.isFixed()) {
838             if ((width = specifiedWidth.value()) > 0)
839                 return width;
840         }
841         if (specifiedWidth.isPercent()) {
842             if (float containerWidth = block->containingBlock()->contentLogicalWidth().toFloat()) {
843                 if ((width = floatValueForLength(specifiedWidth, containerWidth)) > 0)
844                     return width;
845             }
846         }
847         if ((width = block->contentLogicalWidth().toFloat()) > 0)
848             return width;
849     }
850     return 0;
851 }
852
853 float TextAutosizer::multiplierFromBlock(const RenderBlock* block)
854 {
855     // If block->needsLayout() is false, it does not need to be in m_blocksThatHaveBegunLayout.
856     // This can happen during layout of a positioned object if the cluster's DBCAT is deeper
857     // than the positioned object's containing block, and wasn't marked as needing layout.
858     ASSERT(m_blocksThatHaveBegunLayout.contains(block) || !block->needsLayout());
859
860     // Block width, in CSS pixels.
861     float blockWidth = widthFromBlock(block);
862     float multiplier = m_pageInfo.m_frameWidth ? std::min(blockWidth, static_cast<float>(m_pageInfo.m_layoutWidth)) / m_pageInfo.m_frameWidth : 1.0f;
863
864     return std::max(m_pageInfo.m_baseMultiplier * multiplier, 1.0f);
865 }
866
867 const RenderBlock* TextAutosizer::deepestBlockContainingAllText(Cluster* cluster)
868 {
869     if (!cluster->m_deepestBlockContainingAllText)
870         cluster->m_deepestBlockContainingAllText = deepestBlockContainingAllText(cluster->m_root);
871
872     return cluster->m_deepestBlockContainingAllText;
873 }
874
875 // FIXME: Refactor this to look more like TextAutosizer::deepestCommonAncestor.
876 const RenderBlock* TextAutosizer::deepestBlockContainingAllText(const RenderBlock* root) const
877 {
878     size_t firstDepth = 0;
879     const RenderObject* firstTextLeaf = findTextLeaf(root, firstDepth, First);
880     if (!firstTextLeaf)
881         return root;
882
883     size_t lastDepth = 0;
884     const RenderObject* lastTextLeaf = findTextLeaf(root, lastDepth, Last);
885     ASSERT(lastTextLeaf);
886
887     // Equalize the depths if necessary. Only one of the while loops below will get executed.
888     const RenderObject* firstNode = firstTextLeaf;
889     const RenderObject* lastNode = lastTextLeaf;
890     while (firstDepth > lastDepth) {
891         firstNode = firstNode->parent();
892         --firstDepth;
893     }
894     while (lastDepth > firstDepth) {
895         lastNode = lastNode->parent();
896         --lastDepth;
897     }
898
899     // Go up from both nodes until the parent is the same. Both pointers will point to the LCA then.
900     while (firstNode != lastNode) {
901         firstNode = firstNode->parent();
902         lastNode = lastNode->parent();
903     }
904
905     if (firstNode->isRenderBlock())
906         return toRenderBlock(firstNode);
907
908     // containingBlock() should never leave the cluster, since it only skips ancestors when finding
909     // the container of position:absolute/fixed blocks, and those cannot exist between a cluster and
910     // its text node's lowest common ancestor as isAutosizingCluster would have made them into their
911     // own independent cluster.
912     const RenderBlock* containingBlock = firstNode->containingBlock();
913     if (!containingBlock)
914         return root;
915
916     ASSERT(containingBlock->isDescendantOf(root));
917     return containingBlock;
918 }
919
920 const RenderObject* TextAutosizer::findTextLeaf(const RenderObject* parent, size_t& depth, TextLeafSearch firstOrLast) const
921 {
922     // List items are treated as text due to the marker.
923     // The actual renderer for the marker (RenderListMarker) may not be in the tree yet since it is added during layout.
924     if (parent->isListItem())
925         return parent;
926
927     if (parent->isText())
928         return parent;
929
930     ++depth;
931     const RenderObject* child = (firstOrLast == First) ? parent->slowFirstChild() : parent->slowLastChild();
932     while (child) {
933         // Note: At this point clusters may not have been created for these blocks so we cannot rely
934         //       on m_clusters. Instead, we use a best-guess about whether the block will become a cluster.
935         if (!classifyBlock(child, INDEPENDENT)) {
936             if (const RenderObject* leaf = findTextLeaf(child, depth, firstOrLast))
937                 return leaf;
938         }
939         child = (firstOrLast == First) ? child->nextSibling() : child->previousSibling();
940     }
941     --depth;
942
943     return 0;
944 }
945
946 void TextAutosizer::applyMultiplier(RenderObject* renderer, float multiplier, RelayoutBehavior relayoutBehavior)
947 {
948     ASSERT(renderer && renderer->style());
949     RenderStyle* currentStyle = renderer->style();
950     if (currentStyle->textAutosizingMultiplier() == multiplier)
951         return;
952
953     // We need to clone the render style to avoid breaking style sharing.
954     RefPtr<RenderStyle> style = RenderStyle::clone(currentStyle);
955     style->setTextAutosizingMultiplier(multiplier);
956     style->setUnique();
957
958     switch (relayoutBehavior) {
959     case AlreadyInLayout:
960         // Don't free currentStyle until the end of the layout pass. This allows other parts of the system
961         // to safely hold raw RenderStyle* pointers during layout, e.g. BreakingContext::m_currentStyle.
962         m_stylesRetainedDuringLayout.append(currentStyle);
963
964         renderer->setStyleInternal(style.release());
965         renderer->setNeedsLayoutAndFullPaintInvalidation();
966         break;
967
968     case LayoutNeeded:
969         renderer->setStyle(style.release());
970         break;
971     }
972
973     if (multiplier != 1)
974         m_pageInfo.m_hasAutosized = true;
975 }
976
977 bool TextAutosizer::isWiderOrNarrowerDescendant(Cluster* cluster)
978 {
979     // FIXME: Why do we return true when hasExplicitWidth returns false??
980     if (!cluster->m_parent || !hasExplicitWidth(cluster->m_root))
981         return true;
982
983     const RenderBlock* parentDeepestBlockContainingAllText = deepestBlockContainingAllText(cluster->m_parent);
984     ASSERT(m_blocksThatHaveBegunLayout.contains(cluster->m_root));
985     ASSERT(m_blocksThatHaveBegunLayout.contains(parentDeepestBlockContainingAllText));
986
987     float contentWidth = cluster->m_root->contentLogicalWidth().toFloat();
988     float clusterTextWidth = parentDeepestBlockContainingAllText->contentLogicalWidth().toFloat();
989
990     // Clusters with a root that is wider than the deepestBlockContainingAllText of their parent
991     // autosize independently of their parent.
992     if (contentWidth > clusterTextWidth)
993         return true;
994
995     // Clusters with a root that is significantly narrower than the deepestBlockContainingAllText of
996     // their parent autosize independently of their parent.
997     static float narrowWidthDifference = 200;
998     if (clusterTextWidth - contentWidth > narrowWidthDifference)
999         return true;
1000
1001     return false;
1002 }
1003
1004 TextAutosizer::Cluster* TextAutosizer::currentCluster() const
1005 {
1006     ASSERT_WITH_SECURITY_IMPLICATION(!m_clusterStack.isEmpty());
1007     return m_clusterStack.last().get();
1008 }
1009
1010 #if ENABLE(ASSERT)
1011 void TextAutosizer::FingerprintMapper::assertMapsAreConsistent()
1012 {
1013     // For each fingerprint -> block mapping in m_blocksForFingerprint we should have an associated
1014     // map from block -> fingerprint in m_fingerprints.
1015     ReverseFingerprintMap::iterator end = m_blocksForFingerprint.end();
1016     for (ReverseFingerprintMap::iterator fingerprintIt = m_blocksForFingerprint.begin(); fingerprintIt != end; ++fingerprintIt) {
1017         Fingerprint fingerprint = fingerprintIt->key;
1018         BlockSet* blocks = fingerprintIt->value.get();
1019         for (BlockSet::iterator blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) {
1020             const RenderBlock* block = (*blockIt);
1021             ASSERT(m_fingerprints.get(block) == fingerprint);
1022         }
1023     }
1024 }
1025 #endif
1026
1027 void TextAutosizer::FingerprintMapper::add(const RenderObject* renderer, Fingerprint fingerprint)
1028 {
1029     remove(renderer);
1030
1031     m_fingerprints.set(renderer, fingerprint);
1032 #if ENABLE(ASSERT)
1033     assertMapsAreConsistent();
1034 #endif
1035 }
1036
1037 void TextAutosizer::FingerprintMapper::addTentativeClusterRoot(const RenderBlock* block, Fingerprint fingerprint)
1038 {
1039     add(block, fingerprint);
1040
1041     ReverseFingerprintMap::AddResult addResult = m_blocksForFingerprint.add(fingerprint, PassOwnPtr<BlockSet>());
1042     if (addResult.isNewEntry)
1043         addResult.storedValue->value = adoptPtr(new BlockSet);
1044     addResult.storedValue->value->add(block);
1045 #if ENABLE(ASSERT)
1046     assertMapsAreConsistent();
1047 #endif
1048 }
1049
1050 bool TextAutosizer::FingerprintMapper::remove(const RenderObject* renderer)
1051 {
1052     Fingerprint fingerprint = m_fingerprints.take(renderer);
1053     if (!fingerprint || !renderer->isRenderBlock())
1054         return false;
1055
1056     ReverseFingerprintMap::iterator blocksIter = m_blocksForFingerprint.find(fingerprint);
1057     if (blocksIter == m_blocksForFingerprint.end())
1058         return false;
1059
1060     BlockSet& blocks = *blocksIter->value;
1061     blocks.remove(toRenderBlock(renderer));
1062     if (blocks.isEmpty())
1063         m_blocksForFingerprint.remove(blocksIter);
1064 #if ENABLE(ASSERT)
1065     assertMapsAreConsistent();
1066 #endif
1067     return true;
1068 }
1069
1070 TextAutosizer::Fingerprint TextAutosizer::FingerprintMapper::get(const RenderObject* renderer)
1071 {
1072     return m_fingerprints.get(renderer);
1073 }
1074
1075 TextAutosizer::BlockSet* TextAutosizer::FingerprintMapper::getTentativeClusterRoots(Fingerprint fingerprint)
1076 {
1077     return m_blocksForFingerprint.get(fingerprint);
1078 }
1079
1080 TextAutosizer::LayoutScope::LayoutScope(RenderBlock* block)
1081     : m_textAutosizer(block->document().textAutosizer())
1082     , m_block(block)
1083 {
1084     if (!m_textAutosizer)
1085         return;
1086
1087     if (m_textAutosizer->shouldHandleLayout())
1088         m_textAutosizer->beginLayout(m_block);
1089     else
1090         m_textAutosizer = 0;
1091 }
1092
1093 TextAutosizer::LayoutScope::~LayoutScope()
1094 {
1095     if (m_textAutosizer)
1096         m_textAutosizer->endLayout(m_block);
1097 }
1098
1099
1100 TextAutosizer::TableLayoutScope::TableLayoutScope(RenderTable* table)
1101     : LayoutScope(table)
1102 {
1103     if (m_textAutosizer) {
1104         ASSERT(m_textAutosizer->shouldHandleLayout());
1105         m_textAutosizer->inflateAutoTable(table);
1106     }
1107 }
1108
1109 TextAutosizer::DeferUpdatePageInfo::DeferUpdatePageInfo(Page* page)
1110     : m_mainFrame(page->deprecatedLocalMainFrame())
1111 {
1112     if (TextAutosizer* textAutosizer = m_mainFrame->document()->textAutosizer()) {
1113         ASSERT(!textAutosizer->m_updatePageInfoDeferred);
1114         textAutosizer->m_updatePageInfoDeferred = true;
1115     }
1116 }
1117
1118 TextAutosizer::DeferUpdatePageInfo::~DeferUpdatePageInfo()
1119 {
1120     if (TextAutosizer* textAutosizer = m_mainFrame->document()->textAutosizer()) {
1121         ASSERT(textAutosizer->m_updatePageInfoDeferred);
1122         textAutosizer->m_updatePageInfoDeferred = false;
1123         textAutosizer->updatePageInfoInAllFrames();
1124     }
1125 }
1126
1127 float TextAutosizer::computeAutosizedFontSize(float specifiedSize, float multiplier)
1128 {
1129     // Somewhat arbitrary "pleasant" font size.
1130     const float pleasantSize = 16;
1131
1132     // Multiply fonts that the page author has specified to be larger than
1133     // pleasantSize by less and less, until huge fonts are not increased at all.
1134     // For specifiedSize between 0 and pleasantSize we directly apply the
1135     // multiplier; hence for specifiedSize == pleasantSize, computedSize will be
1136     // multiplier * pleasantSize. For greater specifiedSizes we want to
1137     // gradually fade out the multiplier, so for every 1px increase in
1138     // specifiedSize beyond pleasantSize we will only increase computedSize
1139     // by gradientAfterPleasantSize px until we meet the
1140     // computedSize = specifiedSize line, after which we stay on that line (so
1141     // then every 1px increase in specifiedSize increases computedSize by 1px).
1142     const float gradientAfterPleasantSize = 0.5;
1143
1144     float computedSize;
1145     if (specifiedSize <= pleasantSize) {
1146         computedSize = multiplier * specifiedSize;
1147     } else {
1148         computedSize = multiplier * pleasantSize + gradientAfterPleasantSize * (specifiedSize - pleasantSize);
1149         if (computedSize < specifiedSize)
1150             computedSize = specifiedSize;
1151     }
1152     return computedSize;
1153 }
1154
1155 void TextAutosizer::trace(Visitor* visitor)
1156 {
1157     visitor->trace(m_document);
1158 }
1159
1160 } // namespace blink