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