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