• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
204     // rect.  We don't use bounds.contains() here, since it would exclude
205     // points on the right and bottom edges of the bounding rect, and we want
206     // to include them.
207     SkScalar fX = SkFloatToScalar(point.x());
208     SkScalar fY = SkFloatToScalar(point.y());
209     if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom)
210         return false;
211 
212     originalPath->setFillType(ft);
213 
214     // Skia has trouble with coordinates close to the max signed 16-bit values
215     // If we have those, we need to scale.
216     //
217     // TODO: remove this code once Skia is patched to work properly with large
218     // values
219     const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
220     SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);
221 
222     if (biggestCoord > kMaxCoordinate) {
223         scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));
224 
225         SkMatrix m;
226         m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
227         originalPath->transform(m, &scaledPath);
228         path = &scaledPath;
229     }
230 
231     int x = static_cast<int>(floorf(point.x() / scale));
232     int y = static_cast<int>(floorf(point.y() / scale));
233     clip.setRect(x - 1, y - 1, x + 1, y + 1);
234 
235     bool contains = rgn.setPath(*path, clip);
236 
237     originalPath->setFillType(originalFillType);
238     return contains;
239 }
240 
scratchContext()241 GraphicsContext* scratchContext()
242 {
243     static ImageBuffer* scratch = 0;
244     if (!scratch)
245         scratch = ImageBuffer::create(IntSize(1, 1)).release();
246     // We don't bother checking for failure creating the ImageBuffer, since our
247     // ImageBuffer initializer won't fail.
248     return scratch->context();
249 }
250 
251 }  // namespace WebCore
252