1 /* libs/graphics/effects/SkEmbossMaskFilter.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "SkEmbossMaskFilter.h" 19 #include "SkBlurMaskFilter.h" 20 #include "SkBlurMask.h" 21 #include "SkEmbossMask.h" 22 #include "SkBuffer.h" 23 24 static inline int pin2byte(int n) { 25 if (n < 0) { 26 n = 0; 27 } else if (n > 0xFF) { 28 n = 0xFF; 29 } 30 return n; 31 } 32 33 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], 34 SkScalar ambient, SkScalar specular, 35 SkScalar blurRadius) { 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, (light, blurRadius)); 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(const Light& light, SkScalar blurRadius) 67 : fLight(light), fBlurRadius(blurRadius) { 68 normalize(fLight.fDirection); 69 } 70 71 SkMask::Format SkEmbossMaskFilter::getFormat() { 72 return SkMask::k3D_Format; 73 } 74 75 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, 76 const SkMatrix& matrix, SkIPoint* margin) { 77 SkScalar radius = matrix.mapRadius(fBlurRadius); 78 79 if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, 80 SkBlurMask::kLow_Quality)) { 81 return false; 82 } 83 84 dst->fFormat = SkMask::k3D_Format; 85 if (margin) { 86 margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); 87 } 88 89 if (src.fImage == NULL) { 90 return true; 91 } 92 93 // create a larger buffer for the other two channels (should force fBlur to do this for us) 94 95 { 96 uint8_t* alphaPlane = dst->fImage; 97 size_t planeSize = dst->computeImageSize(); 98 if (0 == planeSize) { 99 return false; // too big to allocate, abort 100 } 101 dst->fImage = SkMask::AllocImage(planeSize * 3); 102 memcpy(dst->fImage, alphaPlane, planeSize); 103 SkMask::FreeImage(alphaPlane); 104 } 105 106 // run the light direction through the matrix... 107 Light light = fLight; 108 matrix.mapVectors((SkVector*)(void*)light.fDirection, 109 (SkVector*)(void*)fLight.fDirection, 1); 110 111 // now restore the length of the XY component 112 // cast to SkVector so we can call setLength (this double cast silences alias warnings) 113 SkVector* vec = (SkVector*)(void*)light.fDirection; 114 vec->setLength(light.fDirection[0], 115 light.fDirection[1], 116 SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); 117 118 SkEmbossMask::Emboss(dst, light); 119 120 // restore original alpha 121 memcpy(dst->fImage, src.fImage, src.computeImageSize()); 122 123 return true; 124 } 125 126 SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) { 127 return SkNEW_ARGS(SkEmbossMaskFilter, (buffer)); 128 } 129 130 SkFlattenable::Factory SkEmbossMaskFilter::getFactory() { 131 return CreateProc; 132 } 133 134 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) 135 : SkMaskFilter(buffer) { 136 buffer.read(&fLight, sizeof(fLight)); 137 SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean 138 fBlurRadius = buffer.readScalar(); 139 } 140 141 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) { 142 this->INHERITED::flatten(buffer); 143 144 fLight.fPad = 0; // for the font-cache lookup to be clean 145 buffer.writeMul4(&fLight, sizeof(fLight)); 146 buffer.writeScalar(fBlurRadius); 147 } 148 149