Chinaunix首页 | 论坛 | 博客
  • 博客访问: 64099
  • 博文数量: 29
  • 博客积分: 1250
  • 博客等级: 中尉
  • 技术积分: 292
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-30 13:04
文章分类

全部博文(29)

文章存档

2009年(24)

2008年(5)

我的朋友

分类:

2009-03-23 14:47:01

Canvas          : SkCanvas.h 这个文件比较重要。

 

//SkCanvas.h

/*  This is the record we keep for each SkDevice that the user installs.

    The clip/matrix/proc are fields that reflect the top of the save/restore

    stack. Whenever the canvas changes, it marks a dirty flag, and then before

    these are used (assuming we're not on a layer) we rebuild these cache

    values: they reflect the top of the save stack, but translated and clipped

    by the device's XY offset and bitmap-bounds.

*/

//这个结构体是用来保存用户安装的SkDevice的。SkRegionSkMatrix保存了当前SkDevice的状况。

//一旦SkDevice有变化,将会有个dirty标志位。这个时候将会重新构建每个被保存的SkDevice结构体--DeviceCM

//这些被cache的值只反映顶点坐标,而坐标的转换和裁剪由SkDevice获得。

//注意这个结构体是一个链表结构DeviceCM* fNext.

struct DeviceCM {

    DeviceCM*           fNext;

    SkDevice*           fDevice;

    SkRegion            fClip;

    const SkMatrix*     fMatrix;

       SkPaint*                fPaint;    // may be null (in the future)

    int16_t             fX, fY; // relative to base matrix/clip

 

       DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)

            : fNext(NULL) {

        if (NULL != device) {

            device->ref();

            device->lockPixels();

        }

        fDevice = device;       

        fX = SkToS16(x);

        fY = SkToS16(y);

        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;

       }

 

       ~DeviceCM() {

        if (NULL != fDevice) {

            fDevice->unlockPixels();

            fDevice->unref();

        }

              SkDELETE(fPaint);

       }

   

    void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,

                  SkRegion* updateClip) {

        int x = fX;

        int y = fY;

        int width = fDevice->width();

        int height = fDevice->height();

   

        if ((x | y) == 0) { //x==0 && y==0

            fMatrix = &totalMatrix;

            fClip = totalClip;

        } else {

            fMatrixStorage = totalMatrix;

            fMatrixStorage.postTranslate(SkIntToScalar(-x),

                                         SkIntToScalar(-y));

            fMatrix = &fMatrixStorage;

            

            totalClip.translate(-x, -y, &fClip);

        }

 

        fClip.op(0, 0, width, height, SkRegion::kIntersect_Op);

 

        // intersect clip, but don't translate it (yet)

       

        if (updateClip) {

            updateClip->op(x, y, x + width, y + height,

                           SkRegion::kDifference_Op);

        }

       

        fDevice->setMatrixClip(*fMatrix, fClip);

 

#ifdef SK_DEBUG

        if (!fClip.isEmpty()) {

            SkIRect deviceR;

            deviceR.set(0, 0, width, height);

            SkASSERT(deviceR.contains(fClip.getBounds()));

        }

#endif

    }

   

    void translateClip() {

        if (fX | fY) {

            fClip.translate(fX, fY);

        }

    }

 

private:

    SkMatrix    fMatrixStorage;

};

 

/*  This is the record we keep for each save/restore level in the stack.

    Since a level optionally copies the matrix and/or stack, we have pointers

    for these fields. If the value is copied for this level, the copy is

    stored in the ...Storage field, and the pointer points to that. If the

    value is not copied for this level, we ignore ...Storage, and just point

    at the corresponding value in the previous level in the stack.

*/

//这个结构体是用来保存stack中的SkDevice的。SkCanvas可以由多个SkDevice构成,每个SkDevice都会有一个对应的在stack中的结构体保存。

//存取这些结构体使用SkDeque

//注意这个结构体是一个链表结构MCRec* fNext.

class SkCanvas::MCRec {

public:

    MCRec*          fNext;

    SkMatrix*       fMatrix;    // points to either fMatrixStorage or prev MCRec

    SkRegion*       fRegion;    // points to either fRegionStorage or prev MCRec

    SkDrawFilter*   fFilter;    // the current filter (or null)

   

    DeviceCM*   fLayer;

    /*  If there are any layers in the stack, this points to the top-most

        one that is at or below this level in the stack (so we know what

        bitmap/device to draw into from this level. This value is NOT

        reference counted, since the real owner is either our fLayer field,

        or a previous one in a lower level.)

    */

    DeviceCM*      fTopLayer;

 

    MCRec(const MCRec* prev, int flags) {

        if (NULL != prev) {

            if (flags & SkCanvas::kMatrix_SaveFlag) {

                fMatrixStorage = *prev->fMatrix;

                fMatrix = &fMatrixStorage;

            } else {

                fMatrix = prev->fMatrix;

            }

           

            if (flags & SkCanvas::kClip_SaveFlag) {

                fRegionStorage = *prev->fRegion;

                fRegion = &fRegionStorage;

            } else {

                fRegion = prev->fRegion;

            }

 

            fFilter = prev->fFilter;

            fFilter->safeRef();

 

            fTopLayer = prev->fTopLayer;

        } else {   // no prev

            fMatrixStorage.reset();

           

            fMatrix     = &fMatrixStorage;

            fRegion     = &fRegionStorage;

            fFilter     = NULL;

            fTopLayer   = NULL;

        }

        fLayer = NULL;

 

        // don't bother initializing fNext

        inc_rec();

    }

    ~MCRec() {

        fFilter->safeUnref();

        SkDELETE(fLayer);

        dec_rec();

    }

      

private:

    SkMatrix    fMatrixStorage;

    SkRegion    fRegionStorage;

};

 

class SkDrawIter : public SkDraw {

public:

    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {

        fCanvas = canvas;

        canvas->updateDeviceCMCache();

 

        fBounder = canvas->getBounder();

        fCurrLayer = canvas->fMCRec->fTopLayer;

        fSkipEmptyClips = skipEmptyClips;

    }

   

    bool next() {

        // skip over recs with empty clips

        if (fSkipEmptyClips) {

            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {

                fCurrLayer = fCurrLayer->fNext;

            }

        }

 

        if (NULL != fCurrLayer) {

            const DeviceCM* rec = fCurrLayer;

 

            fMatrix = rec->fMatrix;

            fClip   = &rec->fClip;

            fDevice = rec->fDevice;

            fBitmap = &fDevice->accessBitmap(true);

            fLayerX = rec->fX;

            fLayerY = rec->fY;

            fPaint  = rec->fPaint;

            SkDEBUGCODE(this->validate();)

 

            fCurrLayer = rec->fNext;

            if (fBounder) {

                fBounder->setClip(fClip);

            }

 

            // fCurrLayer may be NULL now

           

            fCanvas->prepareForDeviceDraw(fDevice);

            return true;

        }

        return false;

    }

   

    int getX() const { return fLayerX; }

    int getY() const { return fLayerY; }

    SkDevice* getDevice() const { return fDevice; }

    const SkMatrix& getMatrix() const { return *fMatrix; }

    const SkRegion& getClip() const { return *fClip; }

    const SkPaint* getPaint() const { return fPaint; }

private:

    SkCanvas*       fCanvas;

    const DeviceCM* fCurrLayer;

    const SkPaint*  fPaint;     // May be null.

    int             fLayerX;

    int             fLayerY;

    SkBool8         fSkipEmptyClips;

 

    typedef SkDraw INHERITED;

};

 

/////////////////////////////////////////////////////////////////////////////

 

class AutoDrawLooper {

public:

    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, SkDrawFilter::Type t)

            : fCanvas(canvas), fPaint((SkPaint*)&paint), fType(t) {

        if ((fLooper = paint.getLooper()) != NULL) {

            fLooper->init(canvas, (SkPaint*)&paint);

        } else {

            fOnce = true;

        }

        fFilter = canvas->getDrawFilter();

        fNeedFilterRestore = false;

    }

 

    ~AutoDrawLooper() {

        if (fNeedFilterRestore) {

            SkASSERT(fFilter);

            fFilter->restore(fCanvas, fPaint, fType);

        }

        if (NULL != fLooper) {

            fLooper->restore();

        }

    }

   

    bool next() {

        SkDrawFilter* filter = fFilter;

 

        // if we drew earlier with a filter, then we need to restore first

        if (fNeedFilterRestore) {

            SkASSERT(filter);

            filter->restore(fCanvas, fPaint, fType);

            fNeedFilterRestore = false;

        }

           

        bool result;

       

        if (NULL != fLooper) {

            result = fLooper->next();

        } else {

            result = fOnce;

            fOnce = false;

        }

 

        // if we're gonna draw, give the filter a chance to do its work

        if (result && NULL != filter) {

            fNeedFilterRestore = result = filter->filter(fCanvas, fPaint,

                                                         fType);

        }

        return result;

    }

   

private:

    SkDrawLooper*   fLooper;

    SkDrawFilter*   fFilter;

    SkCanvas*       fCanvas;

    SkPaint*        fPaint;

    SkDrawFilter::Type  fType;

    bool            fOnce;

    bool            fNeedFilterRestore;

   

};

 

/*  Stack helper for managing a SkBounder. In the destructor, if we were

    given a bounder, we call its commit() method, signifying that we are

    done accumulating bounds for that draw.

*/

class SkAutoBounderCommit {

public:

    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}

    ~SkAutoBounderCommit() {

        if (NULL != fBounder) {

            fBounder->commit();

        }

    }

private:

    SkBounder*  fBounder;

};

 

 

 

class AutoValidator {

public:

    AutoValidator(SkDevice* device) : fDevice(device) {}

    ~AutoValidator() {

#ifdef SK_DEBUG

        const SkBitmap& bm = fDevice->accessBitmap(false);

        if (bm.config() == SkBitmap::kARGB_4444_Config) {

            for (int y = 0; y < bm.height(); y++) {

                const SkPMColor16* p = bm.getAddr16(0, y);

                for (int x = 0; x < bm.width(); x++) {

                    SkPMColor16 c = p[x];

                    SkPMColor16Assert(c);

                }

            }

        }

#endif

    }

private:

    SkDevice* fDevice;

};

 

 

/** \class SkCanvas

    A Canvas encapsulates all of the state about drawing into a device (bitmap).

    This includes a reference to the device itself, and a stack of matrix/clip

    values. For any given draw call (e.g. drawRect), the geometry of the object

    being drawn is transformed by the concatenation of all the matrices in the

    stack. The transformed geometry is clipped by the intersection of all of

    the clips in the stack.

 

    While the Canvas holds the state of the drawing device, the state (style)

    of the object being drawn is held by the Paint, which is provided as a

    parameter to each of the draw() methods. The Paint holds attributes such as

    color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns),

    etc.

*/

//SkCanvas包含了所有绘画到device上需要的状态。包括对device的参考,一堆矩阵和裁剪值。

class SkCanvas : public SkRefCnt {

public:

    /** Construct a canvas with the specified bitmap to draw into.

        @param bitmap   Specifies a bitmap for the canvas to draw into. Its

                        structure are copied to the canvas.

    */

    explicit SkCanvas(const SkBitmap& bitmap);

    //通过SkBitmap创建SkCanvasSkCanvas将拷贝SkBitmap结构

    //虽然SkCanvas是通过SkBitmap创建,但SkCanvas内部使用的是SkDevice,由传入参数SkBitmap创建这个SkDevice.

 

    /** Construct a canvas with the specified device to draw into.

        @param device   Specifies a device for the canvas to draw into. The

                        device may be null.

    */

    explicit SkCanvas(SkDevice* device = NULL);

    //通过SkDevice创建SkCanvas

    virtual ~SkCanvas();

 

    ///////////////////////////////////////////////////////////////////////////

 

    /** If this subclass of SkCanvas supports GL viewports, return true and set

        size (if not null) to the size of the viewport. If it is not supported,

        ignore vp and return false.

    */

    virtual bool getViewport(SkIPoint* size) const;

    //子类是否支持GL视口

   

    /** If this subclass of SkCanvas supports GL viewports, return true and set

        the viewport to the specified x and y dimensions. If it is not

        supported, ignore x and y and return false.

    */

    virtual bool setViewport(int x, int y);

    //子类是否支持GL视口

 

    /** Return the canvas' device object, which may be null. The device holds

        the bitmap of the pixels that the canvas draws into. The reference count

        of the returned device is not changed by this call.

    */

    SkDevice* getDevice() const;

    //返回SkCanvasSkDevice,可能为空。

 

    /** Specify a device for this canvas to draw into. If it is not null, its

        reference count is incremented. If the canvas was already holding a

        device, its reference count is decremented. The new device is returned.

    */

    SkDevice* setDevice(SkDevice* device);

    //设置SkCanvasSkDevice。如果原来没有SkDevice,SkDevice参考计数器加1。如果有,会将原来的SkDevice参考计数器减一,并用现在的SkDevice代替。

   

    /** Specify a bitmap for the canvas to draw into. This is a help method for

        setDevice(), and it creates a device for the bitmap by calling

        createDevice(). The structure of the bitmap is copied into the device.

    */

    virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap);

    //通过SkBitmap来设置SkCanvasSkDevice

 

    ///////////////////////////////////////////////////////////////////////////

   

    enum SaveFlags {

        /** save the matrix state, restoring it on restore() */

        kMatrix_SaveFlag            = 0x01,

        /** save the clip state, restoring it on restore() */

        kClip_SaveFlag              = 0x02,

        /** the layer needs to support per-pixel alpha */

        kHasAlphaLayer_SaveFlag     = 0x04,

        /** the layer needs to support 8-bits per color component */

        kFullColorLayer_SaveFlag    = 0x08,

        /** the layer should clip against the bounds argument */

        kClipToLayer_SaveFlag       = 0x10,

 

        // helper masks for common choices

        kMatrixClip_SaveFlag        = 0x03,

        kARGB_NoClipLayer_SaveFlag  = 0x0F,

        kARGB_ClipLayer_SaveFlag    = 0x1F

    };

 

    /** This call saves the current matrix and clip information, and pushes a

        copy onto a private stack. Subsequent calls to translate, scale,

        rotate, skew, concat or clipRect, clipPath all operate on this copy.

        When the balancing call to restore() is made, this copy is deleted and

        the previous matrix/clip state is restored.

        @return The value to pass to restoreToCount() to balance this save()

    */

    //这个函数保存当前的matrixclip状态,并把当前的状态做一个备份,压栈。

    //save()之后,所有的操作,translate, scale, rotate, skew, concat or clipRect, clipPath都会在调用restore()函数后去除。

    //所以在save()restore()直接可以做一些临时操作。

    virtual int save(SaveFlags flags = kMatrixClip_SaveFlag);

 

    /** This behaves the same as save(), but in addition it allocates an

        offscreen bitmap. All drawing calls are directed there, and only when

        the balancing call to restore() is made is that offscreen transfered to

        the canvas (or the previous layer). Subsequent calls to translate,

        scale, rotate, skew, concat or clipRect, clipPath all operate on this

        copy. When the balancing call to restore() is made, this copy is deleted

        and the previous matrix/clip state is restored.

        @param bounds (may be null) the maximum size the offscreen bitmap needs

                      to be (in local coordinates)

        @param paint (may be null) This is copied, and is applied to the

                     offscreen when restore() is called

        @param flags  LayerFlags

        @return The value to pass to restoreToCount() to balance this save()

    */

    //这个函数功能和save()一样。但是这个函数会保存到离屏图像上,所有的绘画函数都会直接画到那里,直到restore()调用。

    virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,

                          SaveFlags flags = kARGB_ClipLayer_SaveFlag);

 

    /** This behaves the same as save(), but in addition it allocates an

        offscreen bitmap. All drawing calls are directed there, and only when

        the balancing call to restore() is made is that offscreen transfered to

        the canvas (or the previous layer). Subsequent calls to translate,

        scale, rotate, skew, concat or clipRect, clipPath all operate on this

        copy. When the balancing call to restore() is made, this copy is deleted

        and the previous matrix/clip state is restored.

        @param bounds (may be null) the maximum size the offscreen bitmap needs

                      to be (in local coordinates)

        @param alpha  This is applied to the offscreen when restore() is called.

        @param flags  LayerFlags

        @return The value to pass to restoreToCount() to balance this save()

    */

    int saveLayerAlpha(const SkRect* bounds, U8CPU alpha,

                       SaveFlags flags = kARGB_ClipLayer_SaveFlag);

 

    /** This call balances a previous call to save(), and is used to remove all

        modifications to the matrix/clip state since the last save call. It is

        an error to call restore() more times than save() was called.

    */

    //save()restore()调用数量必须匹配。

    virtual void restore();

 

    /** Returns the number of matrix/clip states on the SkCanvas' private stack.

        This will equal # save() calls - # restore() calls.

    */

    int getSaveCount() const;

 

    /** Efficient way to pop any calls to save() that happened after the save

        count reached saveCount. It is an error for saveCount to be less than

        getSaveCount()

        @param saveCount    The number of save() levels to restore from

    */

    void restoreToCount(int saveCount);

 

    /** Preconcat the current matrix with the specified translation

        @param dx   The distance to translate in X

        @param dy   The distance to translate in Y

        returns true if the operation succeeded (e.g. did not overflow)

    */

    //坐标系统位移

    virtual bool translate(SkScalar dx, SkScalar dy);

 

    /** Preconcat the current matrix with the specified scale.

        @param sx   The amount to scale in X

        @param sy   The amount to scale in Y

        returns true if the operation succeeded (e.g. did not overflow)

    */

    //坐标系统缩放

    virtual bool scale(SkScalar sx, SkScalar sy);

 

    /** Preconcat the current matrix with the specified rotation.

        @param degrees  The amount to rotate, in degrees

        returns true if the operation succeeded (e.g. did not overflow)

    */

    //坐标系统旋转

    virtual bool rotate(SkScalar degrees);

 

    /** Preconcat the current matrix with the specified skew.

        @param sx   The amount to skew in X

        @param sy   The amount to skew in Y

        returns true if the operation succeeded (e.g. did not overflow)

    */

    //坐标系统倾向

    virtual bool skew(SkScalar sx, SkScalar sy);

 

    /** Preconcat the current matrix with the specified matrix.

        @param matrix   The matrix to preconcatenate with the current matrix

        @return true if the operation succeeded (e.g. did not overflow)

    */

    //设置坐标系统联系???

    virtual bool concat(const SkMatrix& matrix);

   

    /** Replace the current matrix with a copy of the specified matrix.

        @param matrix The matrix that will be copied into the current matrix.

    */

    //设置新坐标系统

    virtual void setMatrix(const SkMatrix& matrix);

   

    /** Helper for setMatrix(identity). Sets the current matrix to identity.

    */

    //重置坐标系统

    void resetMatrix();

 

    /** Modify the current clip with the specified rectangle.

        @param rect The rect to intersect with the current clip

        @param op The region op to apply to the current clip

        @return true if the canvas' clip is non-empty

    */

    //通过给定的矩形来改变当前的clip

    virtual bool clipRect(const SkRect& rect,

                          SkRegion::Op op = SkRegion::kIntersect_Op);

 

    /** Modify the current clip with the specified path.

        @param path The path to apply to the current clip

        @param op The region op to apply to the current clip

        @return true if the canvas' new clip is non-empty

    */

    virtual bool clipPath(const SkPath& path,

                          SkRegion::Op op = SkRegion::kIntersect_Op);

 

    /** Modify the current clip with the specified region. Note that unlike

        clipRect() and clipPath() which transform their arguments by the current

        matrix, clipRegion() assumes its argument is already in device

        coordinates, and so no transformation is performed.

        @param deviceRgn    The region to apply to the current clip

        @param op The region op to apply to the current clip

        @return true if the canvas' new clip is non-empty

    */

    virtual bool clipRegion(const SkRegion& deviceRgn,

                            SkRegion::Op op = SkRegion::kIntersect_Op);

 

    /** Helper for clipRegion(rgn, kReplace_Op). Sets the current clip to the

        specified region. This does not intersect or in any other way account

        for the existing clip region.

        @param deviceRgn The region to copy into the current clip.

        @return true if the new clip region is non-empty

    */

    bool setClipRegion(const SkRegion& deviceRgn) {

        return this->clipRegion(deviceRgn, SkRegion::kReplace_Op);

    }

 

阅读(1368) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~