1/* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkEmbossMaskFilter.h" 9#include "SkBlurMaskFilter.h" 10#include "SkBlurMask.h" 11#include "SkEmbossMask.h" 12#include "SkReadBuffer.h" 13#include "SkWriteBuffer.h" 14#include "SkString.h" 15 16SkEmbossMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) { 17 return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light)); 18} 19 20static inline int pin2byte(int n) { 21 if (n < 0) { 22 n = 0; 23 } else if (n > 0xFF) { 24 n = 0xFF; 25 } 26 return n; 27} 28 29SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], 30 SkScalar ambient, SkScalar specular, 31 SkScalar blurRadius) { 32 return SkBlurMaskFilter::CreateEmboss(SkBlurMask::ConvertRadiusToSigma(blurRadius), 33 direction, ambient, specular); 34} 35 36SkMaskFilter* SkBlurMaskFilter::CreateEmboss(SkScalar blurSigma, const SkScalar direction[3], 37 SkScalar ambient, SkScalar specular) { 38 if (direction == NULL) { 39 return NULL; 40 } 41 42 // ambient should be 0...1 as a scalar 43 int am = pin2byte(SkScalarToFixed(ambient) >> 8); 44 45 // specular should be 0..15.99 as a scalar 46 int sp = pin2byte(SkScalarToFixed(specular) >> 12); 47 48 SkEmbossMaskFilter::Light light; 49 50 memcpy(light.fDirection, direction, sizeof(light.fDirection)); 51 light.fAmbient = SkToU8(am); 52 light.fSpecular = SkToU8(sp); 53 54 return SkEmbossMaskFilter::Create(blurSigma, light); 55} 56 57/////////////////////////////////////////////////////////////////////////////// 58 59static void normalize(SkScalar v[3]) { 60 SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]); 61 mag = SkScalarSqrt(mag); 62 63 for (int i = 0; i < 3; i++) { 64 v[i] /= mag; 65 } 66} 67 68SkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light) 69 : fLight(light), fBlurSigma(blurSigma) { 70 normalize(fLight.fDirection); 71} 72 73SkMask::Format SkEmbossMaskFilter::getFormat() const { 74 return SkMask::k3D_Format; 75} 76 77bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, 78 const SkMatrix& matrix, SkIPoint* margin) const { 79 SkScalar sigma = matrix.mapRadius(fBlurSigma); 80 81 if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle, kLow_SkBlurQuality)) { 82 return false; 83 } 84 85 dst->fFormat = SkMask::k3D_Format; 86 if (margin) { 87 margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma)); 88 } 89 90 if (src.fImage == NULL) { 91 return true; 92 } 93 94 // create a larger buffer for the other two channels (should force fBlur to do this for us) 95 96 { 97 uint8_t* alphaPlane = dst->fImage; 98 size_t planeSize = dst->computeImageSize(); 99 if (0 == planeSize) { 100 return false; // too big to allocate, abort 101 } 102 dst->fImage = SkMask::AllocImage(planeSize * 3); 103 memcpy(dst->fImage, alphaPlane, planeSize); 104 SkMask::FreeImage(alphaPlane); 105 } 106 107 // run the light direction through the matrix... 108 Light light = fLight; 109 matrix.mapVectors((SkVector*)(void*)light.fDirection, 110 (SkVector*)(void*)fLight.fDirection, 1); 111 112 // now restore the length of the XY component 113 // cast to SkVector so we can call setLength (this double cast silences alias warnings) 114 SkVector* vec = (SkVector*)(void*)light.fDirection; 115 vec->setLength(light.fDirection[0], 116 light.fDirection[1], 117 SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); 118 119 SkEmbossMask::Emboss(dst, light); 120 121 // restore original alpha 122 memcpy(dst->fImage, src.fImage, src.computeImageSize()); 123 124 return true; 125} 126 127SkFlattenable* SkEmbossMaskFilter::CreateProc(SkReadBuffer& buffer) { 128 Light light; 129 if (buffer.readByteArray(&light, sizeof(Light))) { 130 light.fPad = 0; // for the font-cache lookup to be clean 131 const SkScalar sigma = buffer.readScalar(); 132 return Create(sigma, light); 133 } 134 return NULL; 135} 136 137void SkEmbossMaskFilter::flatten(SkWriteBuffer& buffer) const { 138 Light tmpLight = fLight; 139 tmpLight.fPad = 0; // for the font-cache lookup to be clean 140 buffer.writeByteArray(&tmpLight, sizeof(tmpLight)); 141 buffer.writeScalar(fBlurSigma); 142} 143 144#ifndef SK_IGNORE_TO_STRING 145void SkEmbossMaskFilter::toString(SkString* str) const { 146 str->append("SkEmbossMaskFilter: ("); 147 148 str->append("direction: ("); 149 str->appendScalar(fLight.fDirection[0]); 150 str->append(", "); 151 str->appendScalar(fLight.fDirection[1]); 152 str->append(", "); 153 str->appendScalar(fLight.fDirection[2]); 154 str->append(") "); 155 156 str->appendf("ambient: %d specular: %d ", 157 fLight.fAmbient, fLight.fSpecular); 158 159 str->append("blurSigma: "); 160 str->appendScalar(fBlurSigma); 161 str->append(")"); 162} 163#endif 164