• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
pin2byte(int n)16 static inline int pin2byte(int n) {
17     if (n < 0) {
18         n = 0;
19     } else if (n > 0xFF) {
20         n = 0xFF;
21     }
22     return n;
23 }
24 
CreateEmboss(const SkScalar direction[3],SkScalar ambient,SkScalar specular,SkScalar blurRadius)25 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
26                                              SkScalar ambient, SkScalar specular,
27                                              SkScalar blurRadius) {
28     if (direction == NULL) {
29         return NULL;
30     }
31 
32     // ambient should be 0...1 as a scalar
33     int am = pin2byte(SkScalarToFixed(ambient) >> 8);
34 
35     // specular should be 0..15.99 as a scalar
36     int sp = pin2byte(SkScalarToFixed(specular) >> 12);
37 
38     SkEmbossMaskFilter::Light   light;
39 
40     memcpy(light.fDirection, direction, sizeof(light.fDirection));
41     light.fAmbient = SkToU8(am);
42     light.fSpecular = SkToU8(sp);
43 
44     return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
45 }
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 
normalize(SkScalar v[3])49 static void normalize(SkScalar v[3]) {
50     SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
51     mag = SkScalarSqrt(mag);
52 
53     for (int i = 0; i < 3; i++) {
54         v[i] = SkScalarDiv(v[i], mag);
55     }
56 }
57 
SkEmbossMaskFilter(const Light & light,SkScalar blurRadius)58 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
59         : fLight(light), fBlurRadius(blurRadius) {
60     normalize(fLight.fDirection);
61 }
62 
getFormat() const63 SkMask::Format SkEmbossMaskFilter::getFormat() const {
64     return SkMask::k3D_Format;
65 }
66 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const67 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
68                             const SkMatrix& matrix, SkIPoint* margin) const {
69     SkScalar radius = matrix.mapRadius(fBlurRadius);
70 
71     if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
72                           SkBlurMask::kLow_Quality)) {
73         return false;
74     }
75 
76     dst->fFormat = SkMask::k3D_Format;
77     if (margin) {
78         margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
79     }
80 
81     if (src.fImage == NULL) {
82         return true;
83     }
84 
85     // create a larger buffer for the other two channels (should force fBlur to do this for us)
86 
87     {
88         uint8_t* alphaPlane = dst->fImage;
89         size_t   planeSize = dst->computeImageSize();
90         if (0 == planeSize) {
91             return false;   // too big to allocate, abort
92         }
93         dst->fImage = SkMask::AllocImage(planeSize * 3);
94         memcpy(dst->fImage, alphaPlane, planeSize);
95         SkMask::FreeImage(alphaPlane);
96     }
97 
98     // run the light direction through the matrix...
99     Light   light = fLight;
100     matrix.mapVectors((SkVector*)(void*)light.fDirection,
101                       (SkVector*)(void*)fLight.fDirection, 1);
102 
103     // now restore the length of the XY component
104     // cast to SkVector so we can call setLength (this double cast silences alias warnings)
105     SkVector* vec = (SkVector*)(void*)light.fDirection;
106     vec->setLength(light.fDirection[0],
107                    light.fDirection[1],
108                    SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
109 
110     SkEmbossMask::Emboss(dst, light);
111 
112     // restore original alpha
113     memcpy(dst->fImage, src.fImage, src.computeImageSize());
114 
115     return true;
116 }
117 
SkEmbossMaskFilter(SkFlattenableReadBuffer & buffer)118 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
119         : SkMaskFilter(buffer) {
120     SkASSERT(buffer.getArrayCount() == sizeof(Light));
121     buffer.readByteArray(&fLight);
122     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
123     fBlurRadius = buffer.readScalar();
124 }
125 
flatten(SkFlattenableWriteBuffer & buffer) const126 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
127     this->INHERITED::flatten(buffer);
128 
129     Light tmpLight = fLight;
130     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
131     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
132     buffer.writeScalar(fBlurRadius);
133 }
134