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 "platform/graphics/skia/SkiaUtils.h" 34 35 #include "SkColorPriv.h" 36 #include "SkRegion.h" 37 #include "platform/graphics/GraphicsContext.h" 38 #include "platform/graphics/ImageBuffer.h" 39 40 namespace WebCore { 41 42 static const struct CompositOpToXfermodeMode { 43 uint8_t mCompositOp; 44 uint8_t m_xfermodeMode; 45 } gMapCompositOpsToXfermodeModes[] = { 46 { CompositeClear, SkXfermode::kClear_Mode }, 47 { CompositeCopy, SkXfermode::kSrc_Mode }, 48 { CompositeSourceOver, SkXfermode::kSrcOver_Mode }, 49 { CompositeSourceIn, SkXfermode::kSrcIn_Mode }, 50 { CompositeSourceOut, SkXfermode::kSrcOut_Mode }, 51 { CompositeSourceAtop, SkXfermode::kSrcATop_Mode }, 52 { CompositeDestinationOver, SkXfermode::kDstOver_Mode }, 53 { CompositeDestinationIn, SkXfermode::kDstIn_Mode }, 54 { CompositeDestinationOut, SkXfermode::kDstOut_Mode }, 55 { CompositeDestinationAtop, SkXfermode::kDstATop_Mode }, 56 { CompositeXOR, SkXfermode::kXor_Mode }, 57 { CompositePlusDarker, SkXfermode::kDarken_Mode }, 58 { CompositePlusLighter, SkXfermode::kPlus_Mode } 59 }; 60 61 // keep this array in sync with blink::WebBlendMode enum in public/platform/WebBlendMode.h 62 static const uint8_t gMapBlendOpsToXfermodeModes[] = { 63 SkXfermode::kClear_Mode, // blink::WebBlendModeNormal 64 SkXfermode::kMultiply_Mode, // blink::WebBlendModeMultiply 65 SkXfermode::kScreen_Mode, // blink::WebBlendModeScreen 66 SkXfermode::kOverlay_Mode, // blink::WebBlendModeOverlay 67 SkXfermode::kDarken_Mode, // blink::WebBlendModeDarken 68 SkXfermode::kLighten_Mode, // blink::WebBlendModeLighten 69 SkXfermode::kColorDodge_Mode, // blink::WebBlendModeColorDodge 70 SkXfermode::kColorBurn_Mode, // blink::WebBlendModeColorBurn 71 SkXfermode::kHardLight_Mode, // blink::WebBlendModeHardLight 72 SkXfermode::kSoftLight_Mode, // blink::WebBlendModeSoftLight 73 SkXfermode::kDifference_Mode, // blink::WebBlendModeDifference 74 SkXfermode::kExclusion_Mode, // blink::WebBlendModeExclusion 75 SkXfermode::kHue_Mode, // blink::WebBlendModeHue 76 SkXfermode::kSaturation_Mode, // blink::WebBlendModeSaturation 77 SkXfermode::kColor_Mode, // blink::WebBlendModeColor 78 SkXfermode::kLuminosity_Mode // blink::WebBlendModeLuminosity 79 }; 80 81 PassRefPtr<SkXfermode> WebCoreCompositeToSkiaComposite(CompositeOperator op, blink::WebBlendMode blendMode) 82 { 83 if (blendMode != blink::WebBlendModeNormal) { 84 if ((uint8_t)blendMode >= SK_ARRAY_COUNT(gMapBlendOpsToXfermodeModes)) { 85 SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown blink::WebBlendMode %d\n", blendMode)); 86 return adoptRef(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); 87 } 88 SkXfermode::Mode mode = (SkXfermode::Mode)gMapBlendOpsToXfermodeModes[(uint8_t)blendMode]; 89 return adoptRef(SkXfermode::Create(mode)); 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 adoptRef(SkXfermode::Create((SkXfermode::Mode)table[i].m_xfermodeMode)); 97 } 98 99 SkDEBUGF(("GraphicsContext::setPlatformCompositeOperation unknown CompositeOperator %d\n", op)); 100 return adoptRef(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); // fall-back 101 } 102 103 static U8CPU InvScaleByte(U8CPU component, uint32_t scale) 104 { 105 SkASSERT(component == (uint8_t)component); 106 return (component * scale + 0x8000) >> 16; 107 } 108 109 SkColor 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 131 void ClipRectToCanvas(const GraphicsContext* context, const SkRect& srcRect, SkRect* destRect) 132 { 133 if (!context->getClipBounds(destRect) || !destRect->intersect(srcRect)) 134 destRect->setEmpty(); 135 } 136 137 bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft) 138 { 139 SkRect bounds = originalPath.getBounds(); 140 141 // We can immediately return false if the point is outside the bounding 142 // rect. We don't use bounds.contains() here, since it would exclude 143 // points on the right and bottom edges of the bounding rect, and we want 144 // to include them. 145 SkScalar fX = SkFloatToScalar(point.x()); 146 SkScalar fY = SkFloatToScalar(point.y()); 147 if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) 148 return false; 149 150 // Scale the path to a large size before hit testing for two reasons: 151 // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. 152 // TODO: when Skia is patched to work properly with large values, this will not be necessary. 153 // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. 154 SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); 155 if (SkScalarNearlyZero(biggestCoord)) 156 return false; 157 biggestCoord = std::max(std::max(biggestCoord, fX + 1), fY + 1); 158 159 const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); 160 SkScalar scale = SkScalarDiv(kMaxCoordinate, biggestCoord); 161 162 SkRegion rgn; 163 SkRegion clip; 164 SkMatrix m; 165 SkPath scaledPath(originalPath); 166 167 scaledPath.setFillType(ft); 168 m.setScale(scale, scale); 169 scaledPath.transform(m, 0); 170 171 int x = static_cast<int>(floorf(0.5f + point.x() * scale)); 172 int y = static_cast<int>(floorf(0.5f + point.y() * scale)); 173 clip.setRect(x - 1, y - 1, x + 1, y + 1); 174 175 return rgn.setPath(scaledPath, clip); 176 } 177 178 SkMatrix affineTransformToSkMatrix(const AffineTransform& source) 179 { 180 SkMatrix result; 181 182 result.setScaleX(WebCoreDoubleToSkScalar(source.a())); 183 result.setSkewX(WebCoreDoubleToSkScalar(source.c())); 184 result.setTranslateX(WebCoreDoubleToSkScalar(source.e())); 185 186 result.setScaleY(WebCoreDoubleToSkScalar(source.d())); 187 result.setSkewY(WebCoreDoubleToSkScalar(source.b())); 188 result.setTranslateY(WebCoreDoubleToSkScalar(source.f())); 189 190 // FIXME: Set perspective properly. 191 result.setPerspX(0); 192 result.setPerspY(0); 193 result.set(SkMatrix::kMPersp2, SK_Scalar1); 194 195 return result; 196 } 197 198 } // namespace WebCore 199