18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define _USE_MATH_DEFINES 1
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "GraphicsContextCG.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
315e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block#include "AffineTransform.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FloatConversion.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContextPlatformPrivateCG.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ImageBuffer.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "KURL.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Path.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Pattern.h"
382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "ShadowBlur.h"
39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
40cad810f21b803229eb11403f9209855525a25d57Steve Block#include <CoreGraphics/CoreGraphics.h>
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/MathExtras.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/OwnArrayPtr.h>
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/RetainPtr.h>
44f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <wtf/UnusedParam.h>
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
46d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
47d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "WebCoreSystemInterface.h"
48d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
49d0825bca7fe65beaee391d30da42e937db621564Steve Block
50d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(WIN)
51d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <WebKitSystemInterface/WebKitSystemInterface.h>
52d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
53d0825bca7fe65beaee391d30da42e937db621564Steve Block
54d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
55643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
56643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
57643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum.
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#define HAVE_CG_INTERPOLATION_MEDIUM 1
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
61643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
62643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// Targeting 10.6 or later: use kCGInterpolationMedium.
63643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#define WTF_USE_CG_INTERPOLATION_MEDIUM 1
64643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif
65643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
66643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif
67643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
6881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch// Undocumented CGContextSetCTM function, available at least since 10.4.
6981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochextern "C" {
7081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
7181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch};
7281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
77643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    CGContextSetFillColorWithColor(context, cachedCGColor(color, colorSpace));
80643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
81643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
82643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockstatic void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace)
83643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    CGContextSetStrokeColorWithColor(context, cachedCGColor(color, colorSpace));
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockCGColorSpaceRef deviceRGBColorSpaceRef()
888a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
898a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB();
908a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return deviceSpace;
918a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockCGColorSpaceRef sRGBColorSpaceRef()
948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    // FIXME: Windows should be able to use kCGColorSpaceSRGB, this is tracked by http://webkit.org/b/31363.
968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER)
978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return deviceRGBColorSpaceRef();
988a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#else
998a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    static CGColorSpaceRef sRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
1008a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return sRGBSpace;
1018a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#endif
1028a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
1038a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
104a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochCGColorSpaceRef linearRGBColorSpaceRef()
105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
106a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: Windows should be able to use kCGColorSpaceGenericRGBLinear, this is tracked by http://webkit.org/b/31363.
107a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER)
108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return deviceRGBColorSpaceRef();
109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#else
110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    static CGColorSpaceRef linearRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return linearRGBSpace;
112a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif
113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
115f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::platformInit(CGContextRef cgContext)
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
117f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    m_data = new GraphicsContextPlatformPrivate(cgContext);
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    setPaintingDisabled(!cgContext);
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (cgContext) {
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Make sure the context starts in sync with our state.
121643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setPlatformFillColor(fillColor(), fillColorSpace());
122643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setPlatformStrokeColor(strokeColor(), strokeColorSpace());
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
126f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::platformDestroy()
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    delete m_data;
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectCGContextRef GraphicsContext::platformContext() const
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!paintingDisabled());
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_data->m_cgContext);
135231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return m_data->m_cgContext.get();
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::savePlatformState()
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Note: Do not use this function within this class implementation, since we want to avoid the extra
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // save of the secondary context (in GraphicsContextPlatformPrivateCG.h).
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSaveGState(platformContext());
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->save();
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::restorePlatformState()
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Note: Do not use this function within this class implementation, since we want to avoid the extra
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // restore of the secondary context (in GraphicsContextPlatformPrivateCG.h).
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRestoreGState(platformContext());
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->restore();
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Draws a filled rectangle with a stroked border.
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::drawRect(const IntRect& rect)
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: this function does not handle patterns and gradients
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // like drawPath does, it probably should.
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    CGContextFillRect(context, rect);
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (strokeStyle() != NoStroke) {
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // We do a fill of four rects to simulate the stroke of a border.
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Color oldFillColor = fillColor();
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (oldFillColor != strokeColor())
171643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            setCGFillColor(context, strokeColor(), strokeColorSpace());
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGRect rects[4] = {
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            FloatRect(rect.x(), rect.y(), rect.width(), 1),
1742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            FloatRect(rect.x(), rect.maxY() - 1, rect.width(), 1),
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2),
1762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            FloatRect(rect.maxX() - 1, rect.y() + 1, 1, rect.height() - 2)
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        };
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextFillRects(context, rects, 4);
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (oldFillColor != strokeColor())
180643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            setCGFillColor(context, oldFillColor, fillColorSpace());
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// This is only used to draw borders.
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (strokeStyle() == NoStroke)
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float width = strokeThickness();
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FloatPoint p1 = point1;
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FloatPoint p2 = point2;
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isVerticalLine = (p1.x() == p2.x());
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // works out.  For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g.,
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isVerticalLine) {
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p1.move(0, width);
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p2.move(0, -width);
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p1.move(width, 0);
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p2.move(-width, 0);
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (((int)width) % 2) {
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isVerticalLine) {
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // We're a vertical line.  Adjust our x.
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p1.move(0.5f, 0.0f);
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p2.move(0.5f, 0.0f);
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // We're a horizontal line. Adjust our y.
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p1.move(0.0f, 0.5f);
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p2.move(0.0f, 0.5f);
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int patWidth = 0;
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (strokeStyle()) {
227231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case NoStroke:
228231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case SolidStroke:
229231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
230231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case DottedStroke:
231231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        patWidth = (int)width;
232231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
233231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case DashedStroke:
234231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        patWidth = 3 * (int)width;
235231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
239231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
240635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (shouldAntialias())
241635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSetShouldAntialias(context, false);
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (patWidth) {
244635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSaveGState(context);
245635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Do a rect fill of our endpoints.  This ensures we always have the
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // appearance of being a border.  We then draw the actual dotted/dashed line.
248643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setCGFillColor(context, strokeColor(), strokeColorSpace());  // The save/restore make it safe to mutate the fill color here without setting it back to the old color.
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isVerticalLine) {
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width));
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width));
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width));
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width));
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Example: 80 pixels with a width of 30 pixels.
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remainder is 20.  The maximum pixels of line we could paint
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // will be 50 pixels.
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int remainder = distance % patWidth;
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int coverage = distance - remainder;
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int numSegments = coverage / patWidth;
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float patternOffset = 0.0f;
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Special case 1px dotted borders for speed.
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (patWidth == 1)
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            patternOffset = 1.0f;
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
270231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            bool evenNumberOfSegments = !(numSegments % 2);
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (remainder)
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                evenNumberOfSegments = !evenNumberOfSegments;
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (evenNumberOfSegments) {
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (remainder) {
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset += patWidth - remainder;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset += remainder / 2;
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset = patWidth / 2;
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (remainder)
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset = (patWidth - remainder)/2;
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
284231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const CGFloat dottedLine[2] = { patWidth, patWidth };
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextSetLineDash(context, patternOffset, dottedLine, 2);
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextBeginPath(context);
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextMoveToPoint(context, p1.x(), p1.y());
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddLineToPoint(context, p2.x(), p2.y());
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextStrokePath(context);
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (patWidth)
296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextRestoreGState(context);
297231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (shouldAntialias())
299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSetShouldAntialias(context, true);
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// This method is only used to draw the little circles used in lists.
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::drawEllipse(const IntRect& rect)
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
308f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    Path path;
309f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    path.addEllipse(rect);
310f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    drawPath(path);
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
3165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f)
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSaveGState(context);
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextBeginPath(context);
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetShouldAntialias(context, false);
323231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int x = rect.x();
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int y = rect.y();
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float w = (float)rect.width();
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float h = (float)rect.height();
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float scaleFactor = h / w;
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float reverseScaleFactor = w / h;
330231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (w != h)
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        scale(FloatSize(1, scaleFactor));
333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float hRadius = w / 2;
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float vRadius = h / 2;
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float fa = startAngle;
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float falen =  fa + angleSpan;
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float start = -fa * piFloat / 180.0f;
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float end = -falen * piFloat / 180.0f;
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true);
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (w != h)
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        scale(FloatSize(1, reverseScaleFactor));
344231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float width = strokeThickness();
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int patWidth = 0;
347231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (strokeStyle()) {
349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case DottedStroke:
350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        patWidth = (int)(width / 2);
351231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
352231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case DashedStroke:
353231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        patWidth = 3 * (int)(width / 2);
354231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
355231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    default:
356231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
358231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (patWidth) {
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Example: 80 pixels with a width of 30 pixels.
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remainder is 20.  The maximum pixels of line we could paint
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // will be 50 pixels.
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int distance;
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hRadius == vRadius)
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            distance = static_cast<int>((piFloat * hRadius) / 2.0f);
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else // We are elliptical and will have to estimate the distance
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f);
368231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int remainder = distance % patWidth;
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int coverage = distance - remainder;
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int numSegments = coverage / patWidth;
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float patternOffset = 0.0f;
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Special case 1px dotted borders for speed.
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (patWidth == 1)
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            patternOffset = 1.0f;
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
378231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            bool evenNumberOfSegments = !(numSegments % 2);
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (remainder)
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                evenNumberOfSegments = !evenNumberOfSegments;
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (evenNumberOfSegments) {
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (remainder) {
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset += patWidth - remainder;
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset += remainder / 2.0f;
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset = patWidth / 2.0f;
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (remainder)
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    patternOffset = (patWidth - remainder) / 2.0f;
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
392231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const CGFloat dottedLine[2] = { patWidth, patWidth };
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextSetLineDash(context, patternOffset, dottedLine, 2);
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextStrokePath(context);
398231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRestoreGState(context);
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
402f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochstatic void addConvexPolygonToPath(Path& path, size_t numberOfPoints, const FloatPoint* points)
403ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{
404f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    ASSERT(numberOfPoints > 0);
405f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
406f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    path.moveTo(points[0]);
407f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    for (size_t i = 1; i < numberOfPoints; ++i)
408f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        path.addLineTo(points[i]);
409f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    path.closeSubpath();
410ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block}
411ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
412f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::drawConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialiased)
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (paintingDisabled())
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
417f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (numberOfPoints <= 1)
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (antialiased != shouldAntialias())
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSetShouldAntialias(context, antialiased);
424231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
425f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    Path path;
426f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    addConvexPolygonToPath(path, numberOfPoints, points);
427f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    drawPath(path);
428231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (antialiased != shouldAntialias())
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSetShouldAntialias(context, shouldAntialias());
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
433f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::clipConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialias)
434ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{
435ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    if (paintingDisabled())
436ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        return;
437ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
438f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (numberOfPoints <= 1)
439ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        return;
4400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
4410617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    CGContextRef context = platformContext();
4420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
4430617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (antialias != shouldAntialias())
4440617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        CGContextSetShouldAntialias(context, antialias);
445f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
446f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    Path path;
447f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    addConvexPolygonToPath(path, numberOfPoints, points);
448f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    clipPath(path, RULE_NONZERO);
4490617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
4500617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (antialias != shouldAntialias())
4510617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        CGContextSetShouldAntialias(context, shouldAntialias());
452ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block}
453ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid GraphicsContext::applyStrokePattern()
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CGContextRef cgContext = platformContext();
457231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
458f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.strokePattern->createPlatformPattern(getCTM()));
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!platformPattern)
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
462231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
463231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGContextSetStrokeColorSpace(cgContext, patternSpace.get());
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const CGFloat patternAlpha = 1;
466231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGContextSetStrokePattern(cgContext, platformPattern.get(), &patternAlpha);
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid GraphicsContext::applyFillPattern()
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
471635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CGContextRef cgContext = platformContext();
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
473f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_state.fillPattern->createPlatformPattern(getCTM()));
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!platformPattern)
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
477231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0));
478231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGContextSetFillColorSpace(cgContext, patternSpace.get());
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const CGFloat patternAlpha = 1;
481231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGContextSetFillPattern(cgContext, platformPattern.get(), &patternAlpha);
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode)
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
486643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    bool shouldFill = state.fillPattern || state.fillColor.alpha();
487643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    bool shouldStroke = state.strokePattern || (state.strokeStyle != NoStroke && state.strokeColor.alpha());
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool useEOFill = state.fillRule == RULE_EVENODD;
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (shouldFill) {
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (shouldStroke) {
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (useEOFill)
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                mode = kCGPathEOFillStroke;
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                mode = kCGPathFillStroke;
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else { // fill, no stroke
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (useEOFill)
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                mode = kCGPathEOFill;
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                mode = kCGPathFill;
5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Setting mode to kCGPathStroke even if shouldStroke is false. In that case, we return false and mode will not be used,
504d0825bca7fe65beaee391d30da42e937db621564Steve Block        // but the compiler will not complain about an uninitialized variable.
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        mode = kCGPathStroke;
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return shouldFill || shouldStroke;
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
511f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::drawPath(const Path& path)
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
517f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    const GraphicsContextState& state = m_state;
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
519643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (state.fillGradient || state.strokeGradient) {
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // We don't have any optimized way to fill & stroke a path using gradients
521f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        // FIXME: Be smarter about this.
522f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        fillPath(path);
523f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        strokePath(path);
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
526231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
527f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextBeginPath(context);
528f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextAddPath(context, path.platformPath());
529f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
530643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (state.fillPattern)
531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        applyFillPattern();
532643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (state.strokePattern)
533635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        applyStrokePattern();
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGPathDrawingMode drawingMode;
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (calculateDrawingMode(state, drawingMode))
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextDrawPath(context, drawingMode);
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline void fillPathWithFillRule(CGContextRef context, WindRule fillRule)
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fillRule == RULE_EVENODD)
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextEOFillPath(context);
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextFillPath(context);
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
548f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::fillPath(const Path& path)
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
5518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
554643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
555f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.fillGradient) {
55665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if (hasShadow()) {
55765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            FloatRect rect = path.boundingRect();
55865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
55965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextRef layerContext = CGLayerGetContext(layer);
56065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
56165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextTranslateCTM(layerContext, -rect.x(), -rect.y());
56265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextBeginPath(layerContext);
56365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextAddPath(layerContext, path.platformPath());
56465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform());
56565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
56665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if (fillRule() == RULE_EVENODD)
56765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                CGContextEOClip(layerContext);
56865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            else
56965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                CGContextClip(layerContext);
57065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
57165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            m_state.fillGradient->paint(layerContext);
5722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer);
57365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGLayerRelease(layer);
57465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        } else {
57565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextBeginPath(context);
57665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextAddPath(context, path.platformPath());
57765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextSaveGState(context);
57865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform());
57965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
58065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            if (fillRule() == RULE_EVENODD)
58165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                CGContextEOClip(context);
58265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            else
58365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                CGContextClip(context);
58465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
58565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            m_state.fillGradient->paint(this);
58665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            CGContextRestoreGState(context);
58765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        }
58865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
589643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
591643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
59265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    CGContextBeginPath(context);
59365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    CGContextAddPath(context, path.platformPath());
59465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
595f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.fillPattern)
596643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        applyFillPattern();
597643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    fillPathWithFillRule(context, fillRule());
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
600f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::strokePath(const Path& path)
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
606643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
607f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextBeginPath(context);
608f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextAddPath(context, path.platformPath());
609f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
610f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.strokeGradient) {
61181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (hasShadow()) {
61281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            FloatRect rect = path.boundingRect();
61381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float lineWidth = strokeThickness();
61481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float doubleLineWidth = lineWidth * 2;
61581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float layerWidth = ceilf(rect.width() + doubleLineWidth);
61681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float layerHeight = ceilf(rect.height() + doubleLineWidth);
61781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
61881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0);
61981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextRef layerContext = CGLayerGetContext(layer);
62081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextSetLineWidth(layerContext, lineWidth);
62181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
62281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // Compensate for the line width, otherwise the layer's top-left corner would be
62381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // aligned with the rect's top-left corner. This would result in leaving pixels out of
62481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // the layer on the left and top sides.
62581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float translationX = lineWidth - rect.x();
62681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float translationY = lineWidth - rect.y();
62781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextTranslateCTM(layerContext, translationX, translationY);
62881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
62981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextAddPath(layerContext, path.platformPath());
63081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextReplacePathWithStrokedPath(layerContext);
63181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextClip(layerContext);
63281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextConcatCTM(layerContext, m_state.strokeGradient->gradientSpaceTransform());
63381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            m_state.strokeGradient->paint(layerContext);
63481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
63581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float destinationX = roundf(rect.x() - lineWidth);
63681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            float destinationY = roundf(rect.y() - lineWidth);
63781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer);
63881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGLayerRelease(layer);
63981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else {
64081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextSaveGState(context);
64181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextReplacePathWithStrokedPath(context);
64281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextClip(context);
64381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform());
64481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            m_state.strokeGradient->paint(this);
64581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextRestoreGState(context);
64681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
647643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
6488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
649643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
650f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.strokePattern)
651643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        applyStrokePattern();
652643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    CGContextStrokePath(context);
6538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6552fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic float radiusToLegacyRadius(float radius)
6562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
6572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius;
6582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
6592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6602fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic bool hasBlurredShadow(const GraphicsContextState& state)
6612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
6622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return state.shadowColor.isValid() && state.shadowColor.alpha() && state.shadowBlur;
6632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
6642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::fillRect(const FloatRect& rect)
6668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
669643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
6708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
671643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
672f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.fillGradient) {
6738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextSaveGState(context);
674cad810f21b803229eb11403f9209855525a25d57Steve Block        if (hasShadow()) {
675cad810f21b803229eb11403f9209855525a25d57Steve Block            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
676cad810f21b803229eb11403f9209855525a25d57Steve Block            CGContextRef layerContext = CGLayerGetContext(layer);
6772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextTranslateCTM(layerContext, -rect.x(), -rect.y());
6792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextAddRect(layerContext, rect);
6802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextClip(layerContext);
6812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform());
683cad810f21b803229eb11403f9209855525a25d57Steve Block            m_state.fillGradient->paint(layerContext);
6842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer);
685cad810f21b803229eb11403f9209855525a25d57Steve Block            CGLayerRelease(layer);
686cad810f21b803229eb11403f9209855525a25d57Steve Block        } else {
687cad810f21b803229eb11403f9209855525a25d57Steve Block            CGContextClipToRect(context, rect);
688ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            CGContextConcatCTM(context, m_state.fillGradient->gradientSpaceTransform());
689cad810f21b803229eb11403f9209855525a25d57Steve Block            m_state.fillGradient->paint(this);
690cad810f21b803229eb11403f9209855525a25d57Steve Block        }
6918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CGContextRestoreGState(context);
692643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
694643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
695f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.fillPattern)
696643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        applyFillPattern();
6972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
6982bde8e466a4451c7319e3a072d118917957d6554Steve Block    bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet.
6992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow) {
7002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur;
7012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Turn off CG shadows.
7022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSaveGState(context);
7032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
7042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace);
7062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii());
7072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
7082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
709643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    CGContextFillRect(context, rect);
7102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow)
7122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextRestoreGState(context);
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
715643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
7168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
7188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
719a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
7205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    CGContextRef context = platformContext();
7215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Color oldFillColor = fillColor();
722643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ColorSpace oldColorSpace = fillColorSpace();
723643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
724643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (oldFillColor != color || oldColorSpace != colorSpace)
725a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        setCGFillColor(context, color, colorSpace);
726643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
7272bde8e466a4451c7319e3a072d118917957d6554Steve Block    bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet.
7282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow) {
7292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur;
7302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Turn off CG shadows.
7312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSaveGState(context);
7322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
7332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace);
7352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii());
7362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
7372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    CGContextFillRect(context, rect);
7392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow)
7412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextRestoreGState(context);
742643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
743643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (oldFillColor != color || oldColorSpace != colorSpace)
744a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        setCGFillColor(context, oldFillColor, oldColorSpace);
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
747643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (paintingDisabled())
7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Color oldFillColor = fillColor();
754643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ColorSpace oldColorSpace = fillColorSpace();
755643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
756643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (oldFillColor != color || oldColorSpace != colorSpace)
757643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setCGFillColor(context, color, colorSpace);
7588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7592bde8e466a4451c7319e3a072d118917957d6554Steve Block    bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet.
7602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow) {
7612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur;
7622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Turn off CG shadows.
7642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSaveGState(context);
7652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
7662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace);
7682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii(topLeft, topRight, bottomLeft, bottomRight));
7692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
7702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    bool equalWidths = (topLeft.width() == topRight.width() && topRight.width() == bottomLeft.width() && bottomLeft.width() == bottomRight.width());
7722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    bool equalHeights = (topLeft.height() == bottomLeft.height() && bottomLeft.height() == topRight.height() && topRight.height() == bottomRight.height());
7732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (equalWidths && equalHeights && topLeft.width() * 2 == rect.width() && topLeft.height() * 2 == rect.height())
7742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        CGContextFillEllipseInRect(context, rect);
7752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    else {
7762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        Path path;
7772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
7782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        fillPath(path);
7792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow)
7822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextRestoreGState(context);
7832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
784643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (oldFillColor != color || oldColorSpace != colorSpace)
785643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setCGFillColor(context, oldFillColor, oldColorSpace);
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7882fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace)
7892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
7902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (paintingDisabled())
7912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return;
7922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    CGContextRef context = platformContext();
7942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    Path path;
7962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    path.addRect(rect);
7972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
7982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (!roundedHoleRect.radii().isZero())
7992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        path.addRoundedRect(roundedHoleRect);
8002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    else
8012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        path.addRect(roundedHoleRect.rect());
8022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    WindRule oldFillRule = fillRule();
8042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    Color oldFillColor = fillColor();
8052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ColorSpace oldFillColorSpace = fillColorSpace();
8062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    setFillRule(RULE_EVENODD);
8082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    setFillColor(color, colorSpace);
8092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // fillRectWithRoundedHole() assumes that the edges of rect are clipped out, so we only care about shadows cast around inside the hole.
8112bde8e466a4451c7319e3a072d118917957d6554Steve Block    bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms;
8122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow) {
8132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur;
8142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Turn off CG shadows.
8162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSaveGState(context);
8172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
8182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        ShadowBlur contextShadow(shadowBlur, m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace);
8202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        contextShadow.drawInsetShadow(this, rect, roundedHoleRect.rect(), roundedHoleRect.radii());
8212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
8222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    fillPath(path);
8242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (drawOwnShadow)
8262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        CGContextRestoreGState(context);
8272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    setFillRule(oldFillRule);
8292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    setFillColor(oldFillColor, oldFillColorSpace);
8302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
8312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clip(const FloatRect& rect)
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
8358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextClipToRect(platformContext(), rect);
8378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->clip(rect);
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clipOut(const IntRect& rect)
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
844231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect };
8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextBeginPath(platformContext());
8478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddRects(platformContext(), rects, 2);
8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextEOClip(platformContext());
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
851f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::clipPath(const Path& path, WindRule clipRule)
852635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
853635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (paintingDisabled())
854635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
855635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
856f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (path.isEmpty())
857f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return;
858f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
859635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CGContextRef context = platformContext();
860635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
861f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextBeginPath(platformContext());
862f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextAddPath(platformContext(), path.platformPath());
863f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
864f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (clipRule == RULE_EVENODD)
865f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        CGContextEOClip(context);
866f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    else
867f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        CGContextClip(context);
868635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
869635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
8702fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockIntRect GraphicsContext::clipBounds() const
8712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
8722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return enclosingIntRect(CGContextGetClipBoundingBox(platformContext()));
8732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
8742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    clip(rect);
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
882231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
8838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Add outer ellipse
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
8858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Add inner ellipse.
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness,
8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
888231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextEOClip(context);
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::beginTransparencyLayer(float opacity)
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSaveGState(context);
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetAlpha(context, opacity);
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextBeginTransparencyLayer(context, 0);
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->beginTransparencyLayer();
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::endTransparencyLayer()
9058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextEndTransparencyLayer(context);
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRestoreGState(context);
9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->endTransparencyLayer();
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
91506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenvoid GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, const Color& color, ColorSpace colorSpace)
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // FIXME: we could avoid the shadow setup cost when we know we'll render the shadow ourselves.
9212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
922d0825bca7fe65beaee391d30da42e937db621564Steve Block    CGFloat xOffset = offset.width();
923d0825bca7fe65beaee391d30da42e937db621564Steve Block    CGFloat yOffset = offset.height();
924635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CGFloat blurRadius = blur;
9258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
9268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
927f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (!m_state.shadowsIgnoreTransforms) {
928d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGAffineTransform userToBaseCTM = wkGetUserToBaseCTM(context);
9298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
930d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGFloat A = userToBaseCTM.a * userToBaseCTM.a + userToBaseCTM.b * userToBaseCTM.b;
931d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGFloat B = userToBaseCTM.a * userToBaseCTM.c + userToBaseCTM.b * userToBaseCTM.d;
932635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGFloat C = B;
933d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGFloat D = userToBaseCTM.c * userToBaseCTM.c + userToBaseCTM.d * userToBaseCTM.d;
9348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
935635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9372bde8e466a4451c7319e3a072d118917957d6554Steve Block        blurRadius = blur * smallEigenvalue;
9388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
939d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGSize offsetInBaseSpace = CGSizeApplyAffineTransform(offset, userToBaseCTM);
940635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
941d0825bca7fe65beaee391d30da42e937db621564Steve Block        xOffset = offsetInBaseSpace.width;
942d0825bca7fe65beaee391d30da42e937db621564Steve Block        yOffset = offsetInBaseSpace.height;
943635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9452bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
9462bde8e466a4451c7319e3a072d118917957d6554Steve Block    blurRadius = min(blurRadius, narrowPrecisionToCGFloat(1000.0));
9472bde8e466a4451c7319e3a072d118917957d6554Steve Block
9488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // to the desired integer.
9508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
951d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (xOffset > 0)
952d0825bca7fe65beaee391d30da42e937db621564Steve Block        xOffset += extraShadowOffset;
953d0825bca7fe65beaee391d30da42e937db621564Steve Block    else if (xOffset < 0)
954d0825bca7fe65beaee391d30da42e937db621564Steve Block        xOffset -= extraShadowOffset;
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
956d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (yOffset > 0)
957d0825bca7fe65beaee391d30da42e937db621564Steve Block        yOffset += extraShadowOffset;
958d0825bca7fe65beaee391d30da42e937db621564Steve Block    else if (yOffset < 0)
959d0825bca7fe65beaee391d30da42e937db621564Steve Block        yOffset -= extraShadowOffset;
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check for an invalid color, as this means that the color was not set for the shadow
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // and we should therefore just use the default shadow color.
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!color.isValid())
964d0825bca7fe65beaee391d30da42e937db621564Steve Block        CGContextSetShadow(context, CGSizeMake(xOffset, yOffset), blurRadius);
965a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    else
966a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        CGContextSetShadowWithColor(context, CGSizeMake(xOffset, yOffset), blurRadius, cachedCGColor(color, colorSpace));
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clearPlatformShadow()
9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
9748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setMiterLimit(float limit)
9778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetMiterLimit(platformContext(), limit);
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setAlpha(float alpha)
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetAlpha(platformContext(), alpha);
9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clearRect(const FloatRect& r)
9918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
9938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
9948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextClearRect(platformContext(), r);
9958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
99781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
9988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
10008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1001635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1002635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CGContextRef context = platformContext();
1003643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1004f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.strokeGradient) {
100581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (hasShadow()) {
100681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float doubleLineWidth = lineWidth * 2;
100781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float layerWidth = ceilf(rect.width() + doubleLineWidth);
100881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float layerHeight = ceilf(rect.height() + doubleLineWidth);
100981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0);
101081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
101181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextRef layerContext = CGLayerGetContext(layer);
101281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            m_state.strokeThickness = lineWidth;
101381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextSetLineWidth(layerContext, lineWidth);
101481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
101581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // Compensate for the line width, otherwise the layer's top-left corner would be
101681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // aligned with the rect's top-left corner. This would result in leaving pixels out of
101781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // the layer on the left and top sides.
101881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float translationX = lineWidth - rect.x();
101981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float translationY = lineWidth - rect.y();
102081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextTranslateCTM(layerContext, translationX, translationY);
102181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
102281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextAddRect(layerContext, rect);
102381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextReplacePathWithStrokedPath(layerContext);
102481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextClip(layerContext);
102581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextConcatCTM(layerContext, m_state.strokeGradient->gradientSpaceTransform());
102681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            m_state.strokeGradient->paint(layerContext);
102781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
102881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float destinationX = roundf(rect.x() - lineWidth);
102981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            const float destinationY = roundf(rect.y() - lineWidth);
103081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer);
103181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGLayerRelease(layer);
103281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else {
103381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextSaveGState(context);
103481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            setStrokeThickness(lineWidth);
103581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextAddRect(context, rect);
103681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextReplacePathWithStrokedPath(context);
103781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextClip(context);
103881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform());
103981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            m_state.strokeGradient->paint(this);
104081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            CGContextRestoreGState(context);
104181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
1042643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
1043635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
1044643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1045f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (m_state.strokePattern)
1046643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        applyStrokePattern();
104781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    CGContextStrokeRectWithWidth(context, rect, lineWidth);
10488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setLineCap(LineCap cap)
10518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
10538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
10548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (cap) {
1055231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case ButtCap:
1056231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineCap(platformContext(), kCGLineCapButt);
1057231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1058231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case RoundCap:
1059231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineCap(platformContext(), kCGLineCapRound);
1060231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1061231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case SquareCap:
1062231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineCap(platformContext(), kCGLineCapSquare);
1063231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
10648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
10688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size());
10708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setLineJoin(LineJoin join)
10738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
10758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
10768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (join) {
1077231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case MiterJoin:
1078231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineJoin(platformContext(), kCGLineJoinMiter);
1079231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1080231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case RoundJoin:
1081231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineJoin(platformContext(), kCGLineJoinRound);
1082231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1083231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case BevelJoin:
1084231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetLineJoin(platformContext(), kCGLineJoinBevel);
1085231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
10868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clip(const Path& path)
10908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
10928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
10938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
1094f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
1095f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // CGContextClip does nothing if the path is empty, so in this case, we
1096f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // instead clip against a zero rect to reduce the clipping region to
1097f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // nothing - which is the intended behavior of clip() if the path is empty.
1098f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (path.isEmpty())
1099f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CGContextClipToRect(context, CGRectZero);
1100f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    else {
1101f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CGContextBeginPath(context);
1102f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CGContextAddPath(context, path.platformPath());
1103f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        CGContextClip(context);
1104f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    }
11058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->clip(path);
11068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1108cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockvoid GraphicsContext::canvasClip(const Path& path)
1109cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{
1110cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    clip(path);
1111cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block}
1112cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
11138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::clipOut(const Path& path)
11148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
11168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1117231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
11188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextBeginPath(platformContext());
11198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
11208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextAddPath(platformContext(), path.platformPath());
11218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextEOClip(platformContext());
11228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::scale(const FloatSize& size)
11258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
11278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextScaleCTM(platformContext(), size.width(), size.height());
11298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->scale(size);
11308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
11318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::rotate(float angle)
11348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
11368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRotateCTM(platformContext(), angle);
11388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->rotate(angle);
11398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
11408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::translate(float x, float y)
11438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
11458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextTranslateCTM(platformContext(), x, y);
11478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->translate(x, y);
11488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
11498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11515e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Blockvoid GraphicsContext::concatCTM(const AffineTransform& transform)
11525e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{
11535e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    if (paintingDisabled())
11545e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        return;
11555e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    CGContextConcatCTM(platformContext(), transform);
11565e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    m_data->concatCTM(transform);
11575e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
11585e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block}
11595e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
116081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid GraphicsContext::setCTM(const AffineTransform& transform)
116181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
116281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (paintingDisabled())
116381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return;
116481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    CGContextSetCTM(platformContext(), transform);
116581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    m_data->setCTM(transform);
116681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    m_data->m_userToDeviceTransformKnownToBeIdentity = false;
116781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
116881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
11698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockAffineTransform GraphicsContext::getCTM() const
11705e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block{
11715e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    CGAffineTransform t = CGContextGetCTM(platformContext());
11725e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block    return AffineTransform(t.a, t.b, t.c, t.d, t.tx, t.ty);
11735e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block}
11745e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block
11752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben MurdochFloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode roundingMode)
11768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if PLATFORM(CHROMIUM)
11782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return rect;
11792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#else
1180231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // It is not enough just to round to pixels in device space. The rotation part of the
11818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // affine transform matrix to device space can mess with this conversion if we have a
1182231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // rotating image like the hands of the world clock widget. We just need the scale, so
11838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // we get the affine transform matrix and extract the scale.
11848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_data->m_userToDeviceTransformKnownToBeIdentity)
11868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return rect;
11878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGAffineTransform deviceMatrix = CGContextGetUserSpaceToDeviceSpaceTransform(platformContext());
11898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (CGAffineTransformIsIdentity(deviceMatrix)) {
11908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_data->m_userToDeviceTransformKnownToBeIdentity = true;
11918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return rect;
11928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float deviceScaleX = sqrtf(deviceMatrix.a * deviceMatrix.a + deviceMatrix.b * deviceMatrix.b);
11958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float deviceScaleY = sqrtf(deviceMatrix.c * deviceMatrix.c + deviceMatrix.d * deviceMatrix.d);
11968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGPoint deviceOrigin = CGPointMake(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
11988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGPoint deviceLowerRight = CGPointMake((rect.x() + rect.width()) * deviceScaleX,
11998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        (rect.y() + rect.height()) * deviceScaleY);
12008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    deviceOrigin.x = roundf(deviceOrigin.x);
12028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    deviceOrigin.y = roundf(deviceOrigin.y);
12032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (roundingMode == RoundAllSides) {
12042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        deviceLowerRight.x = roundf(deviceLowerRight.x);
12052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        deviceLowerRight.y = roundf(deviceLowerRight.y);
12062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    } else {
12072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        deviceLowerRight.x = deviceOrigin.x + roundf(rect.width() * deviceScaleX);
12082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        deviceLowerRight.y = deviceOrigin.y + roundf(rect.height() * deviceScaleY);
12092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
1210231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
12118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Don't let the height or width round to 0 unless either was originally 0
1212231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (deviceOrigin.y == deviceLowerRight.y && rect.height())
12138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        deviceLowerRight.y += 1;
1214231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (deviceOrigin.x == deviceLowerRight.x && rect.width())
12158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        deviceLowerRight.x += 1;
12168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY);
12188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY);
12198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
12202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif
12218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
12228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
122381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool printing)
12248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
12258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
12268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
12278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (width <= 0)
12298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
12308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float x = point.x();
12328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float y = point.y();
12338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float lineLength = width;
12348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Use a minimum thickness of 0.5 in user space.
12368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // See http://bugs.webkit.org/show_bug.cgi?id=4255 for details of why 0.5 is the right minimum thickness to use.
12378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float thickness = max(strokeThickness(), 0.5f);
12388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    bool restoreAntialiasMode = false;
1240635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
12418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!printing) {
12428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space).
12438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        float adjustedThickness = max(thickness, 1.0f);
12448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: This should be done a better way.
12468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space
12478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels
12488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // in device space will make the underlines too thick.
12492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness), RoundOriginAndDimensions);
12508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (lineRect.size.height < thickness * 2.0) {
12518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            x = lineRect.origin.x;
12528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            y = lineRect.origin.y;
12538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            lineLength = lineRect.size.width;
12548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            thickness = lineRect.size.height;
1255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (shouldAntialias()) {
1256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                CGContextSetShouldAntialias(platformContext(), false);
1257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                restoreAntialiasMode = true;
1258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
12598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1261231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
12628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fillColor() != strokeColor())
1263643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setCGFillColor(platformContext(), strokeColor(), strokeColorSpace());
12648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness));
1265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (fillColor() != strokeColor())
1266643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setCGFillColor(platformContext(), fillColor(), fillColorSpace());
1267231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (restoreAntialiasMode)
1269635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CGContextSetShouldAntialias(platformContext(), true);
12708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
12718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
12738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
12748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
12758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1276231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1277231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    RetainPtr<CFURLRef> urlRef(AdoptCF, link.createCFURL());
1278231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!urlRef)
1279231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return;
1280231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1281231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGContextRef context = platformContext();
1282231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1283231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // Get the bounding box to handle clipping.
1284231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGRect box = CGContextGetClipBoundingBox(context);
1285231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1286231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
1287231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    IntRect rect = destRect;
1288231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    rect.intersect(intBox);
1289231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1290231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGPDFContextSetURLForRect(context, urlRef.get(),
1291231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
12928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
12938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
12958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
12968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
12978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1298231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
12998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGInterpolationQuality quality = kCGInterpolationDefault;
13008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (mode) {
1301231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case InterpolationDefault:
1302231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        quality = kCGInterpolationDefault;
1303231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1304231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case InterpolationNone:
1305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        quality = kCGInterpolationNone;
1306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case InterpolationLow:
1308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        quality = kCGInterpolationLow;
1309231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1310231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1311643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Fall through to InterpolationHigh if kCGInterpolationMedium is not usable.
1312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case InterpolationMedium:
1313643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#if USE(CG_INTERPOLATION_MEDIUM)
1314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        quality = kCGInterpolationMedium;
1315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
13168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
1317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case InterpolationHigh:
1318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        quality = kCGInterpolationHigh;
1319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
13208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetInterpolationQuality(platformContext(), quality);
13228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
13238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectInterpolationQuality GraphicsContext::imageInterpolationQuality() const
13258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
13268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
13278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return InterpolationDefault;
13288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext());
13308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (quality) {
1331231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case kCGInterpolationDefault:
1332231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return InterpolationDefault;
1333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case kCGInterpolationNone:
1334231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return InterpolationNone;
1335231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case kCGInterpolationLow:
1336231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return InterpolationLow;
13378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if HAVE(CG_INTERPOLATION_MEDIUM)
1338643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum.
1339231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case kCGInterpolationMedium:
1340643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#if USE(CG_INTERPOLATION_MEDIUM)
1341643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Only map to InterpolationMedium if targeting a system that understands it.
1342231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return InterpolationMedium;
1343643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#else
1344643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return InterpolationDefault;
1345643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif  // USE(CG_INTERPOLATION_MEDIUM)
1346643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif  // HAVE(CG_INTERPOLATION_MEDIUM)
1347231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case kCGInterpolationHigh:
1348231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return InterpolationHigh;
13498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return InterpolationDefault;
13518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
13528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1353f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::setAllowsFontSmoothing(bool allowsFontSmoothing)
1354f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
1355f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    UNUSED_PARAM(allowsFontSmoothing);
1356f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1357f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextRef context = platformContext();
1358f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextSetAllowsFontSmoothing(context, allowsFontSmoothing);
1359f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#endif
1360f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
1361f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
13622bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid GraphicsContext::setIsCALayerContext(bool isLayerContext)
136381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
13642bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (isLayerContext)
13652bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_data->m_contextFlags |= IsLayerCGContext;
13662bde8e466a4451c7319e3a072d118917957d6554Steve Block    else
13672bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_data->m_contextFlags &= ~IsLayerCGContext;
136881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
136981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
137081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool GraphicsContext::isCALayerContext() const
137181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
13722bde8e466a4451c7319e3a072d118917957d6554Steve Block    return m_data->m_contextFlags & IsLayerCGContext;
13732bde8e466a4451c7319e3a072d118917957d6554Steve Block}
13742bde8e466a4451c7319e3a072d118917957d6554Steve Block
13752bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid GraphicsContext::setIsAcceleratedContext(bool isAccelerated)
13762bde8e466a4451c7319e3a072d118917957d6554Steve Block{
13772bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (isAccelerated)
13782bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_data->m_contextFlags |= IsAcceleratedCGContext;
13792bde8e466a4451c7319e3a072d118917957d6554Steve Block    else
13802bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_data->m_contextFlags &= ~IsAcceleratedCGContext;
13812bde8e466a4451c7319e3a072d118917957d6554Steve Block}
13822bde8e466a4451c7319e3a072d118917957d6554Steve Block
13832bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool GraphicsContext::isAcceleratedContext() const
13842bde8e466a4451c7319e3a072d118917957d6554Steve Block{
13852bde8e466a4451c7319e3a072d118917957d6554Steve Block    return m_data->m_contextFlags & IsAcceleratedCGContext;
138681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
138781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1388f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode)
13898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
13908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
13918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
13928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Wow, wish CG had used bits here.
13948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextRef context = platformContext();
13958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (mode) {
1396f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeInvisible:
1397231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextInvisible);
1398231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1399f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeFill:
1400231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextFill);
1401231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1402f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeStroke:
1403231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextStroke);
1404231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1405f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeFill | TextModeStroke:
1406231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextFillStroke);
1407231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1408f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeClip:
1409231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextClip);
1410231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1411f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeFill | TextModeClip:
1412231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextFillClip);
1413231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1414f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeStroke | TextModeClip:
1415231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextStrokeClip);
1416231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1417f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    case TextModeFill | TextModeStroke | TextModeClip:
1418231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip);
1419231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1420231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    default:
1421231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
14228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1425643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
14268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
14288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1429643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    setCGStrokeColor(platformContext(), color, colorSpace);
14308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::setPlatformStrokeThickness(float thickness)
14338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
14358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
14368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetLineWidth(platformContext(), thickness);
14378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1439643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
14408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
14428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1443643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    setCGFillColor(platformContext(), color, colorSpace);
14448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid GraphicsContext::setPlatformShouldAntialias(bool enable)
14478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
14498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
14508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetShouldAntialias(platformContext(), enable);
14518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1453f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::setPlatformShouldSmoothFonts(bool enable)
1454f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
1455f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (paintingDisabled())
1456f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return;
1457f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    CGContextSetShouldSmoothFonts(platformContext(), enable);
1458f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
1459f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
1460f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#ifndef BUILDING_ON_TIGER // Tiger's setPlatformCompositeOperation() is defined in GraphicsContextMac.mm.
1461f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::setPlatformCompositeOperation(CompositeOperator mode)
1462231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
14638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (paintingDisabled())
14648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
14658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1466231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    CGBlendMode target = kCGBlendModeNormal;
14678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (mode) {
1468231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeClear:
1469231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeClear;
1470231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1471231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeCopy:
1472231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeCopy;
1473231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1474231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeSourceOver:
1475231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        //kCGBlendModeNormal
1476231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1477231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeSourceIn:
1478231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeSourceIn;
1479231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1480231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeSourceOut:
1481231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeSourceOut;
1482231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1483231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeSourceAtop:
1484231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeSourceAtop;
1485231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1486231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeDestinationOver:
1487231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeDestinationOver;
1488231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1489231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeDestinationIn:
1490231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeDestinationIn;
1491231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1492231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeDestinationOut:
1493231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeDestinationOut;
1494231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1495231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeDestinationAtop:
1496231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeDestinationAtop;
1497231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1498231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeXOR:
1499231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModeXOR;
1500231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1501231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositePlusDarker:
1502231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModePlusDarker;
1503231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1504231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositeHighlight:
1505231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // currently unsupported
1506231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
1507231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    case CompositePlusLighter:
1508231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        target = kCGBlendModePlusLighter;
1509231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        break;
15108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
15118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CGContextSetBlendMode(platformContext(), target);
15128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
15148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1516