KRenderingPaintServerQuartz.mm [plain text]
/*
* Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
* 2006 Alexander Kellett <lypanov@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"
#if SVG_SUPPORT
#import "KRenderingPaintServerQuartz.h"
#import "QuartzSupport.h"
#import "KCanvasResourcesQuartz.h"
#import "KRenderingDeviceQuartz.h"
#import "KCanvasRenderingStyle.h"
#import "KRenderingPaintServer.h"
#import "KRenderingFillPainter.h"
#import "KRenderingStrokePainter.h"
#import "KCanvasMatrix.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 (KSVGPainterFactory::fillPainter(renderPath->style(), renderPath).fillRule() == RULE_EVENODD)
CGContextEOFillPath(context);
else
CGContextFillPath(context);
}
void KRenderingPaintServerQuartzHelper::clipToFillPath(CGContextRef context, const RenderPath *renderPath)
{
if (KSVGPainterFactory::fillPainter(renderPath->style(), renderPath).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());
if ((type & APPLY_TO_FILL) && KSVGPainterFactory::isFilled(renderStyle)) {
CGColorRef colorCG = cgColor(color());
CGColorRef withAlpha = CGColorCreateCopyWithAlpha(colorCG, KSVGPainterFactory::fillPainter(renderStyle, renderObject).opacity());
CGContextSetFillColorWithColor(context, withAlpha);
CGColorRelease(colorCG);
CGColorRelease(withAlpha);
if (isPaintingText()) {
const_cast<RenderObject *>(renderObject)->style()->setColor(color());
CGContextSetTextDrawingMode(context, kCGTextFill);
}
}
if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle)) {
CGColorRef colorCG = cgColor(color());
CGColorRef withAlpha = CGColorCreateCopyWithAlpha(colorCG, KSVGPainterFactory::strokePainter(renderStyle, renderObject).opacity());
CGContextSetStrokeColorWithColor(context, withAlpha);
CGColorRelease(colorCG);
CGColorRelease(withAlpha);
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) && KSVGPainterFactory::isFilled(renderStyle))
KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle))
KRenderingPaintServerQuartzHelper::strokePath(context, renderPath);
}
void KRenderingPaintServerSolidQuartz::teardown(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
{
}
void patternCallback(void *info, CGContextRef context)
{
KCanvasImageQuartz *image = (KCanvasImageQuartz *)info;
CGLayerRef layer = image->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 = CGAffineTransform(patternTransform().matrix());
transform = CGAffineTransformConcat(transform, ctm);
CGSize phase = CGSizeMake(bbox().x(), bbox().y());
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) && KSVGPainterFactory::isFilled(renderStyle)) {
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) && KSVGPainterFactory::isStroked(renderStyle)) {
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) && KSVGPainterFactory::isFilled(renderStyle))
KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
if ((type & APPLY_TO_STROKE) && KSVGPainterFactory::isStroked(renderStyle))
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