Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderBoxModelObject.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7  * Copyright (C) 2010 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "core/rendering/RenderBoxModelObject.h"
28
29 #include "HTMLNames.h"
30 #include "core/frame/Settings.h"
31 #include "core/html/HTMLFrameOwnerElement.h"
32 #include "core/page/scrolling/ScrollingConstraints.h"
33 #include "core/rendering/ImageQualityController.h"
34 #include "core/rendering/RenderBlock.h"
35 #include "core/rendering/RenderFlowThread.h"
36 #include "core/rendering/RenderGeometryMap.h"
37 #include "core/rendering/RenderInline.h"
38 #include "core/rendering/RenderLayer.h"
39 #include "core/rendering/RenderRegion.h"
40 #include "core/rendering/RenderView.h"
41 #include "core/rendering/compositing/CompositedLayerMapping.h"
42 #include "core/rendering/compositing/RenderLayerCompositor.h"
43 #include "core/rendering/style/ShadowList.h"
44 #include "platform/geometry/TransformState.h"
45 #include "platform/graphics/DrawLooperBuilder.h"
46 #include "platform/graphics/GraphicsContextStateSaver.h"
47 #include "platform/graphics/Path.h"
48 #include "wtf/CurrentTime.h"
49
50 using namespace std;
51
52 namespace WebCore {
53
54 using namespace HTMLNames;
55
56 // The HashMap for storing continuation pointers.
57 // An inline can be split with blocks occuring in between the inline content.
58 // When this occurs we need a pointer to the next object. We can basically be
59 // split into a sequence of inlines and blocks. The continuation will either be
60 // an anonymous block (that houses other blocks) or it will be an inline flow.
61 // <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as
62 // its continuation but the <b> will just have an inline as its continuation.
63 typedef HashMap<const RenderBoxModelObject*, RenderBoxModelObject*> ContinuationMap;
64 static ContinuationMap* continuationMap = 0;
65
66 // This HashMap is similar to the continuation map, but connects first-letter
67 // renderers to their remaining text fragments.
68 typedef HashMap<const RenderBoxModelObject*, RenderTextFragment*> FirstLetterRemainingTextMap;
69 static FirstLetterRemainingTextMap* firstLetterRemainingTextMap = 0;
70
71 void RenderBoxModelObject::setSelectionState(SelectionState state)
72 {
73     if (state == SelectionInside && selectionState() != SelectionNone)
74         return;
75
76     if ((state == SelectionStart && selectionState() == SelectionEnd)
77         || (state == SelectionEnd && selectionState() == SelectionStart))
78         RenderObject::setSelectionState(SelectionBoth);
79     else
80         RenderObject::setSelectionState(state);
81
82     // FIXME: We should consider whether it is OK propagating to ancestor RenderInlines.
83     // This is a workaround for http://webkit.org/b/32123
84     // The containing block can be null in case of an orphaned tree.
85     RenderBlock* containingBlock = this->containingBlock();
86     if (containingBlock && !containingBlock->isRenderView())
87         containingBlock->setSelectionState(state);
88 }
89
90 void RenderBoxModelObject::contentChanged(ContentChangeType changeType)
91 {
92     if (!hasLayer())
93         return;
94
95     layer()->contentChanged(changeType);
96 }
97
98 bool RenderBoxModelObject::hasAcceleratedCompositing() const
99 {
100     return view()->compositor()->hasAcceleratedCompositing();
101 }
102
103 InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size)
104 {
105     return ImageQualityController::imageQualityController()->chooseInterpolationQuality(context, this, image, layer, size);
106 }
107
108 RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node)
109     : RenderLayerModelObject(node)
110 {
111 }
112
113 RenderBoxModelObject::~RenderBoxModelObject()
114 {
115     ImageQualityController::remove(this);
116 }
117
118 void RenderBoxModelObject::willBeDestroyed()
119 {
120     // A continuation of this RenderObject should be destroyed at subclasses.
121     ASSERT(!continuation());
122
123     // If this is a first-letter object with a remaining text fragment then the
124     // entry needs to be cleared from the map.
125     if (firstLetterRemainingText())
126         setFirstLetterRemainingText(0);
127
128     RenderLayerModelObject::willBeDestroyed();
129 }
130
131 void RenderBoxModelObject::updateFromStyle()
132 {
133     RenderLayerModelObject::updateFromStyle();
134
135     RenderStyle* styleToUse = style();
136     setHasBoxDecorations(hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow());
137     setInline(styleToUse->isDisplayInlineType());
138     setPositionState(styleToUse->position());
139     setHorizontalWritingMode(styleToUse->isHorizontalWritingMode());
140 }
141
142 static LayoutSize accumulateInFlowPositionOffsets(const RenderObject* child)
143 {
144     if (!child->isAnonymousBlock() || !child->isInFlowPositioned())
145         return LayoutSize();
146     LayoutSize offset;
147     RenderObject* p = toRenderBlock(child)->inlineElementContinuation();
148     while (p && p->isRenderInline()) {
149         if (p->isInFlowPositioned()) {
150             RenderInline* renderInline = toRenderInline(p);
151             offset += renderInline->offsetForInFlowPosition();
152         }
153         p = p->parent();
154     }
155     return offset;
156 }
157
158 bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
159 {
160     Length logicalHeightLength = style()->logicalHeight();
161     if (logicalHeightLength.isAuto())
162         return true;
163
164     // For percentage heights: The percentage is calculated with respect to the height of the generated box's
165     // containing block. If the height of the containing block is not specified explicitly (i.e., it depends
166     // on content height), and this element is not absolutely positioned, the value computes to 'auto'.
167     if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document().inQuirksMode())
168         return false;
169
170     // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
171     // the closest non-anonymous ancestor box is used instead.
172     RenderBlock* cb = containingBlock();
173     while (cb->isAnonymous())
174         cb = cb->containingBlock();
175
176     // Matching RenderBox::percentageLogicalHeightIsResolvableFromBlock() by
177     // ignoring table cell's attribute value, where it says that table cells violate
178     // what the CSS spec says to do with heights. Basically we
179     // don't care if the cell specified a height or not.
180     if (cb->isTableCell())
181         return false;
182
183     if (!cb->style()->logicalHeight().isAuto() || (!cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto()))
184         return false;
185
186     return true;
187 }
188
189 LayoutSize RenderBoxModelObject::relativePositionOffset() const
190 {
191     LayoutSize offset = accumulateInFlowPositionOffsets(this);
192
193     RenderBlock* containingBlock = this->containingBlock();
194
195     // Objects that shrink to avoid floats normally use available line width when computing containing block width.  However
196     // in the case of relative positioning using percentages, we can't do this.  The offset should always be resolved using the
197     // available width of the containing block.  Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly
198     // call availableWidth on our containing block.
199     if (!style()->left().isAuto()) {
200         if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection())
201             offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth()));
202         else
203             offset.expand(valueForLength(style()->left(), containingBlock->availableWidth()), 0);
204     } else if (!style()->right().isAuto()) {
205         offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth()), 0);
206     }
207
208     // If the containing block of a relatively positioned element does not
209     // specify a height, a percentage top or bottom offset should be resolved as
210     // auto. An exception to this is if the containing block has the WinIE quirk
211     // where <html> and <body> assume the size of the viewport. In this case,
212     // calculate the percent offset based on this height.
213     // See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
214     if (!style()->top().isAuto()
215         && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
216             || !style()->top().isPercent()
217             || containingBlock->stretchesToViewport()))
218         offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight()));
219
220     else if (!style()->bottom().isAuto()
221         && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
222             || !style()->bottom().isPercent()
223             || containingBlock->stretchesToViewport()))
224         offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight()));
225
226     return offset;
227 }
228
229 LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const
230 {
231     // If the element is the HTML body element or doesn't have a parent
232     // return 0 and stop this algorithm.
233     if (isBody() || !parent())
234         return LayoutPoint();
235
236     LayoutPoint referencePoint = startPoint;
237     referencePoint.move(parent()->offsetForColumns(referencePoint));
238
239     // If the offsetParent of the element is null, or is the HTML body element,
240     // return the distance between the canvas origin and the left border edge
241     // of the element and stop this algorithm.
242     Element* element = offsetParent();
243     if (!element)
244         return referencePoint;
245
246     if (const RenderBoxModelObject* offsetParent = element->renderBoxModelObject()) {
247         if (offsetParent->isBox() && !offsetParent->isBody())
248             referencePoint.move(-toRenderBox(offsetParent)->borderLeft(), -toRenderBox(offsetParent)->borderTop());
249         if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
250             if (isRelPositioned())
251                 referencePoint.move(relativePositionOffset());
252             else if (isStickyPositioned())
253                 referencePoint.move(stickyPositionOffset());
254
255             RenderObject* current;
256             for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) {
257                 // FIXME: What are we supposed to do inside SVG content?
258                 if (!isOutOfFlowPositioned()) {
259                     if (current->isBox() && !current->isTableRow())
260                         referencePoint.moveBy(toRenderBox(current)->topLeftLocation());
261                     referencePoint.move(current->parent()->offsetForColumns(referencePoint));
262                 }
263             }
264
265             if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned())
266                 referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation());
267         }
268     }
269
270     return referencePoint;
271 }
272
273 void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const
274 {
275     RenderBlock* containingBlock = this->containingBlock();
276
277     LayoutRect containerContentRect = containingBlock->contentBoxRect();
278     LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
279
280     // Sticky positioned element ignore any override logical width on the containing block (as they don't call
281     // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine.
282     LayoutBoxExtent minMargin(minimumValueForLength(style()->marginTop(), maxWidth),
283         minimumValueForLength(style()->marginRight(), maxWidth),
284         minimumValueForLength(style()->marginBottom(), maxWidth),
285         minimumValueForLength(style()->marginLeft(), maxWidth));
286
287     // Compute the container-relative area within which the sticky element is allowed to move.
288     containerContentRect.contract(minMargin);
289     // Map to the view to avoid including page scale factor.
290     constraints.setAbsoluteContainingBlockRect(containingBlock->localToContainerQuad(FloatRect(containerContentRect), view()).boundingBox());
291
292     LayoutRect stickyBoxRect = frameRectForStickyPositioning();
293     LayoutRect flippedStickyBoxRect = stickyBoxRect;
294     containingBlock->flipForWritingMode(flippedStickyBoxRect);
295     LayoutPoint stickyLocation = flippedStickyBoxRect.location();
296
297     // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms.
298     // Map to the view to avoid including page scale factor.
299     FloatRect absContainerFrame = containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), view()).boundingBox();
300
301     if (containingBlock->hasOverflowClip()) {
302         IntSize scrollOffset = containingBlock->layer()->scrollableArea()->adjustedScrollOffset();
303         stickyLocation -= scrollOffset;
304     }
305
306     // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed.
307     FloatRect absoluteStickyBoxRect(absContainerFrame.location() + stickyLocation, flippedStickyBoxRect.size());
308     constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect);
309
310     if (!style()->left().isAuto()) {
311         constraints.setLeftOffset(floatValueForLength(style()->left(), constrainingRect.width()));
312         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
313     }
314
315     if (!style()->right().isAuto()) {
316         constraints.setRightOffset(floatValueForLength(style()->right(), constrainingRect.width()));
317         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
318     }
319
320     if (!style()->top().isAuto()) {
321         constraints.setTopOffset(floatValueForLength(style()->top(), constrainingRect.height()));
322         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
323     }
324
325     if (!style()->bottom().isAuto()) {
326         constraints.setBottomOffset(floatValueForLength(style()->bottom(), constrainingRect.height() ));
327         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
328     }
329 }
330
331 LayoutSize RenderBoxModelObject::stickyPositionOffset() const
332 {
333     FloatRect constrainingRect;
334
335     ASSERT(hasLayer());
336     RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
337     if (enclosingClippingLayer) {
338         RenderBox* enclosingClippingBox = toRenderBox(enclosingClippingLayer->renderer());
339         LayoutRect clipRect = enclosingClippingBox->overflowClipRect(LayoutPoint());
340         clipRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox->paddingTop());
341         clipRect.contract(LayoutSize(enclosingClippingBox->paddingLeft() + enclosingClippingBox->paddingRight(),
342             enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom()));
343         constrainingRect = enclosingClippingBox->localToContainerQuad(FloatRect(clipRect), view()).boundingBox();
344     } else {
345         LayoutRect viewportRect = view()->frameView()->viewportConstrainedVisibleContentRect();
346         constrainingRect = viewportRect;
347     }
348
349     StickyPositionViewportConstraints constraints;
350     computeStickyPositionConstraints(constraints, constrainingRect);
351
352     // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms).
353     return LayoutSize(constraints.computeStickyOffset(constrainingRect));
354 }
355
356 LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const
357 {
358     if (isRelPositioned())
359         return relativePositionOffset();
360
361     if (isStickyPositioned())
362         return stickyPositionOffset();
363
364     return LayoutSize();
365 }
366
367 LayoutUnit RenderBoxModelObject::offsetLeft() const
368 {
369     // Note that RenderInline and RenderBox override this to pass a different
370     // startPoint to adjustedPositionRelativeToOffsetParent.
371     return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x();
372 }
373
374 LayoutUnit RenderBoxModelObject::offsetTop() const
375 {
376     // Note that RenderInline and RenderBox override this to pass a different
377     // startPoint to adjustedPositionRelativeToOffsetParent.
378     return adjustedPositionRelativeToOffsetParent(LayoutPoint()).y();
379 }
380
381 int RenderBoxModelObject::pixelSnappedOffsetWidth() const
382 {
383     return snapSizeToPixel(offsetWidth(), offsetLeft());
384 }
385
386 int RenderBoxModelObject::pixelSnappedOffsetHeight() const
387 {
388     return snapSizeToPixel(offsetHeight(), offsetTop());
389 }
390
391 LayoutUnit RenderBoxModelObject::computedCSSPadding(Length padding) const
392 {
393     LayoutUnit w = 0;
394     if (padding.isPercent())
395         w = containingBlockLogicalWidthForContent();
396     return minimumValueForLength(padding, w);
397 }
398
399 RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight,
400     bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
401 {
402     RoundedRect border = style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge);
403     if (box && (box->nextLineBox() || box->prevLineBox())) {
404         RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge);
405         border.setRadii(segmentBorder.radii());
406     }
407
408     return border;
409 }
410
411 void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const LayoutRect& rect, const RoundedRect& clipRect)
412 {
413     if (clipRect.isRenderable())
414         context->clipRoundedRect(clipRect);
415     else {
416         // We create a rounded rect for each of the corners and clip it, while making sure we clip opposing corners together.
417         if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRight().isEmpty()) {
418             IntRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.maxX() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y());
419             RoundedRect::Radii topCornerRadii;
420             topCornerRadii.setTopLeft(clipRect.radii().topLeft());
421             context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
422
423             IntRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - rect.x(), clipRect.rect().maxY() - rect.y());
424             RoundedRect::Radii bottomCornerRadii;
425             bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight());
426             context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii));
427         }
428
429         if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLeft().isEmpty()) {
430             IntRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().maxX() - rect.x(), rect.maxY() - clipRect.rect().y());
431             RoundedRect::Radii topCornerRadii;
432             topCornerRadii.setTopRight(clipRect.radii().topRight());
433             context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
434
435             IntRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - clipRect.rect().x(), clipRect.rect().maxY() - rect.y());
436             RoundedRect::Radii bottomCornerRadii;
437             bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft());
438             context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii));
439         }
440     }
441 }
442
443 static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRect& rect)
444 {
445     LayoutRect shrunkRect = rect;
446     AffineTransform transform = context->getCTM();
447     shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale())));
448     shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale())));
449     return shrunkRect;
450 }
451
452 LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance) const
453 {
454     // We shrink the rectangle by one pixel on each side to make it fully overlap the anti-aliased background border
455     return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectByOnePixel(context, rect) : rect;
456 }
457
458 RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& borderRect, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
459 {
460     if (bleedAvoidance == BackgroundBleedShrinkBackground) {
461         // We shrink the rectangle by one pixel on each side because the bleed is one pixel maximum.
462         return getBackgroundRoundedRect(shrinkRectByOnePixel(context, borderRect), box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge);
463     }
464     if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
465         return style()->getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge);
466
467     return getBackgroundRoundedRect(borderRect, box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge);
468 }
469
470 static void applyBoxShadowForBackground(GraphicsContext* context, const RenderObject* renderer)
471 {
472     const ShadowList* shadowList = renderer->style()->boxShadow();
473     ASSERT(shadowList);
474     for (size_t i = shadowList->shadows().size(); i--; ) {
475         const ShadowData& boxShadow = shadowList->shadows()[i];
476         if (boxShadow.style() != Normal)
477             continue;
478         FloatSize shadowOffset(boxShadow.x(), boxShadow.y());
479         context->setShadow(shadowOffset, boxShadow.blur(), boxShadow.color(),
480             DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha);
481         return;
482     }
483 }
484
485 void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer* bgLayer, const LayoutRect& rect,
486     BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, CompositeOperator op, RenderObject* backgroundObject)
487 {
488     GraphicsContext* context = paintInfo.context;
489     if (context->paintingDisabled() || rect.isEmpty())
490         return;
491
492     bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true;
493     bool includeRightEdge = box ? box->includeLogicalRightEdge() : true;
494
495     bool hasRoundedBorder = style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge);
496     bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment;
497     bool isBorderFill = bgLayer->clip() == BorderFillBox;
498     bool isRoot = this->isRoot();
499
500     Color bgColor = color;
501     StyleImage* bgImage = bgLayer->image();
502     bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(this, style()->effectiveZoom());
503
504     bool forceBackgroundToWhite = false;
505     if (document().printing()) {
506         if (style()->printColorAdjust() == PrintColorAdjustEconomy)
507             forceBackgroundToWhite = true;
508         if (document().settings() && document().settings()->shouldPrintBackgrounds())
509             forceBackgroundToWhite = false;
510     }
511
512     // When printing backgrounds is disabled or using economy mode,
513     // change existing background colors and images to a solid white background.
514     // If there's no bg color or image, leave it untouched to avoid affecting transparency.
515     // We don't try to avoid loading the background images, because this style flag is only set
516     // when printing, and at that point we've already loaded the background images anyway. (To avoid
517     // loading the background images we'd have to do this check when applying styles rather than
518     // while rendering.)
519     if (forceBackgroundToWhite) {
520         // Note that we can't reuse this variable below because the bgColor might be changed
521         bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.alpha();
522         if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
523             bgColor = Color::white;
524             shouldPaintBackgroundImage = false;
525         }
526     }
527
528     bool colorVisible = bgColor.alpha();
529
530     // Fast path for drawing simple color backgrounds.
531     if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && !bgLayer->next()) {
532         if (!colorVisible)
533             return;
534
535         bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance, box);
536         GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground);
537         if (boxShadowShouldBeAppliedToBackground)
538             applyBoxShadowForBackground(context, this);
539
540         if (hasRoundedBorder && bleedAvoidance != BackgroundBleedClipBackground) {
541             RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge);
542             if (border.isRenderable())
543                 context->fillRoundedRect(border, bgColor);
544             else {
545                 context->save();
546                 clipRoundedInnerRect(context, rect, border);
547                 context->fillRect(border.rect(), bgColor);
548                 context->restore();
549             }
550         } else {
551             context->fillRect(pixelSnappedIntRect(rect), bgColor);
552         }
553
554         return;
555     }
556
557     // BorderFillBox radius clipping is taken care of by BackgroundBleedClipBackground
558     bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedClipBackground);
559     GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadius);
560     if (clipToBorderRadius) {
561         RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge);
562
563         // Clip to the padding or content boxes as necessary.
564         if (bgLayer->clip() == ContentFillBox) {
565             border = style()->getRoundedInnerBorderFor(border.rect(),
566                 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), includeLeftEdge, includeRightEdge);
567         } else if (bgLayer->clip() == PaddingFillBox)
568             border = style()->getRoundedInnerBorderFor(border.rect(), includeLeftEdge, includeRightEdge);
569
570         clipRoundedInnerRect(context, rect, border);
571     }
572
573     int bLeft = includeLeftEdge ? borderLeft() : 0;
574     int bRight = includeRightEdge ? borderRight() : 0;
575     LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : LayoutUnit();
576     LayoutUnit pRight = includeRightEdge ? paddingRight() : LayoutUnit();
577
578     GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithLocalScrolling);
579     LayoutRect scrolledPaintRect = rect;
580     if (clippedWithLocalScrolling) {
581         // Clip to the overflow area.
582         RenderBox* thisBox = toRenderBox(this);
583         context->clip(thisBox->overflowClipRect(rect.location()));
584
585         // Adjust the paint rect to reflect a scrolled content box with borders at the ends.
586         IntSize offset = thisBox->scrolledContentOffset();
587         scrolledPaintRect.move(-offset);
588         scrolledPaintRect.setWidth(bLeft + thisBox->scrollWidth() + bRight);
589         scrolledPaintRect.setHeight(borderTop() + thisBox->scrollHeight() + borderBottom());
590     }
591
592     GraphicsContextStateSaver backgroundClipStateSaver(*context, false);
593     IntRect maskRect;
594
595     switch (bgLayer->clip()) {
596     case PaddingFillBox:
597     case ContentFillBox: {
598         if (clipToBorderRadius)
599             break;
600
601         // Clip to the padding or content boxes as necessary.
602         bool includePadding = bgLayer->clip() == ContentFillBox;
603         LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includePadding ? pLeft : LayoutUnit()),
604             scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop() : LayoutUnit()),
605             scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : LayoutUnit()),
606             scrolledPaintRect.height() - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : LayoutUnit()));
607         backgroundClipStateSaver.save();
608         context->clip(clipRect);
609
610         break;
611     }
612     case TextFillBox: {
613         // First figure out how big the mask has to be.  It should be no bigger than what we need
614         // to actually render, so we should intersect the dirty rect with the border box of the background.
615         maskRect = pixelSnappedIntRect(rect);
616         maskRect.intersect(paintInfo.rect);
617
618         // We draw the background into a separate layer, to be later masked with yet another layer
619         // holding the text content.
620         backgroundClipStateSaver.save();
621         context->clip(maskRect);
622         context->beginTransparencyLayer(1);
623
624         break;
625     }
626     case BorderFillBox:
627         break;
628     default:
629         ASSERT_NOT_REACHED();
630         break;
631     }
632
633     // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
634     // no background in the child document should show the parent's background.
635     bool isOpaqueRoot = false;
636     if (isRoot) {
637         isOpaqueRoot = true;
638         if (!bgLayer->next() && bgColor.hasAlpha() && view()->frameView()) {
639             Element* ownerElement = document().ownerElement();
640             if (ownerElement) {
641                 if (!isHTMLFrameElement(*ownerElement)) {
642                     // Locate the <body> element using the DOM.  This is easier than trying
643                     // to crawl around a render tree with potential :before/:after content and
644                     // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
645                     // render object very easily via the DOM.
646                     HTMLElement* body = document().body();
647                     if (body) {
648                         // Can't scroll a frameset document anyway.
649                         isOpaqueRoot = body->hasLocalName(framesetTag);
650                     } else {
651                         // SVG documents and XML documents with SVG root nodes are transparent.
652                         isOpaqueRoot = !document().hasSVGRootNode();
653                     }
654                 }
655             } else
656                 isOpaqueRoot = !view()->frameView()->isTransparent();
657         }
658         view()->frameView()->setContentIsOpaque(isOpaqueRoot);
659     }
660
661     // Paint the color first underneath all images, culled if background image occludes it.
662     // FIXME: In the bgLayer->hasFiniteBounds() case, we could improve the culling test
663     // by verifying whether the background image covers the entire layout rect.
664     if (!bgLayer->next()) {
665         IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect));
666         bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance, box);
667         if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer->hasOpaqueImage(this) || !bgLayer->hasRepeatXY() || (isOpaqueRoot && !toRenderBox(this)->height()))  {
668             if (!boxShadowShouldBeAppliedToBackground)
669                 backgroundRect.intersect(paintInfo.rect);
670
671             GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground);
672             if (boxShadowShouldBeAppliedToBackground)
673                 applyBoxShadowForBackground(context, this);
674
675             if (isOpaqueRoot) {
676                 // If we have an alpha and we are painting the root element, go ahead and blend with the base background color.
677                 Color baseColor = view()->frameView()->baseBackgroundColor();
678                 bool shouldClearDocumentBackground = document().settings() && document().settings()->shouldClearDocumentBackground();
679                 CompositeOperator operation = shouldClearDocumentBackground ? CompositeCopy : context->compositeOperation();
680
681                 if (baseColor.alpha()) {
682                     if (bgColor.alpha())
683                         baseColor = baseColor.blend(bgColor);
684                     context->fillRect(backgroundRect, baseColor, operation);
685                 } else if (bgColor.alpha()) {
686                     context->fillRect(backgroundRect, bgColor, operation);
687                 } else if (shouldClearDocumentBackground) {
688                     context->clearRect(backgroundRect);
689                 }
690             } else if (bgColor.alpha()) {
691                 context->fillRect(backgroundRect, bgColor, context->compositeOperation());
692             }
693         }
694     }
695
696     // no progressive loading of the background image
697     if (shouldPaintBackgroundImage) {
698         BackgroundImageGeometry geometry;
699         calculateBackgroundImageGeometry(bgLayer, scrolledPaintRect, geometry, backgroundObject);
700         geometry.clip(paintInfo.rect);
701         if (!geometry.destRect().isEmpty()) {
702             CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
703             RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
704             RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geometry.tileSize());
705             InterpolationQuality interpolationQuality = chooseInterpolationQuality(context, image.get(), bgLayer, geometry.tileSize());
706             if (bgLayer->maskSourceType() == MaskLuminance)
707                 context->setColorFilter(ColorFilterLuminanceToAlpha);
708             InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality();
709             context->setImageInterpolationQuality(interpolationQuality);
710             context->drawTiledImage(image.get(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(),
711                 compositeOp, bgLayer->blendMode(), geometry.spaceSize());
712             context->setImageInterpolationQuality(previousInterpolationQuality);
713         }
714     }
715
716     if (bgLayer->clip() == TextFillBox) {
717         // Create the text mask layer.
718         context->setCompositeOperation(CompositeDestinationIn);
719         context->beginTransparencyLayer(1);
720
721         // FIXME: Workaround for https://code.google.com/p/skia/issues/detail?id=1291.
722         context->clearRect(maskRect);
723
724         // Now draw the text into the mask. We do this by painting using a special paint phase that signals to
725         // InlineTextBoxes that they should just add their contents to the clip.
726         PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText, 0);
727         context->setCompositeOperation(CompositeSourceOver);
728         if (box) {
729             RootInlineBox& root = box->root();
730             box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom());
731         } else {
732             LayoutSize localOffset = isBox() ? toRenderBox(this)->locationOffset() : LayoutSize();
733             paint(info, scrolledPaintRect.location() - localOffset);
734         }
735
736         context->endLayer();
737         context->endLayer();
738     }
739 }
740
741 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRatio)
742 {
743     return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height());
744 }
745
746 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRatio)
747 {
748     return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width());
749 }
750
751 static inline IntSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const IntSize& size, const FloatSize& intrinsicRatio, int useWidth, int useHeight)
752 {
753     if (intrinsicRatio.isEmpty()) {
754         if (useWidth)
755             return IntSize(useWidth, size.height());
756         return IntSize(size.width(), useHeight);
757     }
758
759     if (useWidth)
760         return IntSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio));
761     return IntSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight);
762 }
763
764 static inline IntSize resolveAgainstIntrinsicRatio(const IntSize& size, const FloatSize& intrinsicRatio)
765 {
766     // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height())
767     // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area.
768
769     int solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio);
770     int solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio);
771     if (solutionWidth <= size.width()) {
772         if (solutionHeight <= size.height()) {
773             // If both solutions fit, choose the one covering the larger area.
774             int areaOne = solutionWidth * size.height();
775             int areaTwo = size.width() * solutionHeight;
776             if (areaOne < areaTwo)
777                 return IntSize(size.width(), solutionHeight);
778             return IntSize(solutionWidth, size.height());
779         }
780
781         // Only the first solution fits.
782         return IntSize(solutionWidth, size.height());
783     }
784
785     // Only the second solution fits, assert that.
786     ASSERT(solutionHeight <= size.height());
787     return IntSize(size.width(), solutionHeight);
788 }
789
790 IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const IntSize& positioningAreaSize, ScaleByEffectiveZoomOrNot shouldScaleOrNot) const
791 {
792     // A generated image without a fixed size, will always return the container size as intrinsic size.
793     if (image->isGeneratedImage() && image->usesImageContainerSize())
794         return IntSize(positioningAreaSize.width(), positioningAreaSize.height());
795
796     Length intrinsicWidth;
797     Length intrinsicHeight;
798     FloatSize intrinsicRatio;
799     image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio);
800
801     // Intrinsic dimensions expressed as percentages must be resolved relative to the dimensions of the rectangle
802     // that establishes the coordinate system for the 'background-position' property.
803
804     // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
805     if (intrinsicWidth.isPercent() && intrinsicHeight.isPercent() && intrinsicRatio.isEmpty()) {
806         // Resolve width/height percentages against positioningAreaSize, only if no intrinsic ratio is provided.
807         int resolvedWidth = static_cast<int>(round(positioningAreaSize.width() * intrinsicWidth.percent() / 100));
808         int resolvedHeight = static_cast<int>(round(positioningAreaSize.height() * intrinsicHeight.percent() / 100));
809         return IntSize(resolvedWidth, resolvedHeight);
810     }
811
812     IntSize resolvedSize(intrinsicWidth.isFixed() ? intrinsicWidth.value() : 0, intrinsicHeight.isFixed() ? intrinsicHeight.value() : 0);
813     IntSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0);
814     if (shouldScaleOrNot == ScaleByEffectiveZoom)
815         resolvedSize.scale(style()->effectiveZoom());
816     resolvedSize.clampToMinimumSize(minimumSize);
817
818     if (!resolvedSize.isEmpty())
819         return resolvedSize;
820
821     // If the image has one of either an intrinsic width or an intrinsic height:
822     // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio.
823     // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that
824     //   establishes the coordinate system for the 'background-position' property.
825     if (resolvedSize.width() > 0 || resolvedSize.height() > 0)
826         return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedSize.width(), resolvedSize.height());
827
828     // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the
829     // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
830     // establishes the coordinate system for the 'background-position' property.
831     if (!intrinsicRatio.isEmpty())
832         return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio);
833
834     // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that
835     // establishes the coordinate system for the 'background-position' property.
836     return positioningAreaSize;
837 }
838
839 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize)
840 {
841     tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tileSize.width().ceil() : tileSize.width().floor());
842     tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? tileSize.height().ceil() : tileSize.height().floor());
843 }
844
845 IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, const IntSize& positioningAreaSize) const
846 {
847     StyleImage* image = fillLayer->image();
848     EFillSizeType type = fillLayer->size().type;
849
850     IntSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, ScaleByEffectiveZoom);
851     imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
852     switch (type) {
853         case SizeLength: {
854             LayoutSize tileSize = positioningAreaSize;
855
856             Length layerWidth = fillLayer->size().size.width();
857             Length layerHeight = fillLayer->size().size.height();
858
859             if (layerWidth.isFixed())
860                 tileSize.setWidth(layerWidth.value());
861             else if (layerWidth.isPercent())
862                 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width()));
863
864             if (layerHeight.isFixed())
865                 tileSize.setHeight(layerHeight.value());
866             else if (layerHeight.isPercent())
867                 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.height()));
868
869             applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize);
870
871             // If one of the values is auto we have to use the appropriate
872             // scale to maintain our aspect ratio.
873             if (layerWidth.isAuto() && !layerHeight.isAuto()) {
874                 if (imageIntrinsicSize.height())
875                     tileSize.setWidth(imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height());
876             } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
877                 if (imageIntrinsicSize.width())
878                     tileSize.setHeight(imageIntrinsicSize.height() * tileSize.width() / imageIntrinsicSize.width());
879             } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
880                 // If both width and height are auto, use the image's intrinsic size.
881                 tileSize = imageIntrinsicSize;
882             }
883
884             tileSize.clampNegativeToZero();
885             return flooredIntSize(tileSize);
886         }
887         case SizeNone: {
888             // If both values are â€˜auto’ then the intrinsic width and/or height of the image should be used, if any.
889             if (!imageIntrinsicSize.isEmpty())
890                 return imageIntrinsicSize;
891
892             // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for â€˜contain’.
893             type = Contain;
894         }
895         case Contain:
896         case Cover: {
897             float horizontalScaleFactor = imageIntrinsicSize.width()
898                 ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSize.width() : 1;
899             float verticalScaleFactor = imageIntrinsicSize.height()
900                 ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicSize.height() : 1;
901             float scaleFactor = type == Contain ? min(horizontalScaleFactor, verticalScaleFactor) : max(horizontalScaleFactor, verticalScaleFactor);
902             return IntSize(max(1l, lround(imageIntrinsicSize.width() * scaleFactor)), max(1l, lround(imageIntrinsicSize.height() * scaleFactor)));
903        }
904     }
905
906     ASSERT_NOT_REACHED();
907     return IntSize();
908 }
909
910 void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatX(int xOffset)
911 {
912     m_destRect.move(max(xOffset, 0), 0);
913     m_phase.setX(-min(xOffset, 0));
914     m_destRect.setWidth(m_tileSize.width() + min(xOffset, 0));
915 }
916 void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatY(int yOffset)
917 {
918     m_destRect.move(0, max(yOffset, 0));
919     m_phase.setY(-min(yOffset, 0));
920     m_destRect.setHeight(m_tileSize.height() + min(yOffset, 0));
921 }
922
923 void RenderBoxModelObject::BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint)
924 {
925     IntPoint alignedPoint = attachmentPoint;
926     m_phase.move(max(alignedPoint.x() - m_destRect.x(), 0), max(alignedPoint.y() - m_destRect.y(), 0));
927 }
928
929 void RenderBoxModelObject::BackgroundImageGeometry::clip(const IntRect& clipRect)
930 {
931     m_destRect.intersect(clipRect);
932 }
933
934 IntPoint RenderBoxModelObject::BackgroundImageGeometry::relativePhase() const
935 {
936     IntPoint phase = m_phase;
937     phase += m_destRect.location() - m_destOrigin;
938     return phase;
939 }
940
941 bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const
942 {
943     if (!isRoot())
944         return false;
945
946     if (view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
947         return false;
948
949     RenderLayer* rootLayer = view()->layer();
950     if (!rootLayer || rootLayer->compositingState() == NotComposited)
951         return false;
952
953     return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground();
954 }
955
956 static inline int getSpace(int areaSize, int tileSize)
957 {
958     int numberOfTiles = areaSize / tileSize;
959     int space = -1;
960
961     if (numberOfTiles > 1)
962         space = lroundf((float)(areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1));
963
964     return space;
965 }
966
967 void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fillLayer, const LayoutRect& paintRect,
968     BackgroundImageGeometry& geometry, RenderObject* backgroundObject)
969 {
970     LayoutUnit left = 0;
971     LayoutUnit top = 0;
972     IntSize positioningAreaSize;
973     IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
974
975     // Determine the background positioning area and set destRect to the background painting area.
976     // destRect will be adjusted later if the background is non-repeating.
977     bool fixedAttachment = fillLayer->attachment() == FixedBackgroundAttachment;
978
979 #if ENABLE(FAST_MOBILE_SCROLLING)
980     if (view()->frameView() && view()->frameView()->shouldAttemptToScrollUsingFastPath()) {
981         // As a side effect of an optimization to blit on scroll, we do not honor the CSS
982         // property "background-attachment: fixed" because it may result in rendering
983         // artifacts. Note, these artifacts only appear if we are blitting on scroll of
984         // a page that has fixed background images.
985         fixedAttachment = false;
986     }
987 #endif
988
989     if (!fixedAttachment) {
990         geometry.setDestRect(snappedPaintRect);
991
992         LayoutUnit right = 0;
993         LayoutUnit bottom = 0;
994         // Scroll and Local.
995         if (fillLayer->origin() != BorderFillBox) {
996             left = borderLeft();
997             right = borderRight();
998             top = borderTop();
999             bottom = borderBottom();
1000             if (fillLayer->origin() == ContentFillBox) {
1001                 left += paddingLeft();
1002                 right += paddingRight();
1003                 top += paddingTop();
1004                 bottom += paddingBottom();
1005             }
1006         }
1007
1008         // The background of the box generated by the root element covers the entire canvas including
1009         // its margins. Since those were added in already, we have to factor them out when computing
1010         // the background positioning area.
1011         if (isRoot()) {
1012             positioningAreaSize = pixelSnappedIntSize(toRenderBox(this)->size() - LayoutSize(left + right, top + bottom), toRenderBox(this)->location());
1013             left += marginLeft();
1014             top += marginTop();
1015         } else
1016             positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutSize(left + right, top + bottom), paintRect.location());
1017     } else {
1018         IntRect viewportRect = pixelSnappedIntRect(viewRect());
1019         if (fixedBackgroundPaintsInLocalCoordinates())
1020             viewportRect.setLocation(IntPoint());
1021         else if (FrameView* frameView = view()->frameView())
1022             viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPosition()));
1023
1024         geometry.setDestRect(pixelSnappedIntRect(viewportRect));
1025         positioningAreaSize = geometry.destRect().size();
1026     }
1027
1028     RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
1029     IntSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize);
1030     fillLayer->image()->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, style()->effectiveZoom());
1031     geometry.setTileSize(fillTileSize);
1032
1033     EFillRepeat backgroundRepeatX = fillLayer->repeatX();
1034     EFillRepeat backgroundRepeatY = fillLayer->repeatY();
1035     int availableWidth = positioningAreaSize.width() - geometry.tileSize().width();
1036     int availableHeight = positioningAreaSize.height() - geometry.tileSize().height();
1037
1038     LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer->xPosition(), availableWidth);
1039     if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fillTileSize.width() > 0) {
1040         long nrTiles = max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width()));
1041
1042         if (fillLayer->size().size.height().isAuto() && backgroundRepeatY != RoundFill) {
1043             fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.width() / (nrTiles * fillTileSize.width()));
1044         }
1045
1046         fillTileSize.setWidth(positioningAreaSize.width() / nrTiles);
1047         geometry.setTileSize(fillTileSize);
1048         geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
1049         geometry.setSpaceSize(IntSize());
1050     }
1051
1052     LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer->yPosition(), availableHeight);
1053     if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fillTileSize.height() > 0) {
1054         long nrTiles = max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height()));
1055
1056         if (fillLayer->size().size.width().isAuto() && backgroundRepeatX != RoundFill) {
1057             fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.height() / (nrTiles * fillTileSize.height()));
1058         }
1059
1060         fillTileSize.setHeight(positioningAreaSize.height() / nrTiles);
1061         geometry.setTileSize(fillTileSize);
1062         geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0);
1063         geometry.setSpaceSize(IntSize());
1064     }
1065
1066     if (backgroundRepeatX == RepeatFill) {
1067         geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
1068         geometry.setSpaceSize(IntSize());
1069     } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
1070         int space = getSpace(positioningAreaSize.width(), geometry.tileSize().width());
1071         int actualWidth = geometry.tileSize().width() + space;
1072
1073         if (space >= 0) {
1074             computedXPosition = roundedMinimumValueForLength(Length(), availableWidth);
1075             geometry.setSpaceSize(IntSize(space, 0));
1076             geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition + left) % actualWidth : 0);
1077         } else {
1078             backgroundRepeatX = NoRepeatFill;
1079         }
1080     }
1081     if (backgroundRepeatX == NoRepeatFill) {
1082         int xOffset = fillLayer->backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
1083         geometry.setNoRepeatX(left + xOffset);
1084         geometry.setSpaceSize(IntSize(0, geometry.spaceSize().height()));
1085     }
1086
1087     if (backgroundRepeatY == RepeatFill) {
1088         geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0);
1089         geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
1090     } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
1091         int space = getSpace(positioningAreaSize.height(), geometry.tileSize().height());
1092         int actualHeight = geometry.tileSize().height() + space;
1093
1094         if (space >= 0) {
1095             computedYPosition = roundedMinimumValueForLength(Length(), availableHeight);
1096             geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space));
1097             geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition + top) % actualHeight : 0);
1098         } else {
1099             backgroundRepeatY = NoRepeatFill;
1100         }
1101     }
1102     if (backgroundRepeatY == NoRepeatFill) {
1103         int yOffset = fillLayer->backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
1104         geometry.setNoRepeatY(top + yOffset);
1105         geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
1106     }
1107
1108     if (fixedAttachment)
1109         geometry.useFixedAttachment(snappedPaintRect.location());
1110
1111     geometry.clip(snappedPaintRect);
1112     geometry.setDestOrigin(geometry.destRect().location());
1113 }
1114
1115 static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent)
1116 {
1117     if (borderSlice.isNumber())
1118         return borderSlice.number() * borderSide;
1119     if (borderSlice.length().isAuto())
1120         return imageSide;
1121     return valueForLength(borderSlice.length(), boxExtent);
1122 }
1123
1124 bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, const LayoutRect& rect, const RenderStyle* style,
1125                                                const NinePieceImage& ninePieceImage, CompositeOperator op)
1126 {
1127     StyleImage* styleImage = ninePieceImage.image();
1128     if (!styleImage)
1129         return false;
1130
1131     if (!styleImage->isLoaded())
1132         return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
1133
1134     if (!styleImage->canRender(this, style->effectiveZoom()))
1135         return false;
1136
1137     // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function
1138     // doesn't have any understanding of the zoom that is in effect on the tile.
1139     LayoutRect rectWithOutsets = rect;
1140     rectWithOutsets.expand(style->imageOutsets(ninePieceImage));
1141     IntRect borderImageRect = pixelSnappedIntRect(rectWithOutsets);
1142
1143     IntSize imageSize = calculateImageIntrinsicDimensions(styleImage, borderImageRect.size(), DoNotScaleByEffectiveZoom);
1144
1145     // If both values are â€˜auto’ then the intrinsic width and/or height of the image should be used, if any.
1146     styleImage->setContainerSizeForRenderer(this, imageSize, style->effectiveZoom());
1147
1148     int imageWidth = imageSize.width();
1149     int imageHeight = imageSize.height();
1150
1151     float imageScaleFactor = styleImage->imageScaleFactor();
1152     int topSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().top(), imageHeight)) * imageScaleFactor;
1153     int rightSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().right(), imageWidth)) * imageScaleFactor;
1154     int bottomSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().bottom(), imageHeight)) * imageScaleFactor;
1155     int leftSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().left(), imageWidth)) * imageScaleFactor;
1156
1157     ENinePieceImageRule hRule = ninePieceImage.horizontalRule();
1158     ENinePieceImageRule vRule = ninePieceImage.verticalRule();
1159
1160     int topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), style->borderTopWidth(), topSlice, borderImageRect.height());
1161     int rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right(), style->borderRightWidth(), rightSlice, borderImageRect.width());
1162     int bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().bottom(), style->borderBottomWidth(), bottomSlice, borderImageRect.height());
1163     int leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width());
1164
1165     // Reduce the widths if they're too large.
1166     // The spec says: Given Lwidth as the width of the border image area, Lheight as its height, and Wside as the border image width
1167     // offset for the side, let f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbottom)). If f < 1, then all W are reduced by
1168     // multiplying them by f.
1169     int borderSideWidth = max(1, leftWidth + rightWidth);
1170     int borderSideHeight = max(1, topWidth + bottomWidth);
1171     float borderSideScaleFactor = min((float)borderImageRect.width() / borderSideWidth, (float)borderImageRect.height() / borderSideHeight);
1172     if (borderSideScaleFactor < 1) {
1173         topWidth *= borderSideScaleFactor;
1174         rightWidth *= borderSideScaleFactor;
1175         bottomWidth *= borderSideScaleFactor;
1176         leftWidth *= borderSideScaleFactor;
1177     }
1178
1179     bool drawLeft = leftSlice > 0 && leftWidth > 0;
1180     bool drawTop = topSlice > 0 && topWidth > 0;
1181     bool drawRight = rightSlice > 0 && rightWidth > 0;
1182     bool drawBottom = bottomSlice > 0 && bottomWidth > 0;
1183     bool drawMiddle = ninePieceImage.fill() && (imageWidth - leftSlice - rightSlice) > 0 && (borderImageRect.width() - leftWidth - rightWidth) > 0
1184                       && (imageHeight - topSlice - bottomSlice) > 0 && (borderImageRect.height() - topWidth - bottomWidth) > 0;
1185
1186     RefPtr<Image> image = styleImage->image(this, imageSize);
1187
1188     float destinationWidth = borderImageRect.width() - leftWidth - rightWidth;
1189     float destinationHeight = borderImageRect.height() - topWidth - bottomWidth;
1190
1191     float sourceWidth = imageWidth - leftSlice - rightSlice;
1192     float sourceHeight = imageHeight - topSlice - bottomSlice;
1193
1194     float leftSideScale = drawLeft ? (float)leftWidth / leftSlice : 1;
1195     float rightSideScale = drawRight ? (float)rightWidth / rightSlice : 1;
1196     float topSideScale = drawTop ? (float)topWidth / topSlice : 1;
1197     float bottomSideScale = drawBottom ? (float)bottomWidth / bottomSlice : 1;
1198
1199     if (drawLeft) {
1200         // Paint the top and bottom left corners.
1201
1202         // The top left corner rect is (tx, ty, leftWidth, topWidth)
1203         // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
1204         if (drawTop)
1205             graphicsContext->drawImage(image.get(), IntRect(borderImageRect.location(), IntSize(leftWidth, topWidth)),
1206                                        LayoutRect(0, 0, leftSlice, topSlice), op);
1207
1208         // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth)
1209         // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
1210         if (drawBottom)
1211             graphicsContext->drawImage(image.get(), IntRect(borderImageRect.x(), borderImageRect.maxY() - bottomWidth, leftWidth, bottomWidth),
1212                                        LayoutRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op);
1213
1214         // Paint the left edge.
1215         // Have to scale and tile into the border rect.
1216         if (sourceHeight > 0)
1217             graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x(), borderImageRect.y() + topWidth, leftWidth, destinationHeight),
1218                                             IntRect(0, topSlice, leftSlice, sourceHeight),
1219                                             FloatSize(leftSideScale, leftSideScale), Image::StretchTile, (Image::TileRule)vRule, op);
1220     }
1221
1222     if (drawRight) {
1223         // Paint the top and bottom right corners
1224         // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, topWidth)
1225         // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
1226         if (drawTop)
1227             graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX() - rightWidth, borderImageRect.y(), rightWidth, topWidth),
1228                                        LayoutRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op);
1229
1230         // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth)
1231         // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice)
1232         if (drawBottom)
1233             graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX() - rightWidth, borderImageRect.maxY() - bottomWidth, rightWidth, bottomWidth),
1234                                        LayoutRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op);
1235
1236         // Paint the right edge.
1237         if (sourceHeight > 0)
1238             graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.maxX() - rightWidth, borderImageRect.y() + topWidth, rightWidth,
1239                                             destinationHeight),
1240                                             IntRect(imageWidth - rightSlice, topSlice, rightSlice, sourceHeight),
1241                                             FloatSize(rightSideScale, rightSideScale),
1242                                             Image::StretchTile, (Image::TileRule)vRule, op);
1243     }
1244
1245     // Paint the top edge.
1246     if (drawTop && sourceWidth > 0)
1247         graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.y(), destinationWidth, topWidth),
1248                                         IntRect(leftSlice, 0, sourceWidth, topSlice),
1249                                         FloatSize(topSideScale, topSideScale), (Image::TileRule)hRule, Image::StretchTile, op);
1250
1251     // Paint the bottom edge.
1252     if (drawBottom && sourceWidth > 0)
1253         graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.maxY() - bottomWidth,
1254                                         destinationWidth, bottomWidth),
1255                                         IntRect(leftSlice, imageHeight - bottomSlice, sourceWidth, bottomSlice),
1256                                         FloatSize(bottomSideScale, bottomSideScale),
1257                                         (Image::TileRule)hRule, Image::StretchTile, op);
1258
1259     // Paint the middle.
1260     if (drawMiddle) {
1261         FloatSize middleScaleFactor(1, 1);
1262         if (drawTop)
1263             middleScaleFactor.setWidth(topSideScale);
1264         else if (drawBottom)
1265             middleScaleFactor.setWidth(bottomSideScale);
1266         if (drawLeft)
1267             middleScaleFactor.setHeight(leftSideScale);
1268         else if (drawRight)
1269             middleScaleFactor.setHeight(rightSideScale);
1270
1271         // For "stretch" rules, just override the scale factor and replace. We only had to do this for the
1272         // center tile, since sides don't even use the scale factor unless they have a rule other than "stretch".
1273         // The middle however can have "stretch" specified in one axis but not the other, so we have to
1274         // correct the scale here.
1275         if (hRule == StretchImageRule)
1276             middleScaleFactor.setWidth(destinationWidth / sourceWidth);
1277
1278         if (vRule == StretchImageRule)
1279             middleScaleFactor.setHeight(destinationHeight / sourceHeight);
1280
1281         graphicsContext->drawTiledImage(image.get(),
1282             IntRect(borderImageRect.x() + leftWidth, borderImageRect.y() + topWidth, destinationWidth, destinationHeight),
1283             IntRect(leftSlice, topSlice, sourceWidth, sourceHeight),
1284             middleScaleFactor, (Image::TileRule)hRule, (Image::TileRule)vRule, op);
1285     }
1286
1287     return true;
1288 }
1289
1290 class BorderEdge {
1291 public:
1292     BorderEdge(int edgeWidth, const Color& edgeColor, EBorderStyle edgeStyle, bool edgeIsTransparent, bool edgeIsPresent = true)
1293         : width(edgeWidth)
1294         , color(edgeColor)
1295         , style(edgeStyle)
1296         , isTransparent(edgeIsTransparent)
1297         , isPresent(edgeIsPresent)
1298     {
1299         if (style == DOUBLE && edgeWidth < 3)
1300             style = SOLID;
1301     }
1302
1303     BorderEdge()
1304         : width(0)
1305         , style(BHIDDEN)
1306         , isTransparent(false)
1307         , isPresent(false)
1308     {
1309     }
1310
1311     bool hasVisibleColorAndStyle() const { return style > BHIDDEN && !isTransparent; }
1312     bool shouldRender() const { return isPresent && width && hasVisibleColorAndStyle(); }
1313     bool presentButInvisible() const { return usedWidth() && !hasVisibleColorAndStyle(); }
1314     bool obscuresBackgroundEdge(float scale) const
1315     {
1316         if (!isPresent || isTransparent || (width * scale) < 2 || color.hasAlpha() || style == BHIDDEN)
1317             return false;
1318
1319         if (style == DOTTED || style == DASHED)
1320             return false;
1321
1322         if (style == DOUBLE)
1323             return width >= 5 * scale; // The outer band needs to be >= 2px wide at unit scale.
1324
1325         return true;
1326     }
1327     bool obscuresBackground() const
1328     {
1329         if (!isPresent || isTransparent || color.hasAlpha() || style == BHIDDEN)
1330             return false;
1331
1332         if (style == DOTTED || style == DASHED || style == DOUBLE)
1333             return false;
1334
1335         return true;
1336     }
1337
1338     int usedWidth() const { return isPresent ? width : 0; }
1339
1340     void getDoubleBorderStripeWidths(int& outerWidth, int& innerWidth) const
1341     {
1342         int fullWidth = usedWidth();
1343         outerWidth = fullWidth / 3;
1344         innerWidth = fullWidth * 2 / 3;
1345
1346         // We need certain integer rounding results
1347         if (fullWidth % 3 == 2)
1348             outerWidth += 1;
1349
1350         if (fullWidth % 3 == 1)
1351             innerWidth += 1;
1352     }
1353
1354     int width;
1355     Color color;
1356     EBorderStyle style;
1357     bool isTransparent;
1358     bool isPresent;
1359 };
1360
1361 static bool allCornersClippedOut(const RoundedRect& border, const LayoutRect& clipRect)
1362 {
1363     LayoutRect boundingRect = border.rect();
1364     if (clipRect.contains(boundingRect))
1365         return false;
1366
1367     RoundedRect::Radii radii = border.radii();
1368
1369     LayoutRect topLeftRect(boundingRect.location(), radii.topLeft());
1370     if (clipRect.intersects(topLeftRect))
1371         return false;
1372
1373     LayoutRect topRightRect(boundingRect.location(), radii.topRight());
1374     topRightRect.setX(boundingRect.maxX() - topRightRect.width());
1375     if (clipRect.intersects(topRightRect))
1376         return false;
1377
1378     LayoutRect bottomLeftRect(boundingRect.location(), radii.bottomLeft());
1379     bottomLeftRect.setY(boundingRect.maxY() - bottomLeftRect.height());
1380     if (clipRect.intersects(bottomLeftRect))
1381         return false;
1382
1383     LayoutRect bottomRightRect(boundingRect.location(), radii.bottomRight());
1384     bottomRightRect.setX(boundingRect.maxX() - bottomRightRect.width());
1385     bottomRightRect.setY(boundingRect.maxY() - bottomRightRect.height());
1386     if (clipRect.intersects(bottomRightRect))
1387         return false;
1388
1389     return true;
1390 }
1391
1392 static bool borderWillArcInnerEdge(const LayoutSize& firstRadius, const FloatSize& secondRadius)
1393 {
1394     return !firstRadius.isZero() || !secondRadius.isZero();
1395 }
1396
1397 enum BorderEdgeFlag {
1398     TopBorderEdge = 1 << BSTop,
1399     RightBorderEdge = 1 << BSRight,
1400     BottomBorderEdge = 1 << BSBottom,
1401     LeftBorderEdge = 1 << BSLeft,
1402     AllBorderEdges = TopBorderEdge | BottomBorderEdge | LeftBorderEdge | RightBorderEdge
1403 };
1404
1405 static inline BorderEdgeFlag edgeFlagForSide(BoxSide side)
1406 {
1407     return static_cast<BorderEdgeFlag>(1 << side);
1408 }
1409
1410 static inline bool includesEdge(BorderEdgeFlags flags, BoxSide side)
1411 {
1412     return flags & edgeFlagForSide(side);
1413 }
1414
1415 static inline bool includesAdjacentEdges(BorderEdgeFlags flags)
1416 {
1417     return (flags & (TopBorderEdge | RightBorderEdge)) == (TopBorderEdge | RightBorderEdge)
1418         || (flags & (RightBorderEdge | BottomBorderEdge)) == (RightBorderEdge | BottomBorderEdge)
1419         || (flags & (BottomBorderEdge | LeftBorderEdge)) == (BottomBorderEdge | LeftBorderEdge)
1420         || (flags & (LeftBorderEdge | TopBorderEdge)) == (LeftBorderEdge | TopBorderEdge);
1421 }
1422
1423 inline bool edgesShareColor(const BorderEdge& firstEdge, const BorderEdge& secondEdge)
1424 {
1425     return firstEdge.color == secondEdge.color;
1426 }
1427
1428 inline bool styleRequiresClipPolygon(EBorderStyle style)
1429 {
1430     return style == DOTTED || style == DASHED; // These are drawn with a stroke, so we have to clip to get corner miters.
1431 }
1432
1433 static bool borderStyleFillsBorderArea(EBorderStyle style)
1434 {
1435     return !(style == DOTTED || style == DASHED || style == DOUBLE);
1436 }
1437
1438 static bool borderStyleHasInnerDetail(EBorderStyle style)
1439 {
1440     return style == GROOVE || style == RIDGE || style == DOUBLE;
1441 }
1442
1443 static bool borderStyleIsDottedOrDashed(EBorderStyle style)
1444 {
1445     return style == DOTTED || style == DASHED;
1446 }
1447
1448 // OUTSET darkens the bottom and right (and maybe lightens the top and left)
1449 // INSET darkens the top and left (and maybe lightens the bottom and right)
1450 static inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, BoxSide side, BoxSide adjacentSide)
1451 {
1452     // These styles match at the top/left and bottom/right.
1453     if (style == INSET || style == GROOVE || style == RIDGE || style == OUTSET) {
1454         const BorderEdgeFlags topRightFlags = edgeFlagForSide(BSTop) | edgeFlagForSide(BSRight);
1455         const BorderEdgeFlags bottomLeftFlags = edgeFlagForSide(BSBottom) | edgeFlagForSide(BSLeft);
1456
1457         BorderEdgeFlags flags = edgeFlagForSide(side) | edgeFlagForSide(adjacentSide);
1458         return flags == topRightFlags || flags == bottomLeftFlags;
1459     }
1460     return false;
1461 }
1462
1463 static inline bool colorsMatchAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1464 {
1465     if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1466         return false;
1467
1468     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1469         return false;
1470
1471     return !borderStyleHasUnmatchedColorsAtCorner(edges[side].style, side, adjacentSide);
1472 }
1473
1474
1475 static inline bool colorNeedsAntiAliasAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1476 {
1477     if (!edges[side].color.hasAlpha())
1478         return false;
1479
1480     if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1481         return false;
1482
1483     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1484         return true;
1485
1486     return borderStyleHasUnmatchedColorsAtCorner(edges[side].style, side, adjacentSide);
1487 }
1488
1489 // This assumes that we draw in order: top, bottom, left, right.
1490 static inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1491 {
1492     switch (side) {
1493     case BSTop:
1494     case BSBottom:
1495         if (edges[adjacentSide].presentButInvisible())
1496             return false;
1497
1498         if (!edgesShareColor(edges[side], edges[adjacentSide]) && edges[adjacentSide].color.hasAlpha())
1499             return false;
1500
1501         if (!borderStyleFillsBorderArea(edges[adjacentSide].style))
1502             return false;
1503
1504         return true;
1505
1506     case BSLeft:
1507     case BSRight:
1508         // These draw last, so are never overdrawn.
1509         return false;
1510     }
1511     return false;
1512 }
1513
1514 static inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle)
1515 {
1516     if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE || adjacentStyle == RIDGE)
1517         return true;
1518
1519     if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjacentStyle))
1520         return true;
1521
1522     if (style != adjacentStyle)
1523         return true;
1524
1525     return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide);
1526 }
1527
1528 static bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[], bool allowOverdraw)
1529 {
1530     if ((edges[side].isTransparent && edges[adjacentSide].isTransparent) || !edges[adjacentSide].isPresent)
1531         return false;
1532
1533     if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges))
1534         return false;
1535
1536     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1537         return true;
1538
1539     if (borderStylesRequireMitre(side, adjacentSide, edges[side].style, edges[adjacentSide].style))
1540         return true;
1541
1542     return false;
1543 }
1544
1545 void RenderBoxModelObject::paintOneBorderSide(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1546     const IntRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge edges[], const Path* path,
1547     BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor)
1548 {
1549     const BorderEdge& edgeToRender = edges[side];
1550     ASSERT(edgeToRender.width);
1551     const BorderEdge& adjacentEdge1 = edges[adjacentSide1];
1552     const BorderEdge& adjacentEdge2 = edges[adjacentSide2];
1553
1554     bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !antialias);
1555     bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !antialias);
1556
1557     bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edges);
1558     bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edges);
1559
1560     const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.color;
1561
1562     if (path) {
1563         GraphicsContextStateSaver stateSaver(*graphicsContext);
1564         if (innerBorder.isRenderable())
1565             clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, adjacentSide1StylesMatch, adjacentSide2StylesMatch);
1566         else
1567             clipBorderSideForComplexInnerPath(graphicsContext, outerBorder, innerBorder, side, edges);
1568         float thickness = max(max(edgeToRender.width, adjacentEdge1.width), adjacentEdge2.width);
1569         drawBoxSideFromPath(graphicsContext, outerBorder.rect(), *path, edges, edgeToRender.width, thickness, side, style,
1570             colorToPaint, edgeToRender.style, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
1571     } else {
1572         bool clipForStyle = styleRequiresClipPolygon(edgeToRender.style) && (mitreAdjacentSide1 || mitreAdjacentSide2);
1573         bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1, edges) && mitreAdjacentSide1;
1574         bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2, edges) && mitreAdjacentSide2;
1575         bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2;
1576
1577         GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip);
1578         if (shouldClip) {
1579             bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitreAdjacentSide1);
1580             bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitreAdjacentSide2);
1581             clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, !aliasAdjacentSide1, !aliasAdjacentSide2);
1582             // Since we clipped, no need to draw with a mitre.
1583             mitreAdjacentSide1 = false;
1584             mitreAdjacentSide2 = false;
1585         }
1586
1587         drawLineForBoxSide(graphicsContext, sideRect.x(), sideRect.y(), sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.style,
1588                 mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? adjacentEdge2.width : 0, antialias);
1589     }
1590 }
1591
1592 static IntRect calculateSideRect(const RoundedRect& outerBorder, const BorderEdge edges[], int side)
1593 {
1594     IntRect sideRect = outerBorder.rect();
1595     int width = edges[side].width;
1596
1597     if (side == BSTop)
1598         sideRect.setHeight(width);
1599     else if (side == BSBottom)
1600         sideRect.shiftYEdgeTo(sideRect.maxY() - width);
1601     else if (side == BSLeft)
1602         sideRect.setWidth(width);
1603     else
1604         sideRect.shiftXEdgeTo(sideRect.maxX() - width);
1605
1606     return sideRect;
1607 }
1608
1609 void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1610     const IntPoint& innerBorderAdjustment, const BorderEdge edges[], BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance,
1611     bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor)
1612 {
1613     bool renderRadii = outerBorder.isRounded();
1614
1615     Path roundedPath;
1616     if (renderRadii)
1617         roundedPath.addRoundedRect(outerBorder);
1618
1619     // The inner border adjustment for bleed avoidance mode BackgroundBleedBackgroundOverBorder
1620     // is only applied to sideRect, which is okay since BackgroundBleedBackgroundOverBorder
1621     // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath
1622     // only depends on sideRect when painting solid borders.
1623
1624     if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) {
1625         IntRect sideRect = outerBorder.rect();
1626         sideRect.setHeight(edges[BSTop].width + innerBorderAdjustment.y());
1627
1628         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].style) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorder.radii().topRight()));
1629         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1630     }
1631
1632     if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) {
1633         IntRect sideRect = outerBorder.rect();
1634         sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width - innerBorderAdjustment.y());
1635
1636         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().bottomRight()));
1637         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1638     }
1639
1640     if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) {
1641         IntRect sideRect = outerBorder.rect();
1642         sideRect.setWidth(edges[BSLeft].width + innerBorderAdjustment.x());
1643
1644         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().topLeft()));
1645         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1646     }
1647
1648     if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) {
1649         IntRect sideRect = outerBorder.rect();
1650         sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width - innerBorderAdjustment.x());
1651
1652         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight].style) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), innerBorder.radii().topRight()));
1653         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1654     }
1655 }
1656
1657 void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntPoint& innerBorderAdjustment,
1658     const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias)
1659 {
1660     // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
1661     // This is different from BoxSide enum order.
1662     static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
1663
1664     while (edgesToDraw) {
1665         // Find undrawn edges sharing a color.
1666         Color commonColor;
1667
1668         BorderEdgeFlags commonColorEdgeSet = 0;
1669         for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
1670             BoxSide currSide = paintOrder[i];
1671             if (!includesEdge(edgesToDraw, currSide))
1672                 continue;
1673
1674             bool includeEdge;
1675             if (!commonColorEdgeSet) {
1676                 commonColor = edges[currSide].color;
1677                 includeEdge = true;
1678             } else
1679                 includeEdge = edges[currSide].color == commonColor;
1680
1681             if (includeEdge)
1682                 commonColorEdgeSet |= edgeFlagForSide(currSide);
1683         }
1684
1685         bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) && commonColor.hasAlpha();
1686         if (useTransparencyLayer) {
1687             graphicsContext->beginTransparencyLayer(static_cast<float>(commonColor.alpha()) / 255);
1688             commonColor = Color(commonColor.red(), commonColor.green(), commonColor.blue());
1689         }
1690
1691         paintBorderSides(graphicsContext, style, outerBorder, innerBorder, innerBorderAdjustment, edges, commonColorEdgeSet, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, &commonColor);
1692
1693         if (useTransparencyLayer)
1694             graphicsContext->endLayer();
1695
1696         edgesToDraw &= ~commonColorEdgeSet;
1697     }
1698 }
1699
1700 void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& rect, const RenderStyle* style,
1701                                        BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1702 {
1703     GraphicsContext* graphicsContext = info.context;
1704     // border-image is not affected by border-radius.
1705     if (paintNinePieceImage(graphicsContext, rect, style, style->borderImage()))
1706         return;
1707
1708     if (graphicsContext->paintingDisabled())
1709         return;
1710
1711     BorderEdge edges[4];
1712     getBorderEdgeInfo(edges, style, includeLogicalLeftEdge, includeLogicalRightEdge);
1713     RoundedRect outerBorder = style->getRoundedBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge);
1714     RoundedRect innerBorder = style->getRoundedInnerBorderFor(borderInnerRectAdjustedForBleedAvoidance(graphicsContext, rect, bleedAvoidance), includeLogicalLeftEdge, includeLogicalRightEdge);
1715
1716     bool haveAlphaColor = false;
1717     bool haveAllSolidEdges = true;
1718     bool haveAllDoubleEdges = true;
1719     int numEdgesVisible = 4;
1720     bool allEdgesShareColor = true;
1721     bool allEdgesShareWidth = true;
1722     int firstVisibleEdge = -1;
1723     BorderEdgeFlags edgesToDraw = 0;
1724
1725     for (int i = BSTop; i <= BSLeft; ++i) {
1726         const BorderEdge& currEdge = edges[i];
1727
1728         if (edges[i].shouldRender())
1729             edgesToDraw |= edgeFlagForSide(static_cast<BoxSide>(i));
1730
1731         if (currEdge.presentButInvisible()) {
1732             --numEdgesVisible;
1733             allEdgesShareColor = false;
1734             allEdgesShareWidth = false;
1735             continue;
1736         }
1737
1738         if (!currEdge.shouldRender()) {
1739             --numEdgesVisible;
1740             continue;
1741         }
1742
1743         if (firstVisibleEdge == -1) {
1744             firstVisibleEdge = i;
1745         } else {
1746             if (currEdge.color != edges[firstVisibleEdge].color)
1747                 allEdgesShareColor = false;
1748             if (currEdge.width != edges[firstVisibleEdge].width)
1749                 allEdgesShareWidth = false;
1750         }
1751
1752         if (currEdge.color.hasAlpha())
1753             haveAlphaColor = true;
1754
1755         if (currEdge.style != SOLID)
1756             haveAllSolidEdges = false;
1757
1758         if (currEdge.style != DOUBLE)
1759             haveAllDoubleEdges = false;
1760     }
1761
1762     // If no corner intersects the clip region, we can pretend outerBorder is
1763     // rectangular to improve performance.
1764     if (haveAllSolidEdges && outerBorder.isRounded() && allCornersClippedOut(outerBorder, info.rect))
1765         outerBorder.setRadii(RoundedRect::Radii());
1766
1767     // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787
1768     if ((haveAllSolidEdges || haveAllDoubleEdges) && allEdgesShareColor && innerBorder.isRenderable()) {
1769         // Fast path for drawing all solid edges and all unrounded double edges
1770
1771         if (numEdgesVisible == 4 && (outerBorder.isRounded() || haveAlphaColor)
1772             && (haveAllSolidEdges || (!outerBorder.isRounded() && !innerBorder.isRounded()))) {
1773             Path path;
1774
1775             if (outerBorder.isRounded() && allEdgesShareWidth) {
1776
1777                 // Very fast path for single stroked round rect with circular corners
1778
1779                 graphicsContext->fillBetweenRoundedRects(outerBorder, innerBorder, edges[firstVisibleEdge].color);
1780                 return;
1781             }
1782             if (outerBorder.isRounded() && bleedAvoidance != BackgroundBleedClipBackground)
1783                 path.addRoundedRect(outerBorder);
1784             else
1785                 path.addRect(outerBorder.rect());
1786
1787             if (haveAllDoubleEdges) {
1788                 IntRect innerThirdRect = outerBorder.rect();
1789                 IntRect outerThirdRect = outerBorder.rect();
1790                 for (int side = BSTop; side <= BSLeft; ++side) {
1791                     int outerWidth;
1792                     int innerWidth;
1793                     edges[side].getDoubleBorderStripeWidths(outerWidth, innerWidth);
1794
1795                     if (side == BSTop) {
1796                         innerThirdRect.shiftYEdgeTo(innerThirdRect.y() + innerWidth);
1797                         outerThirdRect.shiftYEdgeTo(outerThirdRect.y() + outerWidth);
1798                     } else if (side == BSBottom) {
1799                         innerThirdRect.setHeight(innerThirdRect.height() - innerWidth);
1800                         outerThirdRect.setHeight(outerThirdRect.height() - outerWidth);
1801                     } else if (side == BSLeft) {
1802                         innerThirdRect.shiftXEdgeTo(innerThirdRect.x() + innerWidth);
1803                         outerThirdRect.shiftXEdgeTo(outerThirdRect.x() + outerWidth);
1804                     } else {
1805                         innerThirdRect.setWidth(innerThirdRect.width() - innerWidth);
1806                         outerThirdRect.setWidth(outerThirdRect.width() - outerWidth);
1807                     }
1808                 }
1809
1810                 RoundedRect outerThird = outerBorder;
1811                 RoundedRect innerThird = innerBorder;
1812                 innerThird.setRect(innerThirdRect);
1813                 outerThird.setRect(outerThirdRect);
1814
1815                 if (outerThird.isRounded() && bleedAvoidance != BackgroundBleedClipBackground)
1816                     path.addRoundedRect(outerThird);
1817                 else
1818                     path.addRect(outerThird.rect());
1819
1820                 if (innerThird.isRounded() && bleedAvoidance != BackgroundBleedClipBackground)
1821                     path.addRoundedRect(innerThird);
1822                 else
1823                     path.addRect(innerThird.rect());
1824             }
1825
1826             if (innerBorder.isRounded())
1827                 path.addRoundedRect(innerBorder);
1828             else
1829                 path.addRect(innerBorder.rect());
1830
1831             graphicsContext->setFillRule(RULE_EVENODD);
1832             graphicsContext->setFillColor(edges[firstVisibleEdge].color);
1833             graphicsContext->fillPath(path);
1834             return;
1835         }
1836         // Avoid creating transparent layers
1837         if (haveAllSolidEdges && numEdgesVisible != 4 && !outerBorder.isRounded() && haveAlphaColor) {
1838             Path path;
1839
1840             for (int i = BSTop; i <= BSLeft; ++i) {
1841                 const BorderEdge& currEdge = edges[i];
1842                 if (currEdge.shouldRender()) {
1843                     IntRect sideRect = calculateSideRect(outerBorder, edges, i);
1844                     path.addRect(sideRect);
1845                 }
1846             }
1847
1848             graphicsContext->setFillRule(RULE_NONZERO);
1849             graphicsContext->setFillColor(edges[firstVisibleEdge].color);
1850             graphicsContext->fillPath(path);
1851             return;
1852         }
1853     }
1854
1855     bool clipToOuterBorder = outerBorder.isRounded();
1856     GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder);
1857     if (clipToOuterBorder) {
1858         // Clip to the inner and outer radii rects.
1859         if (bleedAvoidance != BackgroundBleedClipBackground)
1860             graphicsContext->clipRoundedRect(outerBorder);
1861         // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787
1862         // The inside will be clipped out later (in clipBorderSideForComplexInnerPath)
1863         if (innerBorder.isRenderable() && !innerBorder.isEmpty())
1864             graphicsContext->clipOutRoundedRect(innerBorder);
1865     }
1866
1867     // If only one edge visible antialiasing doesn't create seams
1868     bool antialias = shouldAntialiasLines(graphicsContext) || numEdgesVisible == 1;
1869     RoundedRect unadjustedInnerBorder = (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? style->getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge) : innerBorder;
1870     IntPoint innerBorderAdjustment(innerBorder.rect().x() - unadjustedInnerBorder.rect().x(), innerBorder.rect().y() - unadjustedInnerBorder.rect().y());
1871     if (haveAlphaColor)
1872         paintTranslucentBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias);
1873     else
1874         paintBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias);
1875 }
1876
1877 void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const LayoutRect& borderRect, const Path& borderPath, const BorderEdge edges[],
1878     float thickness, float drawThickness, BoxSide side, const RenderStyle* style, Color color, EBorderStyle borderStyle, BackgroundBleedAvoidance bleedAvoidance,
1879     bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1880 {
1881     if (thickness <= 0)
1882         return;
1883
1884     if (borderStyle == DOUBLE && thickness < 3)
1885         borderStyle = SOLID;
1886
1887     switch (borderStyle) {
1888     case BNONE:
1889     case BHIDDEN:
1890         return;
1891     case DOTTED:
1892     case DASHED: {
1893         graphicsContext->setStrokeColor(color);
1894
1895         // The stroke is doubled here because the provided path is the
1896         // outside edge of the border so half the stroke is clipped off.
1897         // The extra multiplier is so that the clipping mask can antialias
1898         // the edges to prevent jaggies.
1899         graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f);
1900         graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke);
1901
1902         // If the number of dashes that fit in the path is odd and non-integral then we
1903         // will have an awkwardly-sized dash at the end of the path. To try to avoid that
1904         // here, we simply make the whitespace dashes ever so slightly bigger.
1905         // FIXME: This could be even better if we tried to manipulate the dash offset
1906         // and possibly the gapLength to get the corners dash-symmetrical.
1907         float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f);
1908         float gapLength = dashLength;
1909         float numberOfDashes = borderPath.length() / dashLength;
1910         // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1911         // FIXME: should do this test per side.
1912         if (numberOfDashes >= 4) {
1913             bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
1914             bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes);
1915             if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
1916                 float numberOfGaps = numberOfDashes / 2;
1917                 gapLength += (dashLength  / numberOfGaps);
1918             }
1919
1920             DashArray lineDash;
1921             lineDash.append(dashLength);
1922             lineDash.append(gapLength);
1923             graphicsContext->setLineDash(lineDash, dashLength);
1924         }
1925
1926         // FIXME: stroking the border path causes issues with tight corners:
1927         // https://bugs.webkit.org/show_bug.cgi?id=58711
1928         // Also, to get the best appearance we should stroke a path between the two borders.
1929         graphicsContext->strokePath(borderPath);
1930         return;
1931     }
1932     case DOUBLE: {
1933         // Get the inner border rects for both the outer border line and the inner border line
1934         int outerBorderTopWidth;
1935         int innerBorderTopWidth;
1936         edges[BSTop].getDoubleBorderStripeWidths(outerBorderTopWidth, innerBorderTopWidth);
1937
1938         int outerBorderRightWidth;
1939         int innerBorderRightWidth;
1940         edges[BSRight].getDoubleBorderStripeWidths(outerBorderRightWidth, innerBorderRightWidth);
1941
1942         int outerBorderBottomWidth;
1943         int innerBorderBottomWidth;
1944         edges[BSBottom].getDoubleBorderStripeWidths(outerBorderBottomWidth, innerBorderBottomWidth);
1945
1946         int outerBorderLeftWidth;
1947         int innerBorderLeftWidth;
1948         edges[BSLeft].getDoubleBorderStripeWidths(outerBorderLeftWidth, innerBorderLeftWidth);
1949
1950         // Draw inner border line
1951         {
1952             GraphicsContextStateSaver stateSaver(*graphicsContext);
1953             RoundedRect innerClip = style->getRoundedInnerBorderFor(borderRect,
1954                 innerBorderTopWidth, innerBorderBottomWidth, innerBorderLeftWidth, innerBorderRightWidth,
1955                 includeLogicalLeftEdge, includeLogicalRightEdge);
1956
1957             graphicsContext->clipRoundedRect(innerClip);
1958             drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
1959         }
1960
1961         // Draw outer border line
1962         {
1963             GraphicsContextStateSaver stateSaver(*graphicsContext);
1964             LayoutRect outerRect = borderRect;
1965             if (bleedAvoidance == BackgroundBleedClipBackground) {
1966                 outerRect.inflate(1);
1967                 ++outerBorderTopWidth;
1968                 ++outerBorderBottomWidth;
1969                 ++outerBorderLeftWidth;
1970                 ++outerBorderRightWidth;
1971             }
1972
1973             RoundedRect outerClip = style->getRoundedInnerBorderFor(outerRect,
1974                 outerBorderTopWidth, outerBorderBottomWidth, outerBorderLeftWidth, outerBorderRightWidth,
1975                 includeLogicalLeftEdge, includeLogicalRightEdge);
1976             graphicsContext->clipOutRoundedRect(outerClip);
1977             drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
1978         }
1979         return;
1980     }
1981     case RIDGE:
1982     case GROOVE:
1983     {
1984         EBorderStyle s1;
1985         EBorderStyle s2;
1986         if (borderStyle == GROOVE) {
1987             s1 = INSET;
1988             s2 = OUTSET;
1989         } else {
1990             s1 = OUTSET;
1991             s2 = INSET;
1992         }
1993
1994         // Paint full border
1995         drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s1, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
1996
1997         // Paint inner only
1998         GraphicsContextStateSaver stateSaver(*graphicsContext);
1999         LayoutUnit topWidth = edges[BSTop].usedWidth() / 2;
2000         LayoutUnit bottomWidth = edges[BSBottom].usedWidth() / 2;
2001         LayoutUnit leftWidth = edges[BSLeft].usedWidth() / 2;
2002         LayoutUnit rightWidth = edges[BSRight].usedWidth() / 2;
2003
2004         RoundedRect clipRect = style->getRoundedInnerBorderFor(borderRect,
2005             topWidth, bottomWidth, leftWidth, rightWidth,
2006             includeLogicalLeftEdge, includeLogicalRightEdge);
2007
2008         graphicsContext->clipRoundedRect(clipRect);
2009         drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
2010         return;
2011     }
2012     case INSET:
2013         if (side == BSTop || side == BSLeft)
2014             color = color.dark();
2015         break;
2016     case OUTSET:
2017         if (side == BSBottom || side == BSRight)
2018             color = color.dark();
2019         break;
2020     default:
2021         break;
2022     }
2023
2024     graphicsContext->setStrokeStyle(NoStroke);
2025     graphicsContext->setFillColor(color);
2026     graphicsContext->drawRect(pixelSnappedIntRect(borderRect));
2027 }
2028
2029 void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
2030                                                  BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches)
2031 {
2032     FloatPoint quad[4];
2033
2034     const LayoutRect& outerRect = outerBorder.rect();
2035     const LayoutRect& innerRect = innerBorder.rect();
2036
2037     FloatPoint centerPoint(innerRect.location().x().toFloat() + innerRect.width().toFloat() / 2, innerRect.location().y().toFloat() + innerRect.height().toFloat() / 2);
2038
2039     // For each side, create a quad that encompasses all parts of that side that may draw,
2040     // including areas inside the innerBorder.
2041     //
2042     //         0----------------3
2043     //       0  \              /  0
2044     //       |\  1----------- 2  /|
2045     //       | 1                1 |
2046     //       | |                | |
2047     //       | |                | |
2048     //       | 2                2 |
2049     //       |/  1------------2  \|
2050     //       3  /              \  3
2051     //         0----------------3
2052     //
2053     switch (side) {
2054     case BSTop:
2055         quad[0] = outerRect.minXMinYCorner();
2056         quad[1] = innerRect.minXMinYCorner();
2057         quad[2] = innerRect.maxXMinYCorner();
2058         quad[3] = outerRect.maxXMinYCorner();
2059
2060         if (!innerBorder.radii().topLeft().isZero()) {
2061             findIntersection(quad[0], quad[1],
2062                 FloatPoint(
2063                     quad[1].x() + innerBorder.radii().topLeft().width(),
2064                     quad[1].y()),
2065                 FloatPoint(
2066                     quad[1].x(),
2067                     quad[1].y() + innerBorder.radii().topLeft().height()),
2068                 quad[1]);
2069         }
2070
2071         if (!innerBorder.radii().topRight().isZero()) {
2072             findIntersection(quad[3], quad[2],
2073                 FloatPoint(
2074                     quad[2].x() - innerBorder.radii().topRight().width(),
2075                     quad[2].y()),
2076                 FloatPoint(
2077                     quad[2].x(),
2078                     quad[2].y() + innerBorder.radii().topRight().height()),
2079                 quad[2]);
2080         }
2081         break;
2082
2083     case BSLeft:
2084         quad[0] = outerRect.minXMinYCorner();
2085         quad[1] = innerRect.minXMinYCorner();
2086         quad[2] = innerRect.minXMaxYCorner();
2087         quad[3] = outerRect.minXMaxYCorner();
2088
2089         if (!innerBorder.radii().topLeft().isZero()) {
2090             findIntersection(quad[0], quad[1],
2091                 FloatPoint(
2092                     quad[1].x() + innerBorder.radii().topLeft().width(),
2093                     quad[1].y()),
2094                 FloatPoint(
2095                     quad[1].x(),
2096                     quad[1].y() + innerBorder.radii().topLeft().height()),
2097                 quad[1]);
2098         }
2099
2100         if (!innerBorder.radii().bottomLeft().isZero()) {
2101             findIntersection(quad[3], quad[2],
2102                 FloatPoint(
2103                     quad[2].x() + innerBorder.radii().bottomLeft().width(),
2104                     quad[2].y()),
2105                 FloatPoint(
2106                     quad[2].x(),
2107                     quad[2].y() - innerBorder.radii().bottomLeft().height()),
2108                 quad[2]);
2109         }
2110         break;
2111
2112     case BSBottom:
2113         quad[0] = outerRect.minXMaxYCorner();
2114         quad[1] = innerRect.minXMaxYCorner();
2115         quad[2] = innerRect.maxXMaxYCorner();
2116         quad[3] = outerRect.maxXMaxYCorner();
2117
2118         if (!innerBorder.radii().bottomLeft().isZero()) {
2119             findIntersection(quad[0], quad[1],
2120                 FloatPoint(
2121                     quad[1].x() + innerBorder.radii().bottomLeft().width(),
2122                     quad[1].y()),
2123                 FloatPoint(
2124                     quad[1].x(),
2125                     quad[1].y() - innerBorder.radii().bottomLeft().height()),
2126                 quad[1]);
2127         }
2128
2129         if (!innerBorder.radii().bottomRight().isZero()) {
2130             findIntersection(quad[3], quad[2],
2131                 FloatPoint(
2132                     quad[2].x() - innerBorder.radii().bottomRight().width(),
2133                     quad[2].y()),
2134                 FloatPoint(
2135                     quad[2].x(),
2136                     quad[2].y() - innerBorder.radii().bottomRight().height()),
2137                 quad[2]);
2138         }
2139         break;
2140
2141     case BSRight:
2142         quad[0] = outerRect.maxXMinYCorner();
2143         quad[1] = innerRect.maxXMinYCorner();
2144         quad[2] = innerRect.maxXMaxYCorner();
2145         quad[3] = outerRect.maxXMaxYCorner();
2146
2147         if (!innerBorder.radii().topRight().isZero()) {
2148             findIntersection(quad[0], quad[1],
2149                 FloatPoint(
2150                     quad[1].x() - innerBorder.radii().topRight().width(),
2151                     quad[1].y()),
2152                 FloatPoint(
2153                     quad[1].x(),
2154                     quad[1].y() + innerBorder.radii().topRight().height()),
2155                 quad[1]);
2156         }
2157
2158         if (!innerBorder.radii().bottomRight().isZero()) {
2159             findIntersection(quad[3], quad[2],
2160                 FloatPoint(
2161                     quad[2].x() - innerBorder.radii().bottomRight().width(),
2162                     quad[2].y()),
2163                 FloatPoint(
2164                     quad[2].x(),
2165                     quad[2].y() - innerBorder.radii().bottomRight().height()),
2166                 quad[2]);
2167         }
2168         break;
2169     }
2170
2171     // If the border matches both of its adjacent sides, don't anti-alias the clip, and
2172     // if neither side matches, anti-alias the clip.
2173     if (firstEdgeMatches == secondEdgeMatches) {
2174         graphicsContext->clipConvexPolygon(4, quad, !firstEdgeMatches);
2175         return;
2176     }
2177
2178     // If antialiasing settings for the first edge and second edge is different,
2179     // they have to be addressed separately. We do this by breaking the quad into
2180     // two parallelograms, made by moving quad[1] and quad[2].
2181     float ax = quad[1].x() - quad[0].x();
2182     float ay = quad[1].y() - quad[0].y();
2183     float bx = quad[2].x() - quad[1].x();
2184     float by = quad[2].y() - quad[1].y();
2185     float cx = quad[3].x() - quad[2].x();
2186     float cy = quad[3].y() - quad[2].y();
2187
2188     const static float kEpsilon = 1e-2f;
2189     float r1, r2;
2190     if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) {
2191         // The quad was actually a triangle.
2192         r1 = r2 = 1.0f;
2193     } else {
2194         // Extend parallelogram a bit to hide calculation error
2195         const static float kExtendFill = 1e-2f;
2196
2197         r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill;
2198         r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill;
2199     }
2200
2201     FloatPoint firstQuad[4];
2202     firstQuad[0] = quad[0];
2203     firstQuad[1] = quad[1];
2204     firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay);
2205     firstQuad[3] = quad[3];
2206     graphicsContext->clipConvexPolygon(4, firstQuad, !firstEdgeMatches);
2207
2208     FloatPoint secondQuad[4];
2209     secondQuad[0] = quad[0];
2210     secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy);
2211     secondQuad[2] = quad[2];
2212     secondQuad[3] = quad[3];
2213     graphicsContext->clipConvexPolygon(4, secondQuad, !secondEdgeMatches);
2214 }
2215
2216 static IntRect calculateSideRectIncludingInner(const RoundedRect& outerBorder, const BorderEdge edges[], BoxSide side)
2217 {
2218     IntRect sideRect = outerBorder.rect();
2219     int width;
2220
2221     switch (side) {
2222     case BSTop:
2223         width = sideRect.height() - edges[BSBottom].width;
2224         sideRect.setHeight(width);
2225         break;
2226     case BSBottom:
2227         width = sideRect.height() - edges[BSTop].width;
2228         sideRect.shiftYEdgeTo(sideRect.maxY() - width);
2229         break;
2230     case BSLeft:
2231         width = sideRect.width() - edges[BSRight].width;
2232         sideRect.setWidth(width);
2233         break;
2234     case BSRight:
2235         width = sideRect.width() - edges[BSLeft].width;
2236         sideRect.shiftXEdgeTo(sideRect.maxX() - width);
2237         break;
2238     }
2239
2240     return sideRect;
2241 }
2242
2243 static RoundedRect calculateAdjustedInnerBorder(const RoundedRect&innerBorder, BoxSide side)
2244 {
2245     // Expand the inner border as necessary to make it a rounded rect (i.e. radii contained within each edge).
2246     // This function relies on the fact we only get radii not contained within each edge if one of the radii
2247     // for an edge is zero, so we can shift the arc towards the zero radius corner.
2248     RoundedRect::Radii newRadii = innerBorder.radii();
2249     IntRect newRect = innerBorder.rect();
2250
2251     float overshoot;
2252     float maxRadii;
2253
2254     switch (side) {
2255     case BSTop:
2256         overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - newRect.width();
2257         if (overshoot > 0) {
2258             ASSERT(!(newRadii.topLeft().width() && newRadii.topRight().width()));
2259             newRect.setWidth(newRect.width() + overshoot);
2260             if (!newRadii.topLeft().width())
2261                 newRect.move(-overshoot, 0);
2262         }
2263         newRadii.setBottomLeft(IntSize(0, 0));
2264         newRadii.setBottomRight(IntSize(0, 0));
2265         maxRadii = max(newRadii.topLeft().height(), newRadii.topRight().height());
2266         if (maxRadii > newRect.height())
2267             newRect.setHeight(maxRadii);
2268         break;
2269
2270     case BSBottom:
2271         overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width() - newRect.width();
2272         if (overshoot > 0) {
2273             ASSERT(!(newRadii.bottomLeft().width() && newRadii.bottomRight().width()));
2274             newRect.setWidth(newRect.width() + overshoot);
2275             if (!newRadii.bottomLeft().width())
2276                 newRect.move(-overshoot, 0);
2277         }
2278         newRadii.setTopLeft(IntSize(0, 0));
2279         newRadii.setTopRight(IntSize(0, 0));
2280         maxRadii = max(newRadii.bottomLeft().height(), newRadii.bottomRight().height());
2281         if (maxRadii > newRect.height()) {
2282             newRect.move(0, newRect.height() - maxRadii);
2283             newRect.setHeight(maxRadii);
2284         }
2285         break;
2286
2287     case BSLeft:
2288         overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height();
2289         if (overshoot > 0) {
2290             ASSERT(!(newRadii.topLeft().height() && newRadii.bottomLeft().height()));
2291             newRect.setHeight(newRect.height() + overshoot);
2292             if (!newRadii.topLeft().height())
2293                 newRect.move(0, -overshoot);
2294         }
2295         newRadii.setTopRight(IntSize(0, 0));
2296         newRadii.setBottomRight(IntSize(0, 0));
2297         maxRadii = max(newRadii.topLeft().width(), newRadii.bottomLeft().width());
2298         if (maxRadii > newRect.width())
2299             newRect.setWidth(maxRadii);
2300         break;
2301
2302     case BSRight:
2303         overshoot = newRadii.topRight().height() + newRadii.bottomRight().height() - newRect.height();
2304         if (overshoot > 0) {
2305             ASSERT(!(newRadii.topRight().height() && newRadii.bottomRight().height()));
2306             newRect.setHeight(newRect.height() + overshoot);
2307             if (!newRadii.topRight().height())
2308                 newRect.move(0, -overshoot);
2309         }
2310         newRadii.setTopLeft(IntSize(0, 0));
2311         newRadii.setBottomLeft(IntSize(0, 0));
2312         maxRadii = max(newRadii.topRight().width(), newRadii.bottomRight().width());
2313         if (maxRadii > newRect.width()) {
2314             newRect.move(newRect.width() - maxRadii, 0);
2315             newRect.setWidth(maxRadii);
2316         }
2317         break;
2318     }
2319
2320     return RoundedRect(newRect, newRadii);
2321 }
2322
2323 void RenderBoxModelObject::clipBorderSideForComplexInnerPath(GraphicsContext* graphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
2324     BoxSide side, const class BorderEdge edges[])
2325 {
2326     graphicsContext->clip(calculateSideRectIncludingInner(outerBorder, edges, side));
2327     RoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(innerBorder, side);
2328     if (!adjustedInnerRect.isEmpty())
2329         graphicsContext->clipOutRoundedRect(adjustedInnerRect);
2330 }
2331
2332 void RenderBoxModelObject::getBorderEdgeInfo(BorderEdge edges[], const RenderStyle* style, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
2333 {
2334     bool horizontal = style->isHorizontalWritingMode();
2335
2336     edges[BSTop] = BorderEdge(style->borderTopWidth(),
2337         resolveColor(style, CSSPropertyBorderTopColor),
2338         style->borderTopStyle(),
2339         style->borderTopIsTransparent(),
2340         horizontal || includeLogicalLeftEdge);
2341
2342     edges[BSRight] = BorderEdge(style->borderRightWidth(),
2343         resolveColor(style, CSSPropertyBorderRightColor),
2344         style->borderRightStyle(),
2345         style->borderRightIsTransparent(),
2346         !horizontal || includeLogicalRightEdge);
2347
2348     edges[BSBottom] = BorderEdge(style->borderBottomWidth(),
2349         resolveColor(style, CSSPropertyBorderBottomColor),
2350         style->borderBottomStyle(),
2351         style->borderBottomIsTransparent(),
2352         horizontal || includeLogicalRightEdge);
2353
2354     edges[BSLeft] = BorderEdge(style->borderLeftWidth(),
2355         resolveColor(style, CSSPropertyBorderLeftColor),
2356         style->borderLeftStyle(),
2357         style->borderLeftIsTransparent(),
2358         !horizontal || includeLogicalLeftEdge);
2359 }
2360
2361 bool RenderBoxModelObject::borderObscuresBackgroundEdge(const FloatSize& contextScale) const
2362 {
2363     BorderEdge edges[4];
2364     getBorderEdgeInfo(edges, style());
2365
2366     for (int i = BSTop; i <= BSLeft; ++i) {
2367         const BorderEdge& currEdge = edges[i];
2368         // FIXME: for vertical text
2369         float axisScale = (i == BSTop || i == BSBottom) ? contextScale.height() : contextScale.width();
2370         if (!currEdge.obscuresBackgroundEdge(axisScale))
2371             return false;
2372     }
2373
2374     return true;
2375 }
2376
2377 bool RenderBoxModelObject::borderObscuresBackground() const
2378 {
2379     if (!style()->hasBorder())
2380         return false;
2381
2382     // Bail if we have any border-image for now. We could look at the image alpha to improve this.
2383     if (style()->borderImage().image())
2384         return false;
2385
2386     BorderEdge edges[4];
2387     getBorderEdgeInfo(edges, style());
2388
2389     for (int i = BSTop; i <= BSLeft; ++i) {
2390         const BorderEdge& currEdge = edges[i];
2391         if (!currEdge.obscuresBackground())
2392             return false;
2393     }
2394
2395     return true;
2396 }
2397
2398 bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const
2399 {
2400     if (bleedAvoidance != BackgroundBleedNone)
2401         return false;
2402
2403     if (style()->hasAppearance())
2404         return false;
2405
2406     const ShadowList* shadowList = style()->boxShadow();
2407     if (!shadowList)
2408         return false;
2409
2410     bool hasOneNormalBoxShadow = false;
2411     size_t shadowCount = shadowList->shadows().size();
2412     for (size_t i = 0; i < shadowCount; ++i) {
2413         const ShadowData& currentShadow = shadowList->shadows()[i];
2414         if (currentShadow.style() != Normal)
2415             continue;
2416
2417         if (hasOneNormalBoxShadow)
2418             return false;
2419         hasOneNormalBoxShadow = true;
2420
2421         if (currentShadow.spread())
2422             return false;
2423     }
2424
2425     if (!hasOneNormalBoxShadow)
2426         return false;
2427
2428     Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
2429     if (backgroundColor.hasAlpha())
2430         return false;
2431
2432     const FillLayer* lastBackgroundLayer = style()->backgroundLayers();
2433     for (const FillLayer* next = lastBackgroundLayer->next(); next; next = lastBackgroundLayer->next())
2434         lastBackgroundLayer = next;
2435
2436     if (lastBackgroundLayer->clip() != BorderFillBox)
2437         return false;
2438
2439     if (lastBackgroundLayer->image() && style()->hasBorderRadius())
2440         return false;
2441
2442     if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*lastBackgroundLayer))
2443         return false;
2444
2445     if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroundAttachment)
2446         return false;
2447
2448     return true;
2449 }
2450
2451 void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRect, const RenderStyle* s, ShadowStyle shadowStyle, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
2452 {
2453     // FIXME: Deal with border-image.  Would be great to use border-image as a mask.
2454     GraphicsContext* context = info.context;
2455     if (context->paintingDisabled() || !s->boxShadow())
2456         return;
2457
2458     RoundedRect border = (shadowStyle == Inset) ? s->getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
2459         : s->getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge);
2460
2461     bool hasBorderRadius = s->hasBorderRadius();
2462     bool isHorizontal = s->isHorizontalWritingMode();
2463     bool hasOpaqueBackground = s->visitedDependentColor(CSSPropertyBackgroundColor).alpha() == 255;
2464
2465     GraphicsContextStateSaver stateSaver(*context, false);
2466
2467     const ShadowList* shadowList = s->boxShadow();
2468     for (size_t i = shadowList->shadows().size(); i--; ) {
2469         const ShadowData& shadow = shadowList->shadows()[i];
2470         if (shadow.style() != shadowStyle)
2471             continue;
2472
2473         FloatSize shadowOffset(shadow.x(), shadow.y());
2474         float shadowBlur = shadow.blur();
2475         float shadowSpread = shadow.spread();
2476
2477         if (shadowOffset.isZero() && !shadowBlur && !shadowSpread)
2478             continue;
2479
2480         const Color& shadowColor = shadow.color();
2481
2482         if (shadow.style() == Normal) {
2483             FloatRect fillRect = border.rect();
2484             fillRect.inflate(shadowSpread);
2485             if (fillRect.isEmpty())
2486                 continue;
2487
2488             FloatRect shadowRect(border.rect());
2489             shadowRect.inflate(shadowBlur + shadowSpread);
2490             shadowRect.move(shadowOffset);
2491
2492             // Save the state and clip, if not already done.
2493             // The clip does not depend on any shadow-specific properties.
2494             if (!stateSaver.saved()) {
2495                 stateSaver.save();
2496                 if (hasBorderRadius) {
2497                     RoundedRect rectToClipOut = border;
2498
2499                     // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time
2500                     // when painting the shadow. On the other hand, it introduces subpixel gaps along the
2501                     // corners. Those are avoided by insetting the clipping path by one pixel.
2502                     if (hasOpaqueBackground)
2503                         rectToClipOut.inflateWithRadii(-1);
2504
2505                     if (!rectToClipOut.isEmpty()) {
2506                         context->clipOutRoundedRect(rectToClipOut);
2507                     }
2508                 } else {
2509                     // This IntRect is correct even with fractional shadows, because it is used for the rectangle
2510                     // of the box itself, which is always pixel-aligned.
2511                     IntRect rectToClipOut = border.rect();
2512
2513                     // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time
2514                     // when painting the shadow. On the other hand, it introduces subpixel gaps along the
2515                     // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path
2516                     // by one pixel.
2517                     if (hasOpaqueBackground) {
2518                         // FIXME: The function to decide on the policy based on the transform should be a named function.
2519                         // FIXME: It's not clear if this check is right. What about integral scale factors?
2520                         AffineTransform transform = context->getCTM();
2521                         if (transform.a() != 1 || (transform.d() != 1 && transform.d() != -1) || transform.b() || transform.c())
2522                             rectToClipOut.inflate(-1);
2523                     }
2524
2525                     if (!rectToClipOut.isEmpty()) {
2526                         context->clipOut(rectToClipOut);
2527                     }
2528                 }
2529             }
2530
2531             // Draw only the shadow.
2532             OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create();
2533             drawLooperBuilder->addShadow(shadowOffset, shadowBlur, shadowColor,
2534                 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha);
2535             context->setDrawLooper(drawLooperBuilder.release());
2536
2537             if (hasBorderRadius) {
2538                 RoundedRect influenceRect(pixelSnappedIntRect(LayoutRect(shadowRect)), border.radii());
2539                 influenceRect.expandRadii(2 * shadowBlur + shadowSpread);
2540                 if (allCornersClippedOut(influenceRect, info.rect))
2541                     context->fillRect(fillRect, Color::black);
2542                 else {
2543                     // TODO: support non-integer shadows - crbug.com/334829
2544                     RoundedRect roundedFillRect = border;
2545                     roundedFillRect.inflate(shadowSpread);
2546
2547                     roundedFillRect.expandRadii(shadowSpread);
2548                     if (!roundedFillRect.isRenderable())
2549                         roundedFillRect.adjustRadii();
2550                     context->fillRoundedRect(roundedFillRect, Color::black);
2551                 }
2552             } else {
2553                 context->fillRect(fillRect, Color::black);
2554             }
2555         } else {
2556             // The inset shadow case.
2557             GraphicsContext::Edges clippedEdges = GraphicsContext::NoEdge;
2558             if (!includeLogicalLeftEdge) {
2559                 if (isHorizontal)
2560                     clippedEdges |= GraphicsContext::LeftEdge;
2561                 else
2562                     clippedEdges |= GraphicsContext::TopEdge;
2563             }
2564             if (!includeLogicalRightEdge) {
2565                 if (isHorizontal)
2566                     clippedEdges |= GraphicsContext::RightEdge;
2567                 else
2568                     clippedEdges |= GraphicsContext::BottomEdge;
2569             }
2570             // TODO: support non-integer shadows - crbug.com/334828
2571             context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowOffset), shadowBlur, shadowSpread, clippedEdges);
2572         }
2573     }
2574 }
2575
2576 LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const
2577 {
2578     return containingBlock()->availableLogicalWidth();
2579 }
2580
2581 RenderBoxModelObject* RenderBoxModelObject::continuation() const
2582 {
2583     if (!continuationMap)
2584         return 0;
2585     return continuationMap->get(this);
2586 }
2587
2588 void RenderBoxModelObject::setContinuation(RenderBoxModelObject* continuation)
2589 {
2590     if (continuation) {
2591         if (!continuationMap)
2592             continuationMap = new ContinuationMap;
2593         continuationMap->set(this, continuation);
2594     } else {
2595         if (continuationMap)
2596             continuationMap->remove(this);
2597     }
2598 }
2599
2600 void RenderBoxModelObject::computeLayerHitTestRects(LayerHitTestRects& rects) const
2601 {
2602     RenderLayerModelObject::computeLayerHitTestRects(rects);
2603
2604     // If there is a continuation then we need to consult it here, since this is
2605     // the root of the tree walk and it wouldn't otherwise get picked up.
2606     // Continuations should always be siblings in the tree, so any others should
2607     // get picked up already by the tree walk.
2608     if (continuation())
2609         continuation()->computeLayerHitTestRects(rects);
2610 }
2611
2612 RenderTextFragment* RenderBoxModelObject::firstLetterRemainingText() const
2613 {
2614     if (!firstLetterRemainingTextMap)
2615         return 0;
2616     return firstLetterRemainingTextMap->get(this);
2617 }
2618
2619 void RenderBoxModelObject::setFirstLetterRemainingText(RenderTextFragment* remainingText)
2620 {
2621     if (remainingText) {
2622         if (!firstLetterRemainingTextMap)
2623             firstLetterRemainingTextMap = new FirstLetterRemainingTextMap;
2624         firstLetterRemainingTextMap->set(this, remainingText);
2625     } else if (firstLetterRemainingTextMap)
2626         firstLetterRemainingTextMap->remove(this);
2627 }
2628
2629 LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset)
2630 {
2631     ASSERT(!firstChild());
2632
2633     // FIXME: This does not take into account either :first-line or :first-letter
2634     // However, as soon as some content is entered, the line boxes will be
2635     // constructed and this kludge is not called any more. So only the caret size
2636     // of an empty :first-line'd block is wrong. I think we can live with that.
2637     RenderStyle* currentStyle = firstLineStyle();
2638     LayoutUnit height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine,  PositionOfInteriorLineBoxes);
2639
2640     enum CaretAlignment { alignLeft, alignRight, alignCenter };
2641
2642     CaretAlignment alignment = alignLeft;
2643
2644     switch (currentStyle->textAlign()) {
2645     case LEFT:
2646     case WEBKIT_LEFT:
2647         break;
2648     case CENTER:
2649     case WEBKIT_CENTER:
2650         alignment = alignCenter;
2651         break;
2652     case RIGHT:
2653     case WEBKIT_RIGHT:
2654         alignment = alignRight;
2655         break;
2656     case JUSTIFY:
2657     case TASTART:
2658         if (!currentStyle->isLeftToRightDirection())
2659             alignment = alignRight;
2660         break;
2661     case TAEND:
2662         if (currentStyle->isLeftToRightDirection())
2663             alignment = alignRight;
2664         break;
2665     }
2666
2667     LayoutUnit x = borderLeft() + paddingLeft();
2668     LayoutUnit maxX = width - borderRight() - paddingRight();
2669
2670     switch (alignment) {
2671     case alignLeft:
2672         if (currentStyle->isLeftToRightDirection())
2673             x += textIndentOffset;
2674         break;
2675     case alignCenter:
2676         x = (x + maxX) / 2;
2677         if (currentStyle->isLeftToRightDirection())
2678             x += textIndentOffset / 2;
2679         else
2680             x -= textIndentOffset / 2;
2681         break;
2682     case alignRight:
2683         x = maxX - caretWidth;
2684         if (!currentStyle->isLeftToRightDirection())
2685             x -= textIndentOffset;
2686         break;
2687     }
2688     x = min(x, max<LayoutUnit>(maxX - caretWidth, 0));
2689
2690     LayoutUnit y = paddingTop() + borderTop();
2691
2692     return currentStyle->isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth, height) : LayoutRect(y, x, height, caretWidth);
2693 }
2694
2695 bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context)
2696 {
2697     // FIXME: We may want to not antialias when scaled by an integral value,
2698     // and we may want to antialias when translated by a non-integral value.
2699     return !context->getCTM().isIdentityOrTranslationOrFlipped();
2700 }
2701
2702 void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
2703 {
2704     // We don't expect to be called during layout.
2705     ASSERT(!view() || !view()->layoutStateEnabled());
2706
2707     RenderObject* o = container();
2708     if (!o)
2709         return;
2710
2711     // The point inside a box that's inside a region has its coordinates relative to the region,
2712     // not the FlowThread that is its container in the RenderObject tree.
2713     if (o->isRenderFlowThread() && isRenderBlock()) {
2714         // FIXME: switch to Box instead of Block when we'll have range information for boxes as well, not just for blocks.
2715         RenderRegion* startRegion;
2716         RenderRegion* ignoredEndRegion;
2717         toRenderFlowThread(o)->getRegionRangeForBox(toRenderBlock(this), startRegion, ignoredEndRegion);
2718         // If there is no region to use the FlowThread, then there's no region range for the content in that FlowThread.
2719         // An API like elementFromPoint might crash without this check.
2720         if (startRegion)
2721             o = startRegion;
2722     }
2723
2724     o->mapAbsoluteToLocalPoint(mode, transformState);
2725
2726     LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
2727
2728     if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
2729         RenderBlock* block = toRenderBlock(o);
2730         LayoutPoint point(roundedLayoutPoint(transformState.mappedPoint()));
2731         point -= containerOffset;
2732         block->adjustForColumnRect(containerOffset, point);
2733     }
2734
2735     bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
2736     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
2737         TransformationMatrix t;
2738         getTransformFromContainer(o, containerOffset, t);
2739         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2740     } else
2741         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2742 }
2743
2744 const RenderObject* RenderBoxModelObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
2745 {
2746     ASSERT(ancestorToStopAt != this);
2747
2748     bool ancestorSkipped;
2749     RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped);
2750     if (!container)
2751         return 0;
2752
2753     bool isInline = isRenderInline();
2754     bool isFixedPos = !isInline && style()->position() == FixedPosition;
2755     bool hasTransform = !isInline && hasLayer() && layer()->transform();
2756
2757     LayoutSize adjustmentForSkippedAncestor;
2758     if (ancestorSkipped) {
2759         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
2760         // to just subtract the delta between the ancestor and o.
2761         adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
2762     }
2763
2764     bool offsetDependsOnPoint = false;
2765     LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
2766
2767     bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
2768     if (shouldUseTransformFromContainer(container)) {
2769         TransformationMatrix t;
2770         getTransformFromContainer(container, containerOffset, t);
2771         t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustmentForSkippedAncestor.height().toFloat());
2772         geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
2773     } else {
2774         containerOffset += adjustmentForSkippedAncestor;
2775         geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
2776     }
2777
2778     return ancestorSkipped ? ancestorToStopAt : container;
2779 }
2780
2781 void RenderBoxModelObject::moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
2782 {
2783     // We assume that callers have cleared their positioned objects list for child moves (!fullRemoveInsert) so the
2784     // positioned renderer maps don't become stale. It would be too slow to do the map lookup on each call.
2785     ASSERT(!fullRemoveInsert || !isRenderBlock() || !toRenderBlock(this)->hasPositionedObjects());
2786
2787     ASSERT(this == child->parent());
2788     ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
2789     if (fullRemoveInsert && (toBoxModelObject->isRenderBlock() || toBoxModelObject->isRenderInline())) {
2790         // Takes care of adding the new child correctly if toBlock and fromBlock
2791         // have different kind of children (block vs inline).
2792         toBoxModelObject->addChild(virtualChildren()->removeChildNode(this, child), beforeChild);
2793     } else
2794         toBoxModelObject->virtualChildren()->insertChildNode(toBoxModelObject, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
2795 }
2796
2797 void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
2798 {
2799     // This condition is rarely hit since this function is usually called on
2800     // anonymous blocks which can no longer carry positioned objects (see r120761)
2801     // or when fullRemoveInsert is false.
2802     if (fullRemoveInsert && isRenderBlock()) {
2803         RenderBlock* block = toRenderBlock(this);
2804         block->removePositionedObjects(0);
2805         if (block->isRenderBlockFlow())
2806             toRenderBlockFlow(block)->removeFloatingObjects();
2807     }
2808
2809     ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
2810     for (RenderObject* child = startChild; child && child != endChild; ) {
2811         // Save our next sibling as moveChildTo will clear it.
2812         RenderObject* nextSibling = child->nextSibling();
2813         moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert);
2814         child = nextSibling;
2815     }
2816 }
2817
2818 } // namespace WebCore