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