1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkEmbossMaskFilter.h" 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMaskFilter.h" 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMask.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkEmbossMask.h" 128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 140bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#include "SkString.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comSkEmbossMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) { 17daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light)); 18daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com} 19daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 203334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgstatic inline int pin2byte(int n) { 213334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org if (n < 0) { 223334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org n = 0; 233334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } else if (n > 0xFF) { 243334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org n = 0xFF; 253334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 263334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org return n; 273334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org} 283334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar ambient, SkScalar specular, 313334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org SkScalar blurRadius) { 327ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com return SkBlurMaskFilter::CreateEmboss(SkBlurMask::ConvertRadiusToSigma(blurRadius), 337ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com direction, ambient, specular); 347ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com} 357ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com 367ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comSkMaskFilter* SkBlurMaskFilter::CreateEmboss(SkScalar blurSigma, const SkScalar direction[3], 377ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com SkScalar ambient, SkScalar specular) { 383334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org if (direction == NULL) { 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return NULL; 403334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // ambient should be 0...1 as a scalar 433334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org int am = pin2byte(SkScalarToFixed(ambient) >> 8); 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // specular should be 0..15.99 as a scalar 463334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org int sp = pin2byte(SkScalarToFixed(specular) >> 12); 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkEmbossMaskFilter::Light light; 49fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(light.fDirection, direction, sizeof(light.fDirection)); 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com light.fAmbient = SkToU8(am); 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com light.fSpecular = SkToU8(sp); 53fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 547c9d0f3104408a64d52b84643f116179022d73bdcommit-bot@chromium.org return SkEmbossMaskFilter::Create(blurSigma, light); 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 573334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 593334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgstatic void normalize(SkScalar v[3]) { 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]); 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mag = SkScalarSqrt(mag); 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 633334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org for (int i = 0; i < 3; i++) { 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com v[i] = SkScalarDiv(v[i], mag); 653334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 687ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.comSkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light) 69b75233b7fabb818aea0f5c940848c0d6f9f6181erobertphillips@google.com : fLight(light), fBlurSigma(blurSigma) { 707ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com normalize(fLight.fDirection); 717ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com} 727ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com 7330711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.comSkMask::Format SkEmbossMaskFilter::getFormat() const { 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return SkMask::k3D_Format; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 773334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgbool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, 787ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com const SkMatrix& matrix, SkIPoint* margin) const { 797ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com SkScalar sigma = matrix.mapRadius(fBlurSigma); 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 81e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle, kLow_SkBlurQuality)) { 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 833334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fFormat = SkMask::k3D_Format; 863334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org if (margin) { 87e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma)); 883334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 903334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org if (src.fImage == NULL) { 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 923334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org } 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // create a larger buffer for the other two channels (should force fBlur to do this for us) 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint8_t* alphaPlane = dst->fImage; 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t planeSize = dst->computeImageSize(); 99543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com if (0 == planeSize) { 100543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com return false; // too big to allocate, abort 101543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com } 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fImage = SkMask::AllocImage(planeSize * 3); 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(dst->fImage, alphaPlane, planeSize); 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::FreeImage(alphaPlane); 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // run the light direction through the matrix... 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Light light = fLight; 1093334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org matrix.mapVectors((SkVector*)(void*)light.fDirection, 1103334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org (SkVector*)(void*)fLight.fDirection, 1); 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now restore the length of the XY component 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // cast to SkVector so we can call setLength (this double cast silences alias warnings) 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkVector* vec = (SkVector*)(void*)light.fDirection; 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com vec->setLength(light.fDirection[0], 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com light.fDirection[1], 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkEmbossMask::Emboss(dst, light); 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // restore original alpha 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memcpy(dst->fImage, src.fImage, src.computeImageSize()); 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1279fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 1289fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkEmbossMaskFilter::SkEmbossMaskFilter(SkReadBuffer& buffer) : SkMaskFilter(buffer) { 129c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com SkASSERT(buffer.getArrayCount() == sizeof(Light)); 130025128811219dc45fd99b6c4d1d14f833cf7a26ecommit-bot@chromium.org buffer.readByteArray(&fLight, sizeof(Light)); 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean 132fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org fBlurSigma = buffer.readScalar(); 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1349fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkEmbossMaskFilter::CreateProc(SkReadBuffer& buffer) { 1379fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed Light light; 1389fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (buffer.readByteArray(&light, sizeof(Light))) { 1399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed light.fPad = 0; // for the font-cache lookup to be clean 1409fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkScalar sigma = buffer.readScalar(); 1419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return Create(sigma, light); 1429fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 1439fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; 1449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedvoid SkEmbossMaskFilter::flatten(SkWriteBuffer& buffer) const { 14754924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com Light tmpLight = fLight; 14854924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com tmpLight.fPad = 0; // for the font-cache lookup to be clean 149c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeByteArray(&tmpLight, sizeof(tmpLight)); 15011e055518a0cbe5329232a55fe2cd177e83836d8robertphillips@google.com buffer.writeScalar(fBlurSigma); 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1520bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com 1530f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING 1540bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.comvoid SkEmbossMaskFilter::toString(SkString* str) const { 1550bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append("SkEmbossMaskFilter: ("); 1560bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com 1570bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append("direction: ("); 1580bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->appendScalar(fLight.fDirection[0]); 1590bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append(", "); 1600bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->appendScalar(fLight.fDirection[1]); 1610bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append(", "); 1620bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->appendScalar(fLight.fDirection[2]); 1630bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append(") "); 1640bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com 1658eaddb0089a170760e157646192813bd940c26e7skia.committer@gmail.com str->appendf("ambient: %d specular: %d ", 1660bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com fLight.fAmbient, fLight.fSpecular); 1670bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com 1687ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com str->append("blurSigma: "); 1697ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com str->appendScalar(fBlurSigma); 1700bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com str->append(")"); 1710bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com} 1720bd80fa01bba2b3f0f49937fcb17928c74bde5a6robertphillips@google.com#endif 173