Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / resolver / StyleAdjuster.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  * Copyright (C) 2013 Google Inc. All rights reserved.
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public License
24  * along with this library; see the file COPYING.LIB.  If not, write to
25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  */
28
29 #include "config.h"
30 #include "core/css/resolver/StyleAdjuster.h"
31
32 #include "core/HTMLNames.h"
33 #include "core/SVGNames.h"
34 #include "core/dom/ContainerNode.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/Element.h"
37 #include "core/dom/NodeRenderStyle.h"
38 #include "core/html/HTMLIFrameElement.h"
39 #include "core/html/HTMLInputElement.h"
40 #include "core/html/HTMLPlugInElement.h"
41 #include "core/html/HTMLTableCellElement.h"
42 #include "core/html/HTMLTextAreaElement.h"
43 #include "core/frame/FrameView.h"
44 #include "core/frame/Settings.h"
45 #include "core/rendering/RenderReplaced.h"
46 #include "core/rendering/RenderTheme.h"
47 #include "core/rendering/style/GridPosition.h"
48 #include "core/rendering/style/RenderStyle.h"
49 #include "core/rendering/style/RenderStyleConstants.h"
50 #include "core/svg/SVGSVGElement.h"
51 #include "platform/Length.h"
52 #include "platform/transforms/TransformOperations.h"
53 #include "wtf/Assertions.h"
54
55 namespace blink {
56
57 using namespace HTMLNames;
58
59 static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing)
60 {
61     switch (display) {
62     case BLOCK:
63     case TABLE:
64     case BOX:
65     case FLEX:
66     case GRID:
67         return display;
68
69     case LIST_ITEM:
70         // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode.
71         if (!strictParsing && isFloating)
72             return BLOCK;
73         return display;
74     case INLINE_TABLE:
75         return TABLE;
76     case INLINE_BOX:
77         return BOX;
78     case INLINE_FLEX:
79         return FLEX;
80     case INLINE_GRID:
81         return GRID;
82
83     case INLINE:
84     case INLINE_BLOCK:
85     case TABLE_ROW_GROUP:
86     case TABLE_HEADER_GROUP:
87     case TABLE_FOOTER_GROUP:
88     case TABLE_ROW:
89     case TABLE_COLUMN_GROUP:
90     case TABLE_COLUMN:
91     case TABLE_CELL:
92     case TABLE_CAPTION:
93         return BLOCK;
94     case NONE:
95         ASSERT_NOT_REACHED();
96         return NONE;
97     }
98     ASSERT_NOT_REACHED();
99     return BLOCK;
100 }
101
102 // CSS requires text-decoration to be reset at each DOM element for tables,
103 // inline blocks, inline tables, shadow DOM crossings, floating elements,
104 // and absolute or relatively positioned elements.
105 static bool doesNotInheritTextDecoration(const RenderStyle* style, const Element* e)
106 {
107     return style->display() == TABLE || style->display() == INLINE_TABLE
108         || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e)
109         || style->isFloating() || style->hasOutOfFlowPosition();
110 }
111
112 // FIXME: This helper is only needed because pseudoStyleForElement passes a null
113 // element to adjustRenderStyle, so we can't just use element->isInTopLayer().
114 static bool isInTopLayer(const Element* element, const RenderStyle* style)
115 {
116     return (element && element->isInTopLayer()) || (style && style->styleType() == BACKDROP);
117 }
118
119 static bool parentStyleForcesZIndexToCreateStackingContext(const RenderStyle* parentStyle)
120 {
121     return parentStyle->isDisplayFlexibleOrGridBox();
122 }
123
124 static bool hasWillChangeThatCreatesStackingContext(const RenderStyle* style)
125 {
126     for (size_t i = 0; i < style->willChangeProperties().size(); ++i) {
127         switch (style->willChangeProperties()[i]) {
128         case CSSPropertyOpacity:
129         case CSSPropertyTransform:
130         case CSSPropertyWebkitTransform:
131         case CSSPropertyTransformStyle:
132         case CSSPropertyWebkitTransformStyle:
133         case CSSPropertyPerspective:
134         case CSSPropertyWebkitPerspective:
135         case CSSPropertyWebkitMask:
136         case CSSPropertyWebkitMaskBoxImage:
137         case CSSPropertyWebkitClipPath:
138         case CSSPropertyWebkitBoxReflect:
139         case CSSPropertyWebkitFilter:
140         case CSSPropertyZIndex:
141         case CSSPropertyPosition:
142             return true;
143         case CSSPropertyMixBlendMode:
144         case CSSPropertyIsolation:
145             if (RuntimeEnabledFeatures::cssCompositingEnabled())
146                 return true;
147             break;
148         default:
149             break;
150         }
151     }
152     return false;
153 }
154
155 void StyleAdjuster::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e, const CachedUAStyle* cachedUAStyle)
156 {
157     ASSERT(parentStyle);
158
159     if (style->display() != NONE) {
160         if (e)
161             adjustStyleForTagName(style, parentStyle, *e);
162
163         // Per the spec, position 'static' and 'relative' in the top layer compute to 'absolute'.
164         if (isInTopLayer(e, style) && (style->position() == StaticPosition || style->position() == RelativePosition))
165             style->setPosition(AbsolutePosition);
166
167         // Absolute/fixed positioned elements, floating elements and the document element need block-like outside display.
168         if (style->hasOutOfFlowPosition() || style->isFloating() || (e && e->document().documentElement() == e))
169             style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !m_useQuirksModeStyles));
170
171         adjustStyleForDisplay(style, parentStyle);
172     }
173
174     // Make sure our z-index value is only applied if the object is positioned.
175     if (style->position() == StaticPosition && !parentStyleForcesZIndexToCreateStackingContext(parentStyle))
176         style->setHasAutoZIndex();
177
178     // Auto z-index becomes 0 for the root element and transparent objects. This prevents
179     // cases where objects that should be blended as a single unit end up with a non-transparent
180     // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
181     if (style->hasAutoZIndex() && ((e && e->document().documentElement() == e)
182         || style->hasOpacity()
183         || style->hasTransformRelatedProperty()
184         || style->hasMask()
185         || style->clipPath()
186         || style->boxReflect()
187         || style->hasFilter()
188         || style->hasBlendMode()
189         || style->hasIsolation()
190         || style->position() == FixedPosition
191         || isInTopLayer(e, style)
192         || hasWillChangeThatCreatesStackingContext(style)))
193         style->setZIndex(0);
194
195     // will-change:transform should result in the same rendering behavior as having a transform,
196     // including the creation of a containing block for fixed position descendants.
197     if (!style->hasTransform() && (style->willChangeProperties().contains(CSSPropertyWebkitTransform) || style->willChangeProperties().contains(CSSPropertyTransform))) {
198         bool makeIdentity = true;
199         style->setTransform(TransformOperations(makeIdentity));
200     }
201
202     if (doesNotInheritTextDecoration(style, e))
203         style->clearAppliedTextDecorations();
204
205     style->applyTextDecorations();
206
207     if (style->overflowX() != OVISIBLE || style->overflowY() != OVISIBLE)
208         adjustOverflow(style);
209
210     // Cull out any useless layers and also repeat patterns into additional layers.
211     style->adjustBackgroundLayers();
212     style->adjustMaskLayers();
213
214     // Let the theme also have a crack at adjusting the style.
215     if (style->hasAppearance())
216         RenderTheme::theme().adjustStyle(style, e, cachedUAStyle);
217
218     // If we have first-letter pseudo style, transitions, or animations, do not share this style.
219     if (style->hasPseudoStyle(FIRST_LETTER) || style->transitions() || style->animations())
220         style->setUnique();
221
222     // FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening.
223     if (style->preserves3D() && (style->overflowX() != OVISIBLE
224         || style->overflowY() != OVISIBLE
225         || style->hasFilter()))
226         style->setTransformStyle3D(TransformStyle3DFlat);
227
228     if (e && e->isSVGElement()) {
229         // Only the root <svg> element in an SVG document fragment tree honors css position
230         if (!(isSVGSVGElement(*e) && e->parentNode() && !e->parentNode()->isSVGElement()))
231             style->setPosition(RenderStyle::initialPosition());
232
233         // SVG text layout code expects us to be a block-level style element.
234         if ((isSVGForeignObjectElement(*e) || isSVGTextElement(*e)) && style->isDisplayInlineType())
235             style->setDisplay(BLOCK);
236     }
237
238     if (e && e->renderStyle() && e->renderStyle()->textAutosizingMultiplier() != 1) {
239         // Preserve the text autosizing multiplier on style recalc.
240         // (The autosizer will update it during layout if it needs to be changed.)
241         style->setTextAutosizingMultiplier(e->renderStyle()->textAutosizingMultiplier());
242         style->setUnique();
243     }
244
245     adjustStyleForAlignment(*style, *parentStyle);
246 }
247
248 void StyleAdjuster::adjustStyleForAlignment(RenderStyle& style, const RenderStyle& parentStyle)
249 {
250     bool isFlexOrGrid = style.isDisplayFlexibleOrGridBox();
251     bool absolutePositioned = style.position() == AbsolutePosition;
252
253     // If the inherited value of justify-items includes the legacy keyword, 'auto'
254     // computes to the the inherited value.
255     // Otherwise, auto computes to:
256     //  - 'stretch' for flex containers and grid containers.
257     //  - 'start' for everything else.
258     if (style.justifyItems() == ItemPositionAuto) {
259         if (parentStyle.justifyItemsPositionType() == LegacyPosition) {
260             style.setJustifyItems(parentStyle.justifyItems());
261             style.setJustifyItemsPositionType(parentStyle.justifyItemsPositionType());
262         } else if (isFlexOrGrid) {
263             style.setJustifyItems(ItemPositionStretch);
264         }
265     }
266
267     // The 'auto' keyword computes to 'stretch' on absolutely-positioned elements,
268     // and to the computed value of justify-items on the parent (minus
269     // any legacy keywords) on all other boxes.
270     if (style.justifySelf() == ItemPositionAuto) {
271         if (absolutePositioned) {
272             style.setJustifySelf(ItemPositionStretch);
273         } else {
274             style.setJustifySelf(parentStyle.justifyItems());
275             style.setJustifySelfOverflowAlignment(parentStyle.justifyItemsOverflowAlignment());
276         }
277     }
278
279     // The 'auto' keyword computes to:
280     //  - 'stretch' for flex containers and grid containers,
281     //  - 'start' for everything else.
282     if (style.alignItems() == ItemPositionAuto) {
283         if (isFlexOrGrid)
284             style.setAlignItems(ItemPositionStretch);
285     }
286
287     // The 'auto' keyword computes to 'stretch' on absolutely-positioned elements,
288     // and to the computed value of align-items on the parent (minus
289     // any 'legacy' keywords) on all other boxes.
290     if (style.alignSelf() == ItemPositionAuto) {
291         if (absolutePositioned) {
292             style.setAlignSelf(ItemPositionStretch);
293         } else {
294             style.setAlignSelf(parentStyle.alignItems());
295             style.setAlignSelfOverflowAlignment(parentStyle.alignItemsOverflowAlignment());
296         }
297     }
298
299     // Block Containers: For table cells, the behavior of the 'auto' depends on the computed
300     // value of 'vertical-align', otherwise behaves as 'start'.
301     // Flex Containers: 'auto' computes to 'flex-start'.
302     // Grid Containers: 'auto' computes to 'start', and 'stretch' behaves like 'start'.
303     if ((style.justifyContent() == ContentPositionAuto) && (style.justifyContentDistribution() == ContentDistributionDefault)) {
304         if (style.isDisplayFlexibleOrGridBox()) {
305             if (style.isDisplayFlexibleBox())
306                 style.setJustifyContent(ContentPositionFlexStart);
307             else
308                 style.setJustifyContent(ContentPositionStart);
309         }
310     }
311 }
312
313 void StyleAdjuster::adjustStyleForTagName(RenderStyle* style, RenderStyle* parentStyle, Element& element)
314 {
315     // <div> and <span> are the most common elements on the web, we skip all the work for them.
316     if (isHTMLDivElement(element) || isHTMLSpanElement(element))
317         return;
318
319     if (isHTMLTableCellElement(element)) {
320         // If we have a <td> that specifies a float property, in quirks mode we just drop the float property.
321         // FIXME: Why is this only <td> and not <th>?
322         if (element.hasTagName(tdTag) && m_useQuirksModeStyles) {
323             style->setDisplay(TABLE_CELL);
324             style->setFloating(NoFloat);
325         }
326         // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead.
327         // Table headers with a text-align of -webkit-auto will change the text-align to center.
328         if (element.hasTagName(thTag) && style->textAlign() == TASTART)
329             style->setTextAlign(CENTER);
330         if (style->whiteSpace() == KHTML_NOWRAP) {
331             // Figure out if we are really nowrapping or if we should just
332             // use normal instead. If the width of the cell is fixed, then
333             // we don't actually use NOWRAP.
334             if (style->width().isFixed())
335                 style->setWhiteSpace(NORMAL);
336             else
337                 style->setWhiteSpace(NOWRAP);
338         }
339         return;
340     }
341
342     if (isHTMLTableElement(element)) {
343         // Sites commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
344         // these tags to retain their display types.
345         if (m_useQuirksModeStyles)
346             style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
347         // Tables never support the -webkit-* values for text-align and will reset back to the default.
348         if (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT)
349             style->setTextAlign(TASTART);
350         return;
351     }
352
353     if (isHTMLFrameElement(element) || isHTMLFrameSetElement(element)) {
354         // Frames and framesets never honor position:relative or position:absolute. This is necessary to
355         // fix a crash where a site tries to position these objects. They also never honor display.
356         style->setPosition(StaticPosition);
357         style->setDisplay(BLOCK);
358         return;
359     }
360
361     if (isHTMLRTElement(element)) {
362         // Ruby text does not support float or position. This might change with evolution of the specification.
363         style->setPosition(StaticPosition);
364         style->setFloating(NoFloat);
365         return;
366     }
367
368     if (isHTMLLegendElement(element)) {
369         style->setDisplay(BLOCK);
370         return;
371     }
372
373     if (isHTMLMarqueeElement(element)) {
374         // For now, <marquee> requires an overflow clip to work properly.
375         style->setOverflowX(OHIDDEN);
376         style->setOverflowY(OHIDDEN);
377         return;
378     }
379
380     if (isHTMLTextAreaElement(element)) {
381         // Textarea considers overflow visible as auto.
382         style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX());
383         style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY());
384         return;
385     }
386
387     if (isHTMLPlugInElement(element)) {
388         style->setRequiresAcceleratedCompositingForExternalReasons(toHTMLPlugInElement(element).shouldAccelerate());
389
390         // Plugins should get the standard replaced width/height instead of 'auto'.
391         // Replaced renderers get this for free, and fallback content doesn't count.
392         if (toHTMLPlugInElement(element).usePlaceholderContent()) {
393             if (style->width().isAuto())
394                 style->setWidth(Length(RenderReplaced::defaultWidth, Fixed));
395             if (style->height().isAuto())
396                 style->setHeight(Length(RenderReplaced::defaultHeight, Fixed));
397         }
398
399         return;
400     }
401 }
402
403 void StyleAdjuster::adjustOverflow(RenderStyle* style)
404 {
405     ASSERT(style->overflowX() != OVISIBLE || style->overflowY() != OVISIBLE);
406
407     // If either overflow value is not visible, change to auto.
408     if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) {
409         // FIXME: Once we implement pagination controls, overflow-x should default to hidden
410         // if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it
411         // default to auto so we can at least scroll through the pages.
412         style->setOverflowX(OAUTO);
413     } else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) {
414         style->setOverflowY(OAUTO);
415     }
416
417     // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
418     // FIXME: Eventually table sections will support auto and scroll.
419     if (style->display() == TABLE || style->display() == INLINE_TABLE
420         || style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
421         if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
422             style->setOverflowX(OVISIBLE);
423         if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
424             style->setOverflowY(OVISIBLE);
425     }
426
427     // Menulists should have visible overflow
428     if (style->appearance() == MenulistPart) {
429         style->setOverflowX(OVISIBLE);
430         style->setOverflowY(OVISIBLE);
431     }
432 }
433
434 void StyleAdjuster::adjustStyleForDisplay(RenderStyle* style, RenderStyle* parentStyle)
435 {
436     if (style->display() == BLOCK && !style->isFloating())
437         return;
438
439     // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
440     // clear how that should work.
441     if (style->display() == INLINE && style->styleType() == NOPSEUDO && style->writingMode() != parentStyle->writingMode())
442         style->setDisplay(INLINE_BLOCK);
443
444     // After performing the display mutation, check table rows. We do not honor position: relative table rows or cells.
445     // This has been established for position: relative in CSS2.1 (and caused a crash in containingBlock()
446     // on some sites).
447     if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP
448         || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW)
449         && style->position() == RelativePosition)
450         style->setPosition(StaticPosition);
451
452     // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
453     // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
454     if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP
455         || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP
456         || style->display() == TABLE_CELL)
457         style->setWritingMode(parentStyle->writingMode());
458
459     // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
460     // of block-flow to anything other than TopToBottomWritingMode.
461     // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
462     if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX))
463         style->setWritingMode(TopToBottomWritingMode);
464
465     if (parentStyle->isDisplayFlexibleOrGridBox()) {
466         style->setFloating(NoFloat);
467         style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !m_useQuirksModeStyles));
468     }
469 }
470
471 }