diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index dcf0b0ea54..d02e4db08f 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -22,516 +22,1129 @@ class SkPixelRef; class SkString; /** \class SkBitmap + SkBitmap describes a two-dimensional raster pixel array. SkBitmap is built on + SkImageInfo, containing integer width and height, SkColorType and SkAlphaType + describing the pixel format, and SkColorSpace describing the range of colors. + SkBitmap points to SkPixelRef, which describes the physical array of pixels. + SkImageInfo bounds may be located anywhere fully inside SkPixelRef bounds. - The SkBitmap class specifies a raster bitmap. A bitmap has an integer width - and height, and a format (colortype), and a pointer to the actual pixels. - Bitmaps can be drawn into a SkCanvas, but they are also used to specify the - target of a SkCanvas' drawing operations. - A const SkBitmap exposes getAddr(), which lets a caller write its pixels; - the constness is considered to apply to the bitmap's configuration, not - its contents. + SkBitmap can be drawn using SkCanvas. SkBitmap can be a drawing destination for SkCanvas + draw methods. SkBitmap flexibility as a pixel container limits some optimizations + available to the target platform. - SkBitmap is not thread safe. Each thread must use its own (shallow) copy. + If pixel array is primarily read-only, use SkImage for better performance. + If pixel array is primarily written to, use SkSurface for better performance. + + Declaring SkBitmap const prevents altering SkImageInfo: the SkBitmap height, width, + and so on cannot change. It does not affect SkPixelRef: a caller may write its + pixels. Declaring SkBitmap const affects SkBitmap configuration, not its contents. + + SkBitmap is not thread safe. Each thread must have its own copy of SkBitmap fields, + although threads may share the underlying pixel array. */ class SK_API SkBitmap { public: class SK_API Allocator; - /** - * Default construct creates a bitmap with zero width and height, and no pixels. - * Its colortype is set to kUnknown_SkColorType. - */ + /** Creates an empty SkBitmap without pixels, with kUnknown_SkColorType, + kUnknown_SkAlphaType, and with a width and height of zero. SkPixelRef origin is + set to (0, 0). SkBitmap is not volatile. + + Use setInfo() to associate SkColorType, SkAlphaType, width, and height + after SkBitmap has been created. + + @return empty SkBitmap + */ SkBitmap(); - /** - * Copy the settings from the src into this bitmap. If the src has pixels - * allocated, they will be shared, not copied, so that the two bitmaps will - * reference the same memory for the pixels. - */ + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src + */ SkBitmap(const SkBitmap& src); - /** - * Copy the settings from the src into this bitmap. If the src has pixels - * allocated, ownership of the pixels will be taken. - */ + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src + */ SkBitmap(SkBitmap&& src); + /** Decrements SkPixelRef reference count, if SkPixelRef is not nullptr. + */ ~SkBitmap(); - /** Copies the src bitmap into this bitmap. Ownership of the src - bitmap's pixels is shared with the src bitmap. + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src */ SkBitmap& operator=(const SkBitmap& src); - /** Copies the src bitmap into this bitmap. Takes ownership of the src - bitmap's pixels. + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src */ SkBitmap& operator=(SkBitmap&& src); - /** Swap the fields of the two bitmaps. This routine is guaranteed to never fail or throw. + /** Swaps the fields of the two bitmaps. + + @param other SkBitmap exchanged with original */ - // This method is not exported to java. void swap(SkBitmap& other); - /////////////////////////////////////////////////////////////////////////// + /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace. + @return reference to SkImageInfo + */ const SkImageInfo& info() const { return fInfo; } + /** Returns pixel count in each pixel row. Should be equal or less than: + rowBytes() / info().bytesPerPixel(). + + Maybe be less than pixelRef().width(). Will not exceed pixelRef().width() less + pixelRefOrigin().fX. + + @return pixel width in SkImageInfo + */ int width() const { return fInfo.width(); } + + /** Returns pixel row count. + + Maybe be less than pixelRef().height(). Will not exceed pixelRef().height() less + pixelRefOrigin().fY. + + @return pixel height in SkImageInfo + */ int height() const { return fInfo.height(); } + + /** Returns SkColorType, one of: kUnknown_SkColorType, kAlpha_8_SkColorType, + kRGB_565_SkColorType, kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, kGray_8_SkColorType, kRGBA_F16_SkColorType. + + @return SkColorType in SkImageInfo + */ SkColorType colorType() const { return fInfo.colorType(); } + + /** Returns SkAlphaType, one of: kUnknown_SkAlphaType, kOpaque_SkAlphaType, + kPremul_SkAlphaType, kUnpremul_SkAlphaType. + + @return SkAlphaType in SkImageInfo + */ SkAlphaType alphaType() const { return fInfo.alphaType(); } + + /** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The + reference count of SkColorSpace is unchanged. The returned SkColorSpace is + immutable. + + @return SkColorSpace in SkImageInfo + */ SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } + + /** Returns a smart pointer to SkColorSpace, the range of colors, associated with + SkImageInfo. The smart pointer tracks the number of objects sharing this + SkColorSpace reference so the memory is released when the owners destruct. + + The returned SkColorSpace is immutable. + + @return SkColorSpace in SkImageInfo wrapped in a smart pointer + */ sk_sp refColorSpace() const { return fInfo.refColorSpace(); } - /** - * Return the number of bytes per pixel based on the colortype. If the colortype is - * kUnknown_SkColorType, then 0 is returned. - */ + /** Returns number of bytes per pixel required by SkColorType. + Returns zero if colorType( is kUnknown_SkColorType. + + @return bytes in pixel + */ int bytesPerPixel() const { return fInfo.bytesPerPixel(); } - /** - * Return the rowbytes expressed as a number of pixels (like width and height). - * If the colortype is kUnknown_SkColorType, then 0 is returned. - */ + /** Returns number of pixels that fit on row. Should be greater than or equal to + width(). + + @return maximum pixels per row + */ int rowBytesAsPixels() const { return fRowBytes >> this->shiftPerPixel(); } - /** - * Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel - * colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType. - */ + /** Returns bit shift converting row bytes to row pixels. + Returns zero for kUnknown_SkColorType. + + @return one of: 0, 1, 2, 3; left shift to convert pixels to bytes + */ int shiftPerPixel() const { return this->fInfo.shiftPerPixel(); } - /////////////////////////////////////////////////////////////////////////// + /** Returns true if either width() or height() are zero. - /** Return true iff the bitmap has empty dimensions. - * Hey! Before you use this, see if you really want to know drawsNothing() instead. - */ + Does not check if SkPixelRef is nullptr; call drawsNothing() to check width(), + height(), and SkPixelRef. + + @return true if dimensions do not enclose area + */ bool empty() const { return fInfo.isEmpty(); } - /** Return true iff the bitmap has no pixelref. Note: this can return true even if the - * dimensions of the bitmap are > 0 (see empty()). - * Hey! Before you use this, see if you really want to know drawsNothing() instead. - */ + /** Return true if SkPixelRef is nullptr. + + Does not check if width() or height() are zero; call drawsNothing() to check + width(), height(), and SkPixelRef. + + @return true if no SkPixelRef is associated + */ bool isNull() const { return nullptr == fPixelRef; } - /** Return true iff drawing this bitmap has no effect. - */ + /** Return true if width() or height() are zero, or if SkPixelRef is nullptr. + If true, SkBitmap has no effect when drawn or drawn into. + + @return true if drawing has no effect + */ bool drawsNothing() const { return this->empty() || this->isNull(); } - /** Return the number of bytes between subsequent rows of the bitmap. */ + /** Returns row bytes, the interval from one pixel row to the next. Row bytes + is at least as large as width() * info().bytesPerPixel(). + + Returns zero if colorType() is kUnknown_SkColorType, or if row bytes supplied to + setInfo() is not large enough to hold a row of pixels. + + @return byte length of pixel row + */ size_t rowBytes() const { return fRowBytes; } - /** - * Set the bitmap's alphaType, returning true on success. If false is - * returned, then the specified new alphaType is incompatible with the - * colortype, and the current alphaType is unchanged. - * - * Note: this changes the alphatype for the underlying pixels, which means - * that all bitmaps that might be sharing (subsets of) the pixels will - * be affected. - */ + /** Sets SkAlphaType, if alphaType is compatible with SkColorType. + Returns true unless alphaType is kUnknown_SkAlphaType and current SkAlphaType + is not kUnknown_SkAlphaType. + + Returns true if SkColorType is kUnknown_SkColorType. alphaType is ignored, and + SkAlphaType remains kUnknown_SkAlphaType. + + Returns true if SkColorType is kRGB_565_SkColorType or kGray_8_SkColorType. + alphaType is ignored, and SkAlphaType remains kOpaque_SkAlphaType. + + If SkColorType is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. + + If SkColorType is kAlpha_8_SkColorType, returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. If alphaType is + kUnpremul_SkAlphaType, it is treated as kPremul_SkAlphaType. + + This changes SkAlphaType in SkPixelRef; all bitmaps sharing SkPixelRef + are affected. + + @param alphaType one of: kUnknown_SkAlphaType, kOpaque_SkAlphaType, + kPremul_SkAlphaType, kUnpremul_SkAlphaType + @return true if SkAlphaType is set + */ bool setAlphaType(SkAlphaType alphaType); - /** Return the address of the pixels for this SkBitmap. + /** Returns pixel address, the base address corresponding to the pixel origin. + + @return pixel address */ void* getPixels() const { return fPixels; } - /** - * Returns the size (in bytes) of the bitmap's image buffer. - * If the calculation overflows, this returns max_size_t. - */ + /** Returns minimum memory required for pixel storage. + Does not include unused memory on last row when rowBytesAsPixels() exceeds width(). + Returns zero if result does not fit in size_t. + Returns zero if height() or width() is 0. + Returns height() times rowBytes() if colorType() is kUnknown_SkColorType. + + @return size in bytes of image buffer + */ size_t computeByteSize() const { return fInfo.computeByteSize(fRowBytes); } - /** Returns true if this bitmap is marked as immutable, meaning that the - contents of its pixels will not change for the lifetime of the bitmap. + /** Returns true if pixels can not change. + + Most immutable SkBitmap checks trigger an assert only on debug builds. + + @return true if pixels are immutable */ bool isImmutable() const; - /** Marks this bitmap as immutable, meaning that the contents of its - pixels will not change for the lifetime of the bitmap and of the - underlying pixelref. This state can be set, but it cannot be - cleared once it is set. This state propagates to all other bitmaps - that share the same pixelref. + /** Sets internal flag to mark SkBitmap as immutable. Once set, pixels can not change. + Any other bitmap sharing the same SkPixelRef are also marked as immutable. + Once SkPixelRef is marked immutable, the setting cannot be cleared. + + Writing to immutable SkBitmap pixels triggers an assert on debug builds. */ void setImmutable(); - /** Returns true if the bitmap is opaque (has no translucent/transparent pixels). + /** Returns true if SkAlphaType is kOpaque_SkAlphaType. + Does not check if SkColorType allows alpha, or if any pixel value has + transparency. + + @return true if SkImageInfo describes opaque alpha */ bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); } - /** Returns true if the bitmap is volatile (i.e. should not be cached by devices.) + /** If true, provides a hint to caller that pixels should not + be cached. Only true if setIsVolatile() has been called to mark as volatile. + + Volatile state is not shared by other bitmaps sharing the same SkPixelRef. + + @return true if marked volatile */ bool isVolatile() const; - /** Specify whether this bitmap is volatile. Bitmaps are not volatile by - default. Temporary bitmaps that are discarded after use should be - marked as volatile. This provides a hint to the device that the bitmap - should not be cached. Providing this hint when appropriate can - improve performance by avoiding unnecessary overhead and resource - consumption on the device. + /** Sets if pixels should be read from SkPixelRef on every access. SkBitmap are not + volatile by default; a GPU back end may upload pixel values expecting them to be + accessed repeatedly. Marking temporary SkBitmap as volatile provides a hint to + SkBaseDevice that the SkBitmap pixels should not be cached. This can + improve performance by avoiding overhead and reducing resource + consumption on SkBaseDevice. + + @param isVolatile true if backing pixels are temporary */ void setIsVolatile(bool isVolatile); - /** Reset the bitmap to its initial state (see default constructor). If we are a (shared) - owner of the pixels, that ownership is decremented. + /** Resets to its initial state; all fields are set to zero, as if SkBitmap had + been initialized by SkBitmap(). + + Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to + kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType. + + If SkPixelRef is allocated, its reference count is decreased by one, releasing + its memory if SkBitmap is the sole owner. */ void reset(); - /** - * This will brute-force return true if all of the pixels in the bitmap - * are opaque. If it fails to read the pixels, or encounters an error, - * it will return false. - * - * Since this can be an expensive operation, the bitmap stores a flag for - * this (isOpaque). Only call this if you need to compute this value from - * "unknown" pixels. - */ + /** Returns true if all pixels are opaque. SkColorType determines how pixels + are encoded, and whether pixel describes alpha. Returns true for SkColorType + without alpha in each pixel; for other SkColorType, returns true if all + pixels have alpha values equivalent to 1.0 or greater. + + For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always + returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType, + kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255. + For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15. + For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or + greater. + + Returns false for kUnknown_SkColorType. + + @param bm SkBitmap to check + @return true if all pixels have opaque values or SkColorType is opaque + */ static bool ComputeIsOpaque(const SkBitmap& bm) { SkPixmap pmap; return bm.peekPixels(&pmap) && pmap.computeIsOpaque(); } - /** - * Return the bitmap's bounds [0, 0, width, height] as an SkRect - */ + /** Returns SkRect { 0, 0, width(), height() }. + + @param bounds container for floating point rectangle + */ void getBounds(SkRect* bounds) const; + + /** Returns SkIRect { 0, 0, width(), height() }. + + @param bounds container for integral rectangle + */ void getBounds(SkIRect* bounds) const; + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ SkIRect bounds() const { return fInfo.bounds(); } + + /** Returns SkISize { width(), height() }. + + @return integral size of width() and height() + */ SkISize dimensions() const { return fInfo.dimensions(); } - // Returns the bounds of this bitmap, offset by its pixelref origin. + + /** Returns the bounds of this bitmap, offset by its SkPixelRef origin. + + @return bounds within SkPixelRef bounds + */ SkIRect getSubset() const { return SkIRect::MakeXYWH(fPixelRefOrigin.x(), fPixelRefOrigin.y(), fInfo.width(), fInfo.height()); } + /** Sets width, height, SkAlphaType, SkColorType, SkColorSpace, and optional + rowBytes. Frees pixels, and returns true if successful. + + imageInfo.alphaType() may be altered to a value permitted by imageInfo.colorSpace(). + If imageInfo.colorType() is kUnknown_SkColorType, imageInfo.alphaType() is + set to kUnknown_SkAlphaType. + If imageInfo.colorType() is kAlpha_8_SkColorType and imageInfo.alphaType() is + kUnpremul_SkAlphaType, imageInfo.alphaType() is replaced by kPremul_SkAlphaType. + If imageInfo.colorType() is kRGB_565_SkColorType or kGray_8_SkColorType, + imageInfo.alphaType() is set to kOpaque_SkAlphaType. + If imageInfo.colorType() is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: imageInfo.alphaType() remains + unchanged. + + rowBytes must equal or exceed imageInfo.minRowBytes(). If imageInfo.colorSpace() is + kUnknown_SkColorType, rowBytes is ignored and treated as zero; for all other + SkColorSpace values, rowBytes of zero is treated as imageInfo.minRowBytes(). + + Calls reset() and returns false if: + - rowBytes exceeds 31 bits + - imageInfo.width() times imageInfo.bytesPerPixel() exceeds 31 bits + - imageInfo.width() is negative + - imageInfo.height() is negative + - rowBytes is positive and less than imageInfo.width() times imageInfo.bytesPerPixel() + + @param imageInfo contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes imageInfo.minRowBytes or larger; or zero + @return true if SkImageInfo set successfully + */ bool setInfo(const SkImageInfo& imageInfo, size_t rowBytes = 0); + /** \enum SkBitmap::AllocFlags + AllocFlags provides the option to zero pixel memory when allocated. + */ enum AllocFlags { - kZeroPixels_AllocFlag = 1 << 0, + /** Instructs tryAllocPixelsFlags() and allocPixelsFlags() to zero pixel memory. */ + kZeroPixels_AllocFlag = 1 << 0, }; - /** - * Allocate the bitmap's pixels to match the requested image info. If the Factory - * is non-null, call it to allcoate the pixelref. - * - * On failure, the bitmap will be set to empty and return false. - */ + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. If flags is kZeroPixels_AllocFlag, memory is zeroed. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated, or memory size exceeds 31 bits, or memory could not optionally + be zeroed. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(), if flags is zero, and calloc(), if flags is + kZeroPixels_AllocFlag. + + Passing kZeroPixels_AllocFlag is usually faster than separately calling + eraseColor(SK_ColorTRANSPARENT). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + @return true if pixels allocation is successful + */ bool SK_WARN_UNUSED_RESULT tryAllocPixelsFlags(const SkImageInfo& info, uint32_t flags); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. If flags is kZeroPixels_AllocFlag, memory is zeroed. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated, or memory size exceeds 31 bits, or memory could not optionally + be zeroed. Abort steps may be provided by the user at compile time by defining + SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(), if flags is zero, and calloc(), if flags is + kZeroPixels_AllocFlag. + + Passing kZeroPixels_AllocFlag is usually faster than separately calling + eraseColor(SK_ColorTRANSPARENT). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + */ void allocPixelsFlags(const SkImageInfo& info, uint32_t flags) { SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags)); } - /** - * Allocate the bitmap's pixels to match the requested image info and - * rowBytes. If the request cannot be met (e.g. the info is invalid or - * the requested rowBytes are not compatible with the info - * (e.g. rowBytes < info.minRowBytes() or rowBytes is not aligned with - * the pixel size specified by info.colorType()) then false is returned - * and the bitmap is set to empty. - */ + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + @return true if pixel storage is allocated + */ bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info, size_t rowBytes); + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated, or memory size exceeds 31 bits. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + */ void allocPixels(const SkImageInfo& info, size_t rowBytes) { SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes)); } + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @return true if pixel storage is allocated + */ bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info) { return this->tryAllocPixels(info, info.minRowBytes()); } + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated, or memory size exceeds 31 bits. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + */ void allocPixels(const SkImageInfo& info) { this->allocPixels(info, info.minRowBytes()); } + /** Sets SkImageInfo to width, height, and the native SkColorType; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType; + otherwise, sets to kPremul_SkAlphaType. + + Calls reset() and returns false if width exceeds 29 bits or is negative, + or height is negative. + + Returns false if allocation fails. + + Use to create SkBitmap that matches native pixel arrangement on the platform, + to draw without converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + @return true if pixel storage is allocated + */ bool SK_WARN_UNUSED_RESULT tryAllocN32Pixels(int width, int height, bool isOpaque = false) { SkImageInfo info = SkImageInfo::MakeN32(width, height, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); return this->tryAllocPixels(info); } + /** Sets SkImageInfo to width, height, and the native SkColorType; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kPremul_SkAlphaType; + otherwise, sets to kOpaque_SkAlphaType. + + Aborts if width exceeds 29 bits or is negative, or height is negative, or + allocation fails. Abort steps may be provided by the user at compile time by + defining SK_ABORT. + + Use to create SkBitmap that matches native pixel arrangement on the platform, + to draw without converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + */ void allocN32Pixels(int width, int height, bool isOpaque = false) { SkImageInfo info = SkImageInfo::MakeN32(width, height, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); this->allocPixels(info); } - /** - * Install a pixelref that wraps the specified pixels and rowBytes, and - * optional ReleaseProc and context. When the pixels are no longer - * referenced, if releaseProc is not null, it will be called with the - * pixels and context as parameters. - * On failure, the bitmap will be set to empty and return false. - * - * If specified, the releaseProc will always be called, even on failure. It is also possible - * for success but the releaseProc is immediately called (e.g. valid Info but NULL pixels). - */ + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. releaseProc, if not nullptr, is called + immediately on failure or when pixels are no longer referenced. context may be + nullptr. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls releaseProc if present, calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, calls releaseProc if + present, returns true. + + If SkImageInfo is set, pixels is not nullptr, and releaseProc is not nullptr: + when pixels are no longer referenced, calls releaseProc with pixels and context + as parameters. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @param releaseProc function called when pixels can be deleted; may be nullptr + @param context caller state passed to releaseProc; may be nullptr + @return true if SkImageInfo is set to info + */ bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, void (*releaseProc)(void* addr, void* context), void* context); - /** - * Call installPixels with no ReleaseProc specified. This means that the - * caller must ensure that the specified pixels are valid for the lifetime - * of the created bitmap (and its pixelRef). - */ + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixels are valid for the lifetime of SkBitmap and SkPixelRef. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @return true if SkImageInfo is set to info + */ bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { return this->installPixels(info, pixels, rowBytes, nullptr, nullptr); } - /** - * Call installPixels with no ReleaseProc specified. This means that the caller must ensure - * that the specified pixels are valid for the lifetime of the created bitmap - * (and its pixelRef). - */ + /** Sets SkImageInfo to pixmap.info() following the rules in setInfo(), and creates + SkPixelRef containing pixmap.addr() and pixmap.rowBytes(). + + If SkImageInfo could not be set, or pixmap.rowBytes() is less than + SkImageInfo::minRowBytes: calls reset(), and returns false. + + Otherwise, if pixmap.addr() equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixmap is valid for the lifetime of SkBitmap and SkPixelRef. + + @param pixmap SkImageInfo, pixel address, and rowBytes() + @return true if SkImageInfo was set to pixmap.info() + */ bool installPixels(const SkPixmap& pixmap); - /** - * Calls installPixels() with the value in the SkMask. The caller must - * ensure that the specified mask pixels are valid for the lifetime - * of the created bitmap (and its pixelRef). - */ + /** Sets SkImageInfo to mask width, mask height, kAlpha_8_SkColorType, and + kPremul_SkAlphaType. Sets SkPixelRef to mask image and mask rowBytes(). + + Returns false and calls reset() if mask format is not SkMask::kA8_Format, + or if mask width or mask height is negative, or if mask rowBytes() is less + than mask width. + + Caller must ensure that mask is valid for the lifetime of SkBitmap and SkPixelRef. + + @param mask alpha 8-bit bitmap + @return true if SkImageInfo and SkPixelRef refer to mask + */ bool installMaskPixels(const SkMask& mask); - /** Use this to assign a new pixel address for an existing bitmap. This - will automatically release any pixelref previously installed. Only call - this if you are handling ownership/lifetime of the pixel memory. + /** Replaces SkPixelRef with pixels, preserving SkImageInfo and rowBytes(). + Sets SkPixelRef origin to (0, 0). - @param pixels Address for the pixels, managed by the caller. + If pixels is nullptr, or if info().colorType equals kUnknown_SkColorType; + release reference to SkPixelRef, and set SkPixelRef to nullptr. + + Caller is responsible for handling ownership pixel memory for the lifetime + of SkBitmap and SkPixelRef. + + @param pixels address of pixel storage, managed by caller */ void setPixels(void* pixels); - /** Use the standard HeapAllocator to create the pixelref that manages the - pixel memory. It will be sized based on the current ImageInfo. - If this is called multiple times, a new pixelref object will be created - each time. + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. - @return true if the allocation succeeds. If not the pixelref field of - the bitmap will be unchanged. + Returns false if info().colorType is kUnknown_SkColorType, or allocation exceeds + 31 bits, or allocation fails. + + @return true if the allocation succeeds */ bool SK_WARN_UNUSED_RESULT tryAllocPixels() { return this->tryAllocPixels((Allocator*)nullptr); } + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + + Aborts if info().colorType is kUnknown_SkColorType, or allocation exceeds + 31 bits, or allocation fails. Abort steps may be provided by the user at compile + time by defining SK_ABORT. + */ void allocPixels() { this->allocPixels((Allocator*)nullptr); } - /** Use the specified Allocator to create the pixelref that manages the - pixel memory. It will be sized based on the current ImageInfo. - If this is called multiple times, a new pixelref object will be created - each time. + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. - @param allocator The Allocator to use to create a pixelref that can - manage the pixel memory for the current ImageInfo. - If allocator is NULL, the standard HeapAllocator will be used. - @return true if the allocation succeeds. If not the pixelref field of - the bitmap will be unchanged. + Returns false if allocator allocPixelRef return false. + + @param allocator instance of SkBitmap::Allocator instantiation + @return true if custom allocator reports success */ bool SK_WARN_UNUSED_RESULT tryAllocPixels(Allocator* allocator); + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. + + Aborts if allocator allocPixelRef return false. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + @param allocator instance of SkBitmap::Allocator instantiation + */ void allocPixels(Allocator* allocator) { SkASSERT_RELEASE(this->tryAllocPixels(allocator)); } - /** - * Return the current pixelref object or NULL if there is none. This does - * not affect the refcount of the pixelref. - */ + /** Returns SkPixelRef, which contains: pixel base address; its dimensions; and + rowBytes(), the interval from one row to the next. Does not change SkPixelRef + reference count. SkPixelRef may be shared by multiple bitmaps. + If SkPixelRef has not been set, returns nullptr. + + @return SkPixelRef, or nullptr + */ SkPixelRef* pixelRef() const { return fPixelRef.get(); } - /** - * A bitmap can reference a subset of a pixelref's pixels. That means the - * bitmap's width/height can be <= the dimensions of the pixelref. The - * pixelref origin is the x,y location within the pixelref's pixels for - * the bitmap's top/left corner. To be valid the following must be true: - * - * origin_x + bitmap_width <= pixelref_width - * origin_y + bitmap_height <= pixelref_height - * - * pixelRefOrigin() returns this origin, or (0,0) if there is no pixelRef. - */ + /** Returns origin of pixels within SkPixelRef. SkBitmap bounds is always contained + by SkPixelRef bounds, which may be the same size or larger. Multiple SkBitmap + can share the same SkPixelRef, where each SkBitmap has different bounds. + + The returned origin added to SkBitmap dimensions equals or is smaller than the + SkPixelRef dimensions. + + Returns (0, 0) if SkPixelRef is nullptr. + + @return pixel origin within SkPixelRef + */ SkIPoint pixelRefOrigin() const { return fPixelRefOrigin; } - /** - * Assign a pixelref and origin to the bitmap. (dx,dy) specify the offset - * within the pixelref's pixels for the top/left corner of the bitmap. For - * a bitmap that encompases the entire pixels of the pixelref, these will - * be (0,0). - */ + /** Replaces pixelRef and origin in SkBitmap. dx and dy specify the offset + within the SkPixelRef pixels for the top-left corner of the bitmap. + + Asserts in debug builds if dx or dy are out of range. Pins dx and dy + to legal range in release builds. + + The caller is responsible for ensuring that the pixels match the + SkColorType and SkAlphaType in SkImageInfo. + + @param pixelRef SkPixelRef describing pixel address and rowBytes() + @param dx column offset in SkPixelRef for bitmap origin + @param dy row offset in SkPixelRef for bitmap origin + */ void setPixelRef(sk_sp pixelRef, int dx, int dy); - /** Call this to be sure that the bitmap is valid enough to be drawn (i.e. - it has non-null pixels). + /** Returns true if SkBitmap is can be drawn. + + @return true if getPixels() is not nullptr */ bool readyToDraw() const { return this->getPixels() != nullptr; } - /** Returns a non-zero, unique value corresponding to the pixels in our - pixelref. Each time the pixels are changed (and notifyPixelsChanged - is called), a different generation ID will be returned. Finally, if - there is no pixelRef then zero is returned. + /** Returns a unique value corresponding to the pixels in SkPixelRef. + Returns a different value after notifyPixelsChanged() has been called. + Returns zero if SkPixelRef is nullptr. + + Determines if pixels have changed since last examined. + + @return unique value for pixels in SkPixelRef */ uint32_t getGenerationID() const; - /** Call this if you have changed the contents of the pixels. This will in- - turn cause a different generation ID value to be returned from - getGenerationID(). + /** Marks that pixels in SkPixelRef have changed. Subsequent calls to + getGenerationID() return a different value. */ void notifyPixelsChanged() const; - /** - * Fill the entire bitmap with the specified color. - * If the bitmap's colortype does not support alpha (e.g. 565) then the alpha - * of the color is ignored (treated as opaque). If the colortype only supports - * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. - */ + /** Replaces pixel values with c. All pixels contained by bounds() are affected. + If the colorType() is kGray_8_SkColorType or k565_SkColorType, then color alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + @param c unpremultiplied color + */ void eraseColor(SkColor c) const; - /** - * Fill the entire bitmap with the specified color. - * If the bitmap's colortype does not support alpha (e.g. 565) then the alpha - * of the color is ignored (treated as opaque). If the colortype only supports - * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. - */ + /** Replaces pixel values with unpremultiplied color built from a, r, g, and b. + All pixels contained by bounds() are affected. + If the colorType() is kGray_8_SkColorType or k565_SkColorType, then a + is ignored; r, g, and b are treated as opaque. If colorType() is kAlpha_8_SkColorType, + then r, g, and b are ignored. + + @param a amount of color alpha, from fully transparent (0) to fully opaque (255) + @param r amount of color rgb red, from no red (0) to full red (255) + @param g amount of color rgb green, from no green (0) to full green (255) + @param b amount of color rgb blue, from no blue (0) to full blue (255) + */ void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { this->eraseColor(SkColorSetARGB(a, r, g, b)); } + /** Deprecated. Use eraseARGB() or eraseColor(). + + @param r amount of red + @param g amount of green + @param b amount of blue + */ SK_ATTR_DEPRECATED("use eraseARGB or eraseColor") void eraseRGB(U8CPU r, U8CPU g, U8CPU b) const { this->eraseARGB(0xFF, r, g, b); } - /** - * Fill the specified area of this bitmap with the specified color. - * If the bitmap's colortype does not support alpha (e.g. 565) then the alpha - * of the color is ignored (treated as opaque). If the colortype only supports - * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. - */ + /** Replaces pixel values inside area with c. If area does not intersect bounds(), + call has no effect. + + If the colorType() is kGray_8_SkColorType or k565_SkColorType, then color alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + @param c unpremultiplied color + @param area rectangle to fill + */ void erase(SkColor c, const SkIRect& area) const; - // DEPRECATED + /** Legacy call to be deprecated. + */ void eraseArea(const SkIRect& area, SkColor c) const { this->erase(c, area); } - /** - * Converts the pixel at the specified coordinate to an unpremultiplied - * SkColor. Note: this ignores any SkColorSpace information, and may return - * lower precision data than is actually in the pixel. Alpha only - * colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate - * alpha set. The value is undefined for kUnknown_SkColorType or if x or y - * are out of bounds, or if the bitmap does not have any pixels. - */ + /** Returns pixel at (x, y) as unpremultiplied color. + Returns black with alpha if SkColorType is kAlpha_8_SkColorType. + + Input is not validated: out of bounds values of x or y trigger an assert() if + built with SK_DEBUG defined; and returns undefined values or may crash if + SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or + pixel address is nullptr. + + SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the + conversion to unpremultiplied color; original pixel data may have additional + precision. + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return pixel converted to unpremultiplied color + */ SkColor getColor(int x, int y) const { SkPixmap pixmap; SkAssertResult(this->peekPixels(&pixmap)); return pixmap.getColor(x, y); } - /** Returns the address of the specified pixel. This performs a runtime - check to know the size of the pixels, and will return the same answer - as the corresponding size-specific method (e.g. getAddr16). Since the - check happens at runtime, it is much slower than using a size-specific - version. Unlike the size-specific methods, this routine also checks if - getPixels() returns null, and returns that. The size-specific routines - perform a debugging assert that getPixels() is not null, but they do - not do any runtime checks. + /** Returns pixel address at (x, y). + + Input is not validated: out of bounds values of x or y, or kUnknown_SkColorType, + trigger an assert() if built with SK_DEBUG defined. Returns nullptr if + SkColorType is kUnknown_SkColorType, or SkPixelRef is nullptr. + + Performs a lookup of pixel size; for better performance, call + one of: getAddr8(), getAddr16(), or getAddr32(). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return generic pointer to pixel */ void* getAddr(int x, int y) const; - /** Returns the address of the pixel specified by x,y for 32bit pixels. - * In debug build, this asserts that the pixels are allocated and that the - * colortype is 32-bit, however none of these checks are performed - * in the release build. - */ + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not four + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 32-bit pointer to pixel at (x, y) + */ inline uint32_t* getAddr32(int x, int y) const; - /** Returns the address of the pixel specified by x,y for 16bit pixels. - * In debug build, this asserts that the pixels are allocated - * and that the colortype is 16-bit, however none of these checks are performed - * in the release build. - */ + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not two + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 16-bit pointer to pixel at (x, y) + */ inline uint16_t* getAddr16(int x, int y) const; - /** Returns the address of the pixel specified by x,y for 8bit pixels. - * In debug build, this asserts that the pixels are allocated - * and that the colortype is 8-bit, however none of these checks are performed - * in the release build. - */ + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not one + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 8-bit pointer to pixel at (x, y) + */ inline uint8_t* getAddr8(int x, int y) const; - /** Set dst to be a setset of this bitmap. If possible, it will share the - pixel memory, and just point into a subset of it. However, if the colortype - does not support this, a local copy will be made and associated with - the dst bitmap. If the subset rectangle, intersected with the bitmap's - dimensions is empty, or if there is an unsupported colortype, false will be - returned and dst will be untouched. - @param dst The bitmap that will be set to a subset of this bitmap - @param subset The rectangle of pixels in this bitmap that dst will - reference. - @return true if the subset copy was successfully made. + /** Shares SkPixelRef with dst. Pixels are not copied; SkBitmap and dst point + to the same pixels; dst bounds() are set to the intersection of subset + and the original bounds(). + + subset may be larger than bounds(). Any area outside of bounds() is ignored. + + Any contents of dst are discarded. isVolatile() setting is copied to dst. + dst is set to colorType(), alphaType(), and colorSpace(). + + Return false if: + - dst is nullptr + - SkPixelRef is nullptr + - subset does not intersect bounds() + + @param dst SkBitmap set to subset + @param subset rectangle of pixels to reference + @return true if dst is replaced by subset */ bool extractSubset(SkBitmap* dst, const SkIRect& subset) const; - /** - * Copy the bitmap's pixels into the specified buffer (pixels + rowBytes), - * converting them into the requested format (SkImageInfo). The src pixels are read - * starting at the specified (srcX,srcY) offset, relative to the top-left corner. - * - * The specified ImageInfo and (srcX,srcY) offset specifies a source rectangle - * - * srcR.setXYWH(srcX, srcY, dstInfo.width(), dstInfo.height()); - * - * srcR is intersected with the bounds of the bitmap. If this intersection is not empty, - * then we have two sets of pixels (of equal size). Replace the dst pixels with the - * corresponding src pixels, performing any colortype/alphatype transformations needed - * (in the case where the src and dst have different colortypes or alphatypes). - * - * This call can fail, returning false, for several reasons: - * - If srcR does not intersect the bitmap bounds. - * - If the requested colortype/alphatype cannot be converted from the src's types. - * - If the src pixels are not available. - */ + /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not exceed + (this->width(), this->height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and + SkColorSpace of destination. dstRowBytes specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dstInfo.addr() equals nullptr + - dstRowBytes is less than dstInfo.minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If this->colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If this->alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If this->colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). + + If behavior is SkTransferFunctionBehavior::kRespect: converts source + pixels to a linear space before converting to dstInfo. + If behavior is SkTransferFunctionBehavior::kIgnore: source + pixels are treated as if they are linear, regardless of how they are encoded. + + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @param behavior one of: SkTransferFunctionBehavior::kRespect, + SkTransferFunctionBehavior::kIgnore + @return true if pixels are copied to dstPixels + */ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, SkTransferFunctionBehavior behavior) const; + + /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not exceed + (this->width(), this->height()). + + dstInfo specifies width, height, SkColorType, SkAlphaType, and + SkColorSpace of destination. dstRowBytes specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dstInfo.addr() equals nullptr + - dstRowBytes is less than dstInfo.minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If this->colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If this->alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If this->colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). + + @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace + @param dstPixels destination pixel storage + @param dstRowBytes destination row length + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dstPixels + */ bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) const { return this->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, SkTransferFunctionBehavior::kRespect); } + + /** Copies a SkRect of pixels to dst. Copy starts at (srcX, srcY), and does not exceed + (this->width(), this->height()). + + dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of destination. dst.rowBytes() specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dst pixel storage equals nullptr + - dst.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If this->colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If this->alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If this->colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + srcX and srcY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @param srcX column index whose absolute value is less than width() + @param srcY row index whose absolute value is less than height() + @return true if pixels are copied to dst + */ bool readPixels(const SkPixmap& dst, int srcX, int srcY) const; + + /** Copies a SkRect of pixels to dst. Copy starts at (0, 0), and does not exceed + (this->width(), this->height()). + + dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of destination. dst.rowBytes() specifics the gap from one destination + row to the next. Returns true if pixels are copied. Returns false if: + - dst pixel storage equals nullptr + - dst.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If this->colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If this->alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If this->colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @return true if pixels are copied to dst + */ bool readPixels(const SkPixmap& dst) const { return this->readPixels(dst, 0, 0); } - /** - * Copy the src pixmap's pixels into this bitmap, offset by dstX, dstY. - * - * This is logically the same as creating a bitmap around src, and calling readPixels on it - * with this bitmap as the dst. - */ + /** Copies a SkRect of pixels from src. Copy starts at (dstX, dstY), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If this->colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If this->alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If this->colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + dstX and dstY may be negative to copy only top or left of source. Returns + false if width() or height() is zero or negative. + Returns false if abs(dstX) >= this->width(), or if abs(dstY) >= this->height(). + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @param dstX column index whose absolute value is less than width() + @param dstY row index whose absolute value is less than height() + @return true if src pixels are copied to SkBitmap + */ bool writePixels(const SkPixmap& src, int dstX, int dstY) { return this->writePixels(src, dstX, dstY, SkTransferFunctionBehavior::kRespect); } + + /** Copies a SkRect of pixels from src. Copy starts at (0, 0), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If this->colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If this->alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If this->colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @return true if src pixels are copied to SkBitmap + */ bool writePixels(const SkPixmap& src) { return this->writePixels(src, 0, 0); } + + /** Copies a SkRect of pixels from src. Copy starts at (0, 0), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If this->colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If this->colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If this->alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If this->colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. Returns false if width() or height() + is zero or negative. + + If behavior is SkTransferFunctionBehavior::kRespect: converts src + pixels to a linear space before converting to SkImageInfo. + If behavior is SkTransferFunctionBehavior::kIgnore: src + pixels are treated as if they are linear, regardless of how they are encoded. + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @param x column index whose absolute value is less than width() + @param y row index whose absolute value is less than height() + @param behavior one of: SkTransferFunctionBehavior::kRespect, + SkTransferFunctionBehavior::kIgnore + @return true if src pixels are copied to SkBitmap + */ bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior); #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + /** Android framework only. + + @return true if setHasHardwareMipMap() has been called with true + */ bool hasHardwareMipMap() const { return (fFlags & kHasHardwareMipMap_Flag) != 0; } + /** Android framework only. + + @param hasHardwareMipMap sets state + */ void setHasHardwareMipMap(bool hasHardwareMipMap) { if (hasHardwareMipMap) { fFlags |= kHasHardwareMipMap_Flag; @@ -541,63 +1154,113 @@ public: } #endif + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + Uses HeapAllocator to reserve memory for dst SkPixelRef. + + @param dst holds SkPixelRef to fill with alpha layer + @return true if alpha layer was constructed in dst SkPixelRef + */ bool extractAlpha(SkBitmap* dst) const { return this->extractAlpha(dst, nullptr, nullptr, nullptr); } + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter::filterMask + generates mask alpha from SkBitmap. Uses HeapAllocator to reserve memory for dst + SkPixelRef. Sets offset to top-left position for dst for alignment with SkBitmap; + (0, 0) unless SkMaskFilter generates mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef + */ bool extractAlpha(SkBitmap* dst, const SkPaint* paint, SkIPoint* offset) const { return this->extractAlpha(dst, paint, nullptr, offset); } - /** Set dst to contain alpha layer of this bitmap. If destination bitmap - fails to be initialized, e.g. because allocator can't allocate pixels - for it, dst will not be modified and false will be returned. + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. - @param dst The bitmap to be filled with alpha layer - @param paint The paint to draw with - @param allocator Allocator used to allocate the pixelref for the dst - bitmap. If this is null, the standard HeapAllocator - will be used. - @param offset If not null, it is set to top-left coordinate to position - the returned bitmap so that it visually lines up with the - original + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter::filterMask + generates mask alpha from SkBitmap. allocator may reference a custom allocation + class or be set to nullptr to use HeapAllocator. Sets offset to top-left + position for dst for alignment with SkBitmap; (0, 0) unless SkMaskFilter generates + mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param allocator method to reserve memory for SkPixelRef; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef */ bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, SkIPoint* offset) const; - /** - * If the pixels are available from this bitmap return true, and fill out the - * specified pixmap (if not null). If there are no pixels, return false and - * ignore the pixmap parameter. - * - * Note: if this returns true, the results (in the pixmap) are only valid until the bitmap - * is changed in any way, in which case the results are invalid. - */ + /** Copies SkBitmap pixel address, row bytes, and SkImageInfo to pixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave pixmap unchanged. + + pixmap contents become invalid on any future change to SkBitmap. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkBitmap has direct access to pixels + */ bool peekPixels(SkPixmap* pixmap) const; + /** Asserts if internal values are illegal or inconsistent. Only available if + SK_DEBUG is defined at compile time. + */ SkDEBUGCODE(void validate() const;) + /** \class SkBitmap::Allocator + Abstract subclass of HeapAllocator. + */ class Allocator : public SkRefCnt { public: - /** Allocate the pixel memory for the bitmap, given its dimensions and - colortype. Return true on success, where success means either setPixels - or setPixelRef was called. + + /** Allocates the pixel memory for the bitmap, given its dimensions and + color type. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if SkPixelRef was allocated */ virtual bool allocPixelRef(SkBitmap* bitmap) = 0; private: typedef SkRefCnt INHERITED; }; - /** Subclass of Allocator that returns a pixelref that allocates its pixel - memory from the heap. This is the default Allocator invoked by + /** \class SkBitmap::HeapAllocator + Subclass of allocator that returns a SkPixelRef that allocates its pixel + memory from the heap. This is the default allocator invoked by allocPixels(). */ class HeapAllocator : public Allocator { public: + + /** Allocates the pixel memory for the bitmap, given its dimensions and + color type. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if pixels are allocated + */ bool allocPixelRef(SkBitmap* bitmap) override; }; + /** macro expands to: void toString(SkString* str) const; + Creates string representation. The representation is read by + internal debugging tools. The interface and implementation may be + suppressed by defining SK_IGNORE_TO_STRING. + + @param str storage for string representation + */ SK_TO_STRING_NONVIRT() private: diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 69e22dcbda..8ae7ac0268 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -114,7 +114,7 @@ public: Pixel buffer size should be height times rowBytes. @param width pixel column count on raster surface created; must be zero or greater - @param height pixel row count on raster surface created.; must be zero or greater + @param height pixel row count on raster surface created; must be zero or greater @param pixels pointer to destination pixels buffer; buffer size should be height times rowBytes @param rowBytes interval from one SkSurface row to the next, or zero @@ -267,7 +267,7 @@ public: @param info storage for writable pixels' SkImageInfo; may be nullptr @param rowBytes storage for writable pixels' row bytes; may be nullptr - @param origin storage for SkCanvas top layer origin, its top left corner; + @param origin storage for SkCanvas top layer origin, its top-left corner; may be nullptr @return address of pixels, or nullptr if inaccessible */ @@ -276,7 +276,7 @@ public: /** Returns custom context that tracks the SkMatrix and clip. Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed - by the host platform's user interface. The custom context returned is generated by + by the host platform user interface. The custom context returned is generated by SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for the drawing destination. @@ -294,17 +294,16 @@ public: pixmap is valid only while SkCanvas is in scope and unchanged. Any SkCanvas or SkSurface call may invalidate the pixmap values. - @param pixmap storage for SkCanvas pixel state if SkCanvas pixels are readable; - otherwise, ignored + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored @return true if SkCanvas has direct access to pixels */ bool peekPixels(SkPixmap* pixmap); - /** Copies rectangle of pixels from SkCanvas into dstPixels. SkMatrix and clip are - ignored. Source rectangle corners are (srcX, srcY) and - (this->imageInfo.width(), this->imageInfo.height()). + /** Copies SkRect of pixels from SkCanvas into dstPixels. SkMatrix and clip are + ignored. Source SkRect corners are (srcX, srcY) and + (imageInfo().width(), imageInfo().height()). - Destination rectangle corners are (0, 0) and (bitmap.width(), bitmap.height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). Copies each readable pixel intersecting both rectangles, without scaling, converting to dstInfo.colorType() and dstInfo.alphaType() if required. @@ -317,7 +316,7 @@ public: Pixel values are converted only if SkColorType and SkAlphaType do not match. Only pixels within both source and destination rectangles - are copied. dstPixels contents outside the rectangle intersection are unchanged. + are copied. dstPixels contents outside SkRect intersection are unchanged. Pass negative values for srcX or srcY to offset pixels across or down destination. @@ -337,11 +336,11 @@ public: bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY); - /** Copies rectangle of pixels from SkCanvas into pixmap. SkMatrix and clip are - ignored. Source rectangle corners are (srcX, srcY) and - (this->imageInfo.width(), this->imageInfo.height()). + /** Copies SkRect of pixels from SkCanvas into pixmap. SkMatrix and clip are + ignored. Source SkRect corners are (srcX, srcY) and + (imageInfo().width(), imageInfo().height()). - Destination rectangle corners are (0, 0) and (bitmap.width(), bitmap.height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). Copies each readable pixel intersecting both rectangles, without scaling, converting to pixmap.colorType() and pixmap.alphaType() if required. @@ -353,8 +352,8 @@ public: Caller must allocate pixel storage in pixmap if needed. Pixel values are converted only if SkColorType and SkAlphaType - do not match. Only pixels within both source and destination rectangles - are copied. pixmap pixels contents outside the rectangle intersection are unchanged. + do not match. Only pixels within both source and destination SkRect + are copied. pixmap pixels contents outside SkRect intersection are unchanged. Pass negative values for srcX or srcY to offset pixels across or down pixmap. @@ -372,11 +371,11 @@ public: */ bool readPixels(const SkPixmap& pixmap, int srcX, int srcY); - /** Copies rectangle of pixels from SkCanvas into bitmap. SkMatrix and clip are - ignored. Source rectangle corners are (srcX, srcY) and - (this->imageInfo.width(), this->imageInfo.height()). + /** Copies SkRect of pixels from SkCanvas into bitmap. SkMatrix and clip are + ignored. Source SkRect corners are (srcX, srcY) and + (imageInfo().width(), imageInfo().height()). - Destination rectangle corners are (0, 0) and (bitmap.width(), bitmap.height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). Copies each readable pixel intersecting both rectangles, without scaling, converting to bitmap.colorType() and bitmap.alphaType() if required. @@ -389,7 +388,7 @@ public: SkBitmap values are converted only if SkColorType and SkAlphaType do not match. Only pixels within both source and destination rectangles - are copied. SkBitmap pixels outside the rectangle intersection are unchanged. + are copied. SkBitmap pixels outside SkRect intersection are unchanged. Pass negative values for srcX or srcY to offset pixels across or down bitmap. @@ -407,15 +406,13 @@ public: */ bool readPixels(const SkBitmap& bitmap, int srcX, int srcY); - /** Copies rectangle from pixels to SkCanvas. SkMatrix and clip are ignored. - Source rectangle corners are (0, 0) and (info.width(), info.height()). - Destination rectangle corners are (x, y) and - (this->imageInfo.width(), this->imageInfo.height()). + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (info.width(), info.height()). + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). Copies each readable pixel intersecting both rectangles, without scaling, - converting to - this->imageInfo.colorType()and - this->imageInfo.alphaType()if required. + converting to imageInfo().colorType() and imageInfo().alphaType() if required. Pixels are writable when SkBaseDevice is raster, or backed by a GPU. Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, @@ -424,15 +421,15 @@ public: Pixel values are converted only if SkColorType and SkAlphaType do not match. Only pixels within both source and destination rectangles - are copied. SkCanvas pixels outside the rectangle intersection are unchanged. + are copied. SkCanvas pixels outside SkRect intersection are unchanged. Pass negative values for x or y to offset pixels to the left or above SkCanvas pixels. Does not copy, and returns false if: - Source and destination rectangles do not intersect. - - pixels could not be converted to this->imageInfo.colorType() or - this->imageInfo.alphaType(). + - pixels could not be converted to this->imageInfo().colorType() or + this->imageInfo().alphaType(). - SkCanvas pixels are not writable; for instance, SkCanvas is document-based. - rowBytes is too small to contain one row of pixels. @@ -445,16 +442,14 @@ public: */ bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y); - /** Copies rectangle from pixels to SkCanvas. SkMatrix and clip are ignored. - Source rectangle corners are (0, 0) and (bitmap.width(), bitmap.height()). + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). - Destination rectangle corners are (x, y) and - (this->imageInfo.width(), this->imageInfo.height()). + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). Copies each readable pixel intersecting both rectangles, without scaling, - converting to - this->imageInfo.colorType()and - this->imageInfo.alphaType()if required. + converting to imageInfo().colorType() and imageInfo().alphaType() if required. Pixels are writable when SkBaseDevice is raster, or backed by a GPU. Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, @@ -463,7 +458,7 @@ public: Pixel values are converted only if SkColorType and SkAlphaType do not match. Only pixels within both source and destination rectangles - are copied. SkCanvas pixels outside the rectangle intersection are unchanged. + are copied. SkCanvas pixels outside SkRect intersection are unchanged. Pass negative values for x or y to offset pixels to the left or above SkCanvas pixels. @@ -471,8 +466,8 @@ public: Does not copy, and returns false if: - Source and destination rectangles do not intersect. - bitmap does not have allocated pixels. - - bitmap pixels could not be converted to this->imageInfo.colorType() or - this->imageInfo.alphaType(). + - bitmap pixels could not be converted to this->imageInfo().colorType() or + this->imageInfo().alphaType(). - SkCanvas pixels are not writable; for instance, SkCanvas is document based. - bitmap pixels are inaccessible; for instance, bitmap wraps a texture. @@ -626,6 +621,7 @@ public: typedef uint32_t SaveLayerFlags; /** \struct SkCanvas::SaveLayerRec + SaveLayerRec contains the state used to create the layer. */ struct SaveLayerRec { @@ -1205,7 +1201,7 @@ public: if stroked, SkPaint stroke width describes the line thickness, and SkPaint::Join draws the corners rounded or square. - @param rect rectangle to be drawn + @param rect rectangle to draw @param paint stroke or fill, blend, color, and so on, used to draw */ void drawRect(const SkRect& rect, const SkPaint& paint); @@ -1215,7 +1211,7 @@ public: if stroked, SkPaint stroke width describes the line thickness, and SkPaint::Join draws the corners rounded or square. - @param rect rectangle to be drawn + @param rect rectangle to draw @param paint stroke or fill, blend, color, and so on, used to draw */ void drawIRect(const SkIRect& rect, const SkPaint& paint) { @@ -1229,7 +1225,7 @@ public: if stroked, SkPaint stroke width describes the line thickness, and SkPaint::Join draws the corners rounded or square. - @param region region to be drawn + @param region region to draw @param paint SkPaint stroke or fill, blend, color, and so on, used to draw */ void drawRegion(const SkRegion& region, const SkPaint& paint); @@ -1360,7 +1356,7 @@ public: If paint contains SkMaskFilter, generate mask from image bounds. If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the - image's edge color when it samples outside of its bounds. + image edge color when it samples outside of its bounds. @param image uncompressed rectangular map of pixels @param left left side of image @@ -1379,7 +1375,7 @@ public: If paint contains SkMaskFilter, generate mask from image bounds. If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the - image's edge color when it samples outside of its bounds. + image edge color when it samples outside of its bounds. @param image uncompressed rectangular map of pixels @param left left side of image @@ -1421,7 +1417,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within src; set to kFast_SrcRectConstraint allows sampling outside to @@ -1449,7 +1445,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to @@ -1475,7 +1471,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within image; set to kFast_SrcRectConstraint allows sampling outside to @@ -1499,7 +1495,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within src; set to kFast_SrcRectConstraint allows sampling outside to @@ -1528,7 +1524,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within image; set to kFast_SrcRectConstraint allows sampling outside to @@ -1556,7 +1552,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to sample within image; set to kFast_SrcRectConstraint allows sampling outside to @@ -1586,7 +1582,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. @param image SkImage containing pixels, dimensions, and format @param center SkIRect edge of image corners and sides @@ -1610,7 +1606,7 @@ public: If generated mask extends beyond image bounds, replicate image edge colors, just as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set - replicates the image's edge color when it samples outside of its bounds. + replicates the image edge color when it samples outside of its bounds. @param image SkImage containing pixels, dimensions, and format @param center SkIRect edge of image corners and sides @@ -1632,7 +1628,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. @param bitmap SkBitmap containing pixels, dimensions, and format @@ -1653,7 +1649,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to @@ -1681,7 +1677,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to @@ -1709,7 +1705,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to @@ -1739,7 +1735,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. @param bitmap SkBitmap containing pixels, dimensions, and format @@ -1816,7 +1812,7 @@ public: Lattice lattice divides bitmap into a rectangular grid. Each intersection of an even-numbered row and column is fixed; like the corners of drawBitmapNine(), fixed lattice elements never scale larger than their initial - size and shrink proportionately when all fixed elements exceed the bitmap's + size and shrink proportionately when all fixed elements exceed the bitmap dimension. All other grid elements scale to fill the available space, if any. Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. @@ -1827,7 +1823,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. @param bitmap SkBitmap containing pixels, dimensions, and format @@ -1844,7 +1840,7 @@ public: Lattice lattice divides image into a rectangular grid. Each intersection of an even-numbered row and column is fixed; like the corners of drawBitmapNine(), fixed lattice elements never scale larger than their initial - size and shrink proportionately when all fixed elements exceed the bitmap's + size and shrink proportionately when all fixed elements exceed the bitmap dimension. All other grid elements scale to fill the available space, if any. Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. @@ -1855,7 +1851,7 @@ public: If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, just as SkShader made from SkShader::MakeBitmapShader with - SkShader::kClamp_TileMode set replicates the bitmap's edge color when it samples + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples outside of its bounds. @param image SkImage containing pixels, dimensions, and format @@ -1869,11 +1865,11 @@ public: /** Draw text, with origin at (x, y), using clip, SkMatrix, and SkPaint paint. - text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + text meaning depends on SkPaint::TextEncoding; by default, text is encoded as UTF-8. x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default - text draws left to right, positioning the first glyph's left side bearing at x + text draws left to right, positioning the first glyph left side bearing at x and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, @@ -1892,12 +1888,12 @@ public: /** Draw null terminated string, with origin at (x, y), using clip, SkMatrix, and SkPaint paint. - string's meaning depends on SkPaint::TextEncoding; by default, string encoding is - UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired + string meaning depends on SkPaint::TextEncoding; by default, strings are encoded + as UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired results, since zero bytes may be embedded in the string. x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default - string draws left to right, positioning the first glyph's left side bearing at x + string draws left to right, positioning the first glyph left side bearing at x and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, @@ -1920,12 +1916,12 @@ public: /** Draw null terminated string, with origin at (x, y), using clip, SkMatrix, and SkPaint paint. - string's meaning depends on SkPaint::TextEncoding; by default, string encoding is - UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired + string meaning depends on SkPaint::TextEncoding; by default, strings are encoded + as UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired results, since zero bytes may be embedded in the string. x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default - string draws left to right, positioning the first glyph's left side bearing at x + string draws left to right, positioning the first glyph left side bearing at x and its baseline at y. Text size is affected by SkMatrix and SkPaint text size. All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, @@ -1944,9 +1940,9 @@ public: SkPaint paint. The number of entries in pos array must match the number of glyphs described by byteLength of text. - text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + text meaning depends on SkPaint::TextEncoding; by default, text is encoded as UTF-8. pos elements' meaning depends on SkPaint::Align and SkPaint vertical text; - by default each glyph's left side bearing is positioned at x and its + by default each glyph left side bearing is positioned at x and its baseline is positioned at y. Text size is affected by SkMatrix and SkPaint text size. @@ -1955,7 +1951,7 @@ public: filled 12 point black glyphs. Layout engines such as Harfbuzz typically position each glyph - rather than using the font's advance widths. + rather than using the font advance widths. @param text character code points or glyphs drawn @param byteLength byte length of text array @@ -1969,9 +1965,9 @@ public: constY, using clip, SkMatrix, and SkPaint paint. The number of entries in xpos array must match the number of glyphs described by byteLength of text. - text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + text meaning depends on SkPaint::TextEncoding; by default, text is encoded as UTF-8. xpos elements' meaning depends on SkPaint::Align and SkPaint vertical text; - by default each glyph's left side bearing is positioned at an xpos element and + by default each glyph left side bearing is positioned at an xpos element and its baseline is positioned at constY. Text size is affected by SkMatrix and SkPaint text size. @@ -1980,7 +1976,7 @@ public: filled 12 point black glyphs. Layout engines such as Harfbuzz typically position each glyph - rather than using the font's advance widths if all glyphs share the same + rather than using the font advance widths if all glyphs share the same baseline. @param text character code points or glyphs drawn @@ -1997,12 +1993,12 @@ public: Origin of text is at distance hOffset along the path, offset by a perpendicular vector of length vOffset. If the path section corresponding the glyph advance is curved, the glyph is drawn curved to match; control points in the glyph are - mapped to projected points parallel to the path. If the text's advance is larger + mapped to projected points parallel to the path. If the text advance is larger than the path length, the excess text is clipped. - text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + text meaning depends on SkPaint::TextEncoding; by default, text is encoded as UTF-8. Origin meaning depends on SkPaint::Align and SkPaint vertical text; by - default text positions the first glyph's left side bearing at origin x and its + default text positions the first glyph left side bearing at origin x and its baseline at origin y. Text size is affected by SkMatrix and SkPaint text size. All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, @@ -2024,12 +2020,12 @@ public: Origin of text is at beginning of path offset by matrix, if provided, before it is mapped to path. If the path section corresponding the glyph advance is curved, the glyph is drawn curved to match; control points in the glyph are - mapped to projected points parallel to the path. If the text's advance is larger + mapped to projected points parallel to the path. If the text advance is larger than the path length, the excess text is clipped. - text's meaning depends on SkPaint::TextEncoding; by default, text encoding is + text meaning depends on SkPaint::TextEncoding; by default, text is encoded as UTF-8. Origin meaning depends on SkPaint::Align and SkPaint vertical text; by - default text positions the first glyph's left side bearing at origin x and its + default text positions the first glyph left side bearing at origin x and its baseline at origin y. Text size is affected by SkMatrix and SkPaint text size. All elements of paint: SkPathEffect, SkRasterizer, SkMaskFilter, SkShader, @@ -2181,20 +2177,20 @@ public: /** Draws a Coons patch: the interpolation of four cubics with shared corners, associating a color, and optionally a texture coordinate, with each corner. - The Coons patch uses clip and SkMatrix, SkPaint paint's SkShader, SkColorFilter, + The Coons patch uses clip and SkMatrix, paint SkShader, SkColorFilter, color alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated as the Coons patch texture; SkBlendMode mode combines color colors and SkShader if both are provided. - SkPoint array cubics specifies four cubics starting at the top left corner, + SkPoint array cubics specifies four cubics starting at the top-left corner, in clockwise order, sharing every fourth point. The last cubic ends at the first point. - Color array color associates colors with corners in top left, top right, - bottom right, bottom left order. + Color array color associates colors with corners in top-left, top-right, + bottom-right, bottom-left order. If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to - corners in top left, top right, bottom right, bottom left order. + corners in top-left, top-right, bottom-right, bottom-left order. @param cubics SkPath cubic array, sharing common points @param colors color array, one for each corner @@ -2209,20 +2205,20 @@ public: /** Draws cubic Coons patch: the interpolation of four cubics with shared corners, associating a color, and optionally a texture coordinate, with each corner. - The Coons patch uses clip and SkMatrix, SkPaint paint's SkShader, SkColorFilter, + The Coons patch uses clip and SkMatrix, paint SkShader, SkColorFilter, color alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated as the Coons patch texture; SkBlendMode mode combines color colors and SkShader if both are provided. - SkPoint array cubics specifies four cubics starting at the top left corner, + SkPoint array cubics specifies four cubics starting at the top-left corner, in clockwise order, sharing every fourth point. The last cubic ends at the first point. - Color array color associates colors with corners in top left, top right, - bottom right, bottom left order. + Color array color associates colors with corners in top-left, top-right, + bottom-right, bottom-left order. If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to - corners in top left, top right, bottom right, bottom left order. + corners in top-left, top-right, bottom-right, bottom-left order. @param cubics SkPath cubic array, sharing common points @param colors color array, one for each corner @@ -2757,12 +2753,20 @@ private: typedef SkRefCnt INHERITED; }; -/** Stack helper class to automatically call restoreToCount() on the canvas - when this object goes out of scope. Use this to guarantee that the canvas - is restored to a known state. +/** \class SkAutoCanvasRestore + Stack helper class calls SkCanvas::restoreToCount() when SkAutoCanvasRestore + goes out of scope. Use this to guarantee that the canvas is restored to a known + state. */ class SkAutoCanvasRestore : SkNoncopyable { public: + + /** Preserves SkCanvas save count. Optionally saves SkCanvas clip and SkMatrix. + + @param canvas SkCanvas to guard + @param doSave call SkCanvas::save() + @return utility to restore SkCanvas state on destructor + */ SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) { if (fCanvas) { fSaveCount = canvas->getSaveCount(); @@ -2771,16 +2775,18 @@ public: } } } + + /** Restores SkCanvas to saved state. + */ ~SkAutoCanvasRestore() { if (fCanvas) { fCanvas->restoreToCount(fSaveCount); } } - /** - * Perform the restore now, instead of waiting for the destructor. Will - * only do this once. - */ + /** Restores SkCanvas to saved state immediately. Subsequent calls and + ~SkAutoCanvasRestore have no effect. + */ void restore() { if (fCanvas) { fCanvas->restoreToCount(fSaveCount); diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 49be97aa29..58bcff8fc4 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -17,52 +16,89 @@ struct SkPoint3; class SkString; /** \class SkMatrix + SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping + SkPoint and SkVector with translation, scaling, skewing, rotation, and + perspective. - The SkMatrix class holds a 3x3 matrix for transforming coordinates. - SkMatrix does not have a constructor, so it must be explicitly initialized - using either reset() - to construct an identity matrix, or one of the set - functions (e.g. setTranslate, setRotate, etc.). + SkMatrix elements are in row major order. SkMatrix does not have a constructor, + so it must be explicitly initialized. setIdentity() initializes SkMatrix + so it has no effect. setTranslate(), setScale(), setSkew(), setRotate(), set9 and setAll() + initializes all SkMatrix elements with the corresponding mapping. - SkMatrix is not thread safe unless you've first called SkMatrix::getType(). + SkMatrix includes a hidden variable that classifies the type of matrix to + improve performance. SkMatrix is not thread safe unless getType() is called first. */ SK_BEGIN_REQUIRE_DENSE class SK_API SkMatrix { public: + + /** Sets SkMatrix to scale by (sx, sy). Returned matrix is: + + | sx 0 0 | + | 0 sy 0 | + | 0 0 1 | + + @param sx horizontal scale factor + @param sy vertical scale factor + @return SkMatrix with scale + */ static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar sx, SkScalar sy) { SkMatrix m; m.setScale(sx, sy); return m; } + /** Sets SkMatrix to scale by (scale, scale). Returned matrix is: + + | scale 0 0 | + | 0 scale 0 | + | 0 0 1 | + + @param scale horizontal and vertical scale factor + @return SkMatrix with scale + */ static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar scale) { SkMatrix m; m.setScale(scale, scale); return m; } + /** Sets SkMatrix to translate by (dx, dy). Returned matrix is: + + | 1 0 dx | + | 0 1 dy | + | 0 0 1 | + + @param dx horizontal translation + @param dy vertical translation + @return SkMatrix with translation + */ static SkMatrix SK_WARN_UNUSED_RESULT MakeTrans(SkScalar dx, SkScalar dy) { SkMatrix m; m.setTranslate(dx, dy); return m; } - /** Enum of bit fields for the mask return by getType(). - Use this to identify the complexity of the matrix. + /** \enum SkMatrix::TypeMask + Enum of bit fields for mask returned by getType(). + Used to identify the complexity of SkMatrix, to optimize performance. */ enum TypeMask { - kIdentity_Mask = 0, - kTranslate_Mask = 0x01, //!< set if the matrix has translation - kScale_Mask = 0x02, //!< set if the matrix has X or Y scale - kAffine_Mask = 0x04, //!< set if the matrix skews or rotates - kPerspective_Mask = 0x08, //!< set if the matrix is in perspective + kIdentity_Mask = 0, //!< all bits clear if SkMatrix is identity + kTranslate_Mask = 0x01, //!< set if SkMatrix has translation + kScale_Mask = 0x02, //!< set if SkMatrix has x or y scale + kAffine_Mask = 0x04, //!< set if SkMatrix skews or rotates + kPerspective_Mask = 0x08, //!< set if SkMatrix has perspective }; - /** Returns a bitfield describing the transformations the matrix may - perform. The bitfield is computed conservatively, so it may include - false positives. For example, when kPerspective_Mask is true, all - other bits may be set to true even in the case of a pure perspective - transform. - */ + /** Returns a bit field describing the transformations the matrix may + perform. The bit field is computed conservatively, so it may include + false positives. For example, when kPerspective_Mask is set, all + other bits are set. + + @return kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask, + kAffine_Mask, kPerspective_Mask + */ TypeMask getType() const { if (fTypeMask & kUnknown_Mask) { fTypeMask = this->computeTypeMask(); @@ -71,21 +107,61 @@ public: return (TypeMask)(fTypeMask & 0xF); } - /** Returns true if the matrix is identity. + /** Returns true if SkMatrix is identity. Identity matrix is: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return true if SkMatrix has no effect */ bool isIdentity() const { return this->getType() == 0; } + /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity, + contain only scale elements, only translate elements, or both. SkMatrix form is: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity; or scales, translates, or both + */ bool isScaleTranslate() const { return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); } + /** Returns true if SkMatrix is identity, or translates. SkMatrix form is: + + | 1 0 translate-x | + | 0 1 translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity, or translates + */ bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); } - /** Returns true if will map a rectangle to another rectangle. This can be - true if the matrix is identity, scale-only, or rotates a multiple of - 90 degrees, or mirrors in x or y. + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors in x or y. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called preservesAxisAlignment(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another */ bool rectStaysRect() const { if (fTypeMask & kUnknown_Mask) { @@ -93,50 +169,102 @@ public: } return (fTypeMask & kRectStaysRect_Mask) != 0; } - // alias for rectStaysRect() + + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors in x or y. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called rectStaysRect(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another + */ bool preservesAxisAlignment() const { return this->rectStaysRect(); } - /** - * Returns true if the matrix contains perspective elements. - */ + /** Returns true if the matrix contains perspective elements. SkMatrix form is: + + | -- -- -- | + | -- -- -- | + | perspective-x perspective-y perspective-scale | + + where perspective-x or perspective-y is non-zero, or perspective-scale is + not one. All other elements may have any value. + + @return true if SkMatrix is in most general form + */ bool hasPerspective() const { return SkToBool(this->getPerspectiveTypeMaskOnly() & kPerspective_Mask); } - /** Returns true if the matrix contains only translation, rotation/reflection or uniform scale - Returns false if other transformation types are included or is degenerate - */ + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + uniform scale. + Returns false if SkMatrix contains different scales, skewing, perspective, or + degenerate forms that collapse to a line or point. + + Describes that the SkMatrix makes rendering with and without the matrix are + visually alike; a transformed circle remains a circle. Mathematically, this is + referred to as similarity of a Euclidean space, or a similarity transformation. + + Preserves right angles, keeping the arms of the angle equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, uniformly scales, translates + */ bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; - /** Returns true if the matrix contains only translation, rotation/reflection or scale - (non-uniform scale is allowed). - Returns false if other transformation types are included or is degenerate - */ + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + scale. Scale may differ along rotated axes. + Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse + to a line or point. + + Preserves right angles, but not requiring that the arms of the angle + retain equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, scales, translates + */ bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; + /** \enum + SkMatrix organizes its values in row order. These members correspond to + each value in SkMatrix. + */ enum { - kMScaleX, - kMSkewX, - kMTransX, - kMSkewY, - kMScaleY, - kMTransY, - kMPersp0, - kMPersp1, - kMPersp2, + kMScaleX, //!< horizontal scale factor + kMSkewX, //!< horizontal skew factor + kMTransX, //!< horizontal translation + kMSkewY, //!< vertical skew factor + kMScaleY, //!< vertical scale factor + kMTransY, //!< vertical translation + kMPersp0, //!< input x perspective factor + kMPersp1, //!< input y perspective factor + kMPersp2, //!< perspective bias }; - /** Affine arrays are in column major order - because that's how PDF and XPS like it. - */ + /** \enum + Affine arrays are in column major order to match the matrix used by + PDF and XPS. + */ enum { - kAScaleX, - kASkewY, - kASkewX, - kAScaleY, - kATransX, - kATransY, + kAScaleX, //!< horizontal scale factor + kASkewY, //!< vertical skew factor + kASkewX, //!< horizontal skew factor + kAScaleY, //!< vertical scale factor + kATransX, //!< horizontal translation + kATransY, //!< vertical translation }; SkScalar operator[](int index) const { @@ -144,41 +272,169 @@ public: return fMat[index]; } + /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is + defined. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return value corresponding to index + */ SkScalar get(int index) const { SkASSERT((unsigned)index < 9); return fMat[index]; } + /** Returns scale factor multiplied by x input, contributing to x output. + With mapPoints(), scales SkPoint along the x-axis. + + @return horizontal scale factor + */ SkScalar getScaleX() const { return fMat[kMScaleX]; } + + /** Returns scale factor multiplied by y input, contributing to y output. + With mapPoints(), scales SkPoint along the y-axis. + + @return vertical scale factor + */ SkScalar getScaleY() const { return fMat[kMScaleY]; } + + /** Returns scale factor multiplied by x input, contributing to y output. + With mapPoints(), skews SkPoint along the y-axis. + Skew x and y together can rotate SkPoint. + + @return vertical skew factor + */ SkScalar getSkewY() const { return fMat[kMSkewY]; } + + /** Returns scale factor multiplied by y input, contributing to x output. + With mapPoints(), skews SkPoint along the x-axis. + Skew x and y together can rotate SkPoint. + + @return horizontal scale factor + */ SkScalar getSkewX() const { return fMat[kMSkewX]; } + + /** Returns translation contributing to x output. + With mapPoints(), moves SkPoint along the x-axis. + + @return horizontal translation factor + */ SkScalar getTranslateX() const { return fMat[kMTransX]; } + + /** Returns translation contributing to y output. + With mapPoints(), moves SkPoint along the y-axis. + + @return vertical translation factor + */ SkScalar getTranslateY() const { return fMat[kMTransY]; } + + /** Returns factor scaling input x relative to input y. + + @return input x perspective factor + */ SkScalar getPerspX() const { return fMat[kMPersp0]; } + + /** Returns factor scaling input y relative to input x. + + @return input y perspective factor + */ SkScalar getPerspY() const { return fMat[kMPersp1]; } + /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Clears internal cache anticipating that caller will change SkMatrix value. + + Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix + value must be followed by dirtyMatrixTypeCache(). + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return writable value corresponding to index + */ SkScalar& operator[](int index) { SkASSERT((unsigned)index < 9); this->setTypeMask(kUnknown_Mask); return fMat[index]; } + /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Safer than operator[]; internal cache is always maintained. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @param value scalar to store in SkMatrix + */ void set(int index, SkScalar value) { SkASSERT((unsigned)index < 9); fMat[index] = value; this->setTypeMask(kUnknown_Mask); } + /** Sets horizontal scale factor. + + @param v horizontal scale factor to store + */ void setScaleX(SkScalar v) { this->set(kMScaleX, v); } + + /** Sets vertical scale factor. + + @param v vertical scale factor to store + */ void setScaleY(SkScalar v) { this->set(kMScaleY, v); } + + /** Sets vertical skew factor. + + @param v vertical skew factor to store + */ void setSkewY(SkScalar v) { this->set(kMSkewY, v); } + + /** Sets horizontal skew factor. + + @param v horizontal skew factor to store + */ void setSkewX(SkScalar v) { this->set(kMSkewX, v); } + + /** Sets horizontal translation. + + @param v horizontal translation to store + */ void setTranslateX(SkScalar v) { this->set(kMTransX, v); } + + /** Sets vertical translation. + + @param v vertical translation to store + */ void setTranslateY(SkScalar v) { this->set(kMTransY, v); } + + /** Sets input x perspective factor, which causes mapXY() to vary input x inversely + proportional to input y. + + @param v perspective factor + */ void setPerspX(SkScalar v) { this->set(kMPersp0, v); } + + /** Sets input y perspective factor, which causes mapXY() to vary input y inversely + proportional to input x. + + @param v perspective factor + */ void setPerspY(SkScalar v) { this->set(kMPersp1, v); } + /** Sets all values from parameters. Sets matrix to: + + | scaleX skewX transX | + | skewY scaleY transY | + | persp0 persp1 persp2 | + + @param scaleX horizontal scale factor to store + @param skewX horizontal skew factor to store + @param transX horizontal translation to store + @param skewY vertical skew factor to store + @param scaleY vertical scale factor to store + @param transY vertical translation to store + @param persp0 input x perspective factor to store + @param persp1 input y perspective factor to store + @param persp2 perspective scale factor to store + */ void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2) { @@ -194,200 +450,684 @@ public: this->setTypeMask(kUnknown_Mask); } - /** - * Copy the 9 scalars for this matrix into buffer, in the same order as the kMScaleX - * enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2 - */ + /** Copies nine scalar values contained by SkMatrix into buffer, in member value + ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2. + + @param buffer storage for nine scalar values + */ void get9(SkScalar buffer[9]) const { memcpy(buffer, fMat, 9 * sizeof(SkScalar)); } - /** - * Set this matrix to the 9 scalars from the buffer, in the same order as the kMScaleX - * enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2 - * - * Note: calling set9 followed by get9 may not return the exact same values. Since the matrix - * is used to map non-homogeneous coordinates, it is free to rescale the 9 values as needed. - */ + /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order: + kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, + kMPersp2. + + Sets matrix to: + + | buffer[0] buffer[1] buffer[2] | + | buffer[3] buffer[4] buffer[5] | + | buffer[6] buffer[7] buffer[8] | + + In the future, set9 followed by get9 may not return the same values. Since SkMatrix + maps non-homogeneous coordinates, scaling all nine values produces an equivalent + transformation, possibly improving precision. + + @param buffer nine scalar values + */ void set9(const SkScalar buffer[9]); - /** Set the matrix to identity + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called setIdentity(); use the one that provides better inline + documentation. */ void reset(); - // alias for reset() + + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called reset(); use the one that provides better inline + documentation. + */ void setIdentity() { this->reset(); } - /** Set the matrix to translate by (dx, dy). + /** Sets SkMatrix to translate by (dx, dy). + + @param dx horizontal translation + @param dy vertical translation */ void setTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to translate by (v.fX, v.fY). + + @param v SkVector containing horizontal and vertical translation + */ void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); } - /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). - The pivot point is the coordinate that should remain unchanged by the - specified transformation. + /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot x + @param py pivot y */ void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); - /** Set the matrix to scale by sx and sy. + + /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0). + + @param sx horizontal scale factor + @param sy vertical scale factor */ void setScale(SkScalar sx, SkScalar sy); - /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't - touch the matrix if either divx or divy is zero. + + /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes + @param px pivot x + @param py pivot y */ void setRotate(SkScalar degrees, SkScalar px, SkScalar py); - /** Set the matrix to rotate about (0,0) by the specified number of degrees. + + /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0). + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes */ void setRotate(SkScalar degrees); - /** Set the matrix to rotate by the specified sine and cosine values, with - a pivot point at (px, py). The pivot point is the coordinate that - should remain unchanged by the specified transformation. + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + SkVector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + SkVector length specifies scale. + + @param sinValue rotation vector x component + @param cosValue rotation vector y component + @param px pivot x + @param py pivot y */ void setSinCos(SkScalar sinValue, SkScalar cosValue, SkScalar px, SkScalar py); - /** Set the matrix to rotate by the specified sine and cosine values. + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0). + + SkVector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + SkVector length specifies scale. + + @param sinValue rotation vector x component + @param cosValue rotation vector y component */ void setSinCos(SkScalar sinValue, SkScalar cosValue); + /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form. + + SkVector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative + to (0, 1). SkVector length specifies scale. Mapped point is rotated and scaled + by SkVector, then translated by (rsxForm.fTx, rsxForm.fTy). + + @param rsxForm compressed SkRSXform matrix + @return reference to SkMatrix + */ SkMatrix& setRSXform(const SkRSXform& rsxForm); - /** Set the matrix to skew by sx and sy, with a pivot point at (px, py). - The pivot point is the coordinate that should remain unchanged by the - specified transformation. + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot x + @param py pivot y */ void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); - /** Set the matrix to skew by sx and sy. + + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0). + + @param kx horizontal skew factor + @param ky vertical skew factor */ void setSkew(SkScalar kx, SkScalar ky); - /** Set the matrix to the concatenation of the two specified matrices. - Either of the two matrices may also be the target matrix. - *this = a * b; + + /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression */ void setConcat(const SkMatrix& a, const SkMatrix& b); - /** Preconcats the matrix with the specified translation. - M' = M * T(dx, dy) + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy). + This can be thought of as moving the point to be mapped before applying SkMatrix. + + Given: + + | A B C | | 1 0 dx | + Matrix = | D E F |, T(dx, dy) = | 0 1 dy | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 0 dx | | A B A*dx+B*dy+C | + Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G H G*dx+H*dy+I | + + @param dx x translation before applying SkMatrix + @param dy y translation before applying SkMatrix */ void preTranslate(SkScalar dx, SkScalar dy); - /** Preconcats the matrix with the specified scale. - M' = M * S(sx, sy, px, py) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (px, py). + This can be thought of as scaling about a pivot point before applying SkMatrix. + + Given: + + | A B C | | sx 0 dx | + Matrix = | D E F |, S(sx, sy, px, py) = | 0 sy dy | + | G H I | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | A B C | | sx 0 dx | | A*sx B*sy A*dx+B*dy+C | + Matrix * S(sx, sy, px, py) = | D E F | | 0 sy dy | = | D*sx E*sy D*dx+E*dy+F | + | G H I | | 0 0 1 | | G*sx H*sy G*dx+H*dy+I | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot x + @param py pivot y */ void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); - /** Preconcats the matrix with the specified scale. - M' = M * S(sx, sy) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (0, 0). + This can be thought of as scaling about the origin before applying SkMatrix. + + Given: + + | A B C | | sx 0 0 | + Matrix = | D E F |, S(sx, sy) = | 0 sy 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | sx 0 0 | | A*sx B*sy C | + Matrix * S(sx, sy) = | D E F | | 0 sy 0 | = | D*sx E*sy F | + | G H I | | 0 0 1 | | G*sx H*sy I | + + @param sx horizontal scale factor + @param sy vertical scale factor */ void preScale(SkScalar sx, SkScalar sy); - /** Preconcats the matrix with the specified rotation. - M' = M * R(degrees, px, py) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (px, py). + This can be thought of as rotating about a pivot point before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s dx | + Matrix = | D E F |, R(degrees, px, py) = | s c dy | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + | A B C | | c -s dx | | Ac+Bs -As+Bc A*dx+B*dy+C | + Matrix * R(degrees, px, py) = | D E F | | s c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc G*dx+H*dy+I | + + @param degrees angle of axes relative to upright axes + @param px pivot x + @param py pivot y */ void preRotate(SkScalar degrees, SkScalar px, SkScalar py); - /** Preconcats the matrix with the specified rotation. - M' = M * R(degrees) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (0, 0). + This can be thought of as rotating about the origin before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s 0 | + Matrix = | D E F |, R(degrees, px, py) = | s c 0 | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | A B C | | c -s 0 | | Ac+Bs -As+Bc C | + Matrix * R(degrees, px, py) = | D E F | | s c 0 | = | Dc+Es -Ds+Ec F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc I | + + @param degrees angle of axes relative to upright axes */ void preRotate(SkScalar degrees); - /** Preconcats the matrix with the specified skew. - M' = M * K(kx, ky, px, py) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (px, py). + This can be thought of as skewing about a pivot point before applying SkMatrix. + + Given: + + | A B C | | 1 kx dx | + Matrix = | D E F |, K(kx, ky, px, py) = | ky 1 dy | + | G H I | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | A B C | | 1 kx dx | | A+B*ky A*kx+B A*dx+B*dy+C | + Matrix * K(kx, ky, px, py) = | D E F | | ky 1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H G*dx+H*dy+I | + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot x + @param py pivot y */ void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); - /** Preconcats the matrix with the specified skew. - M' = M * K(kx, ky) + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (0, 0). + This can be thought of as skewing about the origin before applying SkMatrix. + + Given: + + | A B C | | 1 kx 0 | + Matrix = | D E F |, K(kx, ky) = | ky 1 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 kx 0 | | A+B*ky A*kx+B C | + Matrix * K(kx, ky) = | D E F | | ky 1 0 | = | D+E*ky D*kx+E F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H I | + + @param kx horizontal skew factor + @param ky vertical skew factor */ void preSkew(SkScalar kx, SkScalar ky); - /** Preconcats the matrix with the specified matrix. - M' = M * other + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other. + This can be thought of mapping by other before applying SkMatrix. + + Given: + + | A B C | | J K L | + Matrix = | D E F |, other = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on right side of multiply expression */ void preConcat(const SkMatrix& other); - /** Postconcats the matrix with the specified translation. - M' = T(dx, dy) * M + /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix. + This can be thought of as moving the point to be mapped after applying SkMatrix. + + Given: + + | J K L | | 1 0 dx | + Matrix = | M N O |, T(dx, dy) = | 0 1 dy | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 0 dx | | J K L | | J+dx*P K+dx*Q L+dx*R | + T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param dx x translation after applying SkMatrix + @param dy y translation after applying SkMatrix */ void postTranslate(SkScalar dx, SkScalar dy); - /** Postconcats the matrix with the specified scale. - M' = S(sx, sy, px, py) * M + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as scaling about a pivot point after applying SkMatrix. + + Given: + + | J K L | | sx 0 dx | + Matrix = | M N O |, S(sx, sy, px, py) = | 0 sy dy | + | P Q R | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | sx 0 dx | | J K L | | sx*J+dx*P sx*K+dx*Q sx*L+dx+R | + S(sx, sy, px, py) * Matrix = | 0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot x + @param py pivot y */ void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); - /** Postconcats the matrix with the specified scale. - M' = S(sx, sy) * M + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as scaling about the origin after applying SkMatrix. + + Given: + + | J K L | | sx 0 0 | + Matrix = | M N O |, S(sx, sy) = | 0 sy 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | sx 0 0 | | J K L | | sx*J sx*K sx*L | + S(sx, sy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor */ void postScale(SkScalar sx, SkScalar sy); - /** Postconcats the matrix by dividing it by the specified integers. - M' = S(1/divx, 1/divy, 0, 0) * M + + /** Sets SkMatrix to SkMatrix constructed from scaling by (1/divx, 1/divy) about pivot point (px, py), multiplied by SkMatrix. + + Returns false if either divx or divy is zero. + + Given: + + | J K L | | sx 0 0 | + Matrix = | M N O |, I(divx, divy) = | 0 sy 0 | + | P Q R | | 0 0 1 | + + where + + sx = 1 / divx + sy = 1 / divy + + sets SkMatrix to: + + | sx 0 0 | | J K L | | sx*J sx*K sx*L | + I(divx, divy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | + | 0 0 1 | | P Q R | | P Q R | + + @param divx integer divisor for inverse scale in x + @param divy integer divisor for inverse scale in y + @return true on successful scale */ bool postIDiv(int divx, int divy); - /** Postconcats the matrix with the specified rotation. - M' = R(degrees, px, py) * M + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as rotating about a pivot point after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s dx | + Matrix = | M N O |, R(degrees, px, py) = | s c dy | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + |c -s dx| |J K L| |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R| + R(degrees, px, py) * Matrix = |s c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R| + |0 0 1| |P Q R| | P Q R| + + @param degrees angle of axes relative to upright axes + @param px pivot x + @param py pivot y */ void postRotate(SkScalar degrees, SkScalar px, SkScalar py); - /** Postconcats the matrix with the specified rotation. - M' = R(degrees) * M + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as rotating about the origin after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s 0 | + Matrix = | M N O |, R(degrees, px, py) = | s c 0 | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | c -s dx | | J K L | | cJ-sM cK-sN cL-sO | + R(degrees, px, py) * Matrix = | s c dy | | M N O | = | sJ+cM sK+cN sL+cO | + | 0 0 1 | | P Q R | | P Q R | + + @param degrees angle of axes relative to upright axes */ void postRotate(SkScalar degrees); - /** Postconcats the matrix with the specified skew. - M' = K(kx, ky, px, py) * M + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as skewing about a pivot point after applying SkMatrix. + + Given: + + | J K L | | 1 kx dx | + Matrix = | M N O |, K(kx, ky, px, py) = | ky 1 dy | + | P Q R | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | 1 kx dx| |J K L| |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R| + K(kx, ky, px, py) * Matrix = |ky 1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R| + | 0 0 1| |P Q R| | P Q R| + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot x + @param py pivot y */ void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); - /** Postconcats the matrix with the specified skew. - M' = K(kx, ky) * M + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as skewing about the origin after applying SkMatrix. + + Given: + + | J K L | | 1 kx 0 | + Matrix = | M N O |, K(kx, ky) = | ky 1 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 kx 0 | | J K L | | J+kx*M K+kx*N L+kx*O | + K(kx, ky) * Matrix = | ky 1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O | + | 0 0 1 | | P Q R | | P Q R | + + @param kx horizontal skew factor + @param ky vertical skew factor */ void postSkew(SkScalar kx, SkScalar ky); - /** Postconcats the matrix with the specified matrix. - M' = other * M + + /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix. + This can be thought of mapping by other after applying SkMatrix. + + Given: + + | J K L | | A B C | + Matrix = | M N O |, other = | D E F | + | P Q R | | G H I | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on left side of multiply expression */ void postConcat(const SkMatrix& other); + /** \enum SkMatrix::ScaleToFit + ScaleToFit describes how SkMatrix is constructed to map one SkRect to another. + ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling, + or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies + how SkMatrix maps to the side or center of the destination SkRect. + */ enum ScaleToFit { - /** - * Scale in X and Y independently, so that src matches dst exactly. - * This may change the aspect ratio of the src. - */ + /** Computes SkMatrix that scales in x and y independently, so that source SkRect is + mapped to completely fill destination SkRect. The aspect ratio of source SkRect + may change. + */ kFill_ScaleToFit, - /** - * Compute a scale that will maintain the original src aspect ratio, - * but will also ensure that src fits entirely inside dst. At least one - * axis (X or Y) will fit exactly. kStart aligns the result to the - * left and top edges of dst. - */ + + /** Computes SkMatrix that maintains source SkRect aspect ratio, mapping source SkRect + width or height to destination SkRect. Aligns mapping to left and top edges + of destination SkRect. + */ kStart_ScaleToFit, - /** - * Compute a scale that will maintain the original src aspect ratio, - * but will also ensure that src fits entirely inside dst. At least one - * axis (X or Y) will fit exactly. The result is centered inside dst. - */ + + /** Computes SkMatrix that maintains source SkRect aspect ratio, mapping source SkRect + width or height to destination SkRect. Aligns mapping to center of destination + SkRect. + */ kCenter_ScaleToFit, - /** - * Compute a scale that will maintain the original src aspect ratio, - * but will also ensure that src fits entirely inside dst. At least one - * axis (X or Y) will fit exactly. kEnd aligns the result to the - * right and bottom edges of dst. - */ + + /** Computes SkMatrix that maintains source SkRect aspect ratio, mapping source SkRect + width or height to destination SkRect. Aligns mapping to right and bottom + edges of destination SkRect. + */ kEnd_ScaleToFit, }; - /** Set the matrix to the scale and translate values that map the source - rectangle to the destination rectangle, returning true if the the result - can be represented. - @param src the source rectangle to map from. - @param dst the destination rectangle to map to. - @param stf the ScaleToFit option - @return true if the matrix can be represented by the rectangle mapping. + /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether + mapping completely fills dst or preserves the aspect ratio, and how to align + src within dst. Returns false if src is empty, and sets SkMatrix to identity. + Returns true if dst is empty, and sets SkMatrix to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @param stf one of: kFill_ScaleToFit, kStart_ScaleToFit, + kCenter_ScaleToFit, kEnd_ScaleToFit + @return true if SkMatrix can represent SkRect mapping */ bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); + + /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects + whether mapping completely fills dst or preserves the aspect ratio, and how to + align src within dst. Returns the identity SkMatrix if src is empty. If dst is + empty, returns SkMatrix set to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @param stf one of: kFill_ScaleToFit, kStart_ScaleToFit, + kCenter_ScaleToFit, kEnd_ScaleToFit + @return SkMatrix mapping src to dst + */ static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) { SkMatrix m; m.setRectToRect(src, dst, stf); return m; } - /** Set the matrix such that the specified src points would map to the - specified dst points. count must be within [0..4]. - @param src The array of src points - @param dst The array of dst points - @param count The number of points to use for the transformation - @return true if the matrix was set to the specified transformation + /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less. + + If count is zero, sets SkMatrix to identity and returns true. + If count is one, sets SkMatrix to translate and returns true. + If count is two or more, sets SkMatrix to map SkPoint if possible; returns false + if SkMatrix cannot be constructed. If count is four, SkMatrix may include + perspective. + + @param src SkPoint to map from + @param dst SkPoint to map to + @param count number of SkPoint in src and dst + @return true if SkMatrix was constructed successfully */ bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); - /** If this matrix can be inverted, return true and if inverse is not null, - set inverse to be the inverse of this matrix. If this matrix cannot be - inverted, ignore inverse and return false + /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted. + Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix + maps from destination to source. If SkMatrix can not be inverted, inverse is + unchanged. + + @param inverse storage for inverted SkMatrix; may be nullptr + @return true if SkMatrix can be inverted */ bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const { // Allow the trivial case to be inlined. @@ -400,34 +1140,71 @@ public: return this->invertNonIdentity(inverse); } - /** Fills the passed array with affine identity values - in column major order. - @param affine The array to fill with affine identity values. - Must not be NULL. + /** Fills affine with identity values in column major order. + Sets affine to: + + | 1 0 0 | + | 0 1 0 | + + Affine 3x2 matrices in column major order are used by OpenGL and XPS. + + @param affine storage for 3x2 affine matrix */ static void SetAffineIdentity(SkScalar affine[6]); - /** Fills the passed array with the affine values in column major order. - If the matrix is a perspective transform, returns false - and does not change the passed array. - @param affine The array to fill with affine values. Ignored if NULL. + /** Fills affine in column major order. Sets affine to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + If SkMatrix contains perspective, returns false and leaves affine unchanged. + + @param affine storage for 3x2 affine matrix; may be nullptr + @return true if SkMatrix does not contain perspective */ bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const; - /** Set the matrix to the specified affine values. - * Note: these are passed in column major order. - */ + /** Sets SkMatrix to affine values, passed in column major order. Given affine, + column, then row, as: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + SkMatrix is set, row, then column, to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + | 0 0 1 | + + @param affine 3x2 affine matrix + */ void setAffine(const SkScalar affine[6]); - /** Apply this matrix to the array of points specified by src, and write - the transformed points into the array of points specified by dst. - dst[] = M * src[] - @param dst Where the transformed coordinates are written. It must - contain at least count entries - @param src The original coordinates that are to be transformed. It - must contain at least count entries - @param count The number of points in src to read, and then transform - into dst. + /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater + length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped SkPoint + @param src SkPoint to transform + @param count number of SkPoint to transform */ void mapPoints(SkPoint dst[], const SkPoint src[], int count) const { SkASSERT((dst && src && count > 0) || 0 == count); @@ -436,20 +1213,50 @@ public: this->getMapPtsProc()(*this, dst, src, count); } - /** Apply this matrix to the array of points, overwriting it with the - transformed values. - dst[] = M * pts[] - @param pts The points to be transformed. It must contain at least - count entries - @param count The number of points in pts. + /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying + each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = pts[i].fX + y = pts[i].fY + } + + each resulting pts SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param pts storage for mapped SkPoint + @param count number of SkPoint to transform */ void mapPoints(SkPoint pts[], int count) const { this->mapPoints(pts, pts, count); } - /** Like mapPoints but with custom byte stride between the points. Stride - * should be a multiple of sizeof(SkScalar). - */ + /** Maps count pts, skipping stride bytes to advance from one SkPoint to the next. + SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + each resulting pts SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param pts storage for mapped SkPoint + @param stride size of record starting with SkPoint, in bytes + @param count number of SkPoint to transform + */ void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const { SkASSERT(stride >= sizeof(SkPoint)); SkASSERT(0 == stride % sizeof(SkScalar)); @@ -459,7 +1266,24 @@ public: } } - /** Like mapPoints but with custom byte stride between the points. + /** Maps src SkPoint array of length count to dst SkPoint array, skipping stride bytes + to advance from one SkPoint to the next. + SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, src = | y | + | G H I | | 1 | + + each resulting dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param dst storage for mapped SkPoint + @param src SkPoint to transform + @param stride size of record starting with SkPoint, in bytes + @param count number of SkPoint to transform */ void mapPointsWithStride(SkPoint dst[], const SkPoint src[], size_t stride, int count) const { SkASSERT(stride >= sizeof(SkPoint)); @@ -471,88 +1295,216 @@ public: } } - /** Apply this matrix to the array of homogeneous points, specified by src, - where a homogeneous point is defined by 3 contiguous scalar values, - and write the transformed points into the array of scalars specified by dst. - dst[] = M * src[] - @param dst Where the transformed coordinates are written. It must - contain at least count entries - @param src The original coordinates that are to be transformed. It - must contain at least count entries - @param count The number of homogeneous points in src to read, - and then transform into dst. + /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or + greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, src = | y | + | G H I | | z | + + each resulting dst SkPoint is computed as: + + |A B C| |x| + Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz| + |G H I| |z| + + @param dst storage for mapped SkPoint3 array + @param src SkPoint3 array to transform + @param count items in SkPoint3 array to transform */ void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const; + /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-coordinate of SkPoint to map + @param y y-coordinate of SkPoint to map + @param result storage for mapped SkPoint + */ void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { SkASSERT(result); this->getMapXYProc()(*this, x, y, result); } + /** Returns SkPoint (x, y) multiplied by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-coordinate of SkPoint to map + @param y y-coordinate of SkPoint to map + @return mapped SkPoint + */ SkPoint mapXY(SkScalar x, SkScalar y) const { SkPoint result; this->getMapXYProc()(*this, x, y, &result); return result; } - /** Apply this matrix to the array of vectors specified by src, and write - the transformed vectors into the array of vectors specified by dst. - This is similar to mapPoints, but ignores any translation in the matrix. - @param dst Where the transformed coordinates are written. It must - contain at least count entries - @param src The original coordinates that are to be transformed. It - must contain at least count entries - @param count The number of vectors in src to read, and then transform - into dst. + /** Maps src SkVector array of length count to SkVector SkPoint array of equal or greater + length. SkVector are mapped by multiplying each SkVector by SkMatrix, treating + SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, src = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst SkVector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped SkVector + @param src SkVector to transform + @param count number of SkVector to transform */ void mapVectors(SkVector dst[], const SkVector src[], int count) const; - /** Apply this matrix to the array of vectors specified by src, and write - the transformed vectors into the array of vectors specified by dst. - This is similar to mapPoints, but ignores any translation in the matrix. - @param vecs The vectors to be transformed. It must contain at least - count entries - @param count The number of vectors in vecs. + /** Maps vecs SkVector array of length count in place, multiplying each SkVector by + SkMatrix, treating SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, vec = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = vecs[i].fX + y = vecs[i].fY + } + + each result SkVector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param vecs SkVector to transform, and storage for mapped SkVector + @param count number of SkVector to transform */ void mapVectors(SkVector vecs[], int count) const { this->mapVectors(vecs, vecs, count); } + /** Maps SkVector (x, y) to result. SkVector is mapped by multiplying by SkMatrix, + treating SkMatrix translation as zero. Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result SkVector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-coordinate of SkVector to map + @param dy y-coordinate of SkVector to map + @param result storage for mapped SkVector + */ void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const { SkVector vec = { dx, dy }; this->mapVectors(result, &vec, 1); } + /** Returns SkVector (x, y) multiplied by SkMatrix, treating SkMatrix translation as zero. + Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result SkVector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-coordinate of SkVector to map + @param dy y-coordinate of SkVector to map + @return mapped SkVector + */ SkVector mapVector(SkScalar dx, SkScalar dy) const { SkVector vec = { dx, dy }; this->mapVectors(&vec, &vec, 1); return vec; } - /** Apply this matrix to the src rectangle, and write the transformed - rectangle into dst. This is accomplished by transforming the 4 corners - of src, and then setting dst to the bounds of those points. - @param dst Where the transformed rectangle is written. - @param src The original rectangle to be transformed. - @return the result of calling rectStaysRect() + /** Sets dst to bounds of src corners mapped by SkMatrix. + Returns true if mapped corners are dst corners. + + Returned value is the same as calling rectStaysRect(). + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + @return true if dst is equivalent to mapped src */ bool mapRect(SkRect* dst, const SkRect& src) const; - /** Apply this matrix to the rectangle, and write the transformed rectangle - back into it. This is accomplished by transforming the 4 corners of - rect, and then setting it to the bounds of those points - @param rect The rectangle to transform. - @return the result of calling rectStaysRect() + /** Sets rect to bounds of rect corners mapped by SkMatrix. + Returns true if mapped corners are computed rect corners. + + Returned value is the same as calling rectStaysRect(). + + @param rect rectangle to map, and storage for bounds of mapped corners + @return true if result is equivalent to mapped src */ bool mapRect(SkRect* rect) const { return this->mapRect(rect, *rect); } - /** Apply this matrix to the src rectangle, and write the four transformed - points into dst. The points written to dst will be the original top-left, top-right, - bottom-right, and bottom-left points transformed by the matrix. - @param dst Where the transformed quad is written. - @param rect The original rectangle to be transformed. + /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each + rect corner by SkMatrix. rect corner is processed in this order: + (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), + (rect.fLeft, rect.fBottom). + + rect may be empty: rect.fLeft may be greater than or equal to rect.fRight; + rect.fTop may be greater than or equal to rect.fBottom. + + Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where pt is initialized from each of (rect.fLeft, rect.fTop), + (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom), + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param dst storage for mapped corner SkPoint + @param rect SkRect to map */ void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { // This could potentially be faster if we only transformed each x and y of the rect once. @@ -560,119 +1512,208 @@ public: this->mapPoints(dst, 4); } - /** - * Maps a rect to another rect, asserting (in debug mode) that the matrix only contains - * scale and translate elements. If it contains other elements, the results are undefined. - */ + /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains + elements other than scale or translate: asserts if SK_DEBUG is defined; + otherwise, results are undefined. + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + */ void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const; - /** Return the mean radius of a circle after it has been mapped by - this matrix. NOTE: in perspective this value assumes the circle - has its center at the origin. + /** Returns geometric mean radius of ellipse formed by constructing circle of + size radius, and mapping constructed circle with SkMatrix. The result squared is + equal to the major axis length times the minor axis length. + Result is not meaningful if SkMatrix contains perspective elements. + + @param radius circle size to map + @return average mapped radius */ SkScalar mapRadius(SkScalar radius) const; - /** Returns true if the matrix can be stepped in X (not complex - perspective). + /** Returns true if a unit step in x at some y mapped through SkMatrix can be + represented by a constant SkVector. Returns true if getType() returns kIdentity_Mask, + or combinations of: kTranslate_Mask, kScale_Mask, and kAffine_Mask. + + May return true if getType() returns kPerspective_Mask, but only when SkMatrix + does not include rotation or skewing along the y-axis. + + @return true if SkMatrix does not have complex perspective */ bool isFixedStepInX() const; - /** If the matrix can be stepped in X (not complex perspective) - then return the step value. - If it cannot, behavior is undefined. + /** Returns SkVector representing a unit step in x at y mapped through SkMatrix. + If isFixedStepInX() is false, returned value is undefined. + + @param y position of line parallel to x-axis + @return SkVector advance of mapped unit step in x */ SkVector fixedStepInX(SkScalar y) const; - /** Efficient comparison of two matrices. It distinguishes between zero and - * negative zero. It will return false when the sign of zero values is the - * only difference between the two matrices. It considers NaN values to be - * equal to themselves. So a matrix full of NaNs is "cheap equal" to - * another matrix full of NaNs iff the NaN values are bitwise identical - * while according to strict the strict == test a matrix with a NaN value - * is equal to nothing, including itself. - */ + /** Returns true if SkMatrix equals m, using an efficient comparison. + + Returns false when the sign of zero values is the different; when one + matrix has positive zero value and the other has negative zero value. + + Returns true even when both SkMatrix contain NaN. + + NaN never equals any value, including itself. To improve performance, NaN values + are treated as bit patterns that are equal if their bit patterns are equal. + + @param m SkMatrix to compare + @return true if m and SkMatrix are represented by identical bit patterns + */ bool cheapEqualTo(const SkMatrix& m) const { return 0 == memcmp(fMat, m.fMat, sizeof(fMat)); } - // mac chromium dbg requires SK_API to make operator== visible + /** Compares a and b; returns true if a and b are numerically equal. Returns true + even if sign of zero values are different. Returns false if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if m and SkMatrix are numerically equal + */ friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b); + + /** Compares a and b; returns true if a and b are not numerically equal. Returns false + even if sign of zero values are different. Returns true if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if m and SkMatrix are numerically not equal + */ friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) { return !(a == b); } + /** Writes text representation of SkMatrix to standard output. Floating point values + are written with limited precision; it may not be possible to reconstruct + original SkMatrix from output. + */ void dump() const; + + /** Creates string representation of SkMatrix. Floating point values + are written with limited precision; it may not be possible to reconstruct + original SkMatrix from output. + + @param str storage for string representation of SkMatrix + */ void toString(SkString* str) const; - /** - * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper - * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) - * -1 is returned. - * - * @return minimum scale factor - */ + /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return minimum scale factor + */ SkScalar getMinScale() const; - /** - * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper - * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective) - * -1 is returned. - * - * @return maximum scale factor - */ + /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return maximum scale factor + */ SkScalar getMaxScale() const; - /** - * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max - * is scaleFactors[1]. If the min/max scale factors cannot be computed false is returned and the - * values of scaleFactors[] are undefined. - */ + /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the + maximum scaling factor. Scaling factors are computed by decomposing + the SkMatrix scaling and skewing elements. + + Returns true if scaleFactors are found; otherwise, returns false and sets + scaleFactors to undefined values. + + @param scaleFactors storage for minimum and maximum scale factors + @return true if scale factors were computed correctly + */ bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const; - /** - * Attempt to decompose this matrix into a scale-only component and whatever remains, where - * the scale component is to be applied first. - * - * M -> Remaining * Scale - * - * On success, return true and assign the scale and remaining components (assuming their - * respective parameters are not null). On failure return false and ignore the parameters. - * - * Possible reasons to fail: perspective, one or more scale factors are zero. - */ + /** Decomposes SkMatrix into scale components and whatever remains. Returns false if + SkMatrix could not be decomposed. + + Sets scale to portion of SkMatrix that scales in x and y. Sets remaining to SkMatrix + with x and y scaling factored out. remaining may be passed as nullptr + to determine if SkMatrix can be decomposed without computing remainder. + + Returns true if scale components are found. scale and remaining are + unchanged if SkMatrix contains perspective; scale factors are not finite, or + are nearly zero. + + On success + Matrix = scale * Remaining + + @param scale x and y scaling factors; may be nullptr + @param remaining SkMatrix without scaling; may be nullptr + @return true if scale can be computed + */ bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const; - /** - * Return a reference to a const identity matrix - */ + /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return const identity SkMatrix + */ static const SkMatrix& I(); - /** - * Return a reference to a const matrix that is "invalid", one that could - * never be used. - */ + /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set + to: + + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + + @return const invalid SkMatrix + */ static const SkMatrix& InvalidMatrix(); - /** - * Return the concatenation of two matrices, a * b. - */ + /** Returns SkMatrix a multiplied by SkMatrix b. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression + @return SkMatrix computed from a times b + */ static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { SkMatrix result; result.setConcat(a, b); return result; } - /** - * Testing routine; the matrix's type cache should never need to be - * manually invalidated during normal use. - */ + /** Sets internal cache to unknown state. Use to force update after repeated + modifications to SkMatrix element reference returned by operator[](int index). + */ void dirtyMatrixTypeCache() { this->setTypeMask(kUnknown_Mask); } - /** - * Initialize the matrix to be scale + post-translate. - */ + /** Initializes SkMatrix with scale and translate elements. + + | sx 0 tx | + | 0 sy ty | + | 0 0 1 | + + @param sx horizontal scale factor to store + @param sy vertical scale factor to store + @param tx horizontal translation to store + @param ty vertical translation to store + */ void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) { fMat[kMScaleX] = sx; fMat[kMSkewX] = 0; @@ -696,9 +1737,11 @@ public: this->setTypeMask(mask | kRectStaysRect_Mask); } - /** - * Are all elements of the matrix finite? - */ + /** Returns true if all elements of the matrix are finite. Returns false if any + element is infinity, or NaN. + + @return true if matrix has only finite elements + */ bool isFinite() const { return SkScalarsAreFinite(fMat, 9); } private: diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 39e4f65ab2..83d5502742 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -180,8 +180,8 @@ public: */ void unflatten(SkReadBuffer& buffer); - /** Sets all paint's contents to their initial values. This is equivalent to replacing - the paint with the result of SkPaint(). + /** Sets all SkPaint contents to their initial values. This is equivalent to replacing + SkPaint with the result of SkPaint(). */ void reset(); @@ -1062,11 +1062,17 @@ public: /** \enum SkPaint::TextEncoding TextEncoding determines whether text specifies character codes and their encoded - size, or glyph indices. Character codes use the encoding specified by the Unicode standard. + size, or glyph indices. Characters are encoded as specified by the Unicode standard. Character codes encoded size are specified by UTF-8, UTF-16, or UTF-32. - All character encodings are able to represent all of Unicode, differing only - in the total storage required. UTF-8 (RFC 3629) encodes each character as one or more 8-bit bytes. UTF-16 (RFC 2781) encodes each character as one or two 16-bit words. UTF-32 encodes each character as one 32-bit word. + All character code formats are able to represent all of Unicode, differing only + in the total storage required. + + UTF-8 (RFC 3629) encodes each character as one or more 8-bit bytes. + + UTF-16 (RFC 2781) encodes each character as one or two 16-bit words. + + UTF-32 encodes each character as one 32-bit word. font manager uses font data to convert character code points into glyph indices. A glyph index is a 16-bit word. @@ -1112,6 +1118,11 @@ public: */ struct FontMetrics { + /** \enum SkPaint::FontMetrics::FontMetricsFlags + FontMetricsFlags are set in fFlags when underline and strikeout metrics are valid; + the underline or strikeout metric may be valid and zero. + Fonts with embedded bitmaps may not have valid underline or strikeout metrics. + */ enum FontMetricsFlags { kUnderlineThicknessIsValid_Flag = 1 << 0, //!< Set if fUnderlineThickness is valid. kUnderlinePositionIsValid_Flag = 1 << 1, //!< Set if fUnderlinePosition is valid. @@ -1150,6 +1161,7 @@ public: Zero if no average width is stored in the font. */ SkScalar fAvgCharWidth; + SkScalar fMaxCharWidth; //!< Maximum character width. /** Minimum bounding box x value for all glyphs. @@ -1297,8 +1309,7 @@ public: SkPaint::TextEncoding specifies how text represents characters or glyphs. glyphs may be nullptr, to compute the glyph count. - Does not check text for valid character encoding or valid - glyph indices. + Does not check text for valid character codes or valid glyph indices. If byteLength equals zero, returns zero. If byteLength includes a partial character, the partial character is ignored. diff --git a/include/core/SkPath.h b/include/core/SkPath.h index 2a84c753bd..d39d4efcd3 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -37,23 +37,23 @@ class SkWStream; class SK_API SkPath { public: -/** \enum SkPath::Direction - Direction describes whether contour is clockwise or counterclockwise. - When SkPath contains multiple overlapping contours, Direction together with - FillType determines whether overlaps are filled or form holes. + /** \enum SkPath::Direction + Direction describes whether contour is clockwise or counterclockwise. + When SkPath contains multiple overlapping contours, Direction together with + FillType determines whether overlaps are filled or form holes. - Direction also determines how contour is measured. For instance, dashing - measures along SkPath to determine where to start and stop stroke; Direction - will change dashed results as it steps clockwise or counterclockwise. + Direction also determines how contour is measured. For instance, dashing + measures along SkPath to determine where to start and stop stroke; Direction + will change dashed results as it steps clockwise or counterclockwise. - Closed contours like SkRect, SkRRect, circle, and oval added with - kCW_Direction travel clockwise; the same added with kCCW_Direction - travel counterclockwise. -*/ -enum Direction { - kCW_Direction, //!< Contour travels in a clockwise direction. - kCCW_Direction, //!< Contour travels in a counterclockwise direction. -}; + Closed contours like SkRect, SkRRect, circle, and oval added with + kCW_Direction travel clockwise; the same added with kCCW_Direction + travel counterclockwise. + */ + enum Direction { + kCW_Direction, //!< Contour travels in a clockwise direction + kCCW_Direction, //!< Contour travels in a counterclockwise direction + }; /** By default, SkPath has no SkPath::Verb, no SkPoint, and no weights. SkPath::FillType is set to kWinding_FillType. @@ -127,8 +127,7 @@ enum Direction { /** Interpolate between SkPath with equal sized point arrays. Copy verb array and weights to out, and set out SkPoint arrays to a weighted average of this SkPoint arrays and ending - SkPoint arrays, using the formula: - (this->points * weight) + ending->points * (1 - weight) + SkPoint arrays, using the formula: (this->points * weight) + ending->points * (1 - weight). weight is most useful when between zero (ending SkPoint arrays) and one (this Point_Array); will work with values outside of this @@ -886,22 +885,24 @@ enum Direction { ArcSize and Direction select one of the four oval parts. */ enum ArcSize { - kSmall_ArcSize, //!< Smaller of arc pair. - kLarge_ArcSize, //!< Larger of arc pair. + kSmall_ArcSize, //!< smaller of arc pair + kLarge_ArcSize, //!< larger of arc pair }; - /** Append arc to SkPath. Arc is implemented by one or more conics weighted to describe part of oval - with radii (rx, ry) rotated by xAxisRotate degrees. Arc curves from last SkPath SkPoint to (x, y), - choosing one of four possible routes: clockwise or counterclockwise, and smaller or larger. + /** Append arc to SkPath. Arc is implemented by one or more conics weighted to + describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc + curves from last SkPath SkPoint to (x, y), choosing one of four possible routes: + clockwise or counterclockwise, and smaller or larger. - Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if either radii are zero, - or if last SkPath SkPoint equals (x, y). arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and - (x, y) if both are greater than zero but too small. + Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if + either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii + (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but + too small. arcTo() appends up to four conic curves. - arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is - opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while kCW_Direction - cast to int is zero. + arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value + is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, + while kCW_Direction cast to int is zero. @param rx radius in x before x-axis rotation @param ry radius in y before x-axis rotation @@ -941,7 +942,7 @@ enum Direction { /** Append arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or more conic, weighted to describe part of oval with radii (rx, ry) rotated by - xAxisRotate degrees. Arc curves from last SkPath SkPoint (x0, y0) to end SkPoint + xAxisRotate degrees. Arc curves from last SkPath SkPoint (x0, y0) to end SkPoint: (x0 + dx, y0 + dy), choosing one of four possible routes: clockwise or counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint is (0, 0). @@ -1012,10 +1013,9 @@ enum Direction { Quad array is stored in pts; this storage is supplied by caller. Maximum quad count is 2 to the pow2. Every third point in array shares last SkPoint of previous quad and first SkPoint of - next quad. Maximum pts storage size is given by: - (1 + 2 * (1 << pow2)) * sizeof(SkPoint) + next quad. Maximum pts storage size is given by: (1 + 2 * (1 << pow2)) * sizeof(SkPoint). - ConvertConicToQuads returns quad count used the approximation, which may be smaller + Returns quad count used the approximation, which may be smaller than the number requested. conic weight determines the amount of influence conic control point has on the curve. @@ -1123,9 +1123,8 @@ enum Direction { void addOval(const SkRect& oval, Direction dir, unsigned start); /** Add circle centered at (x, y) of size radius to SkPath, appending kMove_Verb, - four kConic_Verb, and kClose_Verb. Circle begins at - (x + radius, y), continuing clockwise if dir is kCW_Direction, and counterclockwise if dir is - kCCW_Direction. + four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing + clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction. Has no effect if radius is zero or negative. @@ -1406,13 +1405,9 @@ enum Direction { }; /** \class SkPath::Iter - Iterates through verb array, and associated SkPoint arrays and conic weight. - Provides options to treat open contours as closed, and to ignore - degenerate data. */ class SK_API Iter { - - public: + public: /** Initializes iter with an empty SkPath. next() on iter returns kDone_Verb. Call setPath to initialize iter at a later time. @@ -1511,12 +1506,9 @@ enum Direction { }; /** \class SkPath::RawIter - Iterates through verb array, and associated SkPoint arrays and conic weight. - verb array, SkPoint arrays, and conic weight are returned unaltered. */ class SK_API RawIter { - - public: + public: /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb. Call setPath to initialize iter at a later time. @@ -1587,12 +1579,12 @@ enum Direction { */ bool contains(SkScalar x, SkScalar y) const; - /** Writes text representation of SkPath to stream. If stream is nullptr, dump() writes to - standard output. Set forceClose to true to get - edges used to fill SkPath. Set dumpAsHex true to get exact binary representations + /** Writes text representation of SkPath to stream. If stream is nullptr, writes to + standard output. Set forceClose to true to get edges used to fill SkPath. + Set dumpAsHex true to generate exact binary representations of floating point numbers used in SkPoint arrays and conic weights. - @param stream writable SkFlattenable receiving SkPath text representation; may be nullptr + @param stream writable SkStream receiving SkPath text representation; may be nullptr @param forceClose true if missing kClose_Verb is output @param dumpAsHex true if SkScalar values are written as hexadecimal */ diff --git a/include/core/SkPixmap.h b/include/core/SkPixmap.h index 3b9f10e073..080389ff0a 100644 --- a/include/core/SkPixmap.h +++ b/include/core/SkPixmap.h @@ -24,8 +24,8 @@ struct SkMask; Use SkBitmap to draw pixels referenced by SkPixmap; use SkSurface to draw into pixels referenced by SkPixmap. - SkPixmap does not try to manage the lifetime of the pixel memory. Use PixelRef - to manage pixel memory; PixelRef is safe across threads. + SkPixmap does not try to manage the lifetime of the pixel memory. Use SkPixelRef + to manage pixel memory; SkPixelRef is safe across threads. */ class SK_API SkPixmap { public: @@ -127,10 +127,10 @@ public: const SkImageInfo& info() const { return fInfo; } /** Returns row bytes, the interval from one pixel row to the next. Row bytes - is at least as large as - width() * info().bytesPerPixel(). + is at least as large as: width() * info().bytesPerPixel(). - It is up to the SkPixmap creator to ensure that row bytes is a useful value. + Returns zero if colorType() is kUnknown_SkColorType. + It is up to the SkBitmap creator to ensure that row bytes is a useful value. @return byte length of pixel row */ @@ -145,7 +145,7 @@ public: const void* addr() const { return fPixels; } /** Returns pixel count in each pixel row. Should be equal or less than: - rowBytes() / info.bytesPerPixel(). + rowBytes() / info().bytesPerPixel(). @return pixel width in SkImageInfo */ @@ -172,21 +172,23 @@ public: */ SkAlphaType alphaType() const { return fInfo.alphaType(); } - /** Returns SkColorSpace associated with SkImageInfo. + /** Returns SkColorSpace associated with SkImageInfo. The + reference count of SkColorSpace is unchanged. The returned SkColorSpace is + immutable. - @return SkColorSpace in SkImageInfo + @return SkColorSpace, the range of colors, in SkImageInfo */ SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } /** Returns true if SkAlphaType is kOpaque_SkAlphaType. - Does not check if SkColorType allows alpha, or alpha in pixel values. + Does not check if SkColorType allows alpha, or if any pixel value has + transparency. @return true if SkImageInfo has opaque SkAlphaType */ bool isOpaque() const { return fInfo.isOpaque(); } - /** Returns SkIRect - { 0, 0, width(), height() }. + /** Returns SkIRect { 0, 0, width(), height() }. @return integral rectangle from origin to width() and height() */ @@ -206,10 +208,14 @@ public: */ int shiftPerPixel() const { return fInfo.shiftPerPixel(); } - /** - * Returns the size (in bytes) of the pixmap's image buffer. - * If the calculation overflows, this returns max_size_t. - */ + /** Returns minimum memory required for pixel storage. + Does not include unused memory on last row when rowBytesAsPixels() exceeds width(). + Returns zero if result does not fit in size_t. + Returns zero if height() or width() is 0. + Returns height() times rowBytes() if colorType() is kUnknown_SkColorType. + + @return size in bytes of image buffer + */ size_t computeByteSize() const { return fInfo.computeByteSize(fRowBytes); } /** Returns true if all pixels are opaque. SkColorType determines how pixels @@ -226,7 +232,7 @@ public: Returns false for kUnknown_SkColorType. - @return true all pixels have opaque values or SkColorType is opaque + @return true if all pixels have opaque values or SkColorType is opaque */ bool computeIsOpaque() const; @@ -248,10 +254,13 @@ public: */ SkColor getColor(int x, int y) const; - /** Returns readable pixel address at (x, y). + /** Returns readable pixel address at (x, y). Returns nullptr if SkPixelRef is nullptr. Input is not validated: out of bounds values of x or y trigger an assert() if - built with SK_DEBUG defined. Returns zero if SkColorType is kUnknown_SkColorType. + built with SK_DEBUG defined. Returns nullptr if SkColorType is kUnknown_SkColorType. + + Performs a lookup of pixel size; for better performance, call + one of: addr8, addr16, addr32, addr64, or addrF16(). @param x column index, zero or greater, and less than width() @param y row index, zero or greater, and less than height() @@ -511,8 +520,8 @@ public: return reinterpret_cast(writable_addr64(x, y)); } - /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not exceed - (this->width(), this->height()). + /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not + exceed (this->width(), this->height()). dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of destination. dstRowBytes specifics the gap from one destination @@ -527,14 +536,13 @@ public: false if pixel conversion is not possible. srcX and srcY may be negative to copy only top or left of source. Returns - false if width() or height() is zero or negative. Returns false if - abs(srcX) >= this->width(), or if - abs(srcY) >= this->height(). + false if width() or height() is zero or negative. Returns false if: + abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). If behavior is SkTransferFunctionBehavior::kRespect: converts source pixels to a linear space before converting to dstInfo. If behavior is SkTransferFunctionBehavior::kIgnore: source - pixels are treated as if they are linear, regardless of their encoding. + pixels are treated as if they are linear, regardless of how they are encoded. @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace @param dstPixels destination pixel storage @@ -549,8 +557,7 @@ public: int srcX, int srcY, SkTransferFunctionBehavior behavior) const; /** Copies a SkRect of pixels to dstPixels. Copy starts at (0, 0), and does not - exceed - (this->width(), this->height()). + exceed (this->width(), this->height()). dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of destination. dstRowBytes specifics the gap from one destination @@ -576,8 +583,7 @@ public: } /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not - exceed - (this->width(), this->height()). + exceed (this->width(), this->height()). dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of destination. dstRowBytes specifics the gap from one destination @@ -592,9 +598,8 @@ public: false if pixel conversion is not possible. srcX and srcY may be negative to copy only top or left of source. Returns - false if this->width() or this->height() is zero or negative. Returns false if - abs(srcX) >= this->width(), or if - abs(srcY) >= this->height(). + false if this->width() or this->height() is zero or negative. Returns false if: + abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). @param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace @param dstPixels destination pixel storage @@ -623,9 +628,8 @@ public: false if pixel conversion is not possible. srcX and srcY may be negative to copy only top or left of source. Returns - false this->width() or this->height() is zero or negative. Returns false if - abs(srcX) >= this->width(), or if - abs(srcY) >= this->height(). + false this->width() or this->height() is zero or negative. Returns false if: + abs(srcX) >= this->width(), or if abs(srcY) >= this->height(). @param dst SkImageInfo and pixel address to write to @param srcX column index whose absolute value is less than width() diff --git a/include/core/SkRect.h b/include/core/SkRect.h index 12afddd9ce..e4ff612883 100644 --- a/include/core/SkRect.h +++ b/include/core/SkRect.h @@ -15,120 +15,278 @@ struct SkRect; /** \struct SkIRect - - SkIRect holds four 32 bit integer coordinates for a rectangle + SkIRect holds four 32 bit integer coordinates describing the upper and + lower bounds of a rectangle. SkIRect may be created from outer bounds or + from position, width, and height. SkIRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. */ struct SK_API SkIRect { + + /** May contain any value. The smaller of the horizontal values when sorted. + When equal to or greater than fRight, SkIRect is empty. + */ int32_t fLeft; + + /** May contain any value. The smaller of the horizontal values when sorted. + When equal to or greater than fBottom, SkIRect is empty. + */ int32_t fTop; + + /** May contain any value. The larger of the vertical values when sorted. + When equal to or less than fLeft, SkIRect is empty. + */ int32_t fRight; + + /** May contain any value. The larger of the vertical values when sorted. + When equal to or less than fTop, SkIRect is empty. + */ int32_t fBottom; + /** Returns constructed SkIRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { return SkIRect{0, 0, 0, 0}; } + /** Returns constructed SkIRect setting left and top to most negative value, and + setting right and bottom to most positive value. + + @return bounds (SK_MinS32, SK_MinS32, SK_MaxS32, SK_MaxS32) + */ static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() { SkIRect r; r.setLargest(); return r; } + /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h + may be negative. + + @param w width of constructed SkRect + @param h height of constructed SkRect + @return bounds (0, 0, w, h) + */ static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { return SkIRect{0, 0, w, h}; } + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { return SkIRect{0, 0, size.fWidth, size.fHeight}; } + /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l integer stored in fLeft + @param t integer stored in fTop + @param r integer stored in fRight + @param b integer stored in fBottom + @return bounds (l, t, r, b) + */ static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { return SkIRect{l, t, r, b}; } + /** Returns constructed SkIRect set to: (x, y, x + w, y + h). Does not validate input; + w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { return SkIRect{x, y, x + w, y + h}; } + /** Returns left edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ int left() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ int top() const { return fTop; } + + /** Returns right edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ int right() const { return fRight; } + + /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ int bottom() const { return fBottom; } - /** return the left edge of the rect */ + /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ int x() const { return fLeft; } - /** return the top edge of the rect */ + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ int y() const { return fTop; } - /** - * Returns the rectangle's width. This does not check for a valid rect - * (i.e. left <= right) so the result may be negative. - */ + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fRight minus fLeft + */ int width() const { return fRight - fLeft; } - /** - * Returns the rectangle's height. This does not check for a valid rect - * (i.e. top <= bottom) so the result may be negative. - */ + /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fBottom minus fTop + */ int height() const { return fBottom - fTop; } + /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, + or if result fits in 32-bit signed integer; result may be negative. + + @return SkISize (width, height) + */ SkISize size() const { return SkISize::Make(this->width(), this->height()); } - /** - * Since the center of an integer rect may fall on a factional value, this - * method is defined to return (right + left) >> 1. - * - * This is a specific "truncation" of the average, which is different than - * (right + left) / 2 when the sum is negative. - */ + /** Returns average of left edge and right edge. Result does not change if SkRect + is sorted. Result may be incorrect if SkRect is far from the origin. + + Result is rounded down. + + @return midpoint in x + */ int centerX() const { return (fRight + fLeft) >> 1; } - /** - * Since the center of an integer rect may fall on a factional value, this - * method is defined to return (bottom + top) >> 1 - * - * This is a specific "truncation" of the average, which is different than - * (bottom + top) / 2 when the sum is negative. - */ + /** Returns average of top edge and bottom edge. Result does not change if SkRect + is sorted. Result may be incorrect if SkRect is far from the origin. + + Result is rounded down. + + @return midpoint in y + */ int centerY() const { return (fBottom + fTop) >> 1; } - /** - * Return true if the rectangle's width or height are <= 0 - */ + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or negative + */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + /** Returns true if SkIRect encloses largest possible area. + + @return true if equal to (SK_MinS32, SK_MinS32, SK_MaxS32, SK_MaxS32) + */ bool isLargest() const { return SK_MinS32 == fLeft && SK_MinS32 == fTop && SK_MaxS32 == fRight && SK_MaxS32 == fBottom; } + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + identical to corresponding members in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are equal + */ friend bool operator==(const SkIRect& a, const SkIRect& b) { return !memcmp(&a, &b, sizeof(a)); } + /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not + identical to the corresponding member in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are not equal + */ friend bool operator!=(const SkIRect& a, const SkIRect& b) { return !(a == b); } + /** Returns true if all members: fLeft, fTop, fRight, and fBottom; values are + equal to or larger than -32768 and equal to or smaller than 32767. + + @return true if members fit in 16-bit word + */ bool is16Bit() const { return SkTFitsIn(fLeft) && SkTFitsIn(fTop) && SkTFitsIn(fRight) && SkTFitsIn(fBottom); } - /** Set the rectangle to (0,0,0,0) + /** Sets SkIRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. */ void setEmpty() { memset(this, 0, sizeof(*this)); } + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left assigned to fLeft + @param top assigned to fTop + @param right assigned to fRight + @param bottom assigned to fBottom + */ void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { fLeft = left; fTop = top; fRight = right; fBottom = bottom; } - // alias for set(l, t, r, b) + + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { this->set(left, top, right, bottom); } + /** Sets SkIRect to: (x, y, x + width, y + height). Does not validate input; + width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { fLeft = x; fTop = y; @@ -136,46 +294,77 @@ struct SK_API SkIRect { fBottom = y + height; } - /** - * Make the largest representable rectangle - */ + /** Sets rectangle left and top to most negative value, and sets + right and bottom to most positive value. + */ void setLargest() { fLeft = fTop = SK_MinS32; fRight = fBottom = SK_MaxS32; } - /** - * Make the largest representable rectangle, but inverted (e.g. fLeft will - * be max 32bit and right will be min 32bit). - */ + /** Sets rectangle left and top to most positive value, and sets + right and bottom to most negative value. This is used internally to + flag that a condition is met, but otherwise has no special purpose. + */ void setLargestInverted() { fLeft = fTop = SK_MaxS32; fRight = fBottom = SK_MinS32; } - /** - * Return a new IRect, built as an offset of this rect. - */ + /** Returns SkIRect offset by (dx, dy). + + If dx is negative, SkIRect returned is moved to the left. + If dx is positive, SkIRect returned is moved to the right. + If dy is negative, SkIRect returned is moved upward. + If dy is positive, SkIRect returned is moved downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + @return SkRect offset in x or y, with original width and height + */ SkIRect makeOffset(int32_t dx, int32_t dy) const { return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy); } - /** - * Return a new IRect, built as an inset of this rect. - */ + /** Returns SkIRect, inset by (dx, dy). + + If dx is negative, SkIRect returned is wider. + If dx is positive, SkIRect returned is narrower. + If dy is negative, SkIRect returned is taller. + If dy is positive, SkIRect returned is shorter. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + @return SkRect inset symmetrically left and right, top and bottom + */ SkIRect makeInset(int32_t dx, int32_t dy) const { return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy); } - /** - * Return a new Rect, built as an outset of this rect. - */ + /** Returns SkIRect, outset by (dx, dy). + + If dx is negative, SkIRect returned is narrower. + If dx is positive, SkIRect returned is wider. + If dy is negative, SkIRect returned is shorter. + If dy is positive, SkIRect returned is taller. + + @param dx offset subtracted to fLeft and added from fRight + @param dy offset subtracted to fTop and added from fBottom + @return SkRect outset symmetrically left and right, top and bottom + */ SkIRect makeOutset(int32_t dx, int32_t dy) const { return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy); } - /** Offset set the rectangle by adding dx to its left and right, - and adding dy to its top and bottom. + /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkIRect returned to the left. + If dx is positive, moves SkIRect returned to the right. + If dy is negative, moves SkIRect returned upward. + If dy is positive, moves SkIRect returned downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom */ void offset(int32_t dx, int32_t dy) { fLeft += dx; @@ -184,13 +373,26 @@ struct SK_API SkIRect { fBottom += dy; } + /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkIRect returned to the left. + If delta.fX is positive, moves SkIRect returned to the right. + If delta.fY is negative, moves SkIRect returned upward. + If delta.fY is positive, moves SkIRect returned downward. + + @param delta offset added to SkIRect + */ void offset(const SkIPoint& delta) { this->offset(delta.fX, delta.fY); } - /** - * Offset this rect such its new x() and y() will equal newX and newY. - */ + /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ void offsetTo(int32_t newX, int32_t newY) { fRight += newX - fLeft; fBottom += newY - fTop; @@ -198,9 +400,15 @@ struct SK_API SkIRect { fTop = newY; } - /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, - making the rectangle narrower. If dx is negative, then the sides are moved outwards, - making the rectangle wider. The same holds true for dy and the top and bottom. + /** Insets SkIRect by (dx,dy). + + If dx is positive, makes SkIRect narrower. + If dx is negative, makes SkIRect wider. + If dy is positive, makes SkIRect shorter. + If dy is negative, makes SkIRect taller. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom */ void inset(int32_t dx, int32_t dy) { fLeft += dx; @@ -209,29 +417,60 @@ struct SK_API SkIRect { fBottom -= dy; } - /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are - moved outwards, making the rectangle wider. If dx is negative, then the - sides are moved inwards, making the rectangle narrower. The same holds - true for dy and the top and bottom. + /** Outsets SkIRect by (dx, dy). + + If dx is positive, makes SkRect wider. + If dx is negative, makes SkRect narrower. + If dy is positive, makes SkRect taller. + If dy is negative, makes SkRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom */ void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } + /** Constructs SkIRect (l, t, r, b) and returns true if constructed SkIRect does not + intersect SkIRect. Does not check to see if construction or SkIRect is empty. + + Is implemented with short circuit logic so that true can be returned after + a single compare. + + @param l x minimum of constructed SkRect + @param t y minimum of constructed SkRect + @param r x maximum of constructed SkRect + @param b y maximum of constructed SkRect + @return true if construction and SkIRect have no area in common + */ bool quickReject(int l, int t, int r, int b) const { return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; } - /** Returns true if (x,y) is inside the rectangle and the rectangle is not - empty. The left and top are considered to be inside, while the right - and bottom are not. Thus for the rectangle (0, 0, 5, 10), the - points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkRect is empty. + + Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and + returns true if constructed area is completely enclosed by SkIRect area. + + @param x test SkPoint x-coordinate + @param y test SkPoint y-coordinate + @return true if (x, y) is inside SkIRect */ bool contains(int32_t x, int32_t y) const { return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); } - /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. - If either rectangle is empty, contains() returns false. + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect contains construction. + Returns false if SkRect is empty or construction is empty. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect + @return true if all sides of SkIRect are outside construction */ bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { return left < right && top < bottom && !this->isEmpty() && // check for empties @@ -239,7 +478,13 @@ struct SK_API SkIRect { fRight >= right && fBottom >= bottom; } - /** Returns true if the specified rectangle r is inside or equal to this rectangle. + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r */ bool contains(const SkIRect& r) const { return !r.isEmpty() && !this->isEmpty() && // check for empties @@ -247,15 +492,29 @@ struct SK_API SkIRect { fRight >= r.fRight && fBottom >= r.fBottom; } - /** Returns true if the specified rectangle r is inside or equal to this rectangle. + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkIRect are outside r */ bool contains(const SkRect& r) const; - /** Return true if this rectangle contains the specified rectangle. - For speed, this method does not check if either this or the specified - rectangles are empty, and if either is, its return value is undefined. - In the debugging build however, we assert that both this and the - specified rectangles are non-empty. + /** Constructs SkIRect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkRect is empty or construction is empty. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect + @return true if all sides of SkIRect are outside construction */ bool containsNoEmptyCheck(int32_t left, int32_t top, int32_t right, int32_t bottom) const { @@ -266,21 +525,38 @@ struct SK_API SkIRect { fRight >= right && fBottom >= bottom; } + /** Returns true if SkRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkRect is empty or construction is empty. + + @param r SkRect contained + @return true if all sides of SkIRect are outside r + */ bool containsNoEmptyCheck(const SkIRect& r) const { return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom); } - /** If r intersects this rectangle, return true and set this rectangle to that - intersection, otherwise return false and do not change this rectangle. - If either rectangle is empty, do nothing and return false. + /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. + + Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. + + @param r limit of result + @return true if r and SkRect have area in common */ bool intersect(const SkIRect& r) { return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); } - /** If rectangles a and b intersect, return true and set this rectangle to - that intersection, otherwise return false and do not change this - rectangle. If either rectangle is empty, do nothing and return false. + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Returns false if either a or b is empty, leaving SkIRect unchanged. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common */ bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& a, const SkIRect& b) { @@ -296,11 +572,14 @@ struct SK_API SkIRect { return false; } - /** If rectangles a and b intersect, return true and set this rectangle to - that intersection, otherwise return false and do not change this - rectangle. For speed, no check to see if a or b are empty is performed. - If either is, then the return result is undefined. In the debug build, - we assert that both rectangles are non-empty. + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Asserts if either a or b is empty, and if SK_DEBUG is defined. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common */ bool SK_WARN_UNUSED_RESULT intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { SkASSERT(!a.isEmpty() && !b.isEmpty()); @@ -316,10 +595,19 @@ struct SK_API SkIRect { return false; } - /** If the rectangle specified by left,top,right,bottom intersects this rectangle, - return true and set this rectangle to that intersection, - otherwise return false and do not change this rectangle. - If either rectangle is empty, do nothing and return false. + /** Constructs SkIRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkIRect intersects construction, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect construction, and leaves SkIRect unchanged. + + Returns false if either construction or SkIRect is empty, leaving SkIRect unchanged. + + @param left x minimum of constructed SkIRect + @param top y minimum of constructed SkIRect + @param right x maximum of constructed SkIRect + @param bottom y maximum of constructed SkIRect + @return true if construction and SkIRect have area in common */ bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { if (left < right && top < bottom && !this->isEmpty() && @@ -333,17 +621,26 @@ struct SK_API SkIRect { return false; } - /** Returns true if a and b are not empty, and they intersect - */ + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ static bool Intersects(const SkIRect& a, const SkIRect& b) { return !a.isEmpty() && !b.isEmpty() && // check for empties a.fLeft < b.fRight && b.fLeft < a.fRight && a.fTop < b.fBottom && b.fTop < a.fBottom; } - /** - * Returns true if a and b intersect. debug-asserts that neither are empty. - */ + /** Returns true if a intersects b. + Asserts if either a or b is empty, and if SK_DEBUG is defined. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) { SkASSERT(!a.isEmpty()); SkASSERT(!b.isEmpty()); @@ -351,24 +648,34 @@ struct SK_API SkIRect { a.fTop < b.fBottom && b.fTop < a.fBottom; } - /** Update this rectangle to enclose itself and the specified rectangle. - If this rectangle is empty, just set it to the specified rectangle. If the specified - rectangle is empty, do nothing. + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Sets SkRect to the union of itself and the construction. + + Has no effect if construction is empty. Otherwise, if SkRect is empty, sets + SkRect to construction. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect */ void join(int32_t left, int32_t top, int32_t right, int32_t bottom); - /** Update this rectangle to enclose itself and the specified rectangle. - If this rectangle is empty, just set it to the specified rectangle. If the specified - rectangle is empty, do nothing. + /** Sets SkRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkRect is empty, sets SkRect to r. + + @param r expansion SkRect */ void join(const SkIRect& r) { this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); } - /** Swap top/bottom or left/right if there are flipped. - This can be called if the edges are computed separately, - and may have crossed over each other. - When this returns, left <= right && top <= bottom + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty, + and width() and height() will be zero or positive. */ void sort() { if (fLeft > fRight) { @@ -379,14 +686,21 @@ struct SK_API SkIRect { } } - /** - * Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom). - */ + /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkIRect + */ SkIRect makeSorted() const { return MakeLTRB(SkMin32(fLeft, fRight), SkMin32(fTop, fBottom), SkMax32(fLeft, fRight), SkMax32(fTop, fBottom)); } + /** Returns a reference to immutable empty SkIRect, set to (0, 0, 0, 0). + + @return global SkIRect set to all zeroes + */ static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() { static const SkIRect gEmpty = { 0, 0, 0, 0 }; return gEmpty; @@ -394,24 +708,66 @@ struct SK_API SkIRect { }; /** \struct SkRect + SkRect holds four SkScalar coordinates describing the upper and + lower bounds of a rectangle. SkRect may be created from outer bounds or + from position, width, and height. SkRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. */ struct SK_API SkRect { - SkScalar fLeft; - SkScalar fTop; - SkScalar fRight; - SkScalar fBottom; + /** May contain any value, including infinities and NaN. The smaller of the + horizontal values when sorted. When equal to or greater than fRight, SkRect is empty. + */ + SkScalar fLeft; + + /** May contain any value, including infinities and NaN. The smaller of the + vertical values when sorted. When equal to or greater than fBottom, SkRect is empty. + */ + SkScalar fTop; + + /** May contain any value, including infinities and NaN. The larger of the + horizontal values when sorted. When equal to or less than fLeft, SkRect is empty. + */ + SkScalar fRight; + + /** May contain any value, including infinities and NaN. The larger of the + vertical values when sorted. When equal to or less than fTop, SkRect is empty. + */ + SkScalar fBottom; + + /** Returns constructed SkRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { return SkRect{0, 0, 0, 0}; } + /** Returns constructed SkRect setting left and top to most negative finite value, and + setting right and bottom to most positive finite value. + + @return bounds (SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax) + */ static SkRect SK_WARN_UNUSED_RESULT MakeLargest() { SkRect r; r.setLargest(); return r; } - // The largest SkRect for which round() is well-defined. + /** Returns constructed SkRect that can be represented exactly with SkIRect. The left + and top are set to the most negative integer value that fits in a 32-bit float, + and the right and bottom are set to the most positive finite value that fits in + a 32-bit float. + + These are the largest values for which round() is well defined. + + @return bounds (SK_MinS32FitsInFloat, SK_MinS32FitsInFloat, + SK_MaxS32FitsInFloat, SK_MaxS32FitsInFloat) + */ static SkRect SK_WARN_UNUSED_RESULT MakeLargestS32() { const SkRect r = MakeLTRB(SK_MinS32FitsInFloat, SK_MinS32FitsInFloat, SK_MaxS32FitsInFloat, SK_MaxS32FitsInFloat); @@ -419,29 +775,78 @@ struct SK_API SkRect { return r; } + /** Returns constructed SkRect set to SkScalar values (0, 0, w, h). Does not + validate input; w or h may be negative. + + Passing integer values may generate a compiler warning since SkRect cannot + represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. + + @param w SkScalar width of constructed SkRect + @param h SkScalar height of constructed SkRect + @return bounds (0, 0, w, h) + */ static constexpr SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { return SkRect{0, 0, w, h}; } + /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate + input; w or h may be negative. + + Use to avoid a compiler warning that input may lose precision when stored. + Use SkIRect for an exact integer rectangle. + + @param w integer width of constructed SkRect + @param h integer height of constructed SkRect + @return bounds (0, 0, w, h) + */ static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) { SkRect r; r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); return r; } + /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not + validate input; size.width() or size.height() may be negative. + + @param size SkScalar values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ static constexpr SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { return SkRect{0, 0, size.fWidth, size.fHeight}; } + /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l SkScalar stored in fLeft + @param t SkScalar stored in fTop + @param r SkScalar stored in fRight + @param b SkScalar stored in fBottom + @return bounds (l, t, r, b) + */ static constexpr SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { return SkRect {l, t, r, b}; } + /** Returns constructed SkRect set to (x, y, x + w, y + h). Does not validate input; + w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ static constexpr SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { return SkRect {x, y, x + w, y + h}; } + /** Deprecated. + + @param irect integer rect + @return irect as SkRect + */ SK_ATTR_DEPRECATED("use Make()") static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) { SkRect r; @@ -452,10 +857,23 @@ struct SK_API SkRect { return r; } + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size integer values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ static SkRect Make(const SkISize& size) { return MakeIWH(size.width(), size.height()); } + /** Returns constructed SkIRect set to irect, promoting integers to scalar. + Does not validate input; fLeft may be greater than fRight, fTop may be greater + than fBottom. + + @param irect integer unsorted bounds + @return irect members converted to SkScalar + */ static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { SkRect r; r.set(SkIntToScalar(irect.fLeft), @@ -465,25 +883,36 @@ struct SK_API SkRect { return r; } - /** - * Return true if the rectangle's width or height are <= 0 - */ + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or negative + */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } - /** - * Return true if the rectangle's width and height are >= 0 - */ + /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal + to or less than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or positive + */ bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } + /** Returns true if SkRect encloses largest possible area. + + @return true if equal to (SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax) + */ bool isLargest() const { return SK_ScalarMin == fLeft && SK_ScalarMin == fTop && SK_ScalarMax == fRight && SK_ScalarMax == fBottom; } - /** - * Returns true iff all values in the rect are finite. If any are - * infinite or NaN then this returns false. - */ + /** Returns true if all values in the rectangle are finite: SK_ScalarMin or larger, + and SK_ScalarMax or smaller. + + @return true if no member is infinite or NaN + */ bool isFinite() const { float accum = 0; accum *= fLeft; @@ -499,34 +928,125 @@ struct SK_API SkRect { return !SkScalarIsNaN(accum); } + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ SkScalar x() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ SkScalar y() const { return fTop; } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ SkScalar left() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ SkScalar top() const { return fTop; } + + /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ SkScalar right() const { return fRight; } + + /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ SkScalar bottom() const { return fBottom; } + + /** Returns span on the x-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fRight minus fLeft + */ SkScalar width() const { return fRight - fLeft; } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fBottom minus fTop + */ SkScalar height() const { return fBottom - fTop; } + + /** Returns average of left edge and right edge. Result does not change if SkRect + is sorted. Result may overflow to infinity if SkRect is far from the origin. + + @return midpoint in x + */ SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } + + /** Returns average of top edge and bottom edge. Result does not change if SkRect + is sorted. Result may overflow to infinity if SkRect is far from the origin. + + @return midpoint in y + */ SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + equal to the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes width different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are equal + */ friend bool operator==(const SkRect& a, const SkRect& b) { return SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); } + /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not + equal the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes width different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are not equal + */ friend bool operator!=(const SkRect& a, const SkRect& b) { return !SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); } - /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right, - bottom-left). TODO: Consider adding param to control whether quad is CW or CCW. - */ + /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, + bottom-right, bottom-left. + Consider adding param to control whether quad is CW or CCW. + + @param quad storage for corners of SkRect + */ void toQuad(SkPoint quad[4]) const; - /** Set this rectangle to the empty rectangle (0,0,0,0) + /** Sets SkRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. */ void setEmpty() { *this = MakeEmpty(); } + /** Sets SkRect to src, promoting src members from integer to scalar. + Very large values in src may lose precision. + + @param src integer SkRect + */ void set(const SkIRect& src) { fLeft = SkIntToScalar(src.fLeft); fTop = SkIntToScalar(src.fTop); @@ -534,20 +1054,45 @@ struct SK_API SkRect { fBottom = SkIntToScalar(src.fBottom); } + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { fLeft = left; fTop = top; fRight = right; fBottom = bottom; } - // alias for set(l, t, r, b) + + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { this->set(left, top, right, bottom); } - /** Initialize the rect with the 4 specified integers. The routine handles - converting them to scalars (by calling SkIntToScalar) - */ + /** Sets SkRect to (left, top, right, bottom). + All parameters are promoted from integer to scalar. + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left promoted to SkScalar and stored in fLeft + @param top promoted to SkScalar and stored in fTop + @param right promoted to SkScalar and stored in fRight + @param bottom promoted to SkScalar and stored in fBottom + */ void iset(int left, int top, int right, int bottom) { fLeft = SkIntToScalar(left); fTop = SkIntToScalar(top); @@ -555,19 +1100,27 @@ struct SK_API SkRect { fBottom = SkIntToScalar(bottom); } - /** - * Set this rectangle to be left/top at 0,0, and have the specified width - * and height (automatically converted to SkScalar). - */ + /** Sets SkRect to (0, 0, width, height). + width and height may be zero or negative. width and height are promoted from + integer to SkScalar, large values may lose precision. + + @param width promoted to SkScalar and stored in fRight + @param height promoted to SkScalar and stored in fBottom + */ void isetWH(int width, int height) { fLeft = fTop = 0; fRight = SkIntToScalar(width); fBottom = SkIntToScalar(height); } - /** Set this rectangle to be the bounds of the array of points. - If the array is empty (count == 0), then set this rectangle - to the empty rectangle (0,0,0,0) + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array */ void set(const SkPoint pts[], int count) { // set() had been checking for non-finite values, so keep that behavior @@ -576,18 +1129,38 @@ struct SK_API SkRect { (void)this->setBoundsCheck(pts, count); } - // alias for set(pts, count) + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + */ void setBounds(const SkPoint pts[], int count) { (void)this->setBoundsCheck(pts, count); } - /** - * Compute the bounds of the array of points, and set this rect to that - * bounds and return true... unless a non-finite value is encountered, - * in which case this rect is set to empty and false is returned. - */ + /** Sets to bounds of SkPoint array with count entries. Returns false if count is + zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases + sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + @return true if all SkPoint values are finite + */ bool setBoundsCheck(const SkPoint pts[], int count); + /** Sets bounds to the smallest SkRect enclosing points p0 and p1. The result is + sorted and may be empty. Does not check to see if values are finite. + + @param p0 corner to include + @param p1 corner to include + */ void set(const SkPoint& p0, const SkPoint& p1) { fLeft = SkMinScalar(p0.fX, p1.fX); fRight = SkMaxScalar(p0.fX, p1.fX); @@ -595,6 +1168,14 @@ struct SK_API SkRect { fBottom = SkMaxScalar(p0.fY, p1.fY); } + /** Sets SkRect to (x, y, x + width, y + height). Does not validate input; + width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { fLeft = x; fTop = y; @@ -602,6 +1183,12 @@ struct SK_API SkRect { fBottom = y + height; } + /** Sets SkRect to (0, 0, width, height). Does not validate input; + width or height may be negative. + + @param width stored in fRight + @param height stored in fBottom + */ void setWH(SkScalar width, SkScalar height) { fLeft = 0; fTop = 0; @@ -609,46 +1196,78 @@ struct SK_API SkRect { fBottom = height; } - /** - * Make the largest representable rectangle - */ + /** Sets rectangle left and top to most negative finite value, and sets + right and bottom to most positive finite value. + */ void setLargest() { fLeft = fTop = SK_ScalarMin; fRight = fBottom = SK_ScalarMax; } - /** - * Make the largest representable rectangle, but inverted (e.g. fLeft will - * be max and right will be min). - */ + /** Sets rectangle left and top to most positive finite value, and sets + right and bottom to most negative finite value. + + Use to initial SkRect before one or more calls to growToInclude(). + */ void setLargestInverted() { fLeft = fTop = SK_ScalarMax; fRight = fBottom = SK_ScalarMin; } - /** - * Return a new Rect, built as an offset of this rect. - */ + /** Returns SkRect offset by (dx, dy). + + If dx is negative, SkRect returned is moved to the left. + If dx is positive, SkRect returned is moved to the right. + If dy is negative, SkRect returned is moved upward. + If dy is positive, SkRect returned is moved downward. + + @param dx added to fLeft and fRight + @param dy added to fTop and fBottom + @return SkRect offset in x or y, with original width and height + */ SkRect makeOffset(SkScalar dx, SkScalar dy) const { return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy); } - /** - * Return a new Rect, built as an inset of this rect. - */ + /** Returns SkRect, inset by (dx, dy). + + If dx is negative, SkRect returned is wider. + If dx is positive, SkRect returned is narrower. + If dy is negative, SkRect returned is taller. + If dy is positive, SkRect returned is shorter. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + @return SkRect inset symmetrically left and right, top and bottom + */ SkRect makeInset(SkScalar dx, SkScalar dy) const { return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy); } - /** - * Return a new Rect, built as an outset of this rect. - */ + /** Returns SkRect, outset by (dx, dy). + + If dx is negative, SkRect returned is narrower. + If dx is positive, SkRect returned is wider. + If dy is negative, SkRect returned is shorter. + If dy is positive, SkRect returned is taller. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + @return SkRect outset symmetrically left and right, top and bottom + */ SkRect makeOutset(SkScalar dx, SkScalar dy) const { return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy); } - /** Offset set the rectangle by adding dx to its left and right, - and adding dy to its top and bottom. + /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkRect to the left. + If dx is positive, moves SkRect to the right. + If dy is negative, moves SkRect upward. + If dy is positive, moves SkRect downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom */ void offset(SkScalar dx, SkScalar dy) { fLeft += dx; @@ -657,13 +1276,26 @@ struct SK_API SkRect { fBottom += dy; } + /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkRect to the left. + If delta.fX is positive, moves SkRect to the right. + If delta.fY is negative, moves SkRect upward. + If delta.fY is positive, moves SkRect downward. + + @param delta added to SkRect + */ void offset(const SkPoint& delta) { this->offset(delta.fX, delta.fY); } - /** - * Offset this rect such its new x() and y() will equal newX and newY. - */ + /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ void offsetTo(SkScalar newX, SkScalar newY) { fRight += newX - fLeft; fBottom += newY - fTop; @@ -671,10 +1303,15 @@ struct SK_API SkRect { fTop = newY; } - /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are - moved inwards, making the rectangle narrower. If dx is negative, then - the sides are moved outwards, making the rectangle wider. The same holds - true for dy and the top and bottom. + /** Insets SkRect by (dx, dy). + + If dx is positive, makes SkRect narrower. + If dx is negative, makes SkRect wider. + If dy is positive, makes SkRect shorter. + If dy is negative, makes SkRect taller. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom */ void inset(SkScalar dx, SkScalar dy) { fLeft += dx; @@ -683,31 +1320,53 @@ struct SK_API SkRect { fBottom -= dy; } - /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are - moved outwards, making the rectangle wider. If dx is negative, then the - sides are moved inwards, making the rectangle narrower. The same holds - true for dy and the top and bottom. + /** Outsets SkRect by (dx, dy). + + If dx is positive, makes SkRect wider. + If dx is negative, makes SkRect narrower. + If dy is positive, makes SkRect taller. + If dy is negative, makes SkRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom */ void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } - /** If this rectangle intersects r, return true and set this rectangle to that - intersection, otherwise return false and do not change this rectangle. - If either rectangle is empty, do nothing and return false. + /** Returns true if SkRect intersects r, and sets SkRect to intersection. + Returns false if SkRect does not intersect r, and leaves SkRect unchanged. + + Returns false if either r or SkRect is empty, leaving SkRect unchanged. + + @param r limit of result + @return true if r and SkRect have area in common */ bool intersect(const SkRect& r); - /** If this rectangle intersects the rectangle specified by left, top, right, bottom, - return true and set this rectangle to that intersection, otherwise return false - and do not change this rectangle. - If either rectangle is empty, do nothing and return false. + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect intersects construction, and sets SkRect to intersection. + Returns false if SkRect does not intersect construction, and leaves SkRect unchanged. + + Returns false if either construction or SkRect is empty, leaving SkRect unchanged. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect + @return true if construction and SkRect have area in common */ bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); - /** - * If rectangles a and b intersect, return true and set this rectangle to - * that intersection, otherwise return false and do not change this - * rectangle. If either rectangle is empty, do nothing and return false. - */ + /** Returns true if a intersects b, and sets SkRect to intersection. + Returns false if a does not intersect b, and leaves SkRect unchanged. + + Returns false if either a or b is empty, leaving SkRect unchanged. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b); @@ -722,42 +1381,81 @@ private: } public: - /** - * Return true if this rectangle is not empty, and the specified sides of - * a rectangle are not empty, and they intersect. - */ + + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect intersects construction. + Returns false if either construction or SkRect is empty, or do not intersect. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect + @return true if construction and SkRect have area in common + */ bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom); } + /** Returns true if SkRect intersects r. + Returns false if either r or SkRect is empty, or do not intersect. + + @param r SkRect to intersect + @return true if r and SkRect have area in common + */ bool intersects(const SkRect& r) const { return Intersects(fLeft, fTop, fRight, fBottom, r.fLeft, r.fTop, r.fRight, r.fBottom); } - /** - * Return true if rectangles a and b are not empty and intersect. - */ + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ static bool Intersects(const SkRect& a, const SkRect& b) { return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom); } - /** - * Update this rectangle to enclose itself and the specified rectangle. - * If this rectangle is empty, just set it to the specified rectangle. - * If the specified rectangle is empty, do nothing. - */ + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Sets SkRect to the union of itself and the construction. + + Has no effect if construction is empty. Otherwise, if SkRect is empty, sets + SkRect to construction. + + @param left x minimum of constructed SkRect + @param top y minimum of constructed SkRect + @param right x maximum of constructed SkRect + @param bottom y maximum of constructed SkRect + */ void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); - /** Update this rectangle to enclose itself and the specified rectangle. - If this rectangle is empty, just set it to the specified rectangle. If the specified - rectangle is empty, do nothing. + /** Sets SkRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkRect is empty, sets + SkRect to r. + + @param r expansion SkRect */ void join(const SkRect& r) { this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); } + /** Sets SkRect to the union of itself and r. + + Asserts if r is empty and SK_DEBUG is defined. + If SkRect is empty, sets SkRect to r. + + May produce incorrect results if r is empty. + + @param r expansion SkRect + */ void joinNonEmptyArg(const SkRect& r) { SkASSERT(!r.isEmpty()); // if we are empty, just assign @@ -768,10 +1466,12 @@ public: } } - /** - * Joins the rectangle with another without checking if either are empty (may produce unexpected - * results if either rect is inverted). - */ + /** Sets SkRect to the union of itself and the construction. + + May produce incorrect results if SkRect or r is empty. + + @param r expansion SkRect + */ void joinPossiblyEmptyRect(const SkRect& r) { fLeft = SkMinScalar(fLeft, r.left()); fTop = SkMinScalar(fTop, r.top()); @@ -779,15 +1479,14 @@ public: fBottom = SkMaxScalar(fBottom, r.bottom()); } - /** - * Grow the rect to include the specified (x,y). After this call, the - * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. - * - * This is close, but not quite the same contract as contains(), since - * contains() treats the left and top different from the right and bottom. - * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note - * that contains(x,y) always returns false if the rect is empty. - */ + /** Grows SkRect to include (pt.fX, pt.fY), modifying it so that: + fLeft <= pt.fX <= fRight && fTop <= pt.fY <= fBottom. + + If SkRect is initialized with setLargestInverted(), then SkRect will contain bounds of + points after one or more calls. In this case, SkRect is empty after first call. + + @param pt SkPoint to include + */ void growToInclude(SkPoint pt) { fLeft = SkMinScalar(pt.fX, fLeft); fRight = SkMaxScalar(pt.fX, fRight); @@ -795,12 +1494,33 @@ public: fBottom = SkMaxScalar(pt.fY, fBottom); } - /** Bulk version of growToInclude */ + /** For each of count SkPoint in pts, grows SkRect to include (pt.fX, pt.fY), modifying + it so that: fLeft <= pt.fX <= fRight && fTop <= pt.fY <= fBottom. + + If SkRect is initialized with setLargestInverted(), then SkRect will contain bounds of + points after one or more calls. In this case, SkRect is empty after first call. + + @param pts SkPoint array + @param count number of points in array + */ void growToInclude(const SkPoint pts[], int count) { this->growToInclude(pts, sizeof(SkPoint), count); } - /** Bulk version of growToInclude with stride. */ + /** For each of count SkPoint in pts, grows SkRect to include (pt.fX, pt.fY), modifying + it so that: fLeft <= pt.fX <= fRight && fTop <= pt.fY <= fBottom. + + SkPoint may be followed with other data in each array element. stride is number + of bytes in element; the interval to skip to advance from one SkPoint to + the next. + + If SkRect is initialized with setLargestInverted(), then SkRect will contain bounds of + points after one or more calls. In this case, SkRect is empty after first call. + + @param pts array of elements beginning with SkPoint + @param stride size of pts elements in 32-bit words; zero or greater + @param count number of elements in array + */ void growToInclude(const SkPoint pts[], size_t stride, int count) { SkASSERT(count >= 0); SkASSERT(stride >= sizeof(SkPoint)); @@ -810,10 +1530,14 @@ public: } } - /** - * Return true if this rectangle contains r, and if both rectangles are - * not empty. - */ + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkRect are outside r + */ bool contains(const SkRect& r) const { // todo: can we eliminate the this->isEmpty check? return !r.isEmpty() && !this->isEmpty() && @@ -821,9 +1545,14 @@ public: fRight >= r.fRight && fBottom >= r.fBottom; } - /** - * Returns true if the specified rectangle r is inside or equal to this rectangle. - */ + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkRect are outside r + */ bool contains(const SkIRect& r) const { // todo: can we eliminate the this->isEmpty check? return !r.isEmpty() && !this->isEmpty() && @@ -831,32 +1560,36 @@ public: fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom); } - /** - * Set the dst rectangle by rounding this rectangle's coordinates to their - * nearest integer values using SkScalarRoundToInt. - */ + /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @param dst storage for SkIRect + */ void round(SkIRect* dst) const { SkASSERT(dst); dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); } - /** - * Set the dst rectangle by rounding "out" this rectangle, choosing the - * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. - */ + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and + rounding up fRight and fbottom, using (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkIRect + */ void roundOut(SkIRect* dst) const { SkASSERT(dst); dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); } - /** - * Set the dst rectangle by rounding "out" this rectangle, choosing the - * SkScalarFloorToScalar of top and left, and the SkScalarCeilToScalar of right and bottom. - * - * It is safe for this == dst - */ + /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and + rounding up fRight and fbottom, using (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkRect + */ void roundOut(SkRect* dst) const { dst->set(SkScalarFloorToScalar(fLeft), SkScalarFloorToScalar(fTop), @@ -864,38 +1597,47 @@ public: SkScalarCeilToScalar(fBottom)); } - /** - * Set the dst rectangle by rounding "in" this rectangle, choosing the - * ceil of top and left, and the floor of right and bottom. This does *not* - * call sort(), so it is possible that the resulting rect is inverted... - * e.g. left >= right or top >= bottom. Call isEmpty() to detect that. - */ + /** Sets SkRect by rounding up fLeft and fTop; and + discarding the fractional portion of fRight and fbottom, using + (SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)). + + @param dst storage for SkIRect + */ void roundIn(SkIRect* dst) const { SkASSERT(dst); dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); } - //! Returns the result of calling round(&dst) + /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @return rounded SkIRect + */ SkIRect round() const { SkIRect ir; this->round(&ir); return ir; } - //! Returns the result of calling roundOut(&dst) + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and + rounding up fRight and fbottom, using (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @return rounded SkIRect + */ SkIRect roundOut() const { SkIRect ir; this->roundOut(&ir); return ir; } - /** - * Swap top/bottom or left/right if there are flipped (i.e. if width() - * or height() would have returned a negative value.) This should be called - * if the edges are computed separately, and may have crossed over each - * other. When this returns, left <= right && top <= bottom - */ + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + */ void sort() { if (fLeft > fRight) { SkTSwap(fLeft, fRight); @@ -906,21 +1648,45 @@ public: } } - /** - * Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom). - */ + /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkRect + */ SkRect makeSorted() const { return MakeLTRB(SkMinScalar(fLeft, fRight), SkMinScalar(fTop, fBottom), SkMaxScalar(fLeft, fRight), SkMaxScalar(fTop, fBottom)); } - /** - * cast-safe way to treat the rect as an array of (4) SkScalars. - */ + /** Returns pointer to first scalar in SkRect, to treat it as an array with four + entries. + + @return pointer to fLeft + */ const SkScalar* asScalars() const { return &fLeft; } + /** Writes text representation of SkRect to standard output. Set asHex to true to + generate exact binary representations of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + */ void dump(bool asHex) const; + + /** Writes text representation of SkRect to standard output. The representation may be + directly compiled as C++ code. Floating point values are written + with limited precision; it may not be possible to reconstruct original SkRect + from output. + */ void dump() const { this->dump(false); } + + /** Writes text representation of SkRect to standard output. The representation may be + directly compiled as C++ code. Floating point values are written + in hexadecimal to preserve their exact bit pattern. The output reconstructs the + original SkRect. + + Use instead of dump() when submitting + */ void dumpHex() const { this->dump(true); } };