1894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com/* 2894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * Copyright 2011 Google Inc. 3894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * 4894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * Use of this source code is governed by a BSD-style license that can be 5894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * found in the LICENSE file. 6894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com */ 7894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com 8894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#ifndef SkImageFilter_DEFINED 9894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#define SkImageFilter_DEFINED 10894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com 11bf521ff9415b3bdb1acde7b8d18139df176236e5bungeman#include "../private/SkTArray.h" 12f3c15b7cfc4eed2528f7db87ea6c1444b55ee856bungeman#include "../private/SkTemplates.h" 1323526963135bd15737505bd560d41b0d5a41439exidachen#include "../private/SkMutex.h" 14afbf71dd924c7bb46ccdac49e7408b4b088563ffbrianosman#include "SkColorSpace.h" 158c874eee943bdea0fab5b4d2707083c863e37c55senorblanco#include "SkFilterQuality.h" 16894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#include "SkFlattenable.h" 174cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org#include "SkMatrix.h" 18194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org#include "SkRect.h" 19894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com 20af9b8c804643952d5ff3deed62f1355319b72f72robertphillipsclass GrContext; 212c55d7b7f3c2c834085d019bf6b1519b315c8aa1reedclass GrFragmentProcessor; 228d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgclass SkColorFilter; 2331abf1fc945c27755173b78037e62576cf2dd62eMatt Sarettclass SkColorSpaceXformer; 24c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.comstruct SkIPoint; 25df7bb471e5455dece2784a970d9ae50d3ab0ca75robertphillipsclass SkSpecialImage; 26900c36779610dc65c42a5004ee3693fd70961ba4senorblancoclass SkImageFilterCache; 27900c36779610dc65c42a5004ee3693fd70961ba4senorblancostruct SkImageFilterCacheKey; 2815356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com 2915356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com/** 3015356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com * Base class for image filters. If one is installed in the paint, then 3115356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com * all drawing occurs as usual, but it is as if the drawing happened into an 3215356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com * offscreen (before the xfermode is applied). This offscreen bitmap will 3315356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com * then be handed to the imagefilter, who in turn creates a new bitmap which 3415356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com * is what will finally be drawn to the device (using the original xfermode). 3515356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com */ 3654e01b2ab985e7a7d38109812069d056d128bfa1senorblanco@chromium.orgclass SK_API SkImageFilter : public SkFlattenable { 37894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.compublic: 382a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // Extra information about the output of a filter DAG. For now, this is just the color space 392a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // (of the original requesting device). This is used when constructing intermediate rendering 402a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // surfaces, so that we ensure we land in a surface that's similar/compatible to the final 412a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // consumer of the DAG's output. 422a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman class OutputProperties { 432a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman public: 442a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {} 452a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman 462a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman SkColorSpace* colorSpace() const { return fColorSpace; } 472a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman 482a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman private: 492a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // This will be a pointer to the device's color space, and our lifetime is bounded by 502a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman // the device, so we can store a bare pointer. 512a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman SkColorSpace* fColorSpace; 522a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman }; 532a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman 544cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org class Context { 554cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org public: 562a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache, 572a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman const OutputProperties& outputProperties) 58c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed : fCTM(ctm) 59c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed , fClipBounds(clipBounds) 60c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed , fCache(cache) 612a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman , fOutputProperties(outputProperties) 62c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed {} 63c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed 644cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org const SkMatrix& ctm() const { return fCTM; } 654cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org const SkIRect& clipBounds() const { return fClipBounds; } 66900c36779610dc65c42a5004ee3693fd70961ba4senorblanco SkImageFilterCache* cache() const { return fCache; } 672a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman const OutputProperties& outputProperties() const { return fOutputProperties; } 68c9b5f8b1522e72449d704d30ed6aee4fc6211ee8reed 694cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org private: 70900c36779610dc65c42a5004ee3693fd70961ba4senorblanco SkMatrix fCTM; 71900c36779610dc65c42a5004ee3693fd70961ba4senorblanco SkIRect fClipBounds; 72900c36779610dc65c42a5004ee3693fd70961ba4senorblanco SkImageFilterCache* fCache; 732a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman OutputProperties fOutputProperties; 744cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org }; 754cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org 76189186337eb91b0b21c15db42377bbf3ae4acf23reed class CropRect { 77189186337eb91b0b21c15db42377bbf3ae4acf23reed public: 78189186337eb91b0b21c15db42377bbf3ae4acf23reed enum CropEdge { 79189186337eb91b0b21c15db42377bbf3ae4acf23reed kHasLeft_CropEdge = 0x01, 80189186337eb91b0b21c15db42377bbf3ae4acf23reed kHasTop_CropEdge = 0x02, 81ed7cf273226ca5818a9d58b0f9183d665bb1ff58senorblanco kHasWidth_CropEdge = 0x04, 82ed7cf273226ca5818a9d58b0f9183d665bb1ff58senorblanco kHasHeight_CropEdge = 0x08, 83189186337eb91b0b21c15db42377bbf3ae4acf23reed kHasAll_CropEdge = 0x0F, 84189186337eb91b0b21c15db42377bbf3ae4acf23reed }; 85189186337eb91b0b21c15db42377bbf3ae4acf23reed CropRect() {} 86189186337eb91b0b21c15db42377bbf3ae4acf23reed explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) 87189186337eb91b0b21c15db42377bbf3ae4acf23reed : fRect(rect), fFlags(flags) {} 88189186337eb91b0b21c15db42377bbf3ae4acf23reed uint32_t flags() const { return fFlags; } 89189186337eb91b0b21c15db42377bbf3ae4acf23reed const SkRect& rect() const { return fRect; } 90189186337eb91b0b21c15db42377bbf3ae4acf23reed#ifndef SK_IGNORE_TO_STRING 91189186337eb91b0b21c15db42377bbf3ae4acf23reed void toString(SkString* str) const; 92189186337eb91b0b21c15db42377bbf3ae4acf23reed#endif 93189186337eb91b0b21c15db42377bbf3ae4acf23reed 94189186337eb91b0b21c15db42377bbf3ae4acf23reed /** 95189186337eb91b0b21c15db42377bbf3ae4acf23reed * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not 966db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco * set, then the corresponding edge from imageBounds will be used. If "embiggen" 976db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco * is true, the crop rect is allowed to enlarge the size of the rect, otherwise 986db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco * it may only reduce the rect. Filters that can affect transparent black should 996db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco * pass "true", while all other filters should pass "false". 100189186337eb91b0b21c15db42377bbf3ae4acf23reed * 101189186337eb91b0b21c15db42377bbf3ae4acf23reed * Note: imageBounds is in "device" space, as the output cropped rectangle will be, 102d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * so the matrix is ignored for those. It is only applied the croprect's bounds. 103189186337eb91b0b21c15db42377bbf3ae4acf23reed */ 1046db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco void applyTo(const SkIRect& imageBounds, const SkMatrix&, bool embiggen, 1056db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco SkIRect* cropped) const; 106189186337eb91b0b21c15db42377bbf3ae4acf23reed 107189186337eb91b0b21c15db42377bbf3ae4acf23reed private: 108189186337eb91b0b21c15db42377bbf3ae4acf23reed SkRect fRect; 109189186337eb91b0b21c15db42377bbf3ae4acf23reed uint32_t fFlags; 110189186337eb91b0b21c15db42377bbf3ae4acf23reed }; 111189186337eb91b0b21c15db42377bbf3ae4acf23reed 112a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco enum TileUsage { 113a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco kPossible_TileUsage, //!< the created device may be drawn tiled 114a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco kNever_TileUsage, //!< the created device will never be drawn tiled 115a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco }; 116a9fbd1676cf8bd0078c5be1f1c4abd4c76ea60adsenorblanco 117894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com /** 1185878dbdf1b5d86201d299c6e07d53e35048713c7senorblanco * Request a new filtered image to be created from the src image. 119894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * 1204418dbac3386f26c8da62ab242be9c178961eb18robertphillips * The context contains the environment in which the filter is occurring. 1214418dbac3386f26c8da62ab242be9c178961eb18robertphillips * It includes the clip bounds, CTM and cache. 122894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * 123894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * Offset is the amount to translate the resulting image relative to the 1246776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * src when it is drawn. This is an out-param. 125894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com * 1265878dbdf1b5d86201d299c6e07d53e35048713c7senorblanco * If the result image cannot be created, or the result would be 1275878dbdf1b5d86201d299c6e07d53e35048713c7senorblanco * transparent black, return null, in which case the offset parameter 1285878dbdf1b5d86201d299c6e07d53e35048713c7senorblanco * should be ignored by the caller. 1294418dbac3386f26c8da62ab242be9c178961eb18robertphillips * 1304418dbac3386f26c8da62ab242be9c178961eb18robertphillips * TODO: Right now the imagefilters sometimes return empty result bitmaps/ 1314418dbac3386f26c8da62ab242be9c178961eb18robertphillips * specialimages. That doesn't seem quite right. 132894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com */ 1332302de920e5434809bd0e85b871a6e002856dfdbrobertphillips sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context&, SkIPoint* offset) const; 134eaf086e3ce1b8351a8cd01762ca5144254bddbc4robertphillips 135d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco enum MapDirection { 136d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco kForward_MapDirection, 137d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco kReverse_MapDirection 138d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco }; 13915356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com /** 140d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * Map a device-space rect recursively forward or backward through the 141d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * filter DAG. kForward_MapDirection is used to determine which pixels of 142d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * the destination canvas a source image rect would touch after filtering. 143127fe3e24b488b7cf67308e791847ee229012862jbroman * kReverse_MapDirection is used to determine which rect of the source 144d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * image would be required to fill the given rect (typically, clip bounds). 145d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * Used for clipping and temp-buffer allocations, so the result need not 146d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * be exact, but should never be smaller than the real answer. The default 147e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * implementation recursively unions all input bounds, or returns the 148e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * source rect if no inputs. 14932d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com */ 150e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm, 151e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco MapDirection = kReverse_MapDirection) const; 152e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco 153af9b8c804643952d5ff3deed62f1355319b72f72robertphillips#if SK_SUPPORT_GPU 1542a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context, 155af9b8c804643952d5ff3deed62f1355319b72f72robertphillips sk_sp<GrFragmentProcessor> fp, 156afbf71dd924c7bb46ccdac49e7408b4b088563ffbrianosman const SkIRect& bounds, 1572a75e5df300a2838f943ca52a52a85a5cf69802bbrianosman const OutputProperties& outputProperties); 158af9b8c804643952d5ff3deed62f1355319b72f72robertphillips#endif 159af9b8c804643952d5ff3deed62f1355319b72f72robertphillips 1608d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org /** 161a1c511b8704c6c266b90860a4c68f30ca7514f9bsugoi@google.com * Returns whether this image filter is a color filter and puts the color filter into the 1624b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com * "filterPtr" parameter if it can. Does nothing otherwise. 1634b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com * If this returns false, then the filterPtr is unchanged. 1644b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler 1654b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com * (i.e. it may not be set to NULL). 1668d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org */ 167cedc36f18b2254c5ee21f6348124886b6db4f4c2reed bool isColorFilterNode(SkColorFilter** filterPtr) const { 168cedc36f18b2254c5ee21f6348124886b6db4f4c2reed return this->onIsColorFilterNode(filterPtr); 169cedc36f18b2254c5ee21f6348124886b6db4f4c2reed } 170cedc36f18b2254c5ee21f6348124886b6db4f4c2reed 171cedc36f18b2254c5ee21f6348124886b6db4f4c2reed // DEPRECATED : use isColorFilterNode() instead 172cedc36f18b2254c5ee21f6348124886b6db4f4c2reed bool asColorFilter(SkColorFilter** filterPtr) const { 173cedc36f18b2254c5ee21f6348124886b6db4f4c2reed return this->isColorFilterNode(filterPtr); 174cedc36f18b2254c5ee21f6348124886b6db4f4c2reed } 175cedc36f18b2254c5ee21f6348124886b6db4f4c2reed 176185a3798db64c64d47ef89a5fd3d4c5c70f1e621xidachen void removeKey(const SkImageFilterCacheKey& key) const; 177185a3798db64c64d47ef89a5fd3d4c5c70f1e621xidachen 178cedc36f18b2254c5ee21f6348124886b6db4f4c2reed /** 179cedc36f18b2254c5ee21f6348124886b6db4f4c2reed * Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely 180cedc36f18b2254c5ee21f6348124886b6db4f4c2reed * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the 181cedc36f18b2254c5ee21f6348124886b6db4f4c2reed * same way. 182cedc36f18b2254c5ee21f6348124886b6db4f4c2reed */ 183a544eda5ddea215037b1ada6ba5cfc98f6c8ee15senorblanco bool asAColorFilter(SkColorFilter** filterPtr) const; 1848d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 1858d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org /** 1868d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org * Returns the number of inputs this filter will accept (some inputs can 1878d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org * be NULL). 1888d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org */ 1896b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips int countInputs() const { return fInputs.count(); } 1908d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 1918d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org /** 1928d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org * Returns the input filter at a given index, or NULL if no input is 1938d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org * connected. The indices used are filter-specific. 1948d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org */ 1958d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org SkImageFilter* getInput(int i) const { 1966b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips SkASSERT(i < fInputs.count()); 1976b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips return fInputs[i].get(); 1988d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org } 1998d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org 200194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org /** 2013f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org * Returns whether any edges of the crop rect have been set. The crop 2023f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org * rect is set at construction time, and determines which pixels from the 203189186337eb91b0b21c15db42377bbf3ae4acf23reed * input image will be processed, and which pixels in the output image will be allowed. 204189186337eb91b0b21c15db42377bbf3ae4acf23reed * The size of the crop rect should be 2053f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org * used as the size of the destination image. The origin of this rect 2063f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org * should be used to offset access to the input images, and should also 2073e302275b324172c845627cbd00cee8a06571bafrobertphillips * be added to the "offset" parameter in onFilterImage. 208194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org */ 2093f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org bool cropRectIsSet() const { return fCropRect.flags() != 0x0; } 210194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org 211b3fe1b87e0ceefa27c183420c02d93d8fdf495dcreed CropRect getCropRect() const { return fCropRect; } 212b3fe1b87e0ceefa27c183420c02d93d8fdf495dcreed 213336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org // Default impl returns union of all input bounds. 214e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco virtual SkRect computeFastBounds(const SkRect&) const; 215336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org 2160abdf766d395ed3b7059511425f431589eca05f6senorblanco // Can this filter DAG compute the resulting bounds of an object-space rectangle? 2176db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco bool canComputeFastBounds() const; 2180abdf766d395ed3b7059511425f431589eca05f6senorblanco 2198c874eee943bdea0fab5b4d2707083c863e37c55senorblanco /** 22094dd7a52d3fe0632cd830f2e9cd14103c2726aacreed * If this filter can be represented by another filter + a localMatrix, return that filter, 22194dd7a52d3fe0632cd830f2e9cd14103c2726aacreed * else return null. 22294dd7a52d3fe0632cd830f2e9cd14103c2726aacreed */ 223372177ee115d46dfb5bfb881a408e6c37ae83678robertphillips sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix&) const; 224372177ee115d46dfb5bfb881a408e6c37ae83678robertphillips 22594dd7a52d3fe0632cd830f2e9cd14103c2726aacreed /** 226bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed * ImageFilters can natively handle scaling and translate components in the CTM. Only some of 227bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed * them can handle affine (or more complex) matrices. This call returns true iff the filter 228bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed * and all of its (non-null) inputs can handle these more complex matrices. 229bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed */ 23096a04f329926099f0002f97883242793ff04f61creed bool canHandleComplexCTM() const; 231bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed 232bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed /** 2338c30a8196dd5903d2d23b4d0a5dc888e802bf698reed * Return an imagefilter which transforms its input by the given matrix. 2348c874eee943bdea0fab5b4d2707083c863e37c55senorblanco */ 235ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix, 2368c30a8196dd5903d2d23b4d0a5dc888e802bf698reed SkFilterQuality quality, 237ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips sk_sp<SkImageFilter> input); 2388c30a8196dd5903d2d23b4d0a5dc888e802bf698reed 239f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips SK_TO_STRING_PUREVIRT() 2403b37545bc594a96de45eba62dea0ce478750f2a9mtklein SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter) 241e1e5c74086ceb7143bf2f7968a324e8c06d33914vjiaoblack SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() 242c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org 243894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.comprotected: 244b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed class Common { 245b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed public: 2469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed /** 2479fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * Attempt to unflatten the cropRect and the expected number of input filters. 2489fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * If any number of input filters is valid, pass -1. 2499fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * If this fails (i.e. corrupt buffer or contents) then return false and common will 2509fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * be left uninitialized. 2519fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * If this returns true, then inputCount() is the number of found input filters, each 2529fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * of which may be NULL or a valid imagefilter. 2539fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed */ 2549fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed bool unflatten(SkReadBuffer&, int expectedInputs); 2559fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 2569fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const CropRect& cropRect() const { return fCropRect; } 257b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed int inputCount() const { return fInputs.count(); } 2582238c9dbca4b791edc512957728a18ce14d55912robertphillips sk_sp<SkImageFilter>* inputs() const { return fInputs.get(); } 259b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed 2602238c9dbca4b791edc512957728a18ce14d55912robertphillips sk_sp<SkImageFilter> getInput(int index) const { return fInputs[index]; } 2619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 262b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed private: 263b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed CropRect fCropRect; 264b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed // most filters accept at most 2 input-filters 2652238c9dbca4b791edc512957728a18ce14d55912robertphillips SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs; 266b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed 267b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed void allocInputs(int count); 268b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed }; 269b959ec7815ae0f65f2aabdeaf280a2a2ee6db955reed 270ce6b4b004b2842e61cd9f86ebb75d1872044b382Mike Reed SkImageFilter(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect); 2719f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org 272d3b65972aad96453ff4510caa3e25a2b847c6d1eBrian Salomon ~SkImageFilter() override; 2739f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org 274c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org /** 2758b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org * Constructs a new SkImageFilter read from an SkReadBuffer object. 276c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org * 277c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org * @param inputCount The exact number of inputs expected for this SkImageFilter object. 278c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org * -1 can be used if the filter accepts any number of inputs. 2798b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org * @param rb SkReadBuffer object from which the SkImageFilter is read. 280c84728d72a47415929464c5cf062300d86a91246commit-bot@chromium.org */ 2818b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org explicit SkImageFilter(int inputCount, SkReadBuffer& rb); 2829f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org 28336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void flatten(SkWriteBuffer&) const override; 28432d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com 28531abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett const CropRect* getCropRectIfSet() const { 28631abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett return this->cropRectIsSet() ? &fCropRect : nullptr; 28731abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett } 28831abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett 2896776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org /** 2906776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * This is the virtual which should be overridden by the derived class 2916776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * to perform image filtering. 2926776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * 2936776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * src is the original primitive bitmap. If the filter has a connected 2946776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * input, it should recurse on that input and use that in place of src. 2956776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * 2966776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * The matrix is the current matrix on the canvas. 2976776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * 2986776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * Offset is the amount to translate the resulting image relative to the 2996776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * src when it is drawn. This is an out-param. 3006776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org * 3013e302275b324172c845627cbd00cee8a06571bafrobertphillips * If the result image cannot be created (either because of error or if, say, the result 3023e302275b324172c845627cbd00cee8a06571bafrobertphillips * is entirely clipped out), this should return nullptr. 3033e302275b324172c845627cbd00cee8a06571bafrobertphillips * Callers that affect transparent black should explicitly handle nullptr 3043e302275b324172c845627cbd00cee8a06571bafrobertphillips * results and press on. In the error case this behavior will produce a better result 3053e302275b324172c845627cbd00cee8a06571bafrobertphillips * than nothing and is necessary for the clipped out case. 3063e302275b324172c845627cbd00cee8a06571bafrobertphillips * If the return value is nullptr then offset should be ignored. 3076776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org */ 3082302de920e5434809bd0e85b871a6e002856dfdbrobertphillips virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&, 3093e302275b324172c845627cbd00cee8a06571bafrobertphillips SkIPoint* offset) const = 0; 310eaf086e3ce1b8351a8cd01762ca5144254bddbc4robertphillips 311d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco /** 312e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * This function recurses into its inputs with the given rect (first 313d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * argument), calls filterBounds() with the given map direction on each, 314e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * and returns the union of those results. If a derived class has special 315e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * recursion requirements (e.g., it has an input which does not participate 316e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco * in bounds computation), it can be overridden here. 317d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * 318d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * Note that this function is *not* responsible for mapping the rect for 319d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * this node's filter bounds requirements (i.e., calling 320d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco * onFilterNodeBounds()); that is handled by filterBounds(). 321d8ff5b336e586ad971ebcafa5fb2eb1e7ac95589senorblanco */ 322e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const; 323db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco 324db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco /** 325db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * Performs a forwards or reverse mapping of the given rect to accommodate 326db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * this filter's margin requirements. kForward_MapDirection is used to 327db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * determine the destination pixels which would be touched by filtering 328db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * the given given source rect (e.g., given source bitmap bounds, 329db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * determine the optimal bounds of the filtered offscreen bitmap). 330db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * kReverse_MapDirection is used to determine which pixels of the 331db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * input(s) would be required to fill the given destination rect 332db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * (e.g., clip bounds). NOTE: these operations may not be the 333db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * inverse of the other. For example, blurring expands the given rect 334db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * in both forward and reverse directions. Unlike 335db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * onFilterBounds(), this function is non-recursive. 336db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco */ 337e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const; 338894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com 339b9519f86bbce946e505980a4fa950fdc4bcf74absenorblanco // Helper function which invokes filter processing on the input at the 3403e302275b324172c845627cbd00cee8a06571bafrobertphillips // specified "index". If the input is null, it returns "src" and leaves 3413e302275b324172c845627cbd00cee8a06571bafrobertphillips // "offset" untouched. If the input is non-null, it 3423e302275b324172c845627cbd00cee8a06571bafrobertphillips // calls filterImage() on that input, and returns the result. 3433e302275b324172c845627cbd00cee8a06571bafrobertphillips sk_sp<SkSpecialImage> filterInput(int index, 3443e302275b324172c845627cbd00cee8a06571bafrobertphillips SkSpecialImage* src, 3453e302275b324172c845627cbd00cee8a06571bafrobertphillips const Context&, 3463e302275b324172c845627cbd00cee8a06571bafrobertphillips SkIPoint* offset) const; 347b9519f86bbce946e505980a4fa950fdc4bcf74absenorblanco 348cedc36f18b2254c5ee21f6348124886b6db4f4c2reed /** 349cedc36f18b2254c5ee21f6348124886b6db4f4c2reed * Return true (and return a ref'd colorfilter) if this node in the DAG is just a 350cedc36f18b2254c5ee21f6348124886b6db4f4c2reed * colorfilter w/o CropRect constraints. 351cedc36f18b2254c5ee21f6348124886b6db4f4c2reed */ 352cedc36f18b2254c5ee21f6348124886b6db4f4c2reed virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const { 353cedc36f18b2254c5ee21f6348124886b6db4f4c2reed return false; 354cedc36f18b2254c5ee21f6348124886b6db4f4c2reed } 355cedc36f18b2254c5ee21f6348124886b6db4f4c2reed 35696a04f329926099f0002f97883242793ff04f61creed /** 35796a04f329926099f0002f97883242793ff04f61creed * Override this to describe the behavior of your subclass - as a leaf node. The caller will 35896a04f329926099f0002f97883242793ff04f61creed * take care of calling your inputs (and return false if any of them could not handle it). 35996a04f329926099f0002f97883242793ff04f61creed */ 36096a04f329926099f0002f97883242793ff04f61creed virtual bool onCanHandleComplexCTM() const { return false; } 361bb34a8ac59850f128d9602e629a7475e3ad1a9d2reed 362af9b8c804643952d5ff3deed62f1355319b72f72robertphillips /** Given a "srcBounds" rect, computes destination bounds for this filter. 363af9b8c804643952d5ff3deed62f1355319b72f72robertphillips * "dstBounds" are computed by transforming the crop rect by the context's 364af9b8c804643952d5ff3deed62f1355319b72f72robertphillips * CTM, applying it to the initial bounds, and intersecting the result with 365af9b8c804643952d5ff3deed62f1355319b72f72robertphillips * the context's clip bounds. "srcBounds" (if non-null) are computed by 366af9b8c804643952d5ff3deed62f1355319b72f72robertphillips * intersecting the initial bounds with "dstBounds", to ensure that we never 367af9b8c804643952d5ff3deed62f1355319b72f72robertphillips * sample outside of the crop rect (this restriction may be relaxed in the 368afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * future). 369118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org */ 370afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const; 371afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco 372afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco /** A variant of the above call which takes the original source bitmap and 373afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * source offset. If the resulting crop rect is not entirely contained by 374afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * the source bitmap's bounds, it creates a new bitmap in "result" and 375afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * pads the edges with transparent black. In that case, the srcOffset is 376afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * modified to be the same as the bounds, since no further adjustment is 377afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * needed by the caller. This version should only be used by filters 378afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * which are not capable of processing a smaller source bitmap into a 379afec27f13b28d900232cb1825c63cab2d6e4e103senorblanco * larger destination. 380118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org */ 3812302de920e5434809bd0e85b871a6e002856dfdbrobertphillips sk_sp<SkSpecialImage> applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset, 3822302de920e5434809bd0e85b871a6e002856dfdbrobertphillips SkIRect* bounds) const; 383eaf086e3ce1b8351a8cd01762ca5144254bddbc4robertphillips 3841aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org /** 385db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * Creates a modified Context for use when recursing up the image filter DAG. 386db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * The clip bounds are adjusted to accommodate any margins that this 387db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * filter requires by calling this node's 388db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco * onFilterNodeBounds(..., kReverse_MapDirection). 389db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco */ 390db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco Context mapContext(const Context& ctx) const; 391db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco 392615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman#if SK_SUPPORT_GPU 393615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman /** 394615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman * Returns a version of the passed-in image (possibly the original), that is in a colorspace 395615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman * with the same gamut as the one from the OutputProperties. This allows filters that do many 396615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman * texture samples to guarantee that any color space conversion has happened before running. 397615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman */ 398615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&); 399615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman#endif 400615d66d1aed8f0b6510d58658e639b69c4d73b35Brian Osman 40131abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett /** 40231abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett * Returns an image filter transformed into a new color space via the |xformer|. 40331abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett */ 40431abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const { 40531abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett return this->onMakeColorSpace(xformer); 40631abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett } 40762745a8bba20d7ca91167915eb459339bcfb8862Matt Sarett virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const = 0; 40831abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett 4096d9f42984d94a2e9116dd951d47cd65cd8f4d401Mike Reed sk_sp<SkImageFilter> refMe() const { 4106d9f42984d94a2e9116dd951d47cd65cd8f4d401Mike Reed return sk_ref_sp(const_cast<SkImageFilter*>(this)); 4116d9f42984d94a2e9116dd951d47cd65cd8f4d401Mike Reed } 4126d9f42984d94a2e9116dd951d47cd65cd8f4d401Mike Reed 413894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.comprivate: 4146d72ed918d8763e65899183c2d12b06958c791f4Matt Sarett // For makeColorSpace(). 41531abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett friend class SkColorSpaceXformer; 4166d72ed918d8763e65899183c2d12b06958c791f4Matt Sarett 417242397a1c95e34e3e2e5e85c85c81090317115cbmtklein friend class SkGraphics; 41831abf1fc945c27755173b78037e62576cf2dd62eMatt Sarett 419242397a1c95e34e3e2e5e85c85c81090317115cbmtklein static void PurgeCache(); 420242397a1c95e34e3e2e5e85c85c81090317115cbmtklein 421ce6b4b004b2842e61cd9f86ebb75d1872044b382Mike Reed void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect); 4224418dbac3386f26c8da62ab242be9c178961eb18robertphillips 42355b6d8be997a447ef9ce0f029697677a940bfc24senorblanco bool usesSrcInput() const { return fUsesSrcInput; } 4246db0a7bdceb6be85721bfb0db8dea7fd27db5970senorblanco virtual bool affectsTransparentBlack() const { return false; } 42555b6d8be997a447ef9ce0f029697677a940bfc24senorblanco 4266b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs; 4276b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips 42855b6d8be997a447ef9ce0f029697677a940bfc24senorblanco bool fUsesSrcInput; 429b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org CropRect fCropRect; 43055b6d8be997a447ef9ce0f029697677a940bfc24senorblanco uint32_t fUniqueID; // Globally unique 431900c36779610dc65c42a5004ee3693fd70961ba4senorblanco mutable SkTArray<SkImageFilterCacheKey> fCacheKeys; 43223526963135bd15737505bd560d41b0d5a41439exidachen mutable SkMutex fMutex; 4336b13473dd4d5915309cc2caddbab2e22f2f21d5frobertphillips typedef SkFlattenable INHERITED; 434894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com}; 435894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com 4369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed/** 4379fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed * Helper to unflatten the common data, and return NULL if we fail. 4389fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed */ 4399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \ 4409fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed Common localVar; \ 4419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed do { \ 4429fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (!localVar.unflatten(buffer, expectedCount)) { \ 4439fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; \ 4449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } \ 4459fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } while (0) 4469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 447894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#endif 448