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