| Index: third_party/WebKit/WebCore/rendering/RenderBoxModelObject.cpp | 
| =================================================================== | 
| --- third_party/WebKit/WebCore/rendering/RenderBoxModelObject.cpp	(revision 9391) | 
| +++ third_party/WebKit/WebCore/rendering/RenderBoxModelObject.cpp	(working copy) | 
| @@ -21,12 +21,20 @@ | 
| #include "config.h" | 
| #include "RenderBoxModelObject.h" | 
|  | 
| +#include "GraphicsContext.h" | 
| +#include "HTMLElement.h" | 
| +#include "HTMLNames.h" | 
| +#include "ImageBuffer.h" | 
| #include "RenderBlock.h" | 
| #include "RenderLayer.h" | 
| #include "RenderView.h" | 
|  | 
| +using namespace std; | 
| + | 
| namespace WebCore { | 
|  | 
| +using namespace HTMLNames; | 
| + | 
| bool RenderBoxModelObject::s_wasFloating = false; | 
|  | 
| RenderBoxModelObject::RenderBoxModelObject(Node* node) | 
| @@ -117,4 +125,379 @@ | 
| return 0; | 
| } | 
|  | 
| +int RenderBoxModelObject::offsetLeft() const | 
| +{ | 
| +    RenderBoxModelObject* offsetPar = offsetParent(); | 
| +    if (!offsetPar) | 
| +        return 0; | 
| +    int xPos = (isBox() ? toRenderBox(this)->x() : 0); | 
| +    if (offsetPar->isBox()) | 
| +        xPos -= toRenderBox(offsetPar)->borderLeft(); | 
| +    if (!isPositioned()) { | 
| +        if (isRelPositioned()) | 
| +            xPos += relativePositionOffsetX(); | 
| +        RenderObject* curr = parent(); | 
| +        while (curr && curr != offsetPar) { | 
| +            // FIXME: What are we supposed to do inside SVG content? | 
| +            if (curr->isBox() && !curr->isTableRow()) | 
| +                xPos += toRenderBox(curr)->x(); | 
| +            curr = curr->parent(); | 
| +        } | 
| +        if (offsetPar->isBox() && offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) | 
| +            xPos += toRenderBox(offsetPar)->x(); | 
| +    } | 
| +    return xPos; | 
| +} | 
| + | 
| +int RenderBoxModelObject::offsetTop() const | 
| +{ | 
| +    RenderBoxModelObject* offsetPar = offsetParent(); | 
| +    if (!offsetPar) | 
| +        return 0; | 
| +    int yPos = (isBox() ? toRenderBox(this)->y() : 0); | 
| +    if (offsetPar->isBox()) | 
| +        yPos -= toRenderBox(offsetPar)->borderTop(); | 
| +    if (!isPositioned()) { | 
| +        if (isRelPositioned()) | 
| +            yPos += relativePositionOffsetY(); | 
| +        RenderObject* curr = parent(); | 
| +        while (curr && curr != offsetPar) { | 
| +            // FIXME: What are we supposed to do inside SVG content? | 
| +            if (curr->isBox() && !curr->isTableRow()) | 
| +                yPos += toRenderBox(curr)->y(); | 
| +            curr = curr->parent(); | 
| +        } | 
| +        if (offsetPar->isBox() && offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) | 
| +            yPos += toRenderBox(offsetPar)->y(); | 
| +    } | 
| +    return yPos; | 
| +} | 
| + | 
| +int RenderBoxModelObject::paddingTop(bool) const | 
| +{ | 
| +    int w = 0; | 
| +    Length padding = style()->paddingTop(); | 
| +    if (padding.isPercent()) | 
| +        w = containingBlock()->availableWidth(); | 
| +    return padding.calcMinValue(w); | 
| +} | 
| + | 
| +int RenderBoxModelObject::paddingBottom(bool) const | 
| +{ | 
| +    int w = 0; | 
| +    Length padding = style()->paddingBottom(); | 
| +    if (padding.isPercent()) | 
| +        w = containingBlock()->availableWidth(); | 
| +    return padding.calcMinValue(w); | 
| +} | 
| + | 
| +int RenderBoxModelObject::paddingLeft(bool) const | 
| +{ | 
| +    int w = 0; | 
| +    Length padding = style()->paddingLeft(); | 
| +    if (padding.isPercent()) | 
| +        w = containingBlock()->availableWidth(); | 
| +    return padding.calcMinValue(w); | 
| +} | 
| + | 
| +int RenderBoxModelObject::paddingRight(bool) const | 
| +{ | 
| +    int w = 0; | 
| +    Length padding = style()->paddingRight(); | 
| +    if (padding.isPercent()) | 
| +        w = containingBlock()->availableWidth(); | 
| +    return padding.calcMinValue(w); | 
| +} | 
| + | 
| + | 
| +void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int clipY, int clipH, | 
| +                                                  int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) | 
| +{ | 
| +    GraphicsContext* context = paintInfo.context; | 
| +    bool includeLeftEdge = box ? box->includeLeftEdge() : true; | 
| +    bool includeRightEdge = box ? box->includeRightEdge() : true; | 
| +    int bLeft = includeLeftEdge ? borderLeft() : 0; | 
| +    int bRight = includeRightEdge ? borderRight() : 0; | 
| +    int pLeft = includeLeftEdge ? paddingLeft() : 0; | 
| +    int pRight = includeRightEdge ? paddingRight() : 0; | 
| + | 
| +    bool clippedToBorderRadius = false; | 
| +    if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) { | 
| +        context->save(); | 
| +        context->addRoundedRectClip(IntRect(tx, ty, w, h), | 
| +            includeLeftEdge ? style()->borderTopLeftRadius() : IntSize(), | 
| +            includeRightEdge ? style()->borderTopRightRadius() : IntSize(), | 
| +            includeLeftEdge ? style()->borderBottomLeftRadius() : IntSize(), | 
| +            includeRightEdge ? style()->borderBottomRightRadius() : IntSize()); | 
| +        clippedToBorderRadius = true; | 
| +    } | 
| + | 
| +    if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { | 
| +        // Clip to the padding or content boxes as necessary. | 
| +        bool includePadding = bgLayer->clip() == ContentFillBox; | 
| +        int x = tx + bLeft + (includePadding ? pLeft : 0); | 
| +        int y = ty + borderTop() + (includePadding ? paddingTop() : 0); | 
| +        int width = w - bLeft - bRight - (includePadding ? pLeft + pRight : 0); | 
| +        int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0); | 
| +        context->save(); | 
| +        context->clip(IntRect(x, y, width, height)); | 
| +    } else if (bgLayer->clip() == TextFillBox) { | 
| +        // We have to draw our text into a mask that can then be used to clip background drawing. | 
| +        // First figure out how big the mask has to be.  It should be no bigger than what we need | 
| +        // to actually render, so we should intersect the dirty rect with the border box of the background. | 
| +        IntRect maskRect(tx, ty, w, h); | 
| +        maskRect.intersect(paintInfo.rect); | 
| + | 
| +        // Now create the mask. | 
| +        auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); | 
| +        if (!maskImage.get()) | 
| +            return; | 
| + | 
| +        GraphicsContext* maskImageContext = maskImage->context(); | 
| +        maskImageContext->translate(-maskRect.x(), -maskRect.y()); | 
| + | 
| +        // Now add the text to the clip.  We do this by painting using a special paint phase that signals to | 
| +        // InlineTextBoxes that they should just add their contents to the clip. | 
| +        PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0); | 
| +        if (box) | 
| +            box->paint(info, tx - box->xPos(), ty - box->yPos()); | 
| +        else | 
| +            paint(info, tx, ty); | 
| + | 
| +        // The mask has been created.  Now we just need to clip to it. | 
| +        context->save(); | 
| +        context->clipToImageBuffer(maskRect, maskImage.get()); | 
| +    } | 
| + | 
| +    StyleImage* bg = bgLayer->image(); | 
| +    bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom()); | 
| +    Color bgColor = c; | 
| + | 
| +    // When this style flag is set, change existing background colors and images to a solid white background. | 
| +    // If there's no bg color or image, leave it untouched to avoid affecting transparency. | 
| +    // We don't try to avoid loading the background images, because this style flag is only set | 
| +    // when printing, and at that point we've already loaded the background images anyway. (To avoid | 
| +    // loading the background images we'd have to do this check when applying styles rather than | 
| +    // while rendering.) | 
| +    if (style()->forceBackgroundsToWhite()) { | 
| +        // Note that we can't reuse this variable below because the bgColor might be changed | 
| +        bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0; | 
| +        if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { | 
| +            bgColor = Color::white; | 
| +            shouldPaintBackgroundImage = false; | 
| +        } | 
| +    } | 
| + | 
| +    // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with | 
| +    // no background in the child document should show the parent's background. | 
| +    bool isTransparent = false; | 
| +    if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && view()->frameView()) { | 
| +        Node* elt = document()->ownerElement(); | 
| +        if (elt) { | 
| +            if (!elt->hasTagName(frameTag)) { | 
| +                // Locate the <body> element using the DOM.  This is easier than trying | 
| +                // to crawl around a render tree with potential :before/:after content and | 
| +                // anonymous blocks created by inline <body> tags etc.  We can locate the <body> | 
| +                // render object very easily via the DOM. | 
| +                HTMLElement* body = document()->body(); | 
| +                isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway. | 
| +            } | 
| +        } else | 
| +            isTransparent = view()->frameView()->isTransparent(); | 
| + | 
| +        // FIXME: This needs to be dynamic.  We should be able to go back to blitting if we ever stop being transparent. | 
| +        if (isTransparent) | 
| +            view()->frameView()->setUseSlowRepaints(); // The parent must show behind the child. | 
| +    } | 
| + | 
| +    // Paint the color first underneath all images. | 
| +    if (!bgLayer->next()) { | 
| +        IntRect rect(tx, clipY, w, clipH); | 
| +        // If we have an alpha and we are painting the root element, go ahead and blend with the base background color. | 
| +        if (isRoot() && (!bgColor.isValid() || bgColor.alpha() < 0xFF) && !isTransparent) { | 
| +            Color baseColor = view()->frameView()->baseBackgroundColor(); | 
| +            if (baseColor.alpha() > 0) { | 
| +                context->save(); | 
| +                context->setCompositeOperation(CompositeCopy); | 
| +                context->fillRect(rect, baseColor); | 
| +                context->restore(); | 
| +            } else | 
| +                context->clearRect(rect); | 
| +        } | 
| + | 
| +        if (bgColor.isValid() && bgColor.alpha() > 0) | 
| +            context->fillRect(rect, bgColor); | 
| +    } | 
| + | 
| +    // no progressive loading of the background image | 
| +    if (shouldPaintBackgroundImage) { | 
| +        IntRect destRect; | 
| +        IntPoint phase; | 
| +        IntSize tileSize; | 
| + | 
| +        calculateBackgroundImageGeometry(bgLayer, tx, ty, w, h, destRect, phase, tileSize); | 
| +        if (!destRect.isEmpty()) { | 
| +            CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; | 
| +            context->drawTiledImage(bg->image(this, tileSize), destRect, phase, tileSize, compositeOp); | 
| +        } | 
| +    } | 
| + | 
| +    if (bgLayer->clip() != BorderFillBox) | 
| +        // Undo the background clip | 
| +        context->restore(); | 
| + | 
| +    if (clippedToBorderRadius) | 
| +        // Undo the border radius clip | 
| +        context->restore(); | 
| +} | 
| + | 
| +IntSize RenderBoxModelObject::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const | 
| +{ | 
| +    StyleImage* bg = bgLayer->image(); | 
| +    bg->setImageContainerSize(IntSize(scaledWidth, scaledHeight)); // Use the box established by background-origin. | 
| + | 
| +    if (bgLayer->isSizeSet()) { | 
| +        int w = scaledWidth; | 
| +        int h = scaledHeight; | 
| +        Length bgWidth = bgLayer->size().width(); | 
| +        Length bgHeight = bgLayer->size().height(); | 
| + | 
| +        if (bgWidth.isFixed()) | 
| +            w = bgWidth.value(); | 
| +        else if (bgWidth.isPercent()) | 
| +            w = bgWidth.calcValue(scaledWidth); | 
| + | 
| +        if (bgHeight.isFixed()) | 
| +            h = bgHeight.value(); | 
| +        else if (bgHeight.isPercent()) | 
| +            h = bgHeight.calcValue(scaledHeight); | 
| + | 
| +        // If one of the values is auto we have to use the appropriate | 
| +        // scale to maintain our aspect ratio. | 
| +        if (bgWidth.isAuto() && !bgHeight.isAuto()) | 
| +            w = bg->imageSize(this, style()->effectiveZoom()).width() * h / bg->imageSize(this, style()->effectiveZoom()).height(); | 
| +        else if (!bgWidth.isAuto() && bgHeight.isAuto()) | 
| +            h = bg->imageSize(this, style()->effectiveZoom()).height() * w / bg->imageSize(this, style()->effectiveZoom()).width(); | 
| +        else if (bgWidth.isAuto() && bgHeight.isAuto()) { | 
| +            // If both width and height are auto, we just want to use the image's | 
| +            // intrinsic size. | 
| +            w = bg->imageSize(this, style()->effectiveZoom()).width(); | 
| +            h = bg->imageSize(this, style()->effectiveZoom()).height(); | 
| +        } | 
| + | 
| +        return IntSize(max(1, w), max(1, h)); | 
| +    } else | 
| +        return bg->imageSize(this, style()->effectiveZoom()); | 
| +} | 
| + | 
| +void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgLayer, int tx, int ty, int w, int h, | 
| +                                                            IntRect& destRect, IntPoint& phase, IntSize& tileSize) | 
| +{ | 
| +    int pw; | 
| +    int ph; | 
| +    int left = 0; | 
| +    int right = 0; | 
| +    int top = 0; | 
| +    int bottom = 0; | 
| +    int cx; | 
| +    int cy; | 
| +    int rw = 0; | 
| +    int rh = 0; | 
| + | 
| +    // CSS2 chapter 14.2.1 | 
| + | 
| +    if (bgLayer->attachment()) { | 
| +        // Scroll | 
| +        if (bgLayer->origin() != BorderFillBox) { | 
| +            left = borderLeft(); | 
| +            right = borderRight(); | 
| +            top = borderTop(); | 
| +            bottom = borderBottom(); | 
| +            if (bgLayer->origin() == ContentFillBox) { | 
| +                left += paddingLeft(); | 
| +                right += paddingRight(); | 
| +                top += paddingTop(); | 
| +                bottom += paddingBottom(); | 
| +            } | 
| +        } | 
| + | 
| +        // The background of the box generated by the root element covers the entire canvas including | 
| +        // its margins.  Since those were added in already, we have to factor them out when computing the | 
| +        // box used by background-origin/size/position. | 
| +        if (isRoot()) { | 
| +            rw = toRenderBox(this)->width() - left - right; | 
| +            rh = toRenderBox(this)->height() - top - bottom; | 
| +            left += marginLeft(); | 
| +            right += marginRight(); | 
| +            top += marginTop(); | 
| +            bottom += marginBottom(); | 
| +        } | 
| +        cx = tx; | 
| +        cy = ty; | 
| +        pw = w - left - right; | 
| +        ph = h - top - bottom; | 
| +    } else { | 
| +        // Fixed | 
| +        IntRect vr = viewRect(); | 
| +        cx = vr.x(); | 
| +        cy = vr.y(); | 
| +        pw = vr.width(); | 
| +        ph = vr.height(); | 
| +    } | 
| + | 
| +    int sx = 0; | 
| +    int sy = 0; | 
| +    int cw; | 
| +    int ch; | 
| + | 
| +    IntSize scaledImageSize; | 
| +    if (isRoot() && bgLayer->attachment()) | 
| +        scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh); | 
| +    else | 
| +        scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph); | 
| + | 
| +    int scaledImageWidth = scaledImageSize.width(); | 
| +    int scaledImageHeight = scaledImageSize.height(); | 
| + | 
| +    EFillRepeat backgroundRepeat = bgLayer->repeat(); | 
| + | 
| +    int xPosition; | 
| +    if (isRoot() && bgLayer->attachment()) | 
| +        xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true); | 
| +    else | 
| +        xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true); | 
| +    if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatXFill) { | 
| +        cw = pw + left + right; | 
| +        sx = scaledImageWidth ? scaledImageWidth - (xPosition + left) % scaledImageWidth : 0; | 
| +    } else { | 
| +        cx += max(xPosition + left, 0); | 
| +        sx = -min(xPosition + left, 0); | 
| +        cw = scaledImageWidth + min(xPosition + left, 0); | 
| +    } | 
| + | 
| +    int yPosition; | 
| +    if (isRoot() && bgLayer->attachment()) | 
| +        yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true); | 
| +    else | 
| +        yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true); | 
| +    if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatYFill) { | 
| +        ch = ph + top + bottom; | 
| +        sy = scaledImageHeight ? scaledImageHeight - (yPosition + top) % scaledImageHeight : 0; | 
| +    } else { | 
| +        cy += max(yPosition + top, 0); | 
| +        sy = -min(yPosition + top, 0); | 
| +        ch = scaledImageHeight + min(yPosition + top, 0); | 
| +    } | 
| + | 
| +    if (!bgLayer->attachment()) { | 
| +        sx += max(tx - cx, 0); | 
| +        sy += max(ty - cy, 0); | 
| +    } | 
| + | 
| +    destRect = IntRect(cx, cy, cw, ch); | 
| +    destRect.intersect(IntRect(tx, ty, w, h)); | 
| +    phase = IntPoint(sx, sy); | 
| +    tileSize = IntSize(scaledImageWidth, scaledImageHeight); | 
| +} | 
| + | 
| } // namespace WebCore | 
|  |