1/*
2 * Copyright (c) 2006,2007,2008, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32
33#include "core/platform/graphics/skia/SkiaUtils.h"
34
35#include "SkColorPriv.h"
36#include "SkMatrix.h"
37#include "SkRegion.h"
38#include "core/platform/graphics/GraphicsContext.h"
39#include "core/platform/graphics/ImageBuffer.h"
40
41namespace WebCore {
42
43static const struct CompositOpToXfermodeMode {
44    uint8_t mCompositOp;
45    uint8_t m_xfermodeMode;
46} gMapCompositOpsToXfermodeModes[] = {
47    { CompositeClear,           SkXfermode::kClear_Mode },
48    { CompositeCopy,            SkXfermode::kSrc_Mode },
49    { CompositeSourceOver,      SkXfermode::kSrcOver_Mode },
50    { CompositeSourceIn,        SkXfermode::kSrcIn_Mode },
51    { CompositeSourceOut,       SkXfermode::kSrcOut_Mode },
52    { CompositeSourceAtop,      SkXfermode::kSrcATop_Mode },
53    { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
54    { CompositeDestinationIn,   SkXfermode::kDstIn_Mode },
55    { CompositeDestinationOut,  SkXfermode::kDstOut_Mode },
56    { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
57    { CompositeXOR,             SkXfermode::kXor_Mode },
58    { CompositePlusDarker,      SkXfermode::kDarken_Mode },
59    { CompositePlusLighter,     SkXfermode::kPlus_Mode }
60};
61
62// keep this array in sync with BlendMode enum in GraphicsTypes.h
63static const uint8_t gMapBlendOpsToXfermodeModes[] = {
64    SkXfermode::kClear_Mode, // BlendModeNormal
65    SkXfermode::kMultiply_Mode, // BlendModeMultiply
66    SkXfermode::kScreen_Mode, // BlendModeScreen
67    SkXfermode::kOverlay_Mode, // BlendModeOverlay
68    SkXfermode::kDarken_Mode, // BlendModeDarken
69    SkXfermode::kLighten_Mode, // BlendModeLighten
70    SkXfermode::kColorDodge_Mode, // BlendModeColorDodge
71    SkXfermode::kColorBurn_Mode, // BlendModeColorBurn
72    SkXfermode::kHardLight_Mode, // BlendModeHardLight
73    SkXfermode::kSoftLight_Mode, // BlendModeSoftLight
74    SkXfermode::kDifference_Mode, // BlendModeDifference
75    SkXfermode::kExclusion_Mode, // BlendModeExclusion
76    SkXfermode::kHue_Mode, // BlendModeHue
77    SkXfermode::kSaturation_Mode, // BlendModeSaturation
78    SkXfermode::kColor_Mode, // BlendModeColor
79    SkXfermode::kLuminosity_Mode // BlendModeLuminosity
80};
81
82SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op, BlendMode blendMode)
83{
84    if (blendMode != BlendModeNormal) {
85        if ((uint8_t)blendMode >= SK_ARRAY_COUNT(gMapBlendOpsToXfermodeModes)) {
86            SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown BlendMode %d\n", blendMode));
87            return SkXfermode::kSrcOver_Mode;
88        }
89        return (SkXfermode::Mode)gMapBlendOpsToXfermodeModes[(uint8_t)blendMode];
90    }
91
92    const CompositOpToXfermodeMode* table = gMapCompositOpsToXfermodeModes;
93
94    for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToXfermodeModes); i++) {
95        if (table[i].mCompositOp == op)
96            return (SkXfermode::Mode)table[i].m_xfermodeMode;
97    }
98
99    SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown CompositeOperator %d\n", op));
100    return SkXfermode::kSrcOver_Mode; // fall-back
101}
102
103static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
104{
105    SkASSERT(component == (uint8_t)component);
106    return (component * scale + 0x8000) >> 16;
107}
108
109SkColor SkPMColorToColor(SkPMColor pm)
110{
111    if (!pm)
112        return 0;
113    unsigned a = SkGetPackedA32(pm);
114    if (!a) {
115        // A zero alpha value when there are non-zero R, G, or B channels is an
116        // invalid premultiplied color (since all channels should have been
117        // multiplied by 0 if a=0).
118        SkASSERT(false);
119        // In production, return 0 to protect against division by zero.
120        return 0;
121    }
122
123    uint32_t scale = (255 << 16) / a;
124
125    return SkColorSetARGB(a,
126                          InvScaleByte(SkGetPackedR32(pm), scale),
127                          InvScaleByte(SkGetPackedG32(pm), scale),
128                          InvScaleByte(SkGetPackedB32(pm), scale));
129}
130
131Color SkPMColorToWebCoreColor(SkPMColor pm)
132{
133    return SkPMColorToColor(pm);
134}
135
136void ClipRectToCanvas(const GraphicsContext* context, const SkRect& srcRect, SkRect* destRect)
137{
138    if (!context->getClipBounds(destRect) || !destRect->intersect(srcRect))
139        destRect->setEmpty();
140}
141
142bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft)
143{
144    SkRect bounds = originalPath.getBounds();
145
146    // We can immediately return false if the point is outside the bounding
147    // rect.  We don't use bounds.contains() here, since it would exclude
148    // points on the right and bottom edges of the bounding rect, and we want
149    // to include them.
150    SkScalar fX = SkFloatToScalar(point.x());
151    SkScalar fY = SkFloatToScalar(point.y());
152    if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom)
153        return false;
154
155    // Scale the path to a large size before hit testing for two reasons:
156    // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down.
157    //    TODO: when Skia is patched to work properly with large values, this will not be necessary.
158    // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy.
159    SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);
160    if (SkScalarNearlyZero(biggestCoord))
161        return false;
162    biggestCoord = std::max(std::max(biggestCoord, fX + 1), fY + 1);
163
164    const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15);
165    SkScalar scale = SkScalarDiv(kMaxCoordinate, biggestCoord);
166
167    SkRegion rgn;
168    SkRegion clip;
169    SkMatrix m;
170    SkPath scaledPath(originalPath);
171
172    scaledPath.setFillType(ft);
173    m.setScale(scale, scale);
174    scaledPath.transform(m, 0);
175
176    int x = static_cast<int>(floorf(0.5f + point.x() * scale));
177    int y = static_cast<int>(floorf(0.5f + point.y() * scale));
178    clip.setRect(x - 1, y - 1, x + 1, y + 1);
179
180    return rgn.setPath(scaledPath, clip);
181}
182
183}  // namespace WebCore
184