TextStream& SVGPaintServerPattern::externalRepresentation(TextStream& ts) const
{
    // Gradients/patterns aren't setup, until they are used for painting. Work around that fact.
    m_ownerElement->buildPattern(FloatRect(0.0f, 0.0f, 1.0f, 1.0f));

    ts << "[type=PATTERN]"
        << " [bbox=" << patternBoundaries() << "]";
    if (!patternTransform().isIdentity())
        ts << " [pattern transform=" << patternTransform() << "]";
    return ts;
}
Пример #2
0
void SVGPatternElement::notifyAttributeChange() const
{
    if (!m_paintServer || !m_paintServer->activeClient() || m_ignoreAttributeChanges)
        return;

    IntSize newSize = IntSize(lroundf(width()->baseVal()->value()), lroundf(height()->baseVal()->value()));
    if (m_tile && (m_tile->size() == newSize) || newSize.width() < 1 || newSize.height() < 1)
        return;

    m_ignoreAttributeChanges = true;

    // FIXME: This whole "target" idea seems completely broken to me
    // basically it seems we're effectively trying to change the "this" pointer
    // for the rest of the method... why don't we just?  Or better yet, why don't
    // we call some method on the "target" and each target in the chain?  -- ECS 11/21/05

    // Find first pattern def that has children
    const SVGPatternElement* target = this;
    const Node *test = this;
    while(test && !test->hasChildNodes())
    {
        DeprecatedString ref = String(target->href()->baseVal()).deprecatedString();
        test = ownerDocument()->getElementById(String(ref.mid(1)).impl());
        if (test && test->hasTagName(SVGNames::patternTag))
            target = static_cast<const SVGPatternElement* >(test);
    }

    unsigned short savedPatternUnits = patternUnits()->baseVal();
    unsigned short savedPatternContentUnits = patternContentUnits()->baseVal();

    KCanvasMatrix patternTransformMatrix;
    if (patternTransform()->baseVal()->numberOfItems() > 0)
        patternTransformMatrix = KCanvasMatrix(patternTransform()->baseVal()->consolidate()->matrix()->matrix());

    fillAttributesFromReferencePattern(target, patternTransformMatrix);
    
    drawPatternContentIntoTile(target, newSize, patternTransformMatrix);
    
    patternUnits()->setBaseVal(savedPatternUnits);
    patternContentUnits()->setBaseVal(savedPatternContentUnits);

    notifyClientsToRepaint();
    
    m_ignoreAttributeChanges = false;
}
Пример #3
0
void SVGPatternElement::parseMappedAttribute(MappedAttribute *attr)
{
    const AtomicString &value = attr->value();
    if (attr->name() == SVGNames::patternUnitsAttr) {
        if (value == "userSpaceOnUse")
            patternUnits()->setBaseVal(SVG_UNIT_TYPE_USERSPACEONUSE);
        else if (value == "objectBoundingBox")
            patternUnits()->setBaseVal(SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
        if (value == "userSpaceOnUse")
            patternContentUnits()->setBaseVal(SVG_UNIT_TYPE_USERSPACEONUSE);
        else if (value == "objectBoundingBox")
            patternContentUnits()->setBaseVal(SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    } else if (attr->name() == SVGNames::patternTransformAttr) {
        SVGTransformList *patternTransforms = patternTransform()->baseVal();
        SVGTransformable::parseTransformAttribute(patternTransforms, value);
    } else if (attr->name() == SVGNames::xAttr)
        x()->baseVal()->setValueAsString(value.impl());
    else if (attr->name() == SVGNames::yAttr)
        y()->baseVal()->setValueAsString(value.impl());
    else if (attr->name() == SVGNames::widthAttr)
        width()->baseVal()->setValueAsString(value.impl());
    else if (attr->name() == SVGNames::heightAttr)
        height()->baseVal()->setValueAsString(value.impl());
    else {
        if (SVGURIReference::parseMappedAttribute(attr))
            return;
        if (SVGTests::parseMappedAttribute(attr))
            return;
        if (SVGLangSpace::parseMappedAttribute(attr))
            return;
        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
            return;
        if (SVGFitToViewBox::parseMappedAttribute(attr))
            return;

        SVGStyledElement::parseMappedAttribute(attr);
    }
}
bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const
{
    FloatRect targetRect = object->objectBoundingBox();

    const SVGRenderStyle* style = object->style()->svgStyle();
    bool isFilled = (type & ApplyToFillTargetType) && style->hasFill();
    bool isStroked = (type & ApplyToStrokeTargetType) && style->hasStroke();

    ASSERT(isFilled && !isStroked || !isFilled && isStroked);

    m_ownerElement->buildPattern(targetRect);
    if (!tile())
        return false;

    context->save();

    ASSERT(!m_pattern);

    IntRect tileRect = tile()->image()->rect();
    if (tileRect.width() > patternBoundaries().width() || tileRect.height() > patternBoundaries().height()) {
        // Draw the first cell of the pattern manually to support overflow="visible" on all platforms.
        int tileWidth = static_cast<int>(patternBoundaries().width() + 0.5f);
        int tileHeight = static_cast<int>(patternBoundaries().height() + 0.5f);
        OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(IntSize(tileWidth, tileHeight));
  
        GraphicsContext* tileImageContext = tileImage->context();

        int numY = static_cast<int>(ceilf(tileRect.height() / tileHeight)) + 1;
        int numX = static_cast<int>(ceilf(tileRect.width() / tileWidth)) + 1;

        tileImageContext->save();
        tileImageContext->translate(-patternBoundaries().width() * numX, -patternBoundaries().height() * numY);
        for (int i = numY; i > 0; i--) {
            tileImageContext->translate(0, patternBoundaries().height());
            for (int j = numX; j > 0; j--) {
                tileImageContext->translate(patternBoundaries().width(), 0);
                tileImageContext->drawImage(tile()->image(), object->style()->colorSpace(), tileRect, tileRect);
            }
            tileImageContext->translate(-patternBoundaries().width() * numX, 0);
        }
        tileImageContext->restore();

        m_pattern = Pattern::create(tileImage->image(), true, true);
    }
    else
        m_pattern = Pattern::create(tile()->image(), true, true);

    if (isFilled) {
        context->setAlpha(style->fillOpacity());
        context->setFillPattern(m_pattern);
        context->setFillRule(style->fillRule());
    }
    if (isStroked) {
        context->setAlpha(style->strokeOpacity());
        context->setStrokePattern(m_pattern);
        applyStrokeStyleToContext(context, object->style(), object);
    }

    TransformationMatrix matrix;
    matrix.translate(patternBoundaries().x(), patternBoundaries().y());
    matrix.multiply(patternTransform());
    m_pattern->setPatternSpaceTransform(matrix);

    if (isPaintingText) {
        context->setTextDrawingMode(isFilled ? cTextFill : cTextStroke);
#if PLATFORM(CG)
        if (isFilled)
            context->applyFillPattern();
        else
            context->applyStrokePattern();
#endif
    }

    return true;
}
bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const
{
    CGContextRef contextRef = context->platformContext();

    // Build pattern tile, passing destination object bounding box
    FloatRect targetRect;
    if (isPaintingText) {
        IntRect textBoundary = const_cast<RenderObject*>(object)->absoluteBoundingBoxRect();
        targetRect = object->absoluteTransform().inverse().mapRect(textBoundary);
    } else
        targetRect = CGContextGetPathBoundingBox(contextRef);

    m_ownerElement->buildPattern(targetRect);

    if (!tile())
        return false;

    CGSize cellSize = CGSize(tile()->size());
    CGFloat alpha = 1; // canvasStyle->opacity(); //which?

    context->save();

    // Repesct local pattern transformations
    CGContextConcatCTM(contextRef, patternTransform());

    // Pattern space seems to start in the lower-left, so we flip the Y here. 
    CGSize phase = CGSizeMake(patternBoundaries().x(), -patternBoundaries().y());
    CGContextSetPatternPhase(contextRef, phase);

    RenderStyle* style = object->style();
    CGContextSetAlpha(contextRef, style->opacity()); // or do I set the alpha above?

    ASSERT(!m_pattern);
    CGPatternCallbacks callbacks = {0, patternCallback, NULL};
    m_pattern = CGPatternCreate(tile(),
                                CGRectMake(0, 0, cellSize.width, cellSize.height),
                                CGContextGetCTM(contextRef),
                                patternBoundaries().width(),
                                patternBoundaries().height(),
                                kCGPatternTilingConstantSpacing, // FIXME: should ask CG guys.
                                true, // has color
                                &callbacks);

    if (!m_patternSpace)
        m_patternSpace = CGColorSpaceCreatePattern(0);

    if ((type & ApplyToFillTargetType) && style->svgStyle()->hasFill()) {
        CGContextSetFillColorSpace(contextRef, m_patternSpace);
        CGContextSetFillPattern(contextRef, m_pattern, &alpha);
 
        if (isPaintingText) 
            context->setTextDrawingMode(cTextFill);
    }

    if ((type & ApplyToStrokeTargetType) && style->svgStyle()->hasStroke()) {
        CGContextSetStrokeColorSpace(contextRef, m_patternSpace);
        CGContextSetStrokePattern(contextRef, m_pattern, &alpha);
        applyStrokeStyleToContext(contextRef, style, object);

        if (isPaintingText) 
            context->setTextDrawingMode(cTextStroke);
    }

    return true;
}