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 "SkBuffer.h" 15 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 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 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 58 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius) 59 : fLight(light), fBlurRadius(blurRadius) { 60 normalize(fLight.fDirection); 61 } 62 63 SkMask::Format SkEmbossMaskFilter::getFormat() { 64 return SkMask::k3D_Format; 65 } 66 67 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, 68 const SkMatrix& matrix, SkIPoint* margin) { 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 118 SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) { 119 return SkNEW_ARGS(SkEmbossMaskFilter, (buffer)); 120 } 121 122 SkFlattenable::Factory SkEmbossMaskFilter::getFactory() { 123 return CreateProc; 124 } 125 126 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) 127 : SkMaskFilter(buffer) { 128 buffer.read(&fLight, sizeof(fLight)); 129 SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean 130 fBlurRadius = buffer.readScalar(); 131 } 132 133 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) { 134 this->INHERITED::flatten(buffer); 135 136 fLight.fPad = 0; // for the font-cache lookup to be clean 137 buffer.writeMul4(&fLight, sizeof(fLight)); 138 buffer.writeScalar(fBlurRadius); 139 } 140 141