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; }
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; }
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; }