2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 * 2006 Alexander Kellett <lypanov@kde.org>
4 * 2006 Rob Buis <buis@kde.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #import "KRenderingPaintServerQuartz.h"
32 #import "QuartzSupport.h"
33 #import "KCanvasResourcesQuartz.h"
34 #import "KRenderingDeviceQuartz.h"
36 #import "KCanvasRenderingStyle.h"
37 #import "KRenderingPaintServer.h"
38 #import "KRenderingFillPainter.h"
39 #import "KRenderingStrokePainter.h"
40 #import "KRenderingDevice.h"
46 void KRenderingPaintServerQuartzHelper::strokePath(CGContextRef context, const RenderPath* renderPath)
48 CGContextStrokePath(context);
51 void KRenderingPaintServerQuartzHelper::clipToStrokePath(CGContextRef context, const RenderPath* renderPath)
53 CGContextReplacePathWithStrokedPath(context);
54 CGContextClip(context);
57 void KRenderingPaintServerQuartzHelper::fillPath(CGContextRef context, const RenderPath* renderPath)
59 if (KSVGPainterFactory::fillPainter(renderPath->style(), renderPath).fillRule() == RULE_EVENODD)
60 CGContextEOFillPath(context);
62 CGContextFillPath(context);
65 void KRenderingPaintServerQuartzHelper::clipToFillPath(CGContextRef context, const RenderPath* renderPath)
67 if (KSVGPainterFactory::fillPainter(renderPath->style(), renderPath).fillRule() == RULE_EVENODD)
68 CGContextEOClip(context);
70 CGContextClip(context);
73 void KRenderingPaintServerSolidQuartz::draw(KRenderingDeviceContext* renderingContext, const RenderPath* path, KCPaintTargetType type) const
75 if (!setup(renderingContext, path, type))
77 renderPath(renderingContext, path, type);
78 teardown(renderingContext, path, type);
81 bool KRenderingPaintServerSolidQuartz::setup(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
83 KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
84 CGContextRef context = quartzContext->cgContext();
85 RenderStyle* renderStyle = renderObject->style();
87 CGContextSetAlpha(context, renderStyle->opacity());
89 static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); // This should be shared from GraphicsContext, or some other central location
91 if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill()) {
92 CGFloat colorComponents[4];
93 color().getRGBA(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
94 ASSERT(!color().hasAlpha());
95 colorComponents[3] = renderStyle->svgStyle()->fillOpacity(); // SVG/CSS colors are not specified w/o alpha
96 CGContextSetFillColorSpace(context, deviceRGBColorSpace);
97 CGContextSetFillColor(context, colorComponents);
98 if (isPaintingText()) {
99 const_cast<RenderObject*>(renderObject)->style()->setColor(color());
100 CGContextSetTextDrawingMode(context, kCGTextFill);
104 if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke()) {
105 CGFloat colorComponents[4];
106 color().getRGBA(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
107 ASSERT(!color().hasAlpha());
108 colorComponents[3] = renderStyle->svgStyle()->strokeOpacity(); // SVG/CSS colors are not specified w/o alpha
109 CGContextSetStrokeColorSpace(context, deviceRGBColorSpace);
110 CGContextSetStrokeColor(context, colorComponents);
111 applyStrokeStyleToContext(context, renderStyle, renderObject);
112 if (isPaintingText()) {
113 const_cast<RenderObject*>(renderObject)->style()->setColor(color());
114 CGContextSetTextDrawingMode(context, kCGTextStroke);
121 void KRenderingPaintServerSolidQuartz::renderPath(KRenderingDeviceContext* renderingContext, const RenderPath* renderPath, KCPaintTargetType type) const
123 RenderStyle* renderStyle = renderPath->style();
124 KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
125 CGContextRef context = quartzContext->cgContext();
126 if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill())
127 KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
128 if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke())
129 KRenderingPaintServerQuartzHelper::strokePath(context, renderPath);
132 void KRenderingPaintServerSolidQuartz::teardown(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
136 void patternCallback(void *info, CGContextRef context)
138 CGLayerRef layer = reinterpret_cast<KCanvasImageQuartz*>(info)->cgLayer();
139 CGContextDrawLayerAtPoint(context, CGPointZero, layer);
142 void KRenderingPaintServerPatternQuartz::draw(KRenderingDeviceContext* renderingContext, const RenderPath* path, KCPaintTargetType type) const
144 if (!setup(renderingContext, path, type))
146 renderPath(renderingContext, path, type);
147 teardown(renderingContext, path, type);
150 bool KRenderingPaintServerPatternQuartz::setup(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
152 if(listener()) // this seems like bad design to me, should be in a common baseclass. -- ecs 8/6/05
153 listener()->resourceNotification();
155 RenderStyle* renderStyle = renderObject->style();
157 KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
158 CGContextRef context = quartzContext->cgContext();
160 KCanvasImage* cell = tile();
164 CGContextSaveGState(context);
166 CGSize cellSize = CGSize(cell->size());
168 CGFloat alpha = 1; // canvasStyle->opacity(); //which?
170 // Patterns don't seem to resepect the CTM unless we make them...
171 CGAffineTransform ctm = CGContextGetCTM(context);
172 CGAffineTransform transform = patternTransform();
173 transform = CGAffineTransformConcat(transform, ctm);
175 CGSize phase = CGSizeMake(bbox().x(), -bbox().y()); // Pattern space seems to start in the lower-left, so we flip the Y here.
176 CGContextSetPatternPhase(context, phase);
178 CGPatternCallbacks callbacks = {0, patternCallback, NULL};
179 m_pattern = CGPatternCreate(
181 CGRectMake(0, 0, cellSize.width, cellSize.height),
183 bbox().width(), //cellSize.width,
184 bbox().height(), //cellSize.height,
185 kCGPatternTilingConstantSpacing, // FIXME: should ask CG guys.
189 CGContextSetAlpha(context, renderStyle->opacity()); // or do I set the alpha above?
191 m_patternSpace = CGColorSpaceCreatePattern(NULL);
193 if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill()) {
194 CGContextSetFillColorSpace(context, m_patternSpace);
195 CGContextSetFillPattern(context, m_pattern, &alpha);
196 if (isPaintingText()) {
197 const_cast<RenderObject*>(renderObject)->style()->setColor(Color());
198 CGContextSetTextDrawingMode(context, kCGTextFill);
202 if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke()) {
203 CGContextSetStrokeColorSpace(context, m_patternSpace);
204 CGContextSetStrokePattern(context, m_pattern, &alpha);
205 applyStrokeStyleToContext(context, renderStyle, renderObject);
206 if (isPaintingText()) {
207 const_cast<RenderObject*>(renderObject)->style()->setColor(Color());
208 CGContextSetTextDrawingMode(context, kCGTextStroke);
215 void KRenderingPaintServerPatternQuartz::renderPath(KRenderingDeviceContext* renderingContext, const RenderPath* renderPath, KCPaintTargetType type) const
217 RenderStyle* renderStyle = renderPath->style();
219 KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
220 CGContextRef context = quartzContext->cgContext();
222 if ((type & APPLY_TO_FILL) && renderStyle->svgStyle()->hasFill())
223 KRenderingPaintServerQuartzHelper::fillPath(context, renderPath);
225 if ((type & APPLY_TO_STROKE) && renderStyle->svgStyle()->hasStroke())
226 KRenderingPaintServerQuartzHelper::strokePath(context, renderPath);
229 void KRenderingPaintServerPatternQuartz::teardown(KRenderingDeviceContext* renderingContext, const RenderObject* renderObject, KCPaintTargetType type) const
231 KRenderingDeviceContextQuartz* quartzContext = static_cast<KRenderingDeviceContextQuartz*>(renderingContext);
232 CGContextRef context = quartzContext->cgContext();
233 CGPatternRelease(m_pattern);
234 CGColorSpaceRelease(m_patternSpace);
235 CGContextRestoreGState(context);
240 #endif // SVG_SUPPORT