blob: 7a2d243c3ccbf6b6df765f0922103f9c5d89c562 [file] [log] [blame]
/*
* Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
* 2006 Alexander Kellett <lypanov@kde.org>
* 2006 Rob Buis <buis@kde.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#ifdef SVG_SUPPORT
#import "KRenderingPaintServerQuartz.h"
#import "QuartzSupport.h"
#import "KCanvasResourcesQuartz.h"
#import "KRenderingDeviceQuartz.h"
#import "KCanvasRenderingStyle.h"
#import "KRenderingPaintServer.h"
#import "KRenderingDevice.h"
#import "Logging.h"
namespace WebCore {
void KRenderingPaintServerQuartzHelper::strokePath(CGContextRef context, const RenderPath* renderPath)
{
CGContextStrokePath(context);
}
void KRenderingPaintServerQuartzHelper::clipToStrokePath(CGContextRef context, const RenderPath* renderPath)
{
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
}
void KRenderingPaintServerQuartzHelper::fillPath(CGContextRef context, const RenderPath* renderPath)
{
if (renderPath->style()->svgStyle()->fillRule() == RULE_EVENODD)
CGContextEOFillPath(context);
else
CGContextFillPath(context);
}
void KRenderingPaintServerQuartzHelper::clipToFillPath(CGContextRef context, const RenderPath* renderPath)
{
if (renderPath->style()->svgStyle()->fillRule() == RULE_EVENODD)
CGContextEOClip(context);
else
CGContextClip(context);
}
void KRenderingPaintServerSolidQuartz::draw(KRenderingDeviceContext* renderingContext, const RenderPath* path, KCPaintTargetType type) const
{
if (!setup(renderingContext, path, type))
return;
renderPath(renderingContext, path, type);
teardown(renderingContext, path, type);
}
bool KRenderingPaintServerSolidQuartz::setup(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
{
KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
CGContextRef context = quartzContext->cgContext();
RenderStyle* renderStyle = renderObject->style();
CGContextSetAlpha(context, renderStyle->opacity());
static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); // This should be shared from GraphicsContext, or some other central location
if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill()) {
CGFloat colorComponents[4];
color().getRGBA(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
ASSERT(!color().hasAlpha());
colorComponents[3] = renderStyle->svgStyle()->fillOpacity(); // SVG/CSS colors are not specified w/o alpha
CGContextSetFillColorSpace(context, deviceRGBColorSpace);
CGContextSetFillColor(context, colorComponents);
if (isPaintingText()) {
const_cast<RenderObject*>(renderObject)->style()->setColor(color());
CGContextSetTextDrawingMode(context, kCGTextFill);
}
}
if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke()) {
CGFloat colorComponents[4];
color().getRGBA(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
ASSERT(!color().hasAlpha());
colorComponents[3] = renderStyle->svgStyle()->strokeOpacity(); // SVG/CSS colors are not specified w/o alpha
CGContextSetStrokeColorSpace(context, deviceRGBColorSpace);
CGContextSetStrokeColor(context, colorComponents);
applyStrokeStyleToContext(context, renderStyle, renderObject);
if (isPaintingText()) {
const_cast<RenderObject*>(renderObject)->style()->setColor(color());
CGContextSetTextDrawingMode(context, kCGTextStroke);
}
}
return true;
}
void KRenderingPaintServerSolidQuartz::renderPath(KRenderingDeviceContext* renderingContext, const RenderPath* renderPath, KCPaintTargetType type) const
{
RenderStyle* renderStyle = renderPath->style();
KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
CGContextRef context = quartzContext->cgContext();
if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill())
KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke())
KRenderingPaintServerQuartzHelper::strokePath(context, renderPath);
}
void KRenderingPaintServerSolidQuartz::teardown(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
{
}
void patternCallback(void *info, CGContextRef context)
{
CGLayerRef layer = reinterpret_cast<KCanvasImageQuartz*>(info)->cgLayer();
CGContextDrawLayerAtPoint(context, CGPointZero, layer);
}
void KRenderingPaintServerPatternQuartz::draw(KRenderingDeviceContext* renderingContext, const RenderPath* path, KCPaintTargetType type) const
{
if (!setup(renderingContext, path, type))
return;
renderPath(renderingContext, path, type);
teardown(renderingContext, path, type);
}
bool KRenderingPaintServerPatternQuartz::setup(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
{
if(listener()) // this seems like bad design to me, should be in a common baseclass. -- ecs 8/6/05
listener()->resourceNotification();
RenderStyle* renderStyle = renderObject->style();
KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
CGContextRef context = quartzContext->cgContext();
KCanvasImage* cell = tile();
if (!cell)
return false;
CGContextSaveGState(context);
CGSize cellSize = CGSize(cell->size());
CGFloat alpha = 1; // canvasStyle->opacity(); //which?
// Patterns don't seem to resepect the CTM unless we make them...
CGAffineTransform ctm = CGContextGetCTM(context);
CGAffineTransform transform = patternTransform();
transform = CGAffineTransformConcat(transform, ctm);
CGSize phase = CGSizeMake(bbox().x(), -bbox().y()); // Pattern space seems to start in the lower-left, so we flip the Y here.
CGContextSetPatternPhase(context, phase);
CGPatternCallbacks callbacks = {0, patternCallback, NULL};
m_pattern = CGPatternCreate(
tile(),
CGRectMake(0, 0, cellSize.width, cellSize.height),
transform,
bbox().width(), //cellSize.width,
bbox().height(), //cellSize.height,
kCGPatternTilingConstantSpacing, // FIXME: should ask CG guys.
true, // has color
&callbacks);
CGContextSetAlpha(context, renderStyle->opacity()); // or do I set the alpha above?
m_patternSpace = CGColorSpaceCreatePattern(NULL);
if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill()) {
CGContextSetFillColorSpace(context, m_patternSpace);
CGContextSetFillPattern(context, m_pattern, &alpha);
if (isPaintingText()) {
const_cast<RenderObject*>(renderObject)->style()->setColor(Color());
CGContextSetTextDrawingMode(context, kCGTextFill);
}
}
if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke()) {
CGContextSetStrokeColorSpace(context, m_patternSpace);
CGContextSetStrokePattern(context, m_pattern, &alpha);
applyStrokeStyleToContext(context, renderStyle, renderObject);
if (isPaintingText()) {
const_cast<RenderObject*>(renderObject)->style()->setColor(Color());
CGContextSetTextDrawingMode(context, kCGTextStroke);
}
}
return true;
}
void KRenderingPaintServerPatternQuartz::renderPath(KRenderingDeviceContext* renderingContext, const RenderPath* renderPath, KCPaintTargetType type) const
{
RenderStyle* renderStyle = renderPath->style();
KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
CGContextRef context = quartzContext->cgContext();
if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill())
KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke())
KRenderingPaintServerQuartzHelper::strokePath(context, renderPath);
}
void KRenderingPaintServerPatternQuartz::teardown(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
{
KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
CGContextRef context = quartzContext->cgContext();
CGPatternRelease(m_pattern);
CGColorSpaceRelease(m_patternSpace);
CGContextRestoreGState(context);
}
}
#endif // SVG_SUPPORT