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