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 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 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::setPlatformCompositeOperation unknown CompositeOperator %d\n", op)); 112 return SkXfermode::kSrcOver_Mode; // fall-back 113 } 114 115 #if PLATFORM(ANDROID) 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 124 static U8CPU InvScaleByte(U8CPU component, uint32_t scale) 125 { 126 SkASSERT(component == (uint8_t)component); 127 return (component * scale + 0x8000) >> 16; 128 } 129 130 SkColor SkPMColorToColor(SkPMColor pm) 131 { 132 if (!pm) 133 return 0; 134 unsigned a = SkGetPackedA32(pm); 135 if (!a) { 136 // A zero alpha value when there are non-zero R, G, or B channels is an 137 // invalid premultiplied color (since all channels should have been 138 // multiplied by 0 if a=0). 139 SkASSERT(false); 140 // In production, return 0 to protect against division by zero. 141 return 0; 142 } 143 144 uint32_t scale = (255 << 16) / a; 145 146 return SkColorSetARGB(a, 147 InvScaleByte(SkGetPackedR32(pm), scale), 148 InvScaleByte(SkGetPackedG32(pm), scale), 149 InvScaleByte(SkGetPackedB32(pm), scale)); 150 } 151 152 Color SkPMColorToWebCoreColor(SkPMColor pm) 153 { 154 return SkPMColorToColor(pm); 155 } 156 #endif 157 158 void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) { 159 // The cliperator requires an int rect, so we round out. 160 SkIRect srcRectRounded; 161 srcRect.roundOut(&srcRectRounded); 162 163 // The Cliperator will iterate over a bunch of rects where our transformed 164 // rect and the clipping region (which may be non-square) overlap. 165 SkRegion::Cliperator cliperator(region, srcRectRounded); 166 if (cliperator.done()) { 167 destRect->setEmpty(); 168 return; 169 } 170 171 // Get the union of all visible rects in the clip that overlap our bitmap. 172 SkIRect currentVisibleRect = cliperator.rect(); 173 cliperator.next(); 174 while (!cliperator.done()) { 175 currentVisibleRect.join(cliperator.rect()); 176 cliperator.next(); 177 } 178 179 destRect->set(currentVisibleRect); 180 } 181 182 void ClipRectToCanvas(const SkCanvas& canvas, const SkRect& srcRect, SkRect* destRect) { 183 // Translate into the canvas' coordinate space. This is where the clipping 184 // region applies. 185 SkRect transformedSrc; 186 canvas.getTotalMatrix().mapRect(&transformedSrc, srcRect); 187 188 // Do the intersection. 189 SkRect transformedDest; 190 IntersectRectAndRegion(canvas.getTotalClip(), transformedSrc, &transformedDest); 191 192 // Now transform it back into world space. 193 SkMatrix inverseTransform; 194 canvas.getTotalMatrix().invert(&inverseTransform); 195 inverseTransform.mapRect(destRect, transformedDest); 196 } 197 198 bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) 199 { 200 SkRegion rgn; 201 SkRegion clip; 202 203 SkPath::FillType originalFillType = originalPath->getFillType(); 204 205 const SkPath* path = originalPath; 206 SkPath scaledPath; 207 int scale = 1; 208 209 SkRect bounds = originalPath->getBounds(); 210 211 // We can immediately return false if the point is outside the bounding 212 // rect. We don't use bounds.contains() here, since it would exclude 213 // points on the right and bottom edges of the bounding rect, and we want 214 // to include them. 215 SkScalar fX = SkFloatToScalar(point.x()); 216 SkScalar fY = SkFloatToScalar(point.y()); 217 if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) 218 return false; 219 220 originalPath->setFillType(ft); 221 222 // Skia has trouble with coordinates close to the max signed 16-bit values 223 // If we have those, we need to scale. 224 // 225 // TODO: remove this code once Skia is patched to work properly with large 226 // values 227 const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); 228 SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); 229 230 if (biggestCoord > kMaxCoordinate) { 231 scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); 232 233 SkMatrix m; 234 m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); 235 originalPath->transform(m, &scaledPath); 236 path = &scaledPath; 237 } 238 239 int x = static_cast<int>(floorf(point.x() / scale)); 240 int y = static_cast<int>(floorf(point.y() / scale)); 241 clip.setRect(x - 1, y - 1, x + 1, y + 1); 242 243 bool contains = rgn.setPath(*path, clip); 244 245 originalPath->setFillType(originalFillType); 246 return contains; 247 } 248 249 GraphicsContext* scratchContext() 250 { 251 static ImageBuffer* scratch = ImageBuffer::create(IntSize(1, 1)).leakPtr(); 252 // We don't bother checking for failure creating the ImageBuffer, since our 253 // ImageBuffer initializer won't fail. 254 return scratch->context(); 255 } 256 257 } // namespace WebCore 258