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