SkEmbossMaskFilter.cpp revision 1cab2921ab279367f8206cdadc9259d12e603548
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 16static 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 25SkMaskFilter* 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 49static 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 58SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius) 59 : fLight(light), fBlurRadius(blurRadius) { 60 normalize(fLight.fDirection); 61} 62 63SkMask::Format SkEmbossMaskFilter::getFormat() { 64 return SkMask::k3D_Format; 65} 66 67bool 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 118SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) { 119 return SkNEW_ARGS(SkEmbossMaskFilter, (buffer)); 120} 121 122SkFlattenable::Factory SkEmbossMaskFilter::getFactory() { 123 return CreateProc; 124} 125 126SkEmbossMaskFilter::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 133void 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