diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp | 296 |
1 files changed, 218 insertions, 78 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp index ced5a7853..c22462509 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBoxModelObject.cpp @@ -173,13 +173,20 @@ void RenderBoxModelObject::updateBoxModelInfoFromStyle() int RenderBoxModelObject::relativePositionOffsetX() const { + // Objects that shrink to avoid floats normally use available line width when computing containing block width. However + // in the case of relative positioning using percentages, we can't do this. The offset should always be resolved using the + // available width of the containing block. Therefore we don't use containingBlockWidthForContent() here, but instead explicitly + // call availableWidth on our containing block. if (!style()->left().isAuto()) { + RenderBlock* cb = containingBlock(); if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL) - return -style()->right().calcValue(containingBlockWidthForContent()); - return style()->left().calcValue(containingBlockWidthForContent()); + return -style()->right().calcValue(cb->availableWidth()); + return style()->left().calcValue(cb->availableWidth()); + } + if (!style()->right().isAuto()) { + RenderBlock* cb = containingBlock(); + return -style()->right().calcValue(cb->availableWidth()); } - if (!style()->right().isAuto()) - return -style()->right().calcValue(containingBlockWidthForContent()); return 0; } @@ -322,6 +329,18 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co clippedToBorderRadius = true; } + bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment; + if (clippedWithLocalScrolling) { + // Clip to the overflow area. + context->save(); + context->clip(toRenderBox(this)->overflowClipRect(tx, ty)); + + // Now adjust our tx, ty, w, h to reflect a scrolled content box with borders at the ends. + layer()->subtractScrolledContentOffset(tx, ty); + w = bLeft + layer()->scrollWidth() + bRight; + h = borderTop() + layer()->scrollHeight() + borderBottom(); + } + if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { // Clip to the padding or content boxes as necessary. bool includePadding = bgLayer->clip() == ContentFillBox; @@ -465,6 +484,9 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (clippedToBorderRadius) // Undo the border radius clip context->restore(); + + if (clippedWithLocalScrolling) // Undo the clip for local background attachments. + context->restore(); } IntSize RenderBoxModelObject::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const @@ -521,9 +543,9 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL int rh = 0; // CSS2 chapter 14.2.1 - - if (bgLayer->attachment()) { - // Scroll + bool fixedAttachment = bgLayer->attachment() == FixedBackgroundAttachment; + if (!fixedAttachment) { + // Scroll and Local if (bgLayer->origin() != BorderFillBox) { left = borderLeft(); right = borderRight(); @@ -553,7 +575,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL pw = w - left - right; ph = h - top - bottom; } else { - // Fixed + // Fixed background attachment. IntRect vr = viewRect(); cx = vr.x(); cy = vr.y(); @@ -567,7 +589,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL int ch; IntSize scaledImageSize; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh); else scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph); @@ -578,7 +600,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL EFillRepeat backgroundRepeat = bgLayer->repeat(); int xPosition; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true); else xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true); @@ -592,7 +614,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL } int yPosition; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true); else yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true); @@ -605,7 +627,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL ch = scaledImageHeight + min(yPosition + top, 0); } - if (!bgLayer->attachment()) { + if (fixedAttachment) { sx += max(tx - cx, 0); sy += max(ty - cy, 0); } @@ -1120,7 +1142,7 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, graphicsContext->restore(); } -void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end) +void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, ShadowStyle shadowStyle, bool begin, bool end) { // FIXME: Deal with border-image. Would be great to use border-image as a mask. @@ -1128,83 +1150,201 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int return; IntRect rect(tx, ty, w, h); + IntSize topLeft; + IntSize topRight; + IntSize bottomLeft; + IntSize bottomRight; + bool hasBorderRadius = s->hasBorderRadius(); + if (hasBorderRadius && (begin || end)) { + IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; + s->getBorderRadiiForRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + if (begin) { + if (shadowStyle == Inset) { + topLeftRadius.expand(-borderLeft(), -borderTop()); + topLeftRadius.clampNegativeToZero(); + bottomLeftRadius.expand(-borderLeft(), -borderBottom()); + bottomLeftRadius.clampNegativeToZero(); + } + topLeft = topLeftRadius; + bottomLeft = bottomLeftRadius; + } + if (end) { + if (shadowStyle == Inset) { + topRightRadius.expand(-borderRight(), -borderTop()); + topRightRadius.clampNegativeToZero(); + bottomRightRadius.expand(-borderRight(), -borderBottom()); + bottomRightRadius.clampNegativeToZero(); + } + topRight = topRightRadius; + bottomRight = bottomRightRadius; + } + } + + if (shadowStyle == Inset) { + rect.move(begin ? borderLeft() : 0, borderTop()); + rect.setWidth(rect.width() - (begin ? borderLeft() : 0) - (end ? borderRight() : 0)); + rect.setHeight(rect.height() - borderTop() - borderBottom()); + } + bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255; for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) { - context->save(); + if (shadow->style != shadowStyle) + continue; IntSize shadowOffset(shadow->x, shadow->y); int shadowBlur = shadow->blur; - IntRect fillRect(rect); - - IntRect shadowRect(rect); - shadowRect.inflate(shadowBlur); - shadowRect.move(shadowOffset); - context->clip(shadowRect); - - // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not - // bleed in (due to antialiasing) if the context is transformed. - IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0); - shadowOffset -= extraOffset; - fillRect.move(extraOffset); - - context->setShadow(shadowOffset, shadowBlur, shadow->color); - if (hasBorderRadius) { - IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; - s->getBorderRadiiForRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); - - IntSize topLeft = begin ? topLeftRadius : IntSize(); - IntSize topRight = end ? topRightRadius : IntSize(); - IntSize bottomLeft = begin ? bottomLeftRadius : IntSize(); - IntSize bottomRight = end ? bottomRightRadius : IntSize(); - - IntRect rectToClipOut = rect; - IntSize topLeftToClipOut = topLeft; - IntSize topRightToClipOut = topRight; - IntSize bottomLeftToClipOut = bottomLeft; - IntSize bottomRightToClipOut = bottomRight; - - // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time - // when painting the shadow. On the other hand, it introduces subpixel gaps along the - // corners. Those are avoided by insetting the clipping path by one pixel. - if (hasOpaqueBackground) { - rectToClipOut.inflate(-1); - - topLeftToClipOut.expand(-1, -1); - topLeftToClipOut.clampNegativeToZero(); - - topRightToClipOut.expand(-1, -1); - topRightToClipOut.clampNegativeToZero(); - - bottomLeftToClipOut.expand(-1, -1); - bottomLeftToClipOut.clampNegativeToZero(); - - bottomRightToClipOut.expand(-1, -1); - bottomRightToClipOut.clampNegativeToZero(); + int shadowSpread = shadow->spread; + Color& shadowColor = shadow->color; + + if (shadow->style == Normal) { + IntRect fillRect(rect); + fillRect.inflate(shadowSpread); + if (fillRect.isEmpty()) + continue; + + IntRect shadowRect(rect); + shadowRect.inflate(shadowBlur + shadowSpread); + shadowRect.move(shadowOffset); + + context->save(); + context->clip(shadowRect); + + // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not + // bleed in (due to antialiasing) if the context is transformed. + IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 2 * shadowSpread + 1, 0); + shadowOffset -= extraOffset; + fillRect.move(extraOffset); + + context->setShadow(shadowOffset, shadowBlur, shadowColor); + if (hasBorderRadius) { + IntRect rectToClipOut = rect; + IntSize topLeftToClipOut = topLeft; + IntSize topRightToClipOut = topRight; + IntSize bottomLeftToClipOut = bottomLeft; + IntSize bottomRightToClipOut = bottomRight; + + if (shadowSpread < 0) { + topLeft.expand(shadowSpread, shadowSpread); + topLeft.clampNegativeToZero(); + + topRight.expand(shadowSpread, shadowSpread); + topRight.clampNegativeToZero(); + + bottomLeft.expand(shadowSpread, shadowSpread); + bottomLeft.clampNegativeToZero(); + + bottomRight.expand(shadowSpread, shadowSpread); + bottomRight.clampNegativeToZero(); + } + + // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time + // when painting the shadow. On the other hand, it introduces subpixel gaps along the + // corners. Those are avoided by insetting the clipping path by one pixel. + if (hasOpaqueBackground) { + rectToClipOut.inflate(-1); + + topLeftToClipOut.expand(-1, -1); + topLeftToClipOut.clampNegativeToZero(); + + topRightToClipOut.expand(-1, -1); + topRightToClipOut.clampNegativeToZero(); + + bottomLeftToClipOut.expand(-1, -1); + bottomLeftToClipOut.clampNegativeToZero(); + + bottomRightToClipOut.expand(-1, -1); + bottomRightToClipOut.clampNegativeToZero(); + } + + if (!rectToClipOut.isEmpty()) + context->clipOutRoundedRect(rectToClipOut, topLeftToClipOut, topRightToClipOut, bottomLeftToClipOut, bottomRightToClipOut); + context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + } else { + IntRect rectToClipOut = rect; + + // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time + // when painting the shadow. On the other hand, it introduces subpixel gaps along the + // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path + // by one pixel. + if (hasOpaqueBackground) { + TransformationMatrix currentTransformation = context->getCTM(); + if (currentTransformation.a() != 1 || (currentTransformation.d() != 1 && currentTransformation.d() != -1) + || currentTransformation.b() || currentTransformation.c()) + rectToClipOut.inflate(-1); + } + + if (!rectToClipOut.isEmpty()) + context->clipOut(rectToClipOut); + context->fillRect(fillRect, Color::black); } - if (!rectToClipOut.isEmpty()) - context->clipOutRoundedRect(rectToClipOut, topLeftToClipOut, topRightToClipOut, bottomLeftToClipOut, bottomRightToClipOut); - context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + context->restore(); } else { - IntRect rectToClipOut = rect; - - // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time - // when painting the shadow. On the other hand, it introduces subpixel gaps along the - // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path - // by one pixel. - if (hasOpaqueBackground) { - TransformationMatrix currentTransformation = context->getCTM(); - if (currentTransformation.a() != 1 || (currentTransformation.d() != 1 && currentTransformation.d() != -1) - || currentTransformation.b() || currentTransformation.c()) - rectToClipOut.inflate(-1); + // Inset shadow. + IntRect holeRect(rect); + holeRect.inflate(-shadowSpread); + + if (holeRect.isEmpty()) { + if (hasBorderRadius) + context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor); + else + context->fillRect(rect, shadowColor); + continue; + } + if (!begin) { + holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0); + holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur); } + if (!end) + holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur); + + Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); - if (!rectToClipOut.isEmpty()) - context->clipOut(rectToClipOut); - context->fillRect(fillRect, Color::black); + IntRect outerRect(rect); + outerRect.inflateX(w - 2 * shadowSpread); + outerRect.inflateY(h - 2 * shadowSpread); + + context->save(); + + if (hasBorderRadius) + context->clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + else + context->clip(rect); + + IntSize extraOffset(2 * w + max(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0); + context->translate(extraOffset.width(), extraOffset.height()); + shadowOffset -= extraOffset; + + context->beginPath(); + context->addPath(Path::createRectangle(outerRect)); + + if (hasBorderRadius) { + if (shadowSpread > 0) { + topLeft.expand(-shadowSpread, -shadowSpread); + topLeft.clampNegativeToZero(); + + topRight.expand(-shadowSpread, -shadowSpread); + topRight.clampNegativeToZero(); + + bottomLeft.expand(-shadowSpread, -shadowSpread); + bottomLeft.clampNegativeToZero(); + + bottomRight.expand(-shadowSpread, -shadowSpread); + bottomRight.clampNegativeToZero(); + } + context->addPath(Path::createRoundedRectangle(holeRect, topLeft, topRight, bottomLeft, bottomRight)); + } else + context->addPath(Path::createRectangle(holeRect)); + + context->setFillRule(RULE_EVENODD); + context->setFillColor(fillColor); + context->setShadow(shadowOffset, shadowBlur, shadowColor); + context->fillPath(); + + context->restore(); } - context->restore(); } } |