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