Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkEmbossMaskFilter.h"
      9 #include "SkBlurMaskFilter.h"
     10 #include "SkBlurMask.h"
     11 #include "SkColorPriv.h"
     12 #include "SkEmbossMask.h"
     13 #include "SkReadBuffer.h"
     14 #include "SkWriteBuffer.h"
     15 #include "SkString.h"
     16 
     17 static void normalize3(SkScalar dst[3], const SkScalar src[3]) {
     18     SkScalar mag = SkScalarSquare(src[0]) + SkScalarSquare(src[1]) + SkScalarSquare(src[2]);
     19     SkScalar scale = SkScalarInvert(SkScalarSqrt(mag));
     20 
     21     for (int i = 0; i < 3; i++) {
     22         dst[i] = src[i] * scale;
     23     }
     24 }
     25 
     26 sk_sp<SkMaskFilter> SkEmbossMaskFilter::Make(SkScalar blurSigma, const Light& light) {
     27     if (!SkScalarIsFinite(blurSigma) || blurSigma <= 0) {
     28         return nullptr;
     29     }
     30 
     31     Light newLight = light;
     32     normalize3(newLight.fDirection, light.fDirection);
     33     if (!SkScalarsAreFinite(newLight.fDirection, 3)) {
     34         return nullptr;
     35     }
     36 
     37     return sk_sp<SkMaskFilter>(new SkEmbossMaskFilter(blurSigma, newLight));
     38 }
     39 
     40 #ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
     41 sk_sp<SkMaskFilter> SkBlurMaskFilter::MakeEmboss(SkScalar blurSigma, const SkScalar direction[3],
     42                                                  SkScalar ambient, SkScalar specular) {
     43     if (direction == nullptr) {
     44         return nullptr;
     45     }
     46 
     47     SkEmbossMaskFilter::Light   light;
     48 
     49     memcpy(light.fDirection, direction, sizeof(light.fDirection));
     50     // ambient should be 0...1 as a scalar
     51     light.fAmbient = SkUnitScalarClampToByte(ambient);
     52     // specular should be 0..15.99 as a scalar
     53     static const SkScalar kSpecularMultiplier = SkIntToScalar(255) / 16;
     54     light.fSpecular = static_cast<U8CPU>(SkScalarPin(specular, 0, 16) * kSpecularMultiplier + 0.5);
     55 
     56     return SkEmbossMaskFilter::Make(blurSigma, light);
     57 }
     58 #endif
     59 
     60 ///////////////////////////////////////////////////////////////////////////////
     61 
     62 SkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light)
     63     : fLight(light), fBlurSigma(blurSigma)
     64 {
     65     SkASSERT(fBlurSigma > 0);
     66     SkASSERT(SkScalarsAreFinite(fLight.fDirection, 3));
     67 }
     68 
     69 SkMask::Format SkEmbossMaskFilter::getFormat() const {
     70     return SkMask::k3D_Format;
     71 }
     72 
     73 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
     74                                     const SkMatrix& matrix, SkIPoint* margin) const {
     75     SkScalar sigma = matrix.mapRadius(fBlurSigma);
     76 
     77     if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle, kLow_SkBlurQuality)) {
     78         return false;
     79     }
     80 
     81     dst->fFormat = SkMask::k3D_Format;
     82     if (margin) {
     83         margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma));
     84     }
     85 
     86     if (src.fImage == nullptr) {
     87         return true;
     88     }
     89 
     90     // create a larger buffer for the other two channels (should force fBlur to do this for us)
     91 
     92     {
     93         uint8_t* alphaPlane = dst->fImage;
     94         size_t   planeSize = dst->computeImageSize();
     95         if (0 == planeSize) {
     96             return false;   // too big to allocate, abort
     97         }
     98         dst->fImage = SkMask::AllocImage(planeSize * 3);
     99         memcpy(dst->fImage, alphaPlane, planeSize);
    100         SkMask::FreeImage(alphaPlane);
    101     }
    102 
    103     // run the light direction through the matrix...
    104     Light   light = fLight;
    105     matrix.mapVectors((SkVector*)(void*)light.fDirection,
    106                       (SkVector*)(void*)fLight.fDirection, 1);
    107 
    108     // now restore the length of the XY component
    109     // cast to SkVector so we can call setLength (this double cast silences alias warnings)
    110     SkVector* vec = (SkVector*)(void*)light.fDirection;
    111     vec->setLength(light.fDirection[0],
    112                    light.fDirection[1],
    113                    SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
    114 
    115     SkEmbossMask::Emboss(dst, light);
    116 
    117     // restore original alpha
    118     memcpy(dst->fImage, src.fImage, src.computeImageSize());
    119 
    120     return true;
    121 }
    122 
    123 sk_sp<SkFlattenable> SkEmbossMaskFilter::CreateProc(SkReadBuffer& buffer) {
    124     Light light;
    125     if (buffer.readByteArray(&light, sizeof(Light))) {
    126         light.fPad = 0; // for the font-cache lookup to be clean
    127         const SkScalar sigma = buffer.readScalar();
    128         return Make(sigma, light);
    129     }
    130     return nullptr;
    131 }
    132 
    133 void SkEmbossMaskFilter::flatten(SkWriteBuffer& buffer) const {
    134     Light tmpLight = fLight;
    135     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
    136     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
    137     buffer.writeScalar(fBlurSigma);
    138 }
    139 
    140 #ifndef SK_IGNORE_TO_STRING
    141 void SkEmbossMaskFilter::toString(SkString* str) const {
    142     str->append("SkEmbossMaskFilter: (");
    143 
    144     str->append("direction: (");
    145     str->appendScalar(fLight.fDirection[0]);
    146     str->append(", ");
    147     str->appendScalar(fLight.fDirection[1]);
    148     str->append(", ");
    149     str->appendScalar(fLight.fDirection[2]);
    150     str->append(") ");
    151 
    152     str->appendf("ambient: %d specular: %d ",
    153         fLight.fAmbient, fLight.fSpecular);
    154 
    155     str->append("blurSigma: ");
    156     str->appendScalar(fBlurSigma);
    157     str->append(")");
    158 }
    159 #endif
    160