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