5c95eebe30e2552df6286e3afd433a8ebee56e7e
[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 "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(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(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     fBlurSigma = buffer.readScalar();
138 }
139
140 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
141     this->INHERITED::flatten(buffer);
142
143     Light tmpLight = fLight;
144     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
145     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
146     buffer.writeScalar(fBlurSigma);
147 }
148
149 #ifdef SK_DEVELOPER
150 void SkEmbossMaskFilter::toString(SkString* str) const {
151     str->append("SkEmbossMaskFilter: (");
152
153     str->append("direction: (");
154     str->appendScalar(fLight.fDirection[0]);
155     str->append(", ");
156     str->appendScalar(fLight.fDirection[1]);
157     str->append(", ");
158     str->appendScalar(fLight.fDirection[2]);
159     str->append(") ");
160
161     str->appendf("ambient: %d specular: %d ",
162         fLight.fAmbient, fLight.fSpecular);
163
164     str->append("blurSigma: ");
165     str->appendScalar(fBlurSigma);
166     str->append(")");
167 }
168 #endif