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 if (direction == NULL) { 30 return NULL; 31 } 32 33 // ambient should be 0...1 as a scalar 34 int am = pin2byte(SkScalarToFixed(ambient) >> 8); 35 36 // specular should be 0..15.99 as a scalar 37 int sp = pin2byte(SkScalarToFixed(specular) >> 12); 38 39 SkEmbossMaskFilter::Light light; 40 41 memcpy(light.fDirection, direction, sizeof(light.fDirection)); 42 light.fAmbient = SkToU8(am); 43 light.fSpecular = SkToU8(sp); 44 45 return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius)); 46 } 47 48 /////////////////////////////////////////////////////////////////////////////// 49 50 static void normalize(SkScalar v[3]) { 51 SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]); 52 mag = SkScalarSqrt(mag); 53 54 for (int i = 0; i < 3; i++) { 55 v[i] = SkScalarDiv(v[i], mag); 56 } 57 } 58 59 SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius) 60 : fLight(light), fBlurRadius(blurRadius) { 61 normalize(fLight.fDirection); 62 } 63 64 SkMask::Format SkEmbossMaskFilter::getFormat() const { 65 return SkMask::k3D_Format; 66 } 67 68 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, 69 const SkMatrix& matrix, SkIPoint* margin) const { 70 SkScalar radius = matrix.mapRadius(fBlurRadius); 71 72 if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, 73 SkBlurMask::kLow_Quality)) { 74 return false; 75 } 76 77 dst->fFormat = SkMask::k3D_Format; 78 if (margin) { 79 margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); 80 } 81 82 if (src.fImage == NULL) { 83 return true; 84 } 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, 102 (SkVector*)(void*)fLight.fDirection, 1); 103 104 // now restore the length of the XY component 105 // cast to SkVector so we can call setLength (this double cast silences alias warnings) 106 SkVector* vec = (SkVector*)(void*)light.fDirection; 107 vec->setLength(light.fDirection[0], 108 light.fDirection[1], 109 SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); 110 111 SkEmbossMask::Emboss(dst, light); 112 113 // restore original alpha 114 memcpy(dst->fImage, src.fImage, src.computeImageSize()); 115 116 return true; 117 } 118 119 SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) 120 : SkMaskFilter(buffer) { 121 SkASSERT(buffer.getArrayCount() == sizeof(Light)); 122 buffer.readByteArray(&fLight); 123 SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean 124 fBlurRadius = buffer.readScalar(); 125 } 126 127 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 128 this->INHERITED::flatten(buffer); 129 130 Light tmpLight = fLight; 131 tmpLight.fPad = 0; // for the font-cache lookup to be clean 132 buffer.writeByteArray(&tmpLight, sizeof(tmpLight)); 133 buffer.writeScalar(fBlurRadius); 134 } 135 136 #ifdef SK_DEVELOPER 137 void SkEmbossMaskFilter::toString(SkString* str) const { 138 str->append("SkEmbossMaskFilter: ("); 139 140 str->append("direction: ("); 141 str->appendScalar(fLight.fDirection[0]); 142 str->append(", "); 143 str->appendScalar(fLight.fDirection[1]); 144 str->append(", "); 145 str->appendScalar(fLight.fDirection[2]); 146 str->append(") "); 147 148 str->appendf("ambient: %d specular: %d ", 149 fLight.fAmbient, fLight.fSpecular); 150 151 str->append("blurRadius: "); 152 str->appendScalar(fBlurRadius); 153 str->append(")"); 154 } 155 #endif 156