blob: 9fa26c573102ad3ddb8ac4d272681fe144897863 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkEmbossMaskFilter.h"
9#include "SkBlurMaskFilter.h"
10#include "SkBlurMask.h"
Mike Reede602f392018-02-06 10:17:08 -050011#include "SkColorPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkEmbossMask.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
robertphillips@google.com0bd80fa2013-03-18 17:53:38 +000015#include "SkString.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reedefdfd512016-04-04 10:02:58 -070017sk_sp<SkMaskFilter> SkEmbossMaskFilter::Make(SkScalar blurSigma, const Light& light) {
18 return sk_sp<SkMaskFilter>(new SkEmbossMaskFilter(blurSigma, light));
reed@google.comdaaafa62014-04-29 15:20:16 +000019}
20
Brian Osman3e31e992017-11-14 16:16:39 +000021#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER
22sk_sp<SkMaskFilter> SkBlurMaskFilter::MakeEmboss(SkScalar blurSigma, const SkScalar direction[3],
23 SkScalar ambient, SkScalar specular) {
24 if (direction == nullptr) {
25 return nullptr;
26 }
27
28 SkEmbossMaskFilter::Light light;
29
30 memcpy(light.fDirection, direction, sizeof(light.fDirection));
31 // ambient should be 0...1 as a scalar
32 light.fAmbient = SkUnitScalarClampToByte(ambient);
33 // specular should be 0..15.99 as a scalar
34 static const SkScalar kSpecularMultiplier = SkIntToScalar(255) / 16;
35 light.fSpecular = static_cast<U8CPU>(SkScalarPin(specular, 0, 16) * kSpecularMultiplier + 0.5);
36
37 return SkEmbossMaskFilter::Make(blurSigma, light);
38}
39#endif
40
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000041///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000043static void normalize(SkScalar v[3]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
45 mag = SkScalarSqrt(mag);
46
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000047 for (int i = 0; i < 3; i++) {
reed80ea19c2015-05-12 10:37:34 -070048 v[i] /= mag;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000049 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000050}
51
robertphillips@google.com7ce661d2013-08-27 16:14:03 +000052SkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light)
robertphillips@google.comb75233b2013-08-27 16:31:31 +000053 : fLight(light), fBlurSigma(blurSigma) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 normalize(fLight.fDirection);
55}
56
reed@google.com30711b72012-12-18 19:18:39 +000057SkMask::Format SkEmbossMaskFilter::getFormat() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 return SkMask::k3D_Format;
59}
60
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000061bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
robertphillips@google.com7ce661d2013-08-27 16:14:03 +000062 const SkMatrix& matrix, SkIPoint* margin) const {
63 SkScalar sigma = matrix.mapRadius(fBlurSigma);
reed@android.com8a1c16f2008-12-17 15:59:43 +000064
commit-bot@chromium.orge3964552014-04-28 16:25:35 +000065 if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle, kLow_SkBlurQuality)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000067 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000068
69 dst->fFormat = SkMask::k3D_Format;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000070 if (margin) {
reed@google.come1ca7052013-12-17 19:22:07 +000071 margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma));
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000072 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000073
halcanary96fcdcc2015-08-27 07:41:13 -070074 if (src.fImage == nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 return true;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000076 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000077
78 // create a larger buffer for the other two channels (should force fBlur to do this for us)
79
80 {
81 uint8_t* alphaPlane = dst->fImage;
82 size_t planeSize = dst->computeImageSize();
reed@android.com543ed932009-04-24 12:43:40 +000083 if (0 == planeSize) {
84 return false; // too big to allocate, abort
85 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 dst->fImage = SkMask::AllocImage(planeSize * 3);
87 memcpy(dst->fImage, alphaPlane, planeSize);
88 SkMask::FreeImage(alphaPlane);
89 }
90
91 // run the light direction through the matrix...
92 Light light = fLight;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000093 matrix.mapVectors((SkVector*)(void*)light.fDirection,
94 (SkVector*)(void*)fLight.fDirection, 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000095
96 // now restore the length of the XY component
97 // cast to SkVector so we can call setLength (this double cast silences alias warnings)
98 SkVector* vec = (SkVector*)(void*)light.fDirection;
99 vec->setLength(light.fDirection[0],
100 light.fDirection[1],
101 SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
102
103 SkEmbossMask::Emboss(dst, light);
104
105 // restore original alpha
106 memcpy(dst->fImage, src.fImage, src.computeImageSize());
107
108 return true;
109}
110
reed60c9b582016-04-03 09:11:13 -0700111sk_sp<SkFlattenable> SkEmbossMaskFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700112 Light light;
113 if (buffer.readByteArray(&light, sizeof(Light))) {
114 light.fPad = 0; // for the font-cache lookup to be clean
115 const SkScalar sigma = buffer.readScalar();
reedefdfd512016-04-04 10:02:58 -0700116 return Make(sigma, light);
reed9fa60da2014-08-21 07:59:51 -0700117 }
halcanary96fcdcc2015-08-27 07:41:13 -0700118 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700119}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000121void SkEmbossMaskFilter::flatten(SkWriteBuffer& buffer) const {
djsollen@google.com54924242012-03-29 15:18:04 +0000122 Light tmpLight = fLight;
123 tmpLight.fPad = 0; // for the font-cache lookup to be clean
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000124 buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
robertphillips@google.com11e05552013-12-03 19:46:58 +0000125 buffer.writeScalar(fBlurSigma);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126}
robertphillips@google.com0bd80fa2013-03-18 17:53:38 +0000127
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000128#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com0bd80fa2013-03-18 17:53:38 +0000129void SkEmbossMaskFilter::toString(SkString* str) const {
130 str->append("SkEmbossMaskFilter: (");
131
132 str->append("direction: (");
133 str->appendScalar(fLight.fDirection[0]);
134 str->append(", ");
135 str->appendScalar(fLight.fDirection[1]);
136 str->append(", ");
137 str->appendScalar(fLight.fDirection[2]);
138 str->append(") ");
139
skia.committer@gmail.com8eaddb02013-03-19 07:15:10 +0000140 str->appendf("ambient: %d specular: %d ",
robertphillips@google.com0bd80fa2013-03-18 17:53:38 +0000141 fLight.fAmbient, fLight.fSpecular);
142
robertphillips@google.com7ce661d2013-08-27 16:14:03 +0000143 str->append("blurSigma: ");
144 str->appendScalar(fBlurSigma);
robertphillips@google.com0bd80fa2013-03-18 17:53:38 +0000145 str->append(")");
146}
147#endif