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