2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
5 * Copyright (C) 2008 Nuanti Ltd.
6 * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
7 * Copyright (C) 2010, 2011 Igalia S.L.
8 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
9 * Copyright (C) 2012, Intel Corporation
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "GraphicsContext.h"
38 #include "AffineTransform.h"
39 #include "CairoUtilities.h"
40 #include "FloatConversion.h"
41 #include "FloatRect.h"
43 #include "GraphicsContextPlatformPrivateCairo.h"
44 #include "OwnPtrCairo.h"
46 #include "NotImplemented.h"
49 #include "PlatformContextCairo.h"
50 #include "PlatformPathCairo.h"
51 #include "RefPtrCairo.h"
52 #include "ShadowBlur.h"
53 #include "SimpleFontData.h"
57 #include <wtf/MathExtras.h>
61 #include <pango/pango.h>
63 #include <cairo-win32.h>
69 #define M_PI 3.14159265358979323846
74 // A helper which quickly fills a rectangle with a simple color fill.
75 static inline void fillRectWithColor(cairo_t* cr, const FloatRect& rect, const Color& color)
79 setSourceRGBAFromColor(cr, color);
80 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
84 static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const FloatPoint* points)
86 cairo_move_to(context, points[0].x(), points[0].y());
87 for (size_t i = 1; i < numPoints; i++)
88 cairo_line_to(context, points[i].x(), points[i].y());
89 cairo_close_path(context);
92 enum PathDrawingStyle {
95 FillAndStroke = Fill + Stroke
98 static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle drawingStyle)
100 ShadowBlur& shadow = context->platformContext()->shadowBlur();
101 if (shadow.type() == ShadowBlur::NoShadow)
104 // Calculate the extents of the rendered solid paths.
105 cairo_t* cairoContext = context->platformContext()->cr();
106 OwnPtr<cairo_path_t> path = adoptPtr(cairo_copy_path(cairoContext));
108 FloatRect solidFigureExtents;
113 if (drawingStyle & Stroke) {
114 cairo_stroke_extents(cairoContext, &x0, &y0, &x1, &y1);
115 solidFigureExtents = FloatRect(x0, y0, x1 - x0, y1 - y0);
117 if (drawingStyle & Fill) {
118 cairo_fill_extents(cairoContext, &x0, &y0, &x1, &y1);
119 FloatRect fillExtents(x0, y0, x1 - x0, y1 - y0);
120 solidFigureExtents.unite(fillExtents);
123 GraphicsContext* shadowContext = shadow.beginShadowLayer(context, solidFigureExtents);
127 cairo_t* cairoShadowContext = shadowContext->platformContext()->cr();
129 // It's important to copy the context properties to the new shadow
130 // context to preserve things such as the fill rule and stroke width.
131 copyContextProperties(cairoContext, cairoShadowContext);
133 if (drawingStyle & Fill) {
134 cairo_save(cairoShadowContext);
135 cairo_append_path(cairoShadowContext, path.get());
136 shadowContext->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::NoAdjustment);
137 cairo_fill(cairoShadowContext);
138 cairo_restore(cairoShadowContext);
141 if (drawingStyle & Stroke) {
142 cairo_append_path(cairoShadowContext, path.get());
143 shadowContext->platformContext()->prepareForStroking(context->state(), PlatformContextCairo::DoNotPreserveAlpha);
144 cairo_stroke(cairoShadowContext);
147 shadow.endShadowLayer(context);
149 // ShadowBlur::endShadowLayer destroys the current path on the Cairo context. We restore it here.
150 cairo_new_path(cairoContext);
151 cairo_append_path(cairoContext, path.get());
154 static inline void shadowAndFillCurrentCairoPath(GraphicsContext* context)
156 cairo_t* cr = context->platformContext()->cr();
159 drawPathShadow(context, Fill);
161 context->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha);
167 static inline void shadowAndStrokeCurrentCairoPath(GraphicsContext* context)
169 drawPathShadow(context, Stroke);
170 context->platformContext()->prepareForStroking(context->state());
171 cairo_stroke(context->platformContext()->cr());
174 GraphicsContext::GraphicsContext(cairo_t* cr)
175 : m_updatingControlTints(false),
176 m_transparencyCount(0)
178 m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr));
181 void GraphicsContext::platformInit(PlatformContextCairo* platformContext)
183 m_data = new GraphicsContextPlatformPrivate(platformContext);
185 m_data->syncContext(platformContext->cr());
187 setPaintingDisabled(true);
190 void GraphicsContext::platformDestroy()
195 AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
197 if (paintingDisabled())
198 return AffineTransform();
200 cairo_t* cr = platformContext()->cr();
202 cairo_get_matrix(cr, &m);
203 return AffineTransform(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
206 PlatformContextCairo* GraphicsContext::platformContext() const
208 return m_data->platformContext;
211 void GraphicsContext::savePlatformState()
213 platformContext()->save();
217 void GraphicsContext::restorePlatformState()
219 platformContext()->restore();
222 platformContext()->shadowBlur().setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur),
223 m_state.shadowOffset,
225 m_state.shadowColorSpace,
226 m_state.shadowsIgnoreTransforms);
229 // Draws a filled rectangle with a stroked border.
230 void GraphicsContext::drawRect(const IntRect& rect)
232 if (paintingDisabled())
235 ASSERT(!rect.isEmpty());
237 cairo_t* cr = platformContext()->cr();
240 fillRectWithColor(cr, rect, fillColor());
242 if (strokeStyle() != NoStroke) {
243 setSourceRGBAFromColor(cr, strokeColor());
246 cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
247 cairo_set_line_width(cr, 1.0);
254 static double calculateStrokePatternOffset(int distance, int patternWidth)
256 // Example: 80 pixels with a width of 30 pixels. Remainder is 20.
257 // The maximum pixels of line we could paint will be 50 pixels.
258 int remainder = distance % patternWidth;
259 int numSegments = (distance - remainder) / patternWidth;
261 // Special case 1px dotted borders for speed.
262 if (patternWidth == 1)
265 bool evenNumberOfSegments = !(numSegments % 2);
267 evenNumberOfSegments = !evenNumberOfSegments;
269 if (evenNumberOfSegments) {
271 return (patternWidth - remainder) + (remainder / 2);
272 return patternWidth / 2;
275 // Odd number of segments.
277 return (patternWidth - remainder) / 2.f;
281 static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2)
283 StrokeStyle style = graphicsContext->strokeStyle();
284 if (style == NoStroke)
287 const Color& strokeColor = graphicsContext->strokeColor();
288 int strokeThickness = floorf(graphicsContext->strokeThickness());
289 if (graphicsContext->strokeThickness() < 1)
292 int patternWidth = 0;
293 if (style == DottedStroke)
294 patternWidth = strokeThickness;
295 else if (style == DashedStroke)
296 patternWidth = 3 * strokeThickness;
298 bool isVerticalLine = point1.x() == point2.x();
299 FloatPoint point1OnPixelBoundaries = point1;
300 FloatPoint point2OnPixelBoundaries = point2;
301 GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style);
303 #if !ENABLE(TIZEN_REMOVE_DRAWLINE_ANTIALIAS_NONE)
304 cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE);
307 // Do a rect fill of our endpoints. This ensures we always have the
308 // appearance of being a border. We then draw the actual dotted/dashed line.
309 FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
310 FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
311 if (isVerticalLine) {
312 firstRect.move(-strokeThickness / 2, -strokeThickness);
313 secondRect.move(-strokeThickness / 2, 0);
315 firstRect.move(-strokeThickness, -strokeThickness / 2);
316 secondRect.move(0, -strokeThickness / 2);
318 fillRectWithColor(context, firstRect, strokeColor);
319 fillRectWithColor(context, secondRect, strokeColor);
321 int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness;
322 double patternOffset = calculateStrokePatternOffset(distance, patternWidth);
323 double patternWidthAsDouble = patternWidth;
324 cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset);
327 setSourceRGBAFromColor(context, strokeColor);
328 cairo_set_line_width(context, strokeThickness);
329 cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y());
330 cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y());
331 cairo_stroke(context);
334 // This is only used to draw borders, so we should not draw shadows.
335 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
337 if (paintingDisabled())
340 cairo_t* cairoContext = platformContext()->cr();
341 cairo_save(cairoContext);
342 drawLineOnCairoContext(this, cairoContext, point1, point2);
343 cairo_restore(cairoContext);
346 // This method is only used to draw the little circles used in lists.
347 void GraphicsContext::drawEllipse(const IntRect& rect)
349 if (paintingDisabled())
352 cairo_t* cr = platformContext()->cr();
354 float yRadius = .5 * rect.height();
355 float xRadius = .5 * rect.width();
356 cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
357 cairo_scale(cr, xRadius, yRadius);
358 cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);
361 if (fillColor().alpha()) {
362 setSourceRGBAFromColor(cr, fillColor());
363 cairo_fill_preserve(cr);
366 if (strokeStyle() != NoStroke) {
367 setSourceRGBAFromColor(cr, strokeColor());
368 cairo_set_line_width(cr, strokeThickness());
374 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
376 if (paintingDisabled() || strokeStyle() == NoStroke)
381 float w = rect.width();
382 float h = rect.height();
383 float scaleFactor = h / w;
384 float reverseScaleFactor = w / h;
386 float hRadius = w / 2;
387 float vRadius = h / 2;
388 float fa = startAngle;
389 float falen = fa + angleSpan;
391 cairo_t* cr = platformContext()->cr();
395 cairo_scale(cr, 1., scaleFactor);
397 cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180);
400 cairo_scale(cr, 1., reverseScaleFactor);
402 int patternWidth = 0;
403 switch (strokeStyle()) {
405 patternWidth = floorf(strokeThickness() / 2.f);
408 patternWidth = 3 * floorf(strokeThickness() / 2.f);
414 setSourceRGBAFromColor(cr, strokeColor());
418 if (hRadius == vRadius)
419 distance = (piFloat * hRadius) / 2.f;
420 else // We are elliptical and will have to estimate the distance
421 distance = (piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.f)) / 2.f;
422 double patternOffset = calculateStrokePatternOffset(floorf(distance), patternWidth);
423 double patternWidthAsDouble = patternWidth;
424 cairo_set_dash(cr, &patternWidthAsDouble, 1, patternOffset);
431 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
433 if (paintingDisabled())
439 cairo_t* cr = platformContext()->cr();
442 cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
443 addConvexPolygonToContext(cr, npoints, points);
445 if (fillColor().alpha()) {
446 setSourceRGBAFromColor(cr, fillColor());
447 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
448 cairo_fill_preserve(cr);
451 if (strokeStyle() != NoStroke) {
452 setSourceRGBAFromColor(cr, strokeColor());
453 cairo_set_line_width(cr, strokeThickness());
461 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
463 if (paintingDisabled())
469 cairo_t* cr = platformContext()->cr();
472 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
473 cairo_antialias_t savedAntialiasRule = cairo_get_antialias(cr);
475 cairo_set_antialias(cr, antialiased ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
476 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
477 addConvexPolygonToContext(cr, numPoints, points);
480 cairo_set_antialias(cr, savedAntialiasRule);
481 cairo_set_fill_rule(cr, savedFillRule);
484 void GraphicsContext::fillPath(const Path& path)
486 if (paintingDisabled())
489 cairo_t* cr = platformContext()->cr();
490 setPathOnCairoContext(cr, path.platformPath()->context());
491 shadowAndFillCurrentCairoPath(this);
494 void GraphicsContext::strokePath(const Path& path)
496 if (paintingDisabled())
499 cairo_t* cr = platformContext()->cr();
500 setPathOnCairoContext(cr, path.platformPath()->context());
501 shadowAndStrokeCurrentCairoPath(this);
504 void GraphicsContext::fillRect(const FloatRect& rect)
506 if (paintingDisabled())
509 cairo_t* cr = platformContext()->cr();
510 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
511 shadowAndFillCurrentCairoPath(this);
514 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
516 if (paintingDisabled())
520 platformContext()->shadowBlur().drawRectShadow(this, rect, RoundedRect::Radii());
522 fillRectWithColor(platformContext()->cr(), rect, color);
525 void GraphicsContext::clip(const FloatRect& rect)
527 if (paintingDisabled())
530 cairo_t* cr = platformContext()->cr();
531 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
532 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
533 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
534 // The rectangular clip function is traditionally not expected to
535 // antialias. If we don't force antialiased clipping here,
536 // edge fringe artifacts may occur at the layer edges
537 // when a transformation is applied to the GraphicsContext
538 // while drawing the transformed layer.
539 cairo_antialias_t savedAntialiasRule = cairo_get_antialias(cr);
540 #if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
541 if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_GL)
542 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
544 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
547 cairo_set_fill_rule(cr, savedFillRule);
548 #if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
549 if (cairo_surface_get_type(cairo_get_target(cr)) != CAIRO_SURFACE_TYPE_GL)
550 cairo_set_antialias(cr, savedAntialiasRule);
552 cairo_set_antialias(cr, savedAntialiasRule);
557 void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
559 if (paintingDisabled())
562 cairo_t* cr = platformContext()->cr();
563 setPathOnCairoContext(cr, path.platformPath()->context());
564 cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
568 IntRect GraphicsContext::clipBounds() const
570 double x1, x2, y1, y2;
571 cairo_clip_extents(platformContext()->cr(), &x1, &y1, &x2, &y2);
572 return enclosingIntRect(FloatRect(x1, y1, x2 - x1, y2 - y1));
575 static inline void adjustFocusRingColor(Color& color)
578 // Force the alpha to 50%. This matches what the Mac does with outline rings.
579 color.setRGB(makeRGBA(color.red(), color.green(), color.blue(), 127));
583 static inline void adjustFocusRingLineWidth(int& width)
590 static inline StrokeStyle focusRingStrokeStyle()
599 void GraphicsContext::drawFocusRing(const Path& path, int width, int /* offset */, const Color& color)
601 // FIXME: We should draw paths that describe a rectangle with rounded corners
602 // so as to be consistent with how we draw rectangular focus rings.
603 Color ringColor = color;
604 adjustFocusRingColor(ringColor);
605 adjustFocusRingLineWidth(width);
607 cairo_t* cr = platformContext()->cr();
609 appendWebCorePathToCairoContext(cr, path);
610 setSourceRGBAFromColor(cr, ringColor);
611 cairo_set_line_width(cr, width);
612 setPlatformStrokeStyle(focusRingStrokeStyle());
617 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
619 #if ENABLE(TIZEN_WEBKIT2_FOCUS_RING)
623 if (paintingDisabled())
626 unsigned rectCount = rects.size();
628 cairo_t* cr = platformContext()->cr();
630 cairo_push_group(cr);
634 #ifdef GTK_API_VERSION_2
635 GdkRegion* reg = gdk_region_new();
637 cairo_region_t* reg = cairo_region_create();
640 for (unsigned i = 0; i < rectCount; i++) {
641 #ifdef GTK_API_VERSION_2
642 GdkRectangle rect = rects[i];
643 gdk_region_union_with_rect(reg, &rect);
645 cairo_rectangle_int_t rect = rects[i];
646 cairo_region_union_rectangle(reg, &rect);
649 gdk_cairo_region(cr, reg);
650 #ifdef GTK_API_VERSION_2
651 gdk_region_destroy(reg);
653 cairo_region_destroy(reg);
656 int radius = (width - 1) / 2;
658 for (unsigned i = 0; i < rectCount; ++i) {
661 path.addRoundedRect(rects[i], FloatSize(radius, radius));
662 appendWebCorePathToCairoContext(cr, path);
665 Color ringColor = color;
666 adjustFocusRingColor(ringColor);
667 adjustFocusRingLineWidth(width);
668 setSourceRGBAFromColor(cr, ringColor);
669 cairo_set_line_width(cr, width);
670 setPlatformStrokeStyle(focusRingStrokeStyle());
672 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
673 cairo_stroke_preserve(cr);
675 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
676 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
679 cairo_pop_group_to_source(cr);
680 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
685 void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
687 if (paintingDisabled())
690 cairo_t* cairoContext = platformContext()->cr();
691 cairo_save(cairoContext);
693 // This bumping of <1 stroke thicknesses matches the one in drawLineOnCairoContext.
694 FloatPoint endPoint(origin + IntSize(width, 0));
695 FloatRect lineExtents(origin, FloatSize(width, strokeThickness()));
697 ShadowBlur& shadow = platformContext()->shadowBlur();
698 if (GraphicsContext* shadowContext = shadow.beginShadowLayer(this, lineExtents)) {
699 drawLineOnCairoContext(this, shadowContext->platformContext()->cr(), origin, endPoint);
700 shadow.endShadowLayer(this);
703 drawLineOnCairoContext(this, cairoContext, origin, endPoint);
704 cairo_restore(cairoContext);
708 #include "DrawErrorUnderline.h"
711 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& origin, float width, DocumentMarkerLineStyle style)
713 if (paintingDisabled())
716 cairo_t* cr = platformContext()->cr();
720 case DocumentMarkerSpellingLineStyle:
721 cairo_set_source_rgb(cr, 1, 0, 0);
723 case DocumentMarkerGrammarLineStyle:
724 cairo_set_source_rgb(cr, 0, 1, 0);
732 // We ignore most of the provided constants in favour of the platform style
733 pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
735 drawErrorUnderline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
741 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
744 double x = frect.x();
745 double y = frect.y();
746 cairo_t* cr = platformContext()->cr();
747 cairo_user_to_device(cr, &x, &y);
750 cairo_device_to_user(cr, &x, &y);
751 result.setX(narrowPrecisionToFloat(x));
752 result.setY(narrowPrecisionToFloat(y));
754 // We must ensure width and height are at least 1 (or -1) when
755 // we're given float values in the range between 0 and 1 (or -1 and 0).
756 double width = frect.width();
757 double height = frect.height();
758 cairo_user_to_device_distance(cr, &width, &height);
759 if (width > -1 && width < 0)
761 else if (width > 0 && width < 1)
764 width = round(width);
765 if (height > -1 && width < 0)
767 else if (height > 0 && height < 1)
770 height = round(height);
771 cairo_device_to_user_distance(cr, &width, &height);
772 result.setWidth(narrowPrecisionToFloat(width));
773 result.setHeight(narrowPrecisionToFloat(height));
778 void GraphicsContext::translate(float x, float y)
780 if (paintingDisabled())
783 cairo_t* cr = platformContext()->cr();
784 cairo_translate(cr, x, y);
785 m_data->translate(x, y);
788 void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
790 // Cairo contexts can't hold separate fill and stroke colors
791 // so we set them just before we actually fill or stroke
794 void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
796 // Cairo contexts can't hold separate fill and stroke colors
797 // so we set them just before we actually fill or stroke
800 void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
802 if (paintingDisabled())
805 cairo_set_line_width(platformContext()->cr(), strokeThickness);
808 #if ENABLE(TIZEN_CANVAS_2D_LINE_JOIN)
809 void GraphicsContext::setPlatformLineJoin(LineJoin lineJoin)
811 if (paintingDisabled())
814 cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER;
820 cairoJoin = CAIRO_LINE_JOIN_ROUND;
823 cairoJoin = CAIRO_LINE_JOIN_BEVEL;
826 cairo_set_line_join(platformContext()->cr(), cairoJoin);
830 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
832 static double dashPattern[] = {5.0, 5.0};
833 static double dotPattern[] = {1.0, 1.0};
835 if (paintingDisabled())
838 switch (strokeStyle) {
840 // FIXME: is it the right way to emulate NoStroke?
841 cairo_set_line_width(platformContext()->cr(), 0);
844 cairo_set_dash(platformContext()->cr(), 0, 0, 0);
847 cairo_set_dash(platformContext()->cr(), dotPattern, 2, 0);
850 cairo_set_dash(platformContext()->cr(), dashPattern, 2, 0);
855 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
860 void GraphicsContext::concatCTM(const AffineTransform& transform)
862 if (paintingDisabled())
865 cairo_t* cr = platformContext()->cr();
866 const cairo_matrix_t matrix = cairo_matrix_t(transform);
867 cairo_transform(cr, &matrix);
868 m_data->concatCTM(transform);
871 void GraphicsContext::setCTM(const AffineTransform& transform)
873 if (paintingDisabled())
876 cairo_t* cr = platformContext()->cr();
877 const cairo_matrix_t matrix = cairo_matrix_t(transform);
878 cairo_set_matrix(cr, &matrix);
879 m_data->setCTM(transform);
882 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
884 if (paintingDisabled())
887 cairo_t* cr = platformContext()->cr();
895 r.inflate(-thickness);
897 appendWebCorePathToCairoContext(cr, p);
899 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
900 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
902 cairo_set_fill_rule(cr, savedFillRule);
905 void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color const& color, ColorSpace)
907 if (paintingDisabled())
910 if (m_state.shadowsIgnoreTransforms) {
911 // Meaning that this graphics context is associated with a CanvasRenderingContext
912 // We flip the height since CG and HTML5 Canvas have opposite Y axis
913 m_state.shadowOffset = FloatSize(size.width(), -size.height());
916 // Cairo doesn't support shadows natively, they are drawn manually in the draw* functions using ShadowBlur.
917 platformContext()->shadowBlur().setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur),
918 m_state.shadowOffset,
920 m_state.shadowColorSpace,
921 m_state.shadowsIgnoreTransforms);
924 void GraphicsContext::clearPlatformShadow()
926 if (paintingDisabled())
929 platformContext()->shadowBlur().clear();
932 #if ENABLE(TIZEN_GRAPHICSCONTEXT_COLLECT_REGION)
933 void GraphicsContext::setCollectClipRegion(bool isCollectRegion)
935 m_data->setCollectRegion(isCollectRegion);
938 void GraphicsContext::collectClipRegion(const IntRect& clipRect)
940 if (m_data->m_isCollectRegion)
941 m_data->collectRegion(clipRect);
945 void GraphicsContext::beginPlatformTransparencyLayer(float opacity)
947 if (paintingDisabled())
950 cairo_t* cr = platformContext()->cr();
951 cairo_push_group(cr);
952 m_data->layers.append(opacity);
955 void GraphicsContext::endPlatformTransparencyLayer()
957 if (paintingDisabled())
960 cairo_t* cr = platformContext()->cr();
962 cairo_pop_group_to_source(cr);
963 #if ENABLE(TIZEN_GRAPHICSCONTEXT_COLLECT_REGION)
964 m_data-> clipWithCollectedRegion(cr);
966 cairo_paint_with_alpha(cr, m_data->layers.last());
967 m_data->layers.removeLast();
970 bool GraphicsContext::supportsTransparencyLayers()
975 void GraphicsContext::clearRect(const FloatRect& rect)
977 if (paintingDisabled())
980 cairo_t* cr = platformContext()->cr();
983 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
984 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
989 void GraphicsContext::strokeRect(const FloatRect& rect, float width)
991 if (paintingDisabled())
994 cairo_t* cr = platformContext()->cr();
996 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
997 cairo_set_line_width(cr, width);
998 shadowAndStrokeCurrentCairoPath(this);
1002 void GraphicsContext::setLineCap(LineCap lineCap)
1004 if (paintingDisabled())
1007 cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT;
1013 cairoCap = CAIRO_LINE_CAP_ROUND;
1016 cairoCap = CAIRO_LINE_CAP_SQUARE;
1019 cairo_set_line_cap(platformContext()->cr(), cairoCap);
1022 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
1024 cairo_set_dash(platformContext()->cr(), dashes.data(), dashes.size(), dashOffset);
1027 void GraphicsContext::setLineJoin(LineJoin lineJoin)
1029 if (paintingDisabled())
1032 #if ENABLE(TIZEN_CANVAS_2D_LINE_JOIN)
1033 m_state.lineJoin = lineJoin;
1034 setPlatformLineJoin(lineJoin);
1036 cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER;
1042 cairoJoin = CAIRO_LINE_JOIN_ROUND;
1045 cairoJoin = CAIRO_LINE_JOIN_BEVEL;
1048 cairo_set_line_join(platformContext()->cr(), cairoJoin);
1052 void GraphicsContext::setMiterLimit(float miter)
1054 if (paintingDisabled())
1057 cairo_set_miter_limit(platformContext()->cr(), miter);
1060 void GraphicsContext::setAlpha(float alpha)
1062 platformContext()->setGlobalAlpha(alpha);
1065 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
1067 if (paintingDisabled())
1070 cairo_set_operator(platformContext()->cr(), toCairoOperator(op));
1073 void GraphicsContext::clip(const Path& path)
1075 if (paintingDisabled())
1078 cairo_t* cr = platformContext()->cr();
1079 OwnPtr<cairo_path_t> pathCopy = adoptPtr(cairo_copy_path(path.platformPath()->context()));
1080 cairo_append_path(cr, pathCopy.get());
1081 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
1082 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
1084 cairo_set_fill_rule(cr, savedFillRule);
1088 void GraphicsContext::canvasClip(const Path& path)
1093 void GraphicsContext::clipOut(const Path& path)
1095 if (paintingDisabled())
1098 cairo_t* cr = platformContext()->cr();
1099 double x1, y1, x2, y2;
1100 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
1101 cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
1102 appendWebCorePathToCairoContext(cr, path);
1104 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
1105 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
1107 cairo_set_fill_rule(cr, savedFillRule);
1110 void GraphicsContext::rotate(float radians)
1112 if (paintingDisabled())
1115 cairo_rotate(platformContext()->cr(), radians);
1116 m_data->rotate(radians);
1119 void GraphicsContext::scale(const FloatSize& size)
1121 if (paintingDisabled())
1124 cairo_scale(platformContext()->cr(), size.width(), size.height());
1125 m_data->scale(size);
1128 void GraphicsContext::clipOut(const IntRect& r)
1130 if (paintingDisabled())
1133 cairo_t* cr = platformContext()->cr();
1134 double x1, y1, x2, y2;
1135 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
1136 cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
1137 cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
1138 cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
1139 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
1141 cairo_set_fill_rule(cr, savedFillRule);
1144 static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile)
1146 FloatPoint phase = dest.location();
1147 phase.move(-tile.x(), -tile.y());
1152 void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
1154 if (paintingDisabled())
1158 platformContext()->shadowBlur().drawRectShadow(this, r, RoundedRect::Radii(topLeft, topRight, bottomLeft, bottomRight));
1160 cairo_t* cr = platformContext()->cr();
1163 path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight);
1164 appendWebCorePathToCairoContext(cr, path);
1165 setSourceRGBAFromColor(cr, color);
1171 void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose)
1173 m_data->expose = expose;
1176 GdkEventExpose* GraphicsContext::gdkExposeEvent() const
1178 return m_data->expose;
1181 GdkWindow* GraphicsContext::gdkWindow() const
1183 if (!m_data->expose)
1186 return m_data->expose->window;
1190 void GraphicsContext::setPlatformShouldAntialias(bool enable)
1192 if (paintingDisabled())
1195 // When true, use the default Cairo backend antialias mode (usually this
1196 // enables standard 'grayscale' antialiasing); false to explicitly disable
1197 // antialiasing. This is the same strategy as used in drawConvexPolygon().
1198 cairo_set_antialias(platformContext()->cr(), enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
1201 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality)
1203 platformContext()->setImageInterpolationQuality(quality);
1206 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
1208 return platformContext()->imageInterpolationQuality();
1211 #if ENABLE(3D_RENDERING) && USE(TEXTURE_MAPPER)
1212 TransformationMatrix GraphicsContext::get3DTransform() const
1214 // FIXME: Can we approximate the transformation better than this?
1215 return getCTM().toTransformationMatrix();
1218 void GraphicsContext::concat3DTransform(const TransformationMatrix& transform)
1220 concatCTM(transform.toAffineTransform());
1223 void GraphicsContext::set3DTransform(const TransformationMatrix& transform)
1225 setCTM(transform.toAffineTransform());
1229 } // namespace WebCore
1231 #endif // USE(CAIRO)