SkImageFilter.h revision 1aa68723b8ef4ce0b6db9fe51e7d8051cdd543ff
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
11894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#include "SkFlattenable.h"
12194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org#include "SkRect.h"
13894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com
1415356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.comclass SkBitmap;
158d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.orgclass SkColorFilter;
161f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.comclass SkBaseDevice;
1715356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.comclass SkMatrix;
18c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.comstruct SkIPoint;
19a1c511b8704c6c266b90860a4c68f30ca7514f9bsugoi@google.comclass SkShader;
200ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.comclass GrEffectRef;
21d0c1a06cb98dd4a009dfa79e37ba6ca23a8c180btomhudson@google.comclass GrTexture;
2215356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com
2315356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com/**
2415356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com *  Base class for image filters. If one is installed in the paint, then
2515356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com *  all drawing occurs as usual, but it is as if the drawing happened into an
2615356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com *  offscreen (before the xfermode is applied). This offscreen bitmap will
2715356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com *  then be handed to the imagefilter, who in turn creates a new bitmap which
2815356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com *  is what will finally be drawn to the device (using the original xfermode).
2915356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com */
3054e01b2ab985e7a7d38109812069d056d128bfa1senorblanco@chromium.orgclass SK_API SkImageFilter : public SkFlattenable {
31894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.compublic:
320456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com    SK_DECLARE_INST_COUNT(SkImageFilter)
330456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com
343f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org    class CropRect {
353f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org    public:
36b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org        enum CropEdge {
37b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org            kHasLeft_CropEdge   = 0x01,
38b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org            kHasTop_CropEdge    = 0x02,
39b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org            kHasRight_CropEdge  = 0x04,
40b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org            kHasBottom_CropEdge = 0x08,
41b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org            kHasAll_CropEdge    = 0x0F,
42b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org        };
43b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org        CropRect() {}
44b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org        explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge) : fRect(rect), fFlags(flags) {}
453f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org        uint32_t flags() const { return fFlags; }
463f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org        const SkRect& rect() const { return fRect; }
473f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org    private:
483f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org        SkRect fRect;
493f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org        uint32_t fFlags;
50b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org    };
51b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org
5276dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    class Proxy {
5376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    public:
548926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        virtual ~Proxy() {};
558926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com
561f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com        virtual SkBaseDevice* createDevice(int width, int height) = 0;
578926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        // returns true if the proxy can handle this filter natively
588926b169f6a0dfa4c2129a98ec2aee205f0c8527reed@google.com        virtual bool canHandleImageFilter(SkImageFilter*) = 0;
5976dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        // returns true if the proxy handled the filter itself. if this returns
6076dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        // false then the filter's code will be called.
6176dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com        virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
6276dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com                                 const SkMatrix& ctm,
6376dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com                                 SkBitmap* result, SkIPoint* offset) = 0;
6476dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    };
65894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com
66894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com    /**
67894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  Request a new (result) image to be created from the src image.
68894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  If the src has no pixels (isNull()) then the request just wants to
69894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  receive the config and width/height of the result.
70894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *
71894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  The matrix is the current matrix on the canvas.
72894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *
73894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  Offset is the amount to translate the resulting image relative to the
74fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     *  src when it is drawn.
75894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *
76894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  If the result image cannot be created, return false, in which case both
77894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     *  the result and offset parameters will be ignored by the caller.
78894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com     */
7976dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
8015356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com                     SkBitmap* result, SkIPoint* offset);
8115356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com
8215356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com    /**
8332d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com     *  Given the src bounds of an image, this returns the bounds of the result
8432d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com     *  image after the filter has been applied.
8532d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com     */
8632d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com    bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
8732d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com
8832d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com    /**
89302cffba86a188373c99833d83392f33e6014542senorblanco@chromium.org     *  Returns true if the filter can be processed on the GPU.  This is most
90302cffba86a188373c99833d83392f33e6014542senorblanco@chromium.org     *  often used for multi-pass effects, where intermediate results must be
918ea78d83dc4e8243c16eedf8100a3987c54123fabsalomon@google.com     *  rendered to textures.  For single-pass effects, use asNewEffect().
92fbaea5336690ffc4fd9ee695608e9457da10eeabsenorblanco@chromium.org     *  The default implementation returns asNewEffect(NULL, NULL, SkMatrix::I()).
9305054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org     */
94302cffba86a188373c99833d83392f33e6014542senorblanco@chromium.org    virtual bool canFilterImageGPU() const;
9505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
9605054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org    /**
973284017a60ea4fc3dc5b95838ba0c301ee1e4e8dskia.committer@gmail.com     *  Process this image filter on the GPU.  This is most often used for
98d043ccee3788ea4192806bd8c94484ed003fa828senorblanco@chromium.org     *  multi-pass effects, where intermediate results must be rendered to
99d043ccee3788ea4192806bd8c94484ed003fa828senorblanco@chromium.org     *  textures.  For single-pass effects, use asNewEffect().  src is the
100d043ccee3788ea4192806bd8c94484ed003fa828senorblanco@chromium.org     *  source image for processing, as a texture-backed bitmap.  result is
101d043ccee3788ea4192806bd8c94484ed003fa828senorblanco@chromium.org     *  the destination bitmap, which should contain a texture-backed pixelref
102de2e4e8a6422c7d8b5847f038f5c6360b187f7a2skia.committer@gmail.com     *  on success.  offset is the amount to translate the resulting image
1037b320703d47ff2b242ae74faba5e4b0af3560d71commit-bot@chromium.org     *  relative to the src when it is drawn. The default implementation does
1047b320703d47ff2b242ae74faba5e4b0af3560d71commit-bot@chromium.org     *  single-pass processing using asNewEffect().
10505054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org     */
1061aa54bf6696afc7d06fc8ecc63dad2840a4d6179commit-bot@chromium.org    virtual bool filterImageGPU(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
1071aa54bf6696afc7d06fc8ecc63dad2840a4d6179commit-bot@chromium.org                                SkBitmap* result, SkIPoint* offset);
10805054f1a78a697b507580d0025db6c90423e033fsenorblanco@chromium.org
1098d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    /**
110a1c511b8704c6c266b90860a4c68f30ca7514f9bsugoi@google.com     *  Returns whether this image filter is a color filter and puts the color filter into the
1114b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com     *  "filterPtr" parameter if it can. Does nothing otherwise.
1124b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com     *  If this returns false, then the filterPtr is unchanged.
1134b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com     *  If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
1144b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com     *  (i.e. it may not be set to NULL).
1158d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     */
1164b6d432f1e4ea0a6556dfff1b4d19b69ca005c27sugoi@google.com    virtual bool asColorFilter(SkColorFilter** filterPtr) const;
1178d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org
1188d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    /**
1198d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     *  Returns the number of inputs this filter will accept (some inputs can
1208d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     *  be NULL).
1218d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     */
1228d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    int countInputs() const { return fInputCount; }
1238d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org
1248d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    /**
1258d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     *  Returns the input filter at a given index, or NULL if no input is
1268d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     *  connected.  The indices used are filter-specific.
1278d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org     */
1288d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    SkImageFilter* getInput(int i) const {
1298d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org        SkASSERT(i < fInputCount);
1308d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org        return fInputs[i];
1318d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    }
1328d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org
133194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org    /**
1343f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  Returns whether any edges of the crop rect have been set. The crop
1353f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  rect is set at construction time, and determines which pixels from the
1363f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  input image will be processed. The size of the crop rect should be
1373f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  used as the size of the destination image. The origin of this rect
1383f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  should be used to offset access to the input images, and should also
1393f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  be added to the "offset" parameter in onFilterImage and
1403f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  filterImageGPU(). (The latter ensures that the resulting buffer is
1413f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org     *  drawn in the correct location.)
142194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org     */
1433f1f2a3a59c43e5bce67ab98e55df45bc7c933a3senorblanco@chromium.org    bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
144194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org
145894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.comprotected:
146b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org    SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = NULL);
1479f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org
148c2e8cef4792b478547973d312b26fff4aab7c729senorblanco@chromium.org    // Convenience constructor for 1-input filters.
149b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org    explicit SkImageFilter(SkImageFilter* input, const CropRect* cropRect = NULL);
150c2e8cef4792b478547973d312b26fff4aab7c729senorblanco@chromium.org
151c2e8cef4792b478547973d312b26fff4aab7c729senorblanco@chromium.org    // Convenience constructor for 2-input filters.
152b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org    SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect = NULL);
1539f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org
1549f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org    virtual ~SkImageFilter();
1559f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org
1569f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org    explicit SkImageFilter(SkFlattenableReadBuffer& rb);
1579f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org
1589f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org    virtual void flatten(SkFlattenableWriteBuffer& wb) const SK_OVERRIDE;
15932d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com
16032d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com    // Default impl returns false
16176dd277b1fa021c42fc3acdd8d61e7dc05f9c267reed@google.com    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
16215356a68b2a87e3ab9fc49392d085a4201ffeb62reed@google.com                               SkBitmap* result, SkIPoint* offset);
16332d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com    // Default impl copies src into dst and returns true
16432d25b6f5f4355d4c5281694034ba3a5aa2cf571reed@google.com    virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
165894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com
166fbaea5336690ffc4fd9ee695608e9457da10eeabsenorblanco@chromium.org    // Applies "matrix" to the crop rect, and sets "rect" to the intersection of
167fbaea5336690ffc4fd9ee695608e9457da10eeabsenorblanco@chromium.org    // "rect" and the transformed crop rect. If there is no overlap, returns
168fbaea5336690ffc4fd9ee695608e9457da10eeabsenorblanco@chromium.org    // false and leaves "rect" unchanged.
169fbaea5336690ffc4fd9ee695608e9457da10eeabsenorblanco@chromium.org    bool applyCropRect(SkIRect* rect, const SkMatrix& matrix) const;
170194d775edcf5fa6e82098a97ad53018d70db1155senorblanco@chromium.org
1711aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org    /**
1721aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  Returns true if the filter can be expressed a single-pass
1731aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  GrEffect, used to process this filter on the GPU, or false if
1741aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  not.
1751aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *
1761aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  If effect is non-NULL, a new GrEffect instance is stored
1771aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  in it.  The caller assumes ownership of the stage, and it is up to the
1781aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  caller to unref it.
1791aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *
1801aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  The effect can assume its vertexCoords space maps 1-to-1 with texels
1811aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  in the texture.  "matrix" is a transformation to apply to filter
1821aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  parameters before they are used in the effect. Note that this function
1831aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  will be called with (NULL, NULL, SkMatrix::I()) to query for support,
1841aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     *  so returning "true" indicates support for all possible matrices.
1851aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org     */
1861aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org    virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkMatrix& matrix) const;
1871aa68723b8ef4ce0b6db9fe51e7d8051cdd543ffsenorblanco@chromium.org
188894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.comprivate:
18954e01b2ab985e7a7d38109812069d056d128bfa1senorblanco@chromium.org    typedef SkFlattenable INHERITED;
1908d21f6c7a9d0cf4f87d77c235c6da7203620c7e5senorblanco@chromium.org    int fInputCount;
1919f25de79009ce721aa13abe71c38179d5a6710e2senorblanco@chromium.org    SkImageFilter** fInputs;
192b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.org    CropRect fCropRect;
193894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com};
194894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com
195894aa9a7af0e5598600df694d184d3c7d2e454b0reed@google.com#endif
196