michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkLayerDrawLooper_DEFINED michael@0: #define SkLayerDrawLooper_DEFINED michael@0: michael@0: #include "SkDrawLooper.h" michael@0: #include "SkPaint.h" michael@0: #include "SkPoint.h" michael@0: #include "SkXfermode.h" michael@0: michael@0: class SK_API SkLayerDrawLooper : public SkDrawLooper { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkLayerDrawLooper) michael@0: michael@0: SkLayerDrawLooper(); michael@0: virtual ~SkLayerDrawLooper(); michael@0: michael@0: /** michael@0: * Bits specifies which aspects of the layer's paint should replace the michael@0: * corresponding aspects on the draw's paint. michael@0: * kEntirePaint_Bits means use the layer's paint completely. michael@0: * 0 means ignore the layer's paint... except for fColorMode, which is michael@0: * always applied. michael@0: */ michael@0: enum Bits { michael@0: kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings michael@0: kTextSkewX_Bit = 1 << 1, //!< use this layer's textskewx michael@0: kPathEffect_Bit = 1 << 2, //!< use this layer's patheffect michael@0: kMaskFilter_Bit = 1 << 3, //!< use this layer's maskfilter michael@0: kShader_Bit = 1 << 4, //!< use this layer's shader michael@0: kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter michael@0: kXfermode_Bit = 1 << 6, //!< use this layer's xfermode michael@0: michael@0: /** michael@0: * Use the layer's paint entirely, with these exceptions: michael@0: * - We never override the draw's paint's text_encoding, since that is michael@0: * used to interpret the text/len parameters in draw[Pos]Text. michael@0: * - Color is always computed using the LayerInfo's fColorMode. michael@0: */ michael@0: kEntirePaint_Bits = -1 michael@0: michael@0: }; michael@0: typedef int32_t BitFlags; michael@0: michael@0: /** michael@0: * Info for how to apply the layer's paint and offset. michael@0: * michael@0: * fColorMode controls how we compute the final color for the layer: michael@0: * The layer's paint's color is treated as the SRC michael@0: * The draw's paint's color is treated as the DST michael@0: * final-color = Mode(layers-color, draws-color); michael@0: * Any SkXfermode::Mode will work. Two common choices are: michael@0: * kSrc_Mode: to use the layer's color, ignoring the draw's michael@0: * kDst_Mode: to just keep the draw's color, ignoring the layer's michael@0: */ michael@0: struct SK_API LayerInfo { michael@0: BitFlags fPaintBits; michael@0: SkXfermode::Mode fColorMode; michael@0: SkVector fOffset; michael@0: bool fPostTranslate; //!< applies to fOffset michael@0: michael@0: /** michael@0: * Initial the LayerInfo. Defaults to settings that will draw the michael@0: * layer with no changes: e.g. michael@0: * fPaintBits == 0 michael@0: * fColorMode == kDst_Mode michael@0: * fOffset == (0, 0) michael@0: */ michael@0: LayerInfo(); michael@0: }; michael@0: michael@0: /** michael@0: * Call for each layer you want to add (from top to bottom). michael@0: * This returns a paint you can modify, but that ptr is only valid until michael@0: * the next call made to addLayer(). michael@0: */ michael@0: SkPaint* addLayer(const LayerInfo&); michael@0: michael@0: /** michael@0: * This layer will draw with the original paint, at the specified offset michael@0: */ michael@0: void addLayer(SkScalar dx, SkScalar dy); michael@0: michael@0: /** michael@0: * This layer will with the original paint and no offset. michael@0: */ michael@0: void addLayer() { this->addLayer(0, 0); } michael@0: michael@0: /// Similar to addLayer, but adds a layer to the top. michael@0: SkPaint* addLayerOnTop(const LayerInfo&); michael@0: michael@0: virtual SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE; michael@0: michael@0: virtual size_t contextSize() const SK_OVERRIDE { return sizeof(LayerDrawLooperContext); } michael@0: michael@0: SK_TO_STRING_OVERRIDE() michael@0: michael@0: /// Implements Flattenable. michael@0: virtual Factory getFactory() const SK_OVERRIDE { return CreateProc; } michael@0: static SkFlattenable* CreateProc(SkReadBuffer& buffer); michael@0: michael@0: protected: michael@0: virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; michael@0: michael@0: private: michael@0: struct Rec { michael@0: Rec* fNext; michael@0: SkPaint fPaint; michael@0: LayerInfo fInfo; michael@0: }; michael@0: Rec* fRecs; michael@0: Rec* fTopRec; michael@0: int fCount; michael@0: michael@0: // state-machine during the init/next cycle michael@0: class LayerDrawLooperContext : public SkDrawLooper::Context { michael@0: public: michael@0: explicit LayerDrawLooperContext(const SkLayerDrawLooper* looper); michael@0: michael@0: protected: michael@0: virtual bool next(SkCanvas*, SkPaint* paint) SK_OVERRIDE; michael@0: michael@0: private: michael@0: Rec* fCurrRec; michael@0: michael@0: static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); michael@0: }; michael@0: michael@0: class MyRegistrar : public SkFlattenable::Registrar { michael@0: public: michael@0: MyRegistrar(); michael@0: }; michael@0: michael@0: typedef SkDrawLooper INHERITED; michael@0: michael@0: public: michael@0: class SK_API Builder { michael@0: public: michael@0: Builder(); michael@0: ~Builder(); michael@0: michael@0: /** michael@0: * Call for each layer you want to add (from top to bottom). michael@0: * This returns a paint you can modify, but that ptr is only valid until michael@0: * the next call made to addLayer(). michael@0: */ michael@0: SkPaint* addLayer(const LayerInfo&); michael@0: michael@0: /** michael@0: * This layer will draw with the original paint, at the specified offset michael@0: */ michael@0: void addLayer(SkScalar dx, SkScalar dy); michael@0: michael@0: /** michael@0: * This layer will with the original paint and no offset. michael@0: */ michael@0: void addLayer() { this->addLayer(0, 0); } michael@0: michael@0: /// Similar to addLayer, but adds a layer to the top. michael@0: SkPaint* addLayerOnTop(const LayerInfo&); michael@0: michael@0: /** michael@0: * Pass list of layers on to newly built looper and return it. This will michael@0: * also reset the builder, so it can be used to build another looper. michael@0: */ michael@0: SkLayerDrawLooper* detachLooper(); michael@0: michael@0: private: michael@0: Rec* fRecs; michael@0: Rec* fTopRec; michael@0: int fCount; michael@0: }; michael@0: }; michael@0: michael@0: #endif