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 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], 25 SkScalar ambient, SkScalar specular, 26 SkScalar blurRadius) 27 { 28 if (direction == NULL) 29 return NULL; 30 31 // ambient should be 0...1 as a scalar 32 int am = SkScalarToFixed(ambient) >> 8; 33 if (am < 0) am = 0; 34 else if (am > 0xFF) am = 0xFF; 35 36 // specular should be 0..15.99 as a scalar 37 int sp = SkScalarToFixed(specular) >> 12; 38 if (sp < 0) sp = 0; 39 else if (sp > 0xFF) sp = 0xFF; 40 41 SkEmbossMaskFilter::Light light; 42 43 memcpy(light.fDirection, direction, sizeof(light.fDirection)); 44 light.fAmbient = SkToU8(am); 45 light.fSpecular = SkToU8(sp); 46 47 return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius)); 48 } 49 50 ///////////////////////////////////////////////////////////////////////////////////////////// 51 52 static void normalize(SkScalar v[3]) 53 { 54 SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]); 55 mag = SkScalarSqrt(mag); 56 57 for (int i = 0; i < 3; i++) 58 v[i] = SkScalarDiv(v[i], mag); 59 } 60 61 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius) 62 : fLight(light), fBlurRadius(blurRadius) 63 { 64 normalize(fLight.fDirection); 65 } 66 67 SkMask::Format SkEmbossMaskFilter::getFormat() 68 { 69 return SkMask::k3D_Format; 70 } 71 72 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) 73 { 74 SkScalar radius = matrix.mapRadius(fBlurRadius); 75 76 if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style)) 77 return false; 78 79 dst->fFormat = SkMask::k3D_Format; 80 if (margin) 81 margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); 82 83 if (src.fImage == NULL) 84 return true; 85 86 // create a larger buffer for the other two channels (should force fBlur to do this for us) 87 88 { 89 uint8_t* alphaPlane = dst->fImage; 90 size_t planeSize = dst->computeImageSize(); 91 if (0 == planeSize) { 92 return false; // too big to allocate, abort 93 } 94 dst->fImage = SkMask::AllocImage(planeSize * 3); 95 memcpy(dst->fImage, alphaPlane, planeSize); 96 SkMask::FreeImage(alphaPlane); 97 } 98 99 // run the light direction through the matrix... 100 Light light = fLight; 101 matrix.mapVectors((SkVector*)(void*)light.fDirection, (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 118 SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) 119 { 120 return SkNEW_ARGS(SkEmbossMaskFilter, (buffer)); 121 } 122 123 SkFlattenable::Factory SkEmbossMaskFilter::getFactory() 124 { 125 return CreateProc; 126 } 127 128 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) : SkMaskFilter(buffer) 129 { 130 buffer.read(&fLight, sizeof(fLight)); 131 SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean 132 fBlurRadius = buffer.readScalar(); 133 } 134 135 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) 136 { 137 this->INHERITED::flatten(buffer); 138 139 fLight.fPad = 0; // for the font-cache lookup to be clean 140 buffer.writeMul4(&fLight, sizeof(fLight)); 141 buffer.writeScalar(fBlurRadius); 142 } 143 144