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