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 "SkiaUtils.h"
34
35 #include "ImageBuffer.h"
36 #include "SharedBuffer.h"
37 #include "SkCanvas.h"
38 #include "SkColorPriv.h"
39 #include "SkMatrix.h"
40 #include "SkRegion.h"
41 #include "SkUnPreMultiply.h"
42
43 namespace WebCore {
44
45 #if PLATFORM(ANDROID)
46 static const struct CompositOpToSkiaMode {
47 uint8_t mCompositOp;
48 uint8_t mMode;
49 } gMapCompositOpsToSkiaModes[] = {
50 { CompositeClear, SkXfermode::kClear_Mode },
51 { CompositeCopy, SkXfermode::kSrc_Mode },
52 { CompositeSourceOver, SkXfermode::kSrcOver_Mode },
53 { CompositeSourceIn, SkXfermode::kSrcIn_Mode },
54 { CompositeSourceOut, SkXfermode::kSrcOut_Mode },
55 { CompositeSourceAtop, SkXfermode::kSrcATop_Mode },
56 { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
57 { CompositeDestinationIn, SkXfermode::kDstIn_Mode },
58 { CompositeDestinationOut, SkXfermode::kDstOut_Mode },
59 { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
60 { CompositeXOR, SkXfermode::kXor_Mode },
61 // need more details on the composite modes to be sure these are right
62 { CompositePlusDarker, SkXfermode::kDarken_Mode },
63 { CompositeHighlight, SkXfermode::kSrcOver_Mode }, // TODO
64 { CompositePlusLighter, SkXfermode::kPlus_Mode }
65 };
66
WebCoreCompositeToSkiaCOmposite(CompositeOperator op)67 SkXfermode::Mode WebCoreCompositeToSkiaCOmposite(CompositeOperator op)
68 {
69 const CompositOpToSkiaMode* table = gMapCompositOpsToSkiaModes;
70
71 for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToSkiaModes); i++) {
72 if (table[i].mCompositOp == op)
73 return (SkXfermode::Mode)table[i].mMode;
74 }
75
76 SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op));
77 return SkXfermode::kSrcOver_Mode; // fall-back
78 }
79
80 #endif
81
82 static const struct CompositOpToXfermodeMode {
83 uint8_t mCompositOp;
84 uint8_t m_xfermodeMode;
85 } gMapCompositOpsToXfermodeModes[] = {
86 { CompositeClear, SkXfermode::kClear_Mode },
87 { CompositeCopy, SkXfermode::kSrc_Mode },
88 { CompositeSourceOver, SkXfermode::kSrcOver_Mode },
89 { CompositeSourceIn, SkXfermode::kSrcIn_Mode },
90 { CompositeSourceOut, SkXfermode::kSrcOut_Mode },
91 { CompositeSourceAtop, SkXfermode::kSrcATop_Mode },
92 { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
93 { CompositeDestinationIn, SkXfermode::kDstIn_Mode },
94 { CompositeDestinationOut, SkXfermode::kDstOut_Mode },
95 { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
96 { CompositeXOR, SkXfermode::kXor_Mode },
97 { CompositePlusDarker, SkXfermode::kDarken_Mode },
98 { CompositeHighlight, SkXfermode::kSrcOver_Mode }, // TODO
99 { CompositePlusLighter, SkXfermode::kPlus_Mode }
100 };
101
WebCoreCompositeToSkiaComposite(CompositeOperator op)102 SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
103 {
104 const CompositOpToXfermodeMode* table = gMapCompositOpsToXfermodeModes;
105
106 for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToXfermodeModes); i++) {
107 if (table[i].mCompositOp == op)
108 return (SkXfermode::Mode)table[i].m_xfermodeMode;
109 }
110
111 SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op));
112 return SkXfermode::kSrcOver_Mode; // fall-back
113 }
114
115 #if PLATFORM(ANDROID)
SkPMColorToWebCoreColor(SkPMColor pm)116 Color SkPMColorToWebCoreColor(SkPMColor pm)
117 {
118 SkColor c = SkUnPreMultiply::PMColorToColor(pm);
119 // need the cast to find the right constructor
120 return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
121 (int)SkColorGetB(c), (int)SkColorGetA(c));
122 }
123 #else
InvScaleByte(U8CPU component,uint32_t scale)124 static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
125 {
126 SkASSERT(component == (uint8_t)component);
127 return (component * scale + 0x8000) >> 16;
128 }
129
SkPMColorToColor(SkPMColor pm)130 SkColor SkPMColorToColor(SkPMColor pm)
131 {
132 if (0 == pm)
133 return 0;
134
135 unsigned a = SkGetPackedA32(pm);
136 uint32_t scale = (255 << 16) / a;
137
138 return SkColorSetARGB(a,
139 InvScaleByte(SkGetPackedR32(pm), scale),
140 InvScaleByte(SkGetPackedG32(pm), scale),
141 InvScaleByte(SkGetPackedB32(pm), scale));
142 }
143
SkPMColorToWebCoreColor(SkPMColor pm)144 Color SkPMColorToWebCoreColor(SkPMColor pm)
145 {
146 return SkPMColorToColor(pm);
147 }
148 #endif
149
IntersectRectAndRegion(const SkRegion & region,const SkRect & srcRect,SkRect * destRect)150 void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) {
151 // The cliperator requires an int rect, so we round out.
152 SkIRect srcRectRounded;
153 srcRect.roundOut(&srcRectRounded);
154
155 // The Cliperator will iterate over a bunch of rects where our transformed
156 // rect and the clipping region (which may be non-square) overlap.
157 SkRegion::Cliperator cliperator(region, srcRectRounded);
158 if (cliperator.done()) {
159 destRect->setEmpty();
160 return;
161 }
162
163 // Get the union of all visible rects in the clip that overlap our bitmap.
164 SkIRect currentVisibleRect = cliperator.rect();
165 cliperator.next();
166 while (!cliperator.done()) {
167 currentVisibleRect.join(cliperator.rect());
168 cliperator.next();
169 }
170
171 destRect->set(currentVisibleRect);
172 }
173
ClipRectToCanvas(const SkCanvas & canvas,const SkRect & srcRect,SkRect * destRect)174 void ClipRectToCanvas(const SkCanvas& canvas, const SkRect& srcRect, SkRect* destRect) {
175 // Translate into the canvas' coordinate space. This is where the clipping
176 // region applies.
177 SkRect transformedSrc;
178 canvas.getTotalMatrix().mapRect(&transformedSrc, srcRect);
179
180 // Do the intersection.
181 SkRect transformedDest;
182 IntersectRectAndRegion(canvas.getTotalClip(), transformedSrc, &transformedDest);
183
184 // Now transform it back into world space.
185 SkMatrix inverseTransform;
186 canvas.getTotalMatrix().invert(&inverseTransform);
187 inverseTransform.mapRect(destRect, transformedDest);
188 }
189
SkPathContainsPoint(SkPath * originalPath,const FloatPoint & point,SkPath::FillType ft)190 bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
191 {
192 SkRegion rgn;
193 SkRegion clip;
194
195 SkPath::FillType originalFillType = originalPath->getFillType();
196
197 const SkPath* path = originalPath;
198 SkPath scaledPath;
199 int scale = 1;
200
201 SkRect bounds = originalPath->getBounds();
202
203 // We can immediately return false if the point is outside the bounding rect
204 if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
205 return false;
206
207 originalPath->setFillType(ft);
208
209 // Skia has trouble with coordinates close to the max signed 16-bit values
210 // If we have those, we need to scale.
211 //
212 // TODO: remove this code once Skia is patched to work properly with large
213 // values
214 const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
215 SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);
216
217 if (biggestCoord > kMaxCoordinate) {
218 scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));
219
220 SkMatrix m;
221 m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
222 originalPath->transform(m, &scaledPath);
223 path = &scaledPath;
224 }
225
226 int x = static_cast<int>(floorf(point.x() / scale));
227 int y = static_cast<int>(floorf(point.y() / scale));
228 clip.setRect(x, y, x + 1, y + 1);
229
230 bool contains = rgn.setPath(*path, clip);
231
232 originalPath->setFillType(originalFillType);
233 return contains;
234 }
235
scratchContext()236 GraphicsContext* scratchContext()
237 {
238 static ImageBuffer* scratch = 0;
239 if (!scratch)
240 scratch = ImageBuffer::create(IntSize(1, 1)).release();
241 // We don't bother checking for failure creating the ImageBuffer, since our
242 // ImageBuffer initializer won't fail.
243 return scratch->context();
244 }
245
246 } // namespace WebCore
247