#include "SkCanvas.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkDrawShadowRec.h"
#include "SkPath.h"
#include "SkPM4f.h"
#include "SkRandom.h"
#if SK_SUPPORT_GPU
#include "GrShape.h"
#include "effects/GrBlurredEdgeFragmentProcessor.h"
-#endif
#include "../../src/effects/shadows/SkAmbientShadowMaskFilter.h"
#include "../../src/effects/shadows/SkSpotShadowMaskFilter.h"
+#endif
/**
* Gaussian color filter -- produces a Gaussian ramp based on the color's B value,
* they are first found in SkResourceCache.
*/
template <typename FACTORY>
-void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color) {
+ void draw_shadow(const FACTORY& factory,
+ std::function<void(const SkVertices*, SkBlendMode, const SkPaint&,
+ SkScalar tx, SkScalar ty)> drawProc, ShadowedPath& path, SkColor color) {
FindContext<FACTORY> context(&path.viewMatrix(), &factory);
SkResourceCache::Key* key = nullptr;
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
- if (translate->fX || translate->fY) {
- canvas->save();
- canvas->translate(translate->fX, translate->fY);
- }
- canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
- if (translate->fX || translate->fY) {
- canvas->restore();
- }
+
+ drawProc(vertices.get(), SkBlendMode::kModulate, paint, translate->fX, translate->fY);
}
}
-static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar occluderZ,
- const SkPoint3& devLightPos, SkScalar lightRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
- uint32_t flags) {
- // only supported in GPU code
- if (!canvas->getGrContext()) {
- return false;
- }
+static bool tilted(const SkPoint3& zPlaneParams) {
+ return !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
+}
+
+static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
+ SkPoint3 result;
+ m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
+ result.fZ = pt.fZ;
+ return result;
+}
+
+#if SK_SUPPORT_GPU
+#include "SkGpuDevice.h"
+void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
+ // check z plane
+ bool tiltZPlane = tilted(rec.fZPlaneParams);
+ bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+
+ const SkMatrix& ctm = this->ctm();
- SkRect rect;
- SkRRect rrect;
- const SkMatrix& ctm = canvas->getTotalMatrix();
- if (ctm.rectStaysRect() && ctm.isSimilarity()) {
+ if (!tiltZPlane && !skipAnalytic && ctm.rectStaysRect() && ctm.isSimilarity()) {
+ SkPoint3 devLightPos = map(ctm, rec.fLightPos);
+
+ const SkScalar occluderZ = rec.fZPlaneParams.fZ;
+ SkPaint ambientPaint, spotPaint;
+ ambientPaint.setColor(rec.fColor);
+ spotPaint.setColor(rec.fColor);
+ if (rec.fAmbientAlpha > 0) {
+ ambientPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ, rec.fAmbientAlpha,
+ rec.fFlags));
+ }
+ if (rec.fSpotAlpha > 0) {
+ spotPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
+ rec.fLightRadius, rec.fSpotAlpha,
+ rec.fFlags));
+ }
+
+ SkRect rect;
+ SkRRect rrect;
if (path.isRect(&rect)) {
- SkPaint newPaint;
- newPaint.setColor(color);
- if (ambientAlpha > 0) {
- newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
- ambientAlpha, flags));
- canvas->drawRect(rect, newPaint);
+ if (rec.fAmbientAlpha > 0) {
+ this->drawRect(rect, ambientPaint);
}
- if (spotAlpha > 0) {
- newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
- lightRadius, spotAlpha,
- flags));
- canvas->drawRect(rect, newPaint);
+ if (rec.fSpotAlpha > 0) {
+ this->drawRect(rect, spotPaint);
}
- return true;
+ return;
} else if (path.isRRect(&rrect) && rrect.isSimpleCircular() &&
rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero) {
- SkPaint newPaint;
- newPaint.setColor(color);
- if (ambientAlpha > 0) {
- newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
- ambientAlpha, flags));
- canvas->drawRRect(rrect, newPaint);
+ if (rec.fAmbientAlpha > 0) {
+ this->drawRRect(rrect, ambientPaint);
}
- if (spotAlpha > 0) {
- newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
- lightRadius, spotAlpha,
- flags));
- canvas->drawRRect(rrect, newPaint);
+ if (rec.fSpotAlpha > 0) {
+ this->drawRRect(rrect, spotPaint);
}
- return true;
+ return;
} else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
rect.width() > SK_ScalarNearlyZero) {
- SkPaint newPaint;
- newPaint.setColor(color);
- if (ambientAlpha > 0) {
- newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
- ambientAlpha, flags));
- canvas->drawOval(rect, newPaint);
+ if (rec.fAmbientAlpha > 0) {
+ this->drawOval(rect, ambientPaint);
}
- if (spotAlpha > 0) {
- newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
- lightRadius, spotAlpha,
- flags));
- canvas->drawOval(rect, newPaint);
+ if (rec.fSpotAlpha > 0) {
+ this->drawOval(rect, spotPaint);
}
- return true;
+ return;
}
}
- return false;
+ // failed to find an accelerated case
+ this->INHERITED::drawShadow(path, rec);
}
+#endif
static SkColor compute_render_color(SkColor color, float alpha) {
return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags) {
- // check z plane
- bool tiltZPlane = !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
-
- // try fast paths
- bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag) || tiltZPlane;
- if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, devLightPos,
- lightRadius, ambientAlpha, spotAlpha, color,
- flags)) {
+ SkMatrix inverse;
+ if (!canvas->getTotalMatrix().invert(&inverse)) {
return;
}
+ SkPoint pt = inverse.mapXY(devLightPos.fX, devLightPos.fY);
+
+ SkDrawShadowRec rec;
+ rec.fZPlaneParams = zPlaneParams;
+ rec.fLightPos = { pt.fX, pt.fY, devLightPos.fZ };
+ rec.fLightRadius = lightRadius;
+ rec.fAmbientAlpha = SkScalarToFloat(ambientAlpha);
+ rec.fSpotAlpha = SkScalarToFloat(spotAlpha);
+ rec.fColor = color;
+ rec.fFlags = flags;
+
+ canvas->private_draw_shadow_rec(path, rec);
+}
+
+void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
+ auto drawVertsProc = [this](const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint,
+ SkScalar tx, SkScalar ty) {
+ SkAutoDeviceCTMRestore adr(this, SkMatrix::Concat(this->ctm(),
+ SkMatrix::MakeTrans(tx, ty)));
+ this->drawVertices(vertices, mode, paint);
+ };
- SkAutoCanvasRestore acr(canvas, true);
- SkMatrix viewMatrix = canvas->getTotalMatrix();
- canvas->resetMatrix();
+ SkMatrix viewMatrix = this->ctm();
+ SkAutoDeviceCTMRestore adr(this, SkMatrix::I());
ShadowedPath shadowedPath(&path, &viewMatrix);
- bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+ bool tiltZPlane = tilted(rec.fZPlaneParams);
+ bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
bool uncached = tiltZPlane || path.isVolatile();
+ SkColor color = rec.fColor;
+ SkPoint3 zPlaneParams = rec.fZPlaneParams;
+ SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
+ float lightRadius = rec.fLightRadius;
+
+ float ambientAlpha = rec.fAmbientAlpha;
if (ambientAlpha > 0) {
ambientAlpha = SkTMin(ambientAlpha, 1.f);
if (uncached) {
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
- SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
- SkGaussianColorFilter::Make()));
- canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+ SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
+ SkGaussianColorFilter::Make()));
+ this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
} else {
AmbientVerticesFactory factory;
factory.fOccluderHeight = zPlaneParams.fZ;
factory.fTransparent = transparent;
SkColor renderColor = compute_render_color(color, ambientAlpha);
- draw_shadow(factory, canvas, shadowedPath, renderColor);
+ draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
}
}
+ float spotAlpha = rec.fSpotAlpha;
if (spotAlpha > 0) {
spotAlpha = SkTMin(spotAlpha, 1.f);
if (uncached) {
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
- canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+ this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
} else {
SpotVerticesFactory factory;
SkScalar occluderHeight = zPlaneParams.fZ;
}
#endif
SkColor renderColor = compute_render_color(color, spotAlpha);
- draw_shadow(factory, canvas, shadowedPath, renderColor);
+ draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
}
}
}