diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2008-12-17 15:59:43 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2008-12-17 15:59:43 +0000 |
commit | 8a1c16ff38322f0210116fa7293eb8817c7e477e (patch) | |
tree | fe40e07f6c8983318a2f79032b9a706ede1090c1 /include/core | |
parent | 2559c629078f738ac37095d896d580b681ac6a30 (diff) |
grab from latest android
git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'include/core')
75 files changed, 13518 insertions, 0 deletions
diff --git a/include/core/Sk64.h b/include/core/Sk64.h new file mode 100644 index 0000000000..c4ae41eb68 --- /dev/null +++ b/include/core/Sk64.h @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef Sk64_DEFINED +#define Sk64_DEFINED + +#include "SkFixed.h" +#include "SkMath.h" + +/** \class Sk64 + + Sk64 is a 64-bit math package that does not require long long support from the compiler. +*/ +struct Sk64 { + int32_t fHi; //!< the high 32 bits of the number (including sign) + uint32_t fLo; //!< the low 32 bits of the number + + /** Returns non-zero if the Sk64 can be represented as a signed 32 bit integer + */ + SkBool is32() const { return fHi == ((int32_t)fLo >> 31); } + + /** Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer + */ + SkBool is64() const { return fHi != ((int32_t)fLo >> 31); } + + /** Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know + if we can shift the value down by 16 to treat it as a SkFixed. + */ + SkBool isFixed() const; + + /** Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero. + */ + int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; } + + /** Return the number >> 16. Asserts that this does not loose any significant high bits. + */ + SkFixed getFixed() const { + SkASSERT(this->isFixed()); + + uint32_t sum = fLo + (1 << 15); + int32_t hi = fHi; + if (sum < fLo) { + hi += 1; + } + return (hi << 16) | (sum >> 16); + } + + /** Return the number >> 30. Asserts that this does not loose any + significant high bits. + */ + SkFract getFract() const; + + /** Returns the square-root of the number as a signed 32 bit value. */ + int32_t getSqrt() const; + + /** Returns the number of leading zeros of the absolute value of this. + Will return in the range [0..64] + */ + int getClzAbs() const; + + /** Returns non-zero if the number is zero */ + SkBool isZero() const { return (fHi | fLo) == 0; } + + /** Returns non-zero if the number is non-zero */ + SkBool nonZero() const { return fHi | fLo; } + + /** Returns non-zero if the number is negative (number < 0) */ + SkBool isNeg() const { return (uint32_t)fHi >> 31; } + + /** Returns non-zero if the number is positive (number > 0) */ + SkBool isPos() const { return ~(fHi >> 31) & (fHi | fLo); } + + /** Returns -1,0,+1 based on the sign of the number */ + int sign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); } + + /** Negate the number */ + void negate(); + + /** If the number < 0, negate the number + */ + void abs(); + + /** Returns the number of bits needed to shift the Sk64 to the right + in order to make it fit in a signed 32 bit integer. + */ + int shiftToMake32() const; + + /** Set the number to zero */ + void setZero() { fHi = fLo = 0; } + + /** Set the high and low 32 bit values of the number */ + void set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; } + + /** Set the number to the specified 32 bit integer */ + void set(int32_t a) { fHi = a >> 31; fLo = a; } + + /** Set the number to the product of the two 32 bit integers */ + void setMul(int32_t a, int32_t b); + + /** extract 32bits after shifting right by bitCount. + Note: itCount must be [0..63]. + Asserts that no significant high bits were lost. + */ + int32_t getShiftRight(unsigned bitCount) const; + + /** Shift the number left by the specified number of bits. + @param bits How far to shift left, must be [0..63] + */ + void shiftLeft(unsigned bits); + + /** Shift the number right by the specified number of bits. + @param bits How far to shift right, must be [0..63]. This + performs an arithmetic right-shift (sign extending). + */ + void shiftRight(unsigned bits); + + /** Shift the number right by the specified number of bits, but + round the result. + @param bits How far to shift right, must be [0..63]. This + performs an arithmetic right-shift (sign extending). + */ + void roundRight(unsigned bits); + + /** Add the specified 32 bit integer to the number */ + void add(int32_t lo) { + int32_t hi = lo >> 31; // 0 or -1 + uint32_t sum = fLo + (uint32_t)lo; + + fHi = fHi + hi + (sum < fLo); + fLo = sum; + } + + /** Add the specified Sk64 to the number */ + void add(int32_t hi, uint32_t lo) { + uint32_t sum = fLo + lo; + + fHi = fHi + hi + (sum < fLo); + fLo = sum; + } + + /** Add the specified Sk64 to the number */ + void add(const Sk64& other) { this->add(other.fHi, other.fLo); } + + /** Subtract the specified Sk64 from the number. (*this) = (*this) - num + */ + void sub(const Sk64& num); + + /** Subtract the number from the specified Sk64. (*this) = num - (*this) + */ + void rsub(const Sk64& num); + + /** Multiply the number by the specified 32 bit integer + */ + void mul(int32_t); + + enum DivOptions { + kTrunc_DivOption, //!< truncate the result when calling div() + kRound_DivOption //!< round the result when calling div() + }; + + /** Divide the number by the specified 32 bit integer, using the specified + divide option (either truncate or round). + */ + void div(int32_t, DivOptions); + + /** return (this + other >> 16) as a 32bit result */ + SkFixed addGetFixed(const Sk64& other) const { + return this->addGetFixed(other.fHi, other.fLo); + } + + /** return (this + Sk64(hi, lo) >> 16) as a 32bit result */ + SkFixed addGetFixed(int32_t hi, uint32_t lo) const { +#ifdef SK_DEBUG + Sk64 tmp(*this); + tmp.add(hi, lo); +#endif + + uint32_t sum = fLo + lo; + hi += fHi + (sum < fLo); + lo = sum; + + sum = lo + (1 << 15); + if (sum < lo) + hi += 1; + + hi = (hi << 16) | (sum >> 16); + SkASSERT(hi == tmp.getFixed()); + return hi; + } + + /** Return the result of dividing the number by denom, treating the answer + as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0. + */ + SkFixed getFixedDiv(const Sk64& denom) const; + + friend bool operator==(const Sk64& a, const Sk64& b) { + return a.fHi == b.fHi && a.fLo == b.fLo; + } + + friend bool operator!=(const Sk64& a, const Sk64& b) { + return a.fHi != b.fHi || a.fLo != b.fLo; + } + + friend bool operator<(const Sk64& a, const Sk64& b) { + return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo < b.fLo); + } + + friend bool operator<=(const Sk64& a, const Sk64& b) { + return a.fHi < b.fHi || (a.fHi == b.fHi && a.fLo <= b.fLo); + } + + friend bool operator>(const Sk64& a, const Sk64& b) { + return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo > b.fLo); + } + + friend bool operator>=(const Sk64& a, const Sk64& b) { + return a.fHi > b.fHi || (a.fHi == b.fHi && a.fLo >= b.fLo); + } + +#ifdef SkLONGLONG + SkLONGLONG getLongLong() const; +#endif + +#ifdef SK_DEBUG + /** @cond UNIT_TEST */ + static void UnitTest(); + /** @endcond */ +#endif +}; + +#endif + diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h new file mode 100644 index 0000000000..02c8cd9621 --- /dev/null +++ b/include/core/SkBitmap.h @@ -0,0 +1,684 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkBitmap_DEFINED +#define SkBitmap_DEFINED + +#include "Sk64.h" +#include "SkColor.h" +#include "SkPoint.h" +#include "SkRefCnt.h" + +#if defined(SK_BUILD_FOR_MAC) +#include <carbon/carbon.h> +#endif + +struct SkIRect; +class SkColorTable; +class SkPaint; +class SkPixelRef; +class SkRegion; +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; + +/** \class SkBitmap + + The SkBitmap class specifies a raster bitmap. A bitmap has an integer width + and height, and a format (config), 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. +*/ +class SkBitmap { +public: + class Allocator; + + enum Config { + kNo_Config, //!< bitmap has not been configured + kA1_Config, //!< 1-bit per pixel, (0 is transparent, 1 is opaque) + kA8_Config, //!< 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque) + kIndex8_Config, //!< 8-bits per pixel, using SkColorTable to specify the colors + kRGB_565_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing) + kARGB_4444_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing) + kARGB_8888_Config, //!< 32-bits per pixel, (see SkColorPriv.h for packing) + kRLE_Index8_Config, + + kConfigCount + }; + + /** Default construct creates a bitmap with zero width and height, and no pixels. + Its config is set to kNo_Config. + */ + SkBitmap(); + /** Constructor initializes the new bitmap by copying the src bitmap. All fields are copied, + but ownership of the pixels remains with the src bitmap. + */ + SkBitmap(const SkBitmap& src); + /** Decrements our (shared) pixel ownership if needed. + */ + ~SkBitmap(); + + /** Copies the src bitmap into this bitmap. Ownership of the src bitmap's pixels remains + with the src bitmap. + */ + SkBitmap& operator=(const SkBitmap& src); + /** Swap the fields of the two bitmaps. This routine is guaranteed to never fail or throw. + */ + // This method is not exported to java. + void swap(SkBitmap& other); + + /** Return true iff the bitmap has empty dimensions. + */ + bool empty() const { return 0 == fWidth || 0 == fHeight; } + + /** Return true iff the bitmap has no pixels nor a pixelref. Note: this can + return true even if the dimensions of the bitmap are > 0 (see empty()). + */ + bool isNull() const { return NULL == fPixels && NULL == fPixelRef; } + + /** Return the config for the bitmap. + */ + Config config() const { return (Config)fConfig; } + /** DEPRECATED, use config() + */ + Config getConfig() const { return this->config(); } + /** Return the bitmap's width, in pixels. + */ + int width() const { return fWidth; } + /** Return the bitmap's height, in pixels. + */ + int height() const { return fHeight; } + /** Return the number of bytes between subsequent rows of the bitmap. + */ + int rowBytes() const { return fRowBytes; } + + /** Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for + 2-bytes per pixel configs, 2 for 4-bytes per pixel configs). Return 0 + for configs that are not at least 1-byte per pixel (e.g. kA1_Config + or kNo_Config) + */ + int shiftPerPixel() const { return fBytesPerPixel >> 1; } + + /** Return the number of bytes per pixel based on the config. If the config + does not have at least 1 byte per (e.g. kA1_Config) then 0 is returned. + */ + int bytesPerPixel() const { return fBytesPerPixel; } + + /** Return the rowbytes expressed as a number of pixels (like width and + height). Note, for 1-byte per pixel configs like kA8_Config, this will + return the same as rowBytes(). Is undefined for configs that are less + than 1-byte per pixel (e.g. kA1_Config) + */ + int rowBytesAsPixels() const { return fRowBytes >> (fBytesPerPixel >> 1); } + + /** Return the address of the pixels for this SkBitmap. + */ + void* getPixels() const { return fPixels; } + + /** Return the byte size of the pixels, based on the height and rowBytes. + Note this truncates the result to 32bits. Call getSize64() to detect + if the real size exceeds 32bits. + */ + size_t getSize() const { return fHeight * fRowBytes; } + + /** Return the byte size of the pixels, based on the height and rowBytes. + This routine is slightly slower than getSize(), but does not truncate + the answer to 32bits. + */ + Sk64 getSize64() const { + Sk64 size; + size.setMul(fHeight, fRowBytes); + return size; + } + + /** Returns true if the bitmap is opaque (has no translucent/transparent pixels). + */ + bool isOpaque() const; + /** Specify if this bitmap's pixels are all opaque or not. Is only meaningful for configs + that support per-pixel alpha (RGB32, A1, A8). + */ + void setIsOpaque(bool); + + /** Reset the bitmap to its initial state (see default constructor). If we are a (shared) + owner of the pixels, that ownership is decremented. + */ + void reset(); + + /** Given a config and a width, this computes the optimal rowBytes value. This is called automatically + if you pass 0 for rowBytes to setConfig(). + */ + static int ComputeRowBytes(Config c, int width); + + /** Return the bytes-per-pixel for the specified config. If the config is + not at least 1-byte per pixel, return 0, including for kNo_Config. + */ + static int ComputeBytesPerPixel(Config c); + + /** Return the shift-per-pixel for the specified config. If the config is + not at least 1-byte per pixel, return 0, including for kNo_Config. + */ + static int ComputeShiftPerPixel(Config c) { + return ComputeBytesPerPixel(c) >> 1; + } + + static Sk64 ComputeSize64(Config, int width, int height); + static size_t ComputeSize(Config, int width, int height); + + /** Set the bitmap's config and dimensions. If rowBytes is 0, then + ComputeRowBytes() is called to compute the optimal value. This resets + any pixel/colortable ownership, just like reset(). + */ + void setConfig(Config, int width, int height, int rowBytes = 0); + /** 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. + + If the bitmap retains a reference to the colortable (assuming it is + not null) it will take care of incrementing the reference count. + + @param pixels Address for the pixels, managed by the caller. + @param ctable ColorTable (or null) that matches the specified pixels + */ + void setPixels(void* p, SkColorTable* ctable = NULL); + + /** Use the standard HeapAllocator to create the pixelref that manages the + pixel memory. It will be sized based on the current width/height/config. + If this is called multiple times, a new pixelref object will be created + each time. + + If the bitmap retains a reference to the colortable (assuming it is + not null) it will take care of incrementing the reference count. + + @param ctable ColorTable (or null) to use with the pixels that will + be allocated. Only used if config == Index8_Config + @return true if the allocation succeeds. If not the pixelref field of + the bitmap will be unchanged. + */ + bool allocPixels(SkColorTable* ctable = NULL) { + return this->allocPixels(NULL, ctable); + } + + /** Use the specified Allocator to create the pixelref that manages the + pixel memory. It will be sized based on the current width/height/config. + If this is called multiple times, a new pixelref object will be created + each time. + + If the bitmap retains a reference to the colortable (assuming it is + not null) it will take care of incrementing the reference count. + + @param allocator The Allocator to use to create a pixelref that can + manage the pixel memory for the current + width/height/config. If allocator is NULL, the standard + HeapAllocator will be used. + @param ctable ColorTable (or null) to use with the pixels that will + be allocated. Only used if config == Index8_Config. + If it is non-null and the config is not Index8, it will + be ignored. + @return true if the allocation succeeds. If not the pixelref field of + the bitmap will be unchanged. + */ + bool allocPixels(Allocator* allocator, SkColorTable* ctable); + + /** Return the current pixelref object, of any + */ + SkPixelRef* pixelRef() const { return fPixelRef; } + /** Return the offset into the pixelref, if any. Will return 0 if there is + no pixelref installed. + */ + size_t pixelRefOffset() const { return fPixelRefOffset; } + /** Assign a pixelref and optional offset. Pixelrefs are reference counted, + so the existing one (if any) will be unref'd and the new one will be + ref'd. + */ + SkPixelRef* setPixelRef(SkPixelRef* pr, size_t offset = 0); + + /** Call this to ensure that the bitmap points to the current pixel address + in the pixelref. Balance it with a call to unlockPixels(). These calls + are harmless if there is no pixelref. + */ + void lockPixels() const; + /** When you are finished access the pixel memory, call this to balance a + previous call to lockPixels(). This allows pixelrefs that implement + cached/deferred image decoding to know when there are active clients of + a given image. + */ + void unlockPixels() const; + + /** Call this to be sure that the bitmap is valid enough to be drawn (i.e. + it has non-null pixels, and if required by its config, it has a + non-null colortable. Returns true if all of the above are met. + */ + bool readyToDraw() const { + return this->getPixels() != NULL && + ((this->config() != kIndex8_Config && this->config() != kRLE_Index8_Config) || + fColorTable != NULL); + } + + /** Return the bitmap's colortable (if any). Does not affect the colortable's + reference count. + */ + SkColorTable* getColorTable() const { return fColorTable; } + + /** Returns a non-zero, unique value corresponding to the pixels in our + pixelref, or 0 if we do not have a pixelref. Each time the pixels are + changed (and notifyPixelsChanged is called), a different generation ID + will be returned. + */ + 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(). + */ + void notifyPixelsChanged() const; + + /** Initialize the bitmap's pixels with the specified color+alpha, automatically converting into the correct format + for the bitmap's config. If the config is kRGB_565_Config, then the alpha value is ignored. + If the config is kA8_Config, then the r,g,b parameters are ignored. + */ + void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const; + /** Initialize the bitmap's pixels with the specified color+alpha, automatically converting into the correct format + for the bitmap's config. If the config is kRGB_565_Config, then the alpha value is presumed + to be 0xFF. If the config is kA8_Config, then the r,g,b parameters are ignored and the + pixels are all set to 0xFF. + */ + void eraseRGB(U8CPU r, U8CPU g, U8CPU b) const { + this->eraseARGB(0xFF, r, g, b); + } + /** Initialize the bitmap's pixels with the specified color, automatically converting into the correct format + for the bitmap's config. If the config is kRGB_565_Config, then the color's alpha value is presumed + to be 0xFF. If the config is kA8_Config, then only the color's alpha value is used. + */ + void eraseColor(SkColor c) const { + this->eraseARGB(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), + SkColorGetB(c)); + } + + /** Scroll (a subset of) the contents of this bitmap by dx/dy. If there are + no pixels allocated (i.e. getPixels() returns null) the method will + still update the inval region (if present). + + @param subset The subset of the bitmap to scroll/move. To scroll the + entire contents, specify [0, 0, width, height] or just + pass null. + @param dx The amount to scroll in X + @param dy The amount to scroll in Y + @param inval Optional (may be null). Returns the area of the bitmap that + was scrolled away. E.g. if dx = dy = 0, then inval would + be set to empty. If dx >= width or dy >= height, then + inval would be set to the entire bounds of the bitmap. + @return true if the scroll was doable. Will return false if the bitmap + uses an unsupported config for scrolling (only kA8, + kIndex8, kRGB_565, kARGB_4444, kARGB_8888 are supported). + If no pixels are present (i.e. getPixels() returns false) + inval will still be updated, and true will be returned. + */ + bool scrollRect(const SkIRect* subset, int dx, int dy, + SkRegion* inval = NULL) const; + + /** 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. + */ + void* getAddr(int x, int y) const; + + /** Returns the address of the pixel specified by x,y for 32bit pixels. + */ + inline uint32_t* getAddr32(int x, int y) const; + /** Returns the address of the pixel specified by x,y for 16bit pixels. + */ + inline uint16_t* getAddr16(int x, int y) const; + /** Returns the address of the pixel specified by x,y for 8bit pixels. + */ + inline uint8_t* getAddr8(int x, int y) const; + /** Returns the address of the byte containing the pixel specified by x,y + for 1bit pixels. + */ + inline uint8_t* getAddr1(int x, int y) const; + + /** Returns the color corresponding to the pixel specified by x,y for + colortable based bitmaps. + */ + inline SkPMColor getIndex8Color(int x, int y) const; + + // OS-specific helpers +#ifndef SK_USE_WXWIDGETS +#ifdef SK_BUILD_FOR_WIN + /** On Windows and PocketPC builds, this will draw the SkBitmap onto the + specified HDC + */ + void drawToHDC(HDC, int left, int top) const; +#elif defined(SK_BUILD_FOR_MAC) + /** On Mac OS X and Carbon builds, this will draw the SkBitmap onto the + specified WindowRef + */ + void drawToPort(WindowRef, CGContextRef) const; +#endif +#endif + + /** 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 config + 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 config, 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. + */ + bool extractSubset(SkBitmap* dst, const SkIRect& subset) const; + + /** Tries to make a new bitmap based on the dimensions of this bitmap, + setting the new bitmap's config to the one specified, and then copying + this bitmap's pixels into the new bitmap. If the conversion is not + supported, or the allocator fails, then this method returns false and + dst is left unchanged. + @param dst The bitmap to be sized and allocated + @param c The desired config for dst + @param allocator Allocator used to allocate the pixelref for the dst + bitmap. If this is null, the standard HeapAllocator + will be used. + @return true if the copy could be made. + */ + bool copyTo(SkBitmap* dst, Config c, Allocator* allocator = NULL) const; + + bool hasMipMap() const; + void buildMipMap(bool forceRebuild = false); + void freeMipMap(); + + /** Given scale factors sx, sy, determine the miplevel available in the + bitmap, and return it (this is the amount to shift matrix iterators + by). If dst is not null, it is set to the correct level. + */ + int extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy); + + void extractAlpha(SkBitmap* dst) const { + this->extractAlpha(dst, NULL, NULL); + } + + void extractAlpha(SkBitmap* dst, const SkPaint* paint, + SkIPoint* offset) const; + + void flatten(SkFlattenableWriteBuffer&) const; + void unflatten(SkFlattenableReadBuffer&); + + SkDEBUGCODE(void validate() const;) + + class Allocator : public SkRefCnt { + public: + /** Allocate the pixel memory for the bitmap, given its dimensions and + config. Return true on success, where success means either setPixels + or setPixelRef was called. The pixels need not be locked when this + returns. If the config requires a colortable, it also must be + installed via setColorTable. If false is returned, the bitmap and + colortable should be left unchanged. + */ + virtual bool allocPixelRef(SkBitmap*, SkColorTable*) = 0; + }; + + /** Subclass of Allocator that returns a pixelref that allocates its pixel + memory from the heap. This is the default Allocator invoked by + allocPixels(). + */ + class HeapAllocator : public Allocator { + public: + virtual bool allocPixelRef(SkBitmap*, SkColorTable*); + }; + + class RLEPixels { + public: + RLEPixels(int width, int height); + virtual ~RLEPixels(); + + uint8_t* packedAtY(int y) const { + SkASSERT((unsigned)y < (unsigned)fHeight); + return fYPtrs[y]; + } + + // called by subclasses during creation + void setPackedAtY(int y, uint8_t* addr) { + SkASSERT((unsigned)y < (unsigned)fHeight); + fYPtrs[y] = addr; + } + + private: + uint8_t** fYPtrs; + int fHeight; + }; + +private: +#ifdef SK_SUPPORT_MIPMAP + struct MipMap; + mutable MipMap* fMipMap; +#endif + + mutable SkPixelRef* fPixelRef; + mutable size_t fPixelRefOffset; + mutable int fPixelLockCount; + // either user-specified (in which case it is not treated as mutable) + // or a cache of the returned value from fPixelRef->lockPixels() + mutable void* fPixels; + mutable SkColorTable* fColorTable; // only meaningful for kIndex8 + + enum Flags { + kImageIsOpaque_Flag = 0x01 + }; + + uint32_t fRowBytes; + uint16_t fWidth, fHeight; + uint8_t fConfig; + uint8_t fFlags; + uint8_t fBytesPerPixel; // based on config + + /* Unreference any pixelrefs or colortables + */ + void freePixels(); + void updatePixelsFromRef() const; + + static SkFixed ComputeMipLevel(SkFixed sx, SkFixed dy); +}; + +/** \class SkColorTable + + SkColorTable holds an array SkPMColors (premultiplied 32-bit colors) used by + 8-bit bitmaps, where the bitmap bytes are interpreted as indices into the colortable. +*/ +class SkColorTable : public SkRefCnt { +public: + /** Constructs an empty color table (zero colors). + */ + explicit SkColorTable(int count); + explicit SkColorTable(SkFlattenableReadBuffer&); + SkColorTable(const SkPMColor colors[], int count); + virtual ~SkColorTable(); + + enum Flags { + kColorsAreOpaque_Flag = 0x01 //!< if set, all of the colors in the table are opaque (alpha==0xFF) + }; + /** Returns the flag bits for the color table. These can be changed with setFlags(). + */ + unsigned getFlags() const { return fFlags; } + /** Set the flags for the color table. See the Flags enum for possible values. + */ + void setFlags(unsigned flags); + + /** Returns the number of colors in the table. + */ + int count() const { return fCount; } + + /** Returns the specified color from the table. In the debug build, this asserts that + the index is in range (0 <= index < count). + */ + SkPMColor operator[](int index) const { + SkASSERT(fColors != NULL && (unsigned)index < fCount); + return fColors[index]; + } + + /** Specify the number of colors in the color table. This does not initialize the colors + to any value, just allocates memory for them. To initialize the values, either call + setColors(array, count), or follow setCount(count) with a call to + lockColors()/{set the values}/unlockColors(true). + */ +// void setColors(int count) { this->setColors(NULL, count); } +// void setColors(const SkPMColor[], int count); + + /** Return the array of colors for reading and/or writing. This must be + balanced by a call to unlockColors(changed?), telling the colortable if + the colors were changed during the lock. + */ + SkPMColor* lockColors() { + SkDEBUGCODE(fColorLockCount += 1;) + return fColors; + } + /** Balancing call to lockColors(). If the colors have been changed, pass true. + */ + void unlockColors(bool changed); + + /** Similar to lockColors(), lock16BitCache() returns the array of + RGB16 colors that mirror the 32bit colors. However, this function + will return null if kColorsAreOpaque_Flag is not set. + Also, unlike lockColors(), the returned array here cannot be modified. + */ + const uint16_t* lock16BitCache(); + /** Balancing call to lock16BitCache(). + */ + void unlock16BitCache() { + SkASSERT(f16BitCacheLockCount > 0); + SkDEBUGCODE(f16BitCacheLockCount -= 1); + } + + void flatten(SkFlattenableWriteBuffer&) const; + +private: + SkPMColor* fColors; + uint16_t* f16BitCache; + uint16_t fCount; + uint8_t fFlags; + SkDEBUGCODE(int fColorLockCount;) + SkDEBUGCODE(int f16BitCacheLockCount;) + + void inval16BitCache(); +}; + +class SkAutoLockPixels { +public: + SkAutoLockPixels(const SkBitmap& bitmap) : fBitmap(bitmap) { + bitmap.lockPixels(); + } + ~SkAutoLockPixels() { + fBitmap.unlockPixels(); + } + +private: + const SkBitmap& fBitmap; +}; + +/** Helper class that performs the lock/unlockColors calls on a colortable. + The destructor will call unlockColors(false) if it has a bitmap's colortable +*/ +class SkAutoLockColors : public SkNoncopyable { +public: + /** Initialize with no bitmap. Call lockColors(bitmap) to lock bitmap's + colortable + */ + SkAutoLockColors() : fCTable(NULL), fColors(NULL) {} + /** Initialize with bitmap, locking its colortable if present + */ + explicit SkAutoLockColors(const SkBitmap& bm) { + fCTable = bm.getColorTable(); + fColors = fCTable ? fCTable->lockColors() : NULL; + } + /** Initialize with a colortable (may be null) + */ + explicit SkAutoLockColors(SkColorTable* ctable) { + fCTable = ctable; + fColors = ctable ? ctable->lockColors() : NULL; + } + ~SkAutoLockColors() { + if (fCTable) { + fCTable->unlockColors(false); + } + } + + /** Return the currently locked colors, or NULL if no bitmap's colortable + is currently locked. + */ + const SkPMColor* colors() const { return fColors; } + + /** If a previous bitmap has been locked by this object, unlock its colors + first. If the specified bitmap has a colortable, lock its colors and + return them. + */ + const SkPMColor* lockColors(const SkBitmap& bm) { + if (fCTable) { + fCTable->unlockColors(false); + } + fCTable = bm.getColorTable(); + fColors = fCTable ? fCTable->lockColors() : NULL; + return fColors; + } + +private: + SkColorTable* fCTable; + const SkPMColor* fColors; +}; + +/////////////////////////////////////////////////////////////////////////////// + +inline uint32_t* SkBitmap::getAddr32(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kARGB_8888_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + return (uint32_t*)((char*)fPixels + y * fRowBytes + (x << 2)); +} + +inline uint16_t* SkBitmap::getAddr16(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kRGB_565_Config || fConfig == kARGB_4444_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + return (uint16_t*)((char*)fPixels + y * fRowBytes + (x << 1)); +} + +inline uint8_t* SkBitmap::getAddr8(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kA8_Config || fConfig == kIndex8_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + return (uint8_t*)fPixels + y * fRowBytes + x; +} + +inline SkPMColor SkBitmap::getIndex8Color(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kIndex8_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + SkASSERT(fColorTable); + return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)]; +} + +// returns the address of the byte that contains the x coordinate +inline uint8_t* SkBitmap::getAddr1(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kA1_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + return (uint8_t*)fPixels + y * fRowBytes + (x >> 3); +} + +#endif + diff --git a/include/core/SkBounder.h b/include/core/SkBounder.h new file mode 100644 index 0000000000..f20961d2ed --- /dev/null +++ b/include/core/SkBounder.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkBounder_DEFINED +#define SkBounder_DEFINED + +#include "SkTypes.h" +#include "SkRefCnt.h" + +struct SkIRect; +struct SkPoint; +struct SkRect; +class SkPaint; +class SkPath; +class SkRegion; + +/** \class SkBounder + + Base class for intercepting the device bounds of shapes before they are drawn. + Install a subclass of this in your canvas. +*/ +class SkBounder : public SkRefCnt { +public: + /* Call to perform a clip test before calling onIRect. + Returns the result from onIRect. + */ + bool doIRect(const SkIRect&); + +protected: + /** Override in your subclass. This is called with the device bounds of an + object (text, geometry, image) just before it is drawn. If your method + returns false, the drawing for that shape is aborted. If your method + returns true, drawing continues. The bounds your method receives have already + been transformed in to device coordinates, and clipped to the current clip. + */ + virtual bool onIRect(const SkIRect&) = 0; + + /** Called after each shape has been drawn. The default implementation does + nothing, but your override could use this notification to signal itself + that the offscreen being rendered into needs to be updated to the screen. + */ + virtual void commit(); + +private: + bool doHairline(const SkPoint&, const SkPoint&, const SkPaint&); + bool doRect(const SkRect&, const SkPaint&); + bool doPath(const SkPath&, const SkPaint&, bool doFill); + void setClip(const SkRegion* clip) { fClip = clip; } + + const SkRegion* fClip; + friend class SkAutoBounderCommit; + friend class SkDraw; + friend class SkDrawIter; + friend struct Draw1Glyph; + friend class SkMaskFilter; +}; + +#endif + diff --git a/include/core/SkBuffer.h b/include/core/SkBuffer.h new file mode 100644 index 0000000000..bc11a1e70e --- /dev/null +++ b/include/core/SkBuffer.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkBuffer_DEFINED +#define SkBuffer_DEFINED + +#include "SkScalar.h" + +/** \class SkRBuffer + + Light weight class for reading data from a memory block. + The RBuffer is given the buffer to read from, with either a specified size + or no size (in which case no range checking is performed). It is iillegal + to attempt to read a value from an empty RBuffer (data == null). +*/ +class SkRBuffer : SkNoncopyable { +public: + SkRBuffer() : fData(0), fPos(0), fStop(0) {} + /** Initialize RBuffer with a data pointer, but no specified length. + This signals the RBuffer to not perform range checks during reading. + */ + SkRBuffer(const void* data) + { + fData = (const char*)data; + fPos = (const char*)data; + fStop = 0; // no bounds checking + } + /** Initialize RBuffer with a data point and length. + */ + SkRBuffer(const void* data, size_t size) + { + SkASSERT(data != 0 || size == 0); + fData = (const char*)data; + fPos = (const char*)data; + fStop = (const char*)data + size; + } + + /** Return the number of bytes that have been read from the beginning + of the data pointer. + */ + size_t pos() const { return fPos - fData; } + /** Return the total size of the data pointer. Only defined if the length was + specified in the constructor or in a call to reset(). + */ + size_t size() const { return fStop - fData; } + /** Return true if the buffer has read to the end of the data pointer. + Only defined if the length was specified in the constructor or in a call + to reset(). Always returns true if the length was not specified. + */ + bool eof() const { return fPos >= fStop; } + + /** Read the specified number of bytes from the data pointer. If buffer is not + null, copy those bytes into buffer. + */ + void read(void* buffer, size_t size) { if (size) this->readNoSizeCheck(buffer, size); } + const void* skip(size_t size); // return start of skipped data + size_t skipToAlign4(); + + void* readPtr() { void* ptr; read(&ptr, sizeof(ptr)); return ptr; } + SkScalar readScalar() { SkScalar x; read(&x, 4); return x; } + uint32_t readU32() { uint32_t x; read(&x, 4); return x; } + int32_t readS32() { int32_t x; read(&x, 4); return x; } + uint16_t readU16() { uint16_t x; read(&x, 2); return x; } + int16_t readS16() { int16_t x; read(&x, 2); return x; } + uint8_t readU8() { uint8_t x; read(&x, 1); return x; } + bool readBool() { return this->readU8() != 0; } + +protected: + void readNoSizeCheck(void* buffer, size_t size); + + const char* fData; + const char* fPos; + const char* fStop; +}; + +/** \class SkWBuffer + + Light weight class for writing data to a memory block. + The WBuffer is given the buffer to write into, with either a specified size + or no size, in which case no range checking is performed. An empty WBuffer + is legal, in which case no data is ever written, but the relative pos() + is updated. +*/ +class SkWBuffer : SkNoncopyable { +public: + SkWBuffer() : fData(0), fPos(0), fStop(0) {} + SkWBuffer(void* data) { reset(data); } + SkWBuffer(void* data, size_t size) { reset(data, size); } + + void reset(void* data) + { + fData = (char*)data; + fPos = (char*)data; + fStop = 0; // no bounds checking + } + void reset(void* data, size_t size) + { + SkASSERT(data != 0 || size == 0); + fData = (char*)data; + fPos = (char*)data; + fStop = (char*)data + size; + } + + void* data() const { return fData; } + size_t pos() const { return fPos - fData; } + size_t size() const { return fStop - fData; } + bool eof() const { return fPos >= fStop; } + void* skip(size_t size); // return start of skipped data + void write(const void* buffer, size_t size) { if (size) this->writeNoSizeCheck(buffer, size); } + size_t padToAlign4(); + + void writePtr(const void* x) { this->writeNoSizeCheck(&x, sizeof(x)); } + void writeScalar(SkScalar x) { this->writeNoSizeCheck(&x, 4); } + void write32(int32_t x) { this->writeNoSizeCheck(&x, 4); } + void write16(int16_t x) { this->writeNoSizeCheck(&x, 2); } + void write8(int8_t x) { this->writeNoSizeCheck(&x, 1); } + void writeBool(bool x) { this->write8(x); } + +protected: + void writeNoSizeCheck(const void* buffer, size_t size); + + char* fData; + char* fPos; + char* fStop; +}; + +#endif + diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h new file mode 100644 index 0000000000..a19a5ae706 --- /dev/null +++ b/include/core/SkCanvas.h @@ -0,0 +1,794 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkCanvas_DEFINED +#define SkCanvas_DEFINED + +#include "SkTypes.h" +#include "SkBitmap.h" +#include "SkDeque.h" +#include "SkPaint.h" +#include "SkRefCnt.h" +#include "SkPorterDuff.h" +#include "SkPath.h" +#include "SkRegion.h" +#include "SkScalarCompare.h" + +class SkBounder; +class SkDevice; +class SkDraw; +class SkDrawFilter; +class SkPicture; + +/** \class SkCanvas + + A Canvas encapsulates all of the state about drawing into a device (bitmap). + This includes a reference to the device itself, and a stack of matrix/clip + values. For any given draw call (e.g. drawRect), the geometry of the object + being drawn is transformed by the concatenation of all the matrices in the + stack. The transformed geometry is clipped by the intersection of all of + the clips in the stack. + + While the Canvas holds the state of the drawing device, the state (style) + of the object being drawn is held by the Paint, which is provided as a + parameter to each of the draw() methods. The Paint holds attributes such as + color, typeface, textSize, strokeWidth, shader (e.g. gradients, patterns), + etc. +*/ +class SkCanvas : public SkRefCnt { +public: + /** Construct a canvas with the specified bitmap to draw into. + @param bitmap Specifies a bitmap for the canvas to draw into. Its + structure are copied to the canvas. + */ + explicit SkCanvas(const SkBitmap& bitmap); + /** Construct a canvas with the specified device to draw into. + @param device Specifies a device for the canvas to draw into. The + device may be null. + */ + explicit SkCanvas(SkDevice* device = NULL); + virtual ~SkCanvas(); + + /////////////////////////////////////////////////////////////////////////// + + /** If this subclass of SkCanvas supports GL viewports, return true and set + size (if not null) to the size of the viewport. If it is not supported, + ignore vp and return false. + */ + virtual bool getViewport(SkIPoint* size) const; + + /** If this subclass of SkCanvas supports GL viewports, return true and set + the viewport to the specified x and y dimensions. If it is not + supported, ignore x and y and return false. + */ + virtual bool setViewport(int x, int y); + + /** Return the canvas' device object, which may be null. The device holds + the bitmap of the pixels that the canvas draws into. The reference count + of the returned device is not changed by this call. + */ + SkDevice* getDevice() const; + + /** Specify a device for this canvas to draw into. If it is not null, its + reference count is incremented. If the canvas was already holding a + device, its reference count is decremented. The new device is returned. + */ + SkDevice* setDevice(SkDevice* device); + + /** Specify a bitmap for the canvas to draw into. This is a help method for + setDevice(), and it creates a device for the bitmap by calling + createDevice(). The structure of the bitmap is copied into the device. + */ + virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap); + + /////////////////////////////////////////////////////////////////////////// + + enum SaveFlags { + /** save the matrix state, restoring it on restore() */ + kMatrix_SaveFlag = 0x01, + /** save the clip state, restoring it on restore() */ + kClip_SaveFlag = 0x02, + /** the layer needs to support per-pixel alpha */ + kHasAlphaLayer_SaveFlag = 0x04, + /** the layer needs to support 8-bits per color component */ + kFullColorLayer_SaveFlag = 0x08, + /** the layer should clip against the bounds argument */ + kClipToLayer_SaveFlag = 0x10, + + // helper masks for common choices + kMatrixClip_SaveFlag = 0x03, + kARGB_NoClipLayer_SaveFlag = 0x0F, + kARGB_ClipLayer_SaveFlag = 0x1F + }; + + /** This call saves the current matrix and clip information, and pushes a + copy onto a private stack. Subsequent calls to translate, scale, + rotate, skew, concat or clipRect, clipPath all operate on this copy. + When the balancing call to restore() is made, this copy is deleted and + the previous matrix/clip state is restored. + @return The value to pass to restoreToCount() to balance this save() + */ + virtual int save(SaveFlags flags = kMatrixClip_SaveFlag); + + /** This behaves the same as save(), but in addition it allocates an + offscreen bitmap. All drawing calls are directed there, and only when + the balancing call to restore() is made is that offscreen transfered to + the canvas (or the previous layer). Subsequent calls to translate, + scale, rotate, skew, concat or clipRect, clipPath all operate on this + copy. When the balancing call to restore() is made, this copy is deleted + and the previous matrix/clip state is restored. + @param bounds (may be null) the maximum size the offscreen bitmap needs + to be (in local coordinates) + @param paint (may be null) This is copied, and is applied to the + offscreen when restore() is called + @param flags LayerFlags + @return The value to pass to restoreToCount() to balance this save() + */ + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags flags = kARGB_ClipLayer_SaveFlag); + + /** This behaves the same as save(), but in addition it allocates an + offscreen bitmap. All drawing calls are directed there, and only when + the balancing call to restore() is made is that offscreen transfered to + the canvas (or the previous layer). Subsequent calls to translate, + scale, rotate, skew, concat or clipRect, clipPath all operate on this + copy. When the balancing call to restore() is made, this copy is deleted + and the previous matrix/clip state is restored. + @param bounds (may be null) the maximum size the offscreen bitmap needs + to be (in local coordinates) + @param alpha This is applied to the offscreen when restore() is called. + @param flags LayerFlags + @return The value to pass to restoreToCount() to balance this save() + */ + int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, + SaveFlags flags = kARGB_ClipLayer_SaveFlag); + + /** This call balances a previous call to save(), and is used to remove all + modifications to the matrix/clip state since the last save call. It is + an error to call restore() more times than save() was called. + */ + virtual void restore(); + + /** Returns the number of matrix/clip states on the SkCanvas' private stack. + This will equal # save() calls - # restore() calls. + */ + int getSaveCount() const; + + /** Efficient way to pop any calls to save() that happened after the save + count reached saveCount. It is an error for saveCount to be less than + getSaveCount() + @param saveCount The number of save() levels to restore from + */ + void restoreToCount(int saveCount); + + /** Preconcat the current matrix with the specified translation + @param dx The distance to translate in X + @param dy The distance to translate in Y + returns true if the operation succeeded (e.g. did not overflow) + */ + virtual bool translate(SkScalar dx, SkScalar dy); + + /** Preconcat the current matrix with the specified scale. + @param sx The amount to scale in X + @param sy The amount to scale in Y + returns true if the operation succeeded (e.g. did not overflow) + */ + virtual bool scale(SkScalar sx, SkScalar sy); + + /** Preconcat the current matrix with the specified rotation. + @param degrees The amount to rotate, in degrees + returns true if the operation succeeded (e.g. did not overflow) + */ + virtual bool rotate(SkScalar degrees); + + /** Preconcat the current matrix with the specified skew. + @param sx The amount to skew in X + @param sy The amount to skew in Y + returns true if the operation succeeded (e.g. did not overflow) + */ + virtual bool skew(SkScalar sx, SkScalar sy); + + /** Preconcat the current matrix with the specified matrix. + @param matrix The matrix to preconcatenate with the current matrix + @return true if the operation succeeded (e.g. did not overflow) + */ + virtual bool concat(const SkMatrix& matrix); + + /** Replace the current matrix with a copy of the specified matrix. + @param matrix The matrix that will be copied into the current matrix. + */ + virtual void setMatrix(const SkMatrix& matrix); + + /** Helper for setMatrix(identity). Sets the current matrix to identity. + */ + void resetMatrix(); + + /** Modify the current clip with the specified rectangle. + @param rect The rect to intersect with the current clip + @param op The region op to apply to the current clip + @return true if the canvas' clip is non-empty + */ + virtual bool clipRect(const SkRect& rect, + SkRegion::Op op = SkRegion::kIntersect_Op); + + /** Modify the current clip with the specified path. + @param path The path to apply to the current clip + @param op The region op to apply to the current clip + @return true if the canvas' new clip is non-empty + */ + virtual bool clipPath(const SkPath& path, + SkRegion::Op op = SkRegion::kIntersect_Op); + + /** Modify the current clip with the specified region. Note that unlike + clipRect() and clipPath() which transform their arguments by the current + matrix, clipRegion() assumes its argument is already in device + coordinates, and so no transformation is performed. + @param deviceRgn The region to apply to the current clip + @param op The region op to apply to the current clip + @return true if the canvas' new clip is non-empty + */ + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op op = SkRegion::kIntersect_Op); + + /** Helper for clipRegion(rgn, kReplace_Op). Sets the current clip to the + specified region. This does not intersect or in any other way account + for the existing clip region. + @param deviceRgn The region to copy into the current clip. + @return true if the new clip region is non-empty + */ + bool setClipRegion(const SkRegion& deviceRgn) { + return this->clipRegion(deviceRgn, SkRegion::kReplace_Op); + } + + /** Enum describing how to treat edges when performing quick-reject tests + of a geometry against the current clip. Treating them as antialiased + (kAA_EdgeType) will take into account the extra pixels that may be drawn + if the edge does not lie exactly on a device pixel boundary (after being + transformed by the current matrix). + */ + enum EdgeType { + /** Treat the edges as B&W (not antialiased) for the purposes of testing + against the current clip + */ + kBW_EdgeType, + /** Treat the edges as antialiased for the purposes of testing + against the current clip + */ + kAA_EdgeType + }; + + /** Return true if the specified rectangle, after being transformed by the + current matrix, would lie completely outside of the current clip. Call + this to check if an area you intend to draw into is clipped out (and + therefore you can skip making the draw calls). + @param rect the rect to compare with the current clip + @param et specifies how to treat the edges (see EdgeType) + @return true if the rect (transformed by the canvas' matrix) does not + intersect with the canvas' clip + */ + bool quickReject(const SkRect& rect, EdgeType et) const; + + /** Return true if the specified path, after being transformed by the + current matrix, would lie completely outside of the current clip. Call + this to check if an area you intend to draw into is clipped out (and + therefore you can skip making the draw calls). Note, for speed it may + return false even if the path itself might not intersect the clip + (i.e. the bounds of the path intersects, but the path does not). + @param path The path to compare with the current clip + @param et specifies how to treat the edges (see EdgeType) + @return true if the path (transformed by the canvas' matrix) does not + intersect with the canvas' clip + */ + bool quickReject(const SkPath& path, EdgeType et) const; + + /** Return true if the horizontal band specified by top and bottom is + completely clipped out. This is a conservative calculation, meaning + that it is possible that if the method returns false, the band may still + in fact be clipped out, but the converse is not true. If this method + returns true, then the band is guaranteed to be clipped out. + @param top The top of the horizontal band to compare with the clip + @param bottom The bottom of the horizontal and to compare with the clip + @return true if the horizontal band is completely clipped out (i.e. does + not intersect the current clip) + */ + bool quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const; + + /** Return the bounds of the current clip (in local coordinates) in the + bounds parameter, and return true if it is non-empty. This can be useful + in a way similar to quickReject, in that it tells you that drawing + outside of these bounds will be clipped out. + */ + bool getClipBounds(SkRect* bounds, EdgeType et = kAA_EdgeType) const; + + /** Fill the entire canvas' bitmap (restricted to the current clip) with the + specified ARGB color, using the specified PorterDuff mode. + @param a the alpha component (0..255) of the color to fill the canvas + @param r the red component (0..255) of the color to fill the canvas + @param g the green component (0..255) of the color to fill the canvas + @param b the blue component (0..255) of the color to fill the canvas + @param mode the mode to apply the color in (defaults to SrcOver) + */ + void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, + SkPorterDuff::Mode mode = SkPorterDuff::kSrcOver_Mode); + + /** Fill the entire canvas' bitmap (restricted to the current clip) with the + specified color and porter-duff xfermode. + @param color the color to draw with + @param mode the mode to apply the color in (defaults to SrcOver) + */ + void drawColor(SkColor color, + SkPorterDuff::Mode mode = SkPorterDuff::kSrcOver_Mode); + + /** Fill the entire canvas' bitmap (restricted to the current clip) with the + specified paint. + @param paint The paint used to fill the canvas + */ + virtual void drawPaint(const SkPaint& paint); + + enum PointMode { + /** drawPoints draws each point separately */ + kPoints_PointMode, + /** drawPoints draws each pair of points as a line segment */ + kLines_PointMode, + /** drawPoints draws the array of points as a polygon */ + kPolygon_PointMode + }; + + /** Draw a series of points, interpreted based on the PointMode mode. For + all modes, the count parameter is interpreted as the total number of + points. For kLine mode, count/2 line segments are drawn. + For kPoint mode, each point is drawn centered at its coordinate, and its + size is specified by the paint's stroke-width. It draws as a square, + unless the paint's cap-type is round, in which the points are drawn as + circles. + For kLine mode, each pair of points is drawn as a line segment, + respecting the paint's settings for cap/join/width. + For kPolygon mode, the entire array is drawn as a series of connected + line segments. + Note that, while similar, kLine and kPolygon modes draw slightly + differently than the equivalent path built with a series of moveto, + lineto calls, in that the path will draw all of its contours at once, + with no interactions if contours intersect each other (think XOR + xfermode). drawPoints always draws each element one at a time. + @param mode PointMode specifying how to draw the array of points. + @param count The number of points in the array + @param pts Array of points to draw + @param paint The paint used to draw the points + */ + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint); + + /** Helper method for drawing a single point. See drawPoints() for a more + details. + */ + void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draws a single pixel in the specified color. + @param x The X coordinate of which pixel to draw + @param y The Y coordiante of which pixel to draw + @param color The color to draw + */ + void drawPoint(SkScalar x, SkScalar y, SkColor color); + + /** Draw a line segment with the specified start and stop x,y coordinates, + using the specified paint. NOTE: since a line is always "framed", the + paint's Style is ignored. + @param x0 The x-coordinate of the start point of the line + @param y0 The y-coordinate of the start point of the line + @param x1 The x-coordinate of the end point of the line + @param y1 The y-coordinate of the end point of the line + @param paint The paint used to draw the line + */ + void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, + const SkPaint& paint); + + /** Draw the specified rectangle using the specified paint. The rectangle + will be filled or stroked based on the Style in the paint. + @param rect The rect to be drawn + @param paint The paint used to draw the rect + */ + virtual void drawRect(const SkRect& rect, const SkPaint& paint); + + /** Draw the specified rectangle using the specified paint. The rectangle + will be filled or framed based on the Style in the paint. + @param rect The rect to be drawn + @param paint The paint used to draw the rect + */ + void drawIRect(const SkIRect& rect, const SkPaint& paint) + { + SkRect r; + r.set(rect); // promotes the ints to scalars + this->drawRect(r, paint); + } + + /** Draw the specified rectangle using the specified paint. The rectangle + will be filled or framed based on the Style in the paint. + @param left The left side of the rectangle to be drawn + @param top The top side of the rectangle to be drawn + @param right The right side of the rectangle to be drawn + @param bottom The bottom side of the rectangle to be drawn + @param paint The paint used to draw the rect + */ + void drawRectCoords(SkScalar left, SkScalar top, SkScalar right, + SkScalar bottom, const SkPaint& paint); + + /** Draw the specified oval using the specified paint. The oval will be + filled or framed based on the Style in the paint. + @param oval The rectangle bounds of the oval to be drawn + @param paint The paint used to draw the oval + */ + void drawOval(const SkRect& oval, const SkPaint&); + + /** Draw the specified circle using the specified paint. If radius is <= 0, + then nothing will be drawn. The circle will be filled + or framed based on the Style in the paint. + @param cx The x-coordinate of the center of the cirle to be drawn + @param cy The y-coordinate of the center of the cirle to be drawn + @param radius The radius of the cirle to be drawn + @param paint The paint used to draw the circle + */ + void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, + const SkPaint& paint); + + /** Draw the specified arc, which will be scaled to fit inside the + specified oval. If the sweep angle is >= 360, then the oval is drawn + completely. Note that this differs slightly from SkPath::arcTo, which + treats the sweep angle mod 360. + @param oval The bounds of oval used to define the shape of the arc + @param startAngle Starting angle (in degrees) where the arc begins + @param sweepAngle Sweep angle (in degrees) measured clockwise + @param useCenter true means include the center of the oval. For filling + this will draw a wedge. False means just use the arc. + @param paint The paint used to draw the arc + */ + void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint); + + /** Draw the specified round-rect using the specified paint. The round-rect + will be filled or framed based on the Style in the paint. + @param rect The rectangular bounds of the roundRect to be drawn + @param rx The x-radius of the oval used to round the corners + @param ry The y-radius of the oval used to round the corners + @param paint The paint used to draw the roundRect + */ + void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, + const SkPaint& paint); + + /** Draw the specified path using the specified paint. The path will be + filled or framed based on the Style in the paint. + @param path The path to be drawn + @param paint The paint used to draw the path + */ + virtual void drawPath(const SkPath& path, const SkPaint& paint); + + /** Draw the specified bitmap, with its top/left corner at (x,y), using the + specified paint, transformed by the current matrix. Note: if the paint + contains a maskfilter that generates a mask which extends beyond the + bitmap's original width/height, then the bitmap will be drawn as if it + were in a Shader with CLAMP mode. Thus the color outside of the original + width/height will be the edge color replicated. + @param bitmap The bitmap to be drawn + @param left The position of the left side of the bitmap being drawn + @param top The position of the top side of the bitmap being drawn + @param paint The paint used to draw the bitmap, or NULL + */ + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint = NULL); + + /** Draw the specified bitmap, with the specified matrix applied (before the + canvas' matrix is applied). + @param bitmap The bitmap to be drawn + @param src Optional: specify the subset of the bitmap to be drawn + @param dst The destination rectangle where the scaled/translated + image will be drawn + @param paint The paint used to draw the bitmap, or NULL + */ + virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, + const SkRect& dst, const SkPaint* paint = NULL); + + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint = NULL); + + /** Draw the specified bitmap, with its top/left corner at (x,y), + NOT transformed by the current matrix. Note: if the paint + contains a maskfilter that generates a mask which extends beyond the + bitmap's original width/height, then the bitmap will be drawn as if it + were in a Shader with CLAMP mode. Thus the color outside of the original + width/height will be the edge color replicated. + @param bitmap The bitmap to be drawn + @param left The position of the left side of the bitmap being drawn + @param top The position of the top side of the bitmap being drawn + @param paint The paint used to draw the bitmap, or NULL + */ + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint = NULL); + + /** Draw the text, with origin at (x,y), using the specified paint. + The origin is interpreted based on the Align setting in the paint. + @param text The text to be drawn + @param byteLength The number of bytes to read from the text parameter + @param x The x-coordinate of the origin of the text being drawn + @param y The y-coordinate of the origin of the text being drawn + @param paint The paint used for the text (e.g. color, size, style) + */ + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint); + + /** Draw the text, with each character/glyph origin specified by the pos[] + array. The origin is interpreted by the Align setting in the paint. + @param text The text to be drawn + @param byteLength The number of bytes to read from the text parameter + @param pos Array of positions, used to position each character + @param paint The paint used for the text (e.g. color, size, style) + */ + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint); + + /** Draw the text, with each character/glyph origin specified by the x + coordinate taken from the xpos[] array, and the y from the constY param. + The origin is interpreted by the Align setting in the paint. + @param text The text to be drawn + @param byteLength The number of bytes to read from the text parameter + @param xpos Array of x-positions, used to position each character + @param constY The shared Y coordinate for all of the positions + @param paint The paint used for the text (e.g. color, size, style) + */ + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint); + + /** Draw the text, with origin at (x,y), using the specified paint, along + the specified path. The paint's Align setting determins where along the + path to start the text. + @param text The text to be drawn + @param byteLength The number of bytes to read from the text parameter + @param path The path the text should follow for its baseline + @param hOffset The distance along the path to add to the text's + starting position + @param vOffset The distance above(-) or below(+) the path to + position the text + @param paint The paint used for the text + */ + void drawTextOnPathHV(const void* text, size_t byteLength, + const SkPath& path, SkScalar hOffset, + SkScalar vOffset, const SkPaint& paint); + + /** Draw the text, with origin at (x,y), using the specified paint, along + the specified path. The paint's Align setting determins where along the + path to start the text. + @param text The text to be drawn + @param byteLength The number of bytes to read from the text parameter + @param path The path the text should follow for its baseline + @param matrix (may be null) Applied to the text before it is + mapped onto the path + @param paint The paint used for the text + */ + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint); + + /** Draw the picture into this canvas. This method effective brackets the + playback of the picture's draw calls with save/restore, so the state + of this canvas will be unchanged after this call. This contrasts with + the more immediate method SkPicture::draw(), which does not bracket + the canvas with save/restore, thus the canvas may be left in a changed + state after the call. + @param picture The recorded drawing commands to playback into this + canvas. + */ + virtual void drawPicture(SkPicture& picture); + + enum VertexMode { + kTriangles_VertexMode, + kTriangleStrip_VertexMode, + kTriangleFan_VertexMode + }; + + /** Draw the array of vertices, interpreted as triangles (based on mode). + @param vmode How to interpret the array of vertices + @param vertexCount The number of points in the vertices array (and + corresponding texs and colors arrays if non-null) + @param vertices Array of vertices for the mesh + @param texs May be null. If not null, specifies the coordinate + in texture space for each vertex. + @param colors May be null. If not null, specifies a color for each + vertex, to be interpolated across the triangle. + @param xmode Used if both texs and colors are present. In this + case the colors are combined with the texture using mode, + before being drawn using the paint. If mode is null, then + the porter-duff MULTIPLY mode is used. + @param indices If not null, array of indices to reference into the + vertex (texs, colors) array. + @param indexCount number of entries in the indices array (if not null) + @param paint Specifies the shader/texture if present. + */ + virtual void drawVertices(VertexMode vmode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint); + + ////////////////////////////////////////////////////////////////////////// + + /** Get the current bounder object. + The bounder's reference count is unchaged. + @return the canva's bounder (or NULL). + */ + SkBounder* getBounder() const { return fBounder; } + + /** Set a new bounder (or NULL). + Pass NULL to clear any previous bounder. + As a convenience, the parameter passed is also returned. + If a previous bounder exists, its reference count is decremented. + If bounder is not NULL, its reference count is incremented. + @param bounder the new bounder (or NULL) to be installed in the canvas + @return the set bounder object + */ + virtual SkBounder* setBounder(SkBounder* bounder); + + /** Get the current filter object. The filter's reference count is not + affected. The filter is part of the state this is affected by + save/restore. + @return the canvas' filter (or NULL). + */ + SkDrawFilter* getDrawFilter() const; + + /** Set the new filter (or NULL). Pass NULL to clear any existing filter. + As a convenience, the parameter is returned. If an existing filter + exists, its refcnt is decrement. If the new filter is not null, its + refcnt is incremented. The filter is part of the state this is affected + by save/restore. + @param filter the new filter (or NULL) + @return the new filter + */ + virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter); + + ////////////////////////////////////////////////////////////////////////// + + /** Return the current matrix on the canvas. + This does not account for the translate in any of the devices. + @return The current matrix on the canvas. + */ + const SkMatrix& getTotalMatrix() const; + + /** Return the current device clip (concatenation of all clip calls). + This does not account for the translate in any of the devices. + @return the current device clip (concatenation of all clip calls). + */ + const SkRegion& getTotalClip() const; + + /** May be overridden by subclasses. This returns a compatible device + for this canvas, with the specified config/width/height. If isOpaque + is true, then the underlying bitmap is optimized to assume that every + pixel will be drawn to, and thus it does not need to clear the alpha + channel ahead of time (assuming the specified config supports per-pixel + alpha.) If isOpaque is false, then the bitmap should clear its alpha + channel. + */ + virtual SkDevice* createDevice(SkBitmap::Config, int width, int height, + bool isOpaque, bool isForLayer); + + /////////////////////////////////////////////////////////////////////////// + + /** After calling saveLayer(), there can be any number of devices that make + up the top-most drawing area. LayerIter can be used to iterate through + those devices. Note that the iterator is only valid until the next API + call made on the canvas. Ownership of all pointers in the iterator stays + with the canvas, so none of them should be modified or deleted. + */ + class LayerIter /*: SkNoncopyable*/ { + public: + /** Initialize iterator with canvas, and set values for 1st device */ + LayerIter(SkCanvas*, bool skipEmptyClips); + ~LayerIter(); + + /** Return true if the iterator is done */ + bool done() const { return fDone; } + /** Cycle to the next device */ + void next(); + + // These reflect the current device in the iterator + + SkDevice* device() const; + const SkMatrix& matrix() const; + const SkRegion& clip() const; + const SkPaint& paint() const; + int x() const; + int y() const; + + private: + // used to embed the SkDrawIter object directly in our instance, w/o + // having to expose that class def to the public. There is an assert + // in our constructor to ensure that fStorage is large enough + // (though needs to be a compile-time-assert!). We use intptr_t to work + // safely with 32 and 64 bit machines (to ensure the storage is enough) + intptr_t fStorage[12]; + class SkDrawIter* fImpl; // this points at fStorage + SkPaint fDefaultPaint; + bool fDone; + }; + +protected: + // all of the drawBitmap variants call this guy + virtual void commonDrawBitmap(const SkBitmap&, const SkMatrix& m, + const SkPaint& paint); + +private: + class MCRec; + + SkDeque fMCStack; + // points to top of stack + MCRec* fMCRec; + // the first N recs that can fit here mean we won't call malloc + uint32_t fMCRecStorage[32]; + + SkBounder* fBounder; + + void prepareForDeviceDraw(SkDevice*); + + bool fDeviceCMDirty; // cleared by updateDeviceCMCache() + void updateDeviceCMCache(); + + friend class SkDrawIter; // needs setupDrawForLayerDevice() + + SkDevice* init(SkDevice*); + void internalDrawBitmap(const SkBitmap&, const SkMatrix& m, + const SkPaint* paint); + void drawDevice(SkDevice*, int x, int y, const SkPaint*); + // shared by save() and saveLayer() + int internalSave(SaveFlags flags); + void internalRestore(); + + /* These maintain a cache of the clip bounds in local coordinates, + (converted to 2s-compliment if floats are slow). + */ + mutable SkRectCompareType fLocalBoundsCompareType; + mutable bool fLocalBoundsCompareTypeDirty; + + const SkRectCompareType& getLocalClipBoundsCompareType() const { + if (fLocalBoundsCompareTypeDirty) { + this->computeLocalClipBoundsCompareType(); + fLocalBoundsCompareTypeDirty = false; + } + return fLocalBoundsCompareType; + } + void computeLocalClipBoundsCompareType() const; +}; + +/** 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 : SkNoncopyable { +public: + SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas) { + SkASSERT(canvas); + fSaveCount = canvas->getSaveCount(); + if (doSave) { + canvas->save(); + } + } + ~SkAutoCanvasRestore() { + fCanvas->restoreToCount(fSaveCount); + } + +private: + SkCanvas* fCanvas; + int fSaveCount; +}; + +#endif + diff --git a/include/core/SkChunkAlloc.h b/include/core/SkChunkAlloc.h new file mode 100644 index 0000000000..0e9ad189cd --- /dev/null +++ b/include/core/SkChunkAlloc.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkChunkAlloc_DEFINED +#define SkChunkAlloc_DEFINED + +#include "SkTypes.h" + +class SkChunkAlloc : SkNoncopyable { +public: + SkChunkAlloc(size_t minSize); + ~SkChunkAlloc(); + + /** Free up all allocated blocks. This invalidates all returned + pointers. + */ + void reset(); + + /** Reuse all allocated blocks. This invalidates all returned + pointers (like reset) but doesn't necessarily free up all + of the privately allocated blocks. This is more efficient + if you plan to reuse the allocator multiple times. + */ + void reuse(); + + enum AllocFailType { + kReturnNil_AllocFailType, + kThrow_AllocFailType + }; + + void* alloc(size_t bytes, AllocFailType); + void* allocThrow(size_t bytes) { + return this->alloc(bytes, kThrow_AllocFailType); + } + + size_t totalCapacity() const { return fTotalCapacity; } + +private: + struct Block; + Block* fBlock; + size_t fMinSize; + Block* fPool; + size_t fTotalCapacity; + + Block* newBlock(size_t bytes, AllocFailType ftype); +}; + +#endif diff --git a/include/core/SkColor.h b/include/core/SkColor.h new file mode 100644 index 0000000000..c97a8ec4d1 --- /dev/null +++ b/include/core/SkColor.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkColor_DEFINED +#define SkColor_DEFINED + +#include "SkScalar.h" + +/** \file SkColor.h + + Types and macros for colors +*/ + +/** 8-bit type for an alpha value. 0xFF is 100% opaque, 0x00 is 100% transparent. +*/ +typedef uint8_t SkAlpha; +/** 32 bit ARGB color value, not premultiplied. The color components are always in + a known order. This is different from SkPMColor, which has its bytes in a configuration + dependent order, to match the format of kARGB32 bitmaps. SkColor is the type used to + specify colors in SkPaint and in gradients. +*/ +typedef uint32_t SkColor; + +/** Return a SkColor value from 8 bit component values +*/ +static inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) +{ + SkASSERT(a <= 255 && r <= 255 && g <= 255 && b <= 255); + + return (a << 24) | (r << 16) | (g << 8) | (b << 0); +} + +/** Return a SkColor value from 8 bit component values, with an implied value + of 0xFF for alpha (fully opaque) +*/ +#define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b) + +/** return the alpha byte from a SkColor value */ +#define SkColorGetA(color) (((color) >> 24) & 0xFF) +/** return the red byte from a SkColor value */ +#define SkColorGetR(color) (((color) >> 16) & 0xFF) +/** return the green byte from a SkColor value */ +#define SkColorGetG(color) (((color) >> 8) & 0xFF) +/** return the blue byte from a SkColor value */ +#define SkColorGetB(color) (((color) >> 0) & 0xFF) + +static inline SkColor SkColorSetA(SkColor c, U8CPU a) { + return (c & 0x00FFFFFF) | (a << 24); +} + +// common colors + +#define SK_ColorBLACK 0xFF000000 //!< black SkColor value +#define SK_ColorDKGRAY 0xFF444444 //!< dark gray SkColor value +#define SK_ColorGRAY 0xFF888888 //!< gray SkColor value +#define SK_ColorLTGRAY 0xFFCCCCCC //!< light gray SkColor value +#define SK_ColorWHITE 0xFFFFFFFF //!< white SkColor value + +#define SK_ColorRED 0xFFFF0000 //!< red SkColor value +#define SK_ColorGREEN 0xFF00FF00 //!< green SkColor value +#define SK_ColorBLUE 0xFF0000FF //!< blue SkColor value +#define SK_ColorYELLOW 0xFFFFFF00 //!< yellow SkColor value +#define SK_ColorCYAN 0xFF00FFFF //!< cyan SkColor value +#define SK_ColorMAGENTA 0xFFFF00FF //!< magenta SkColor value + +//////////////////////////////////////////////////////////////////////// + +/** Convert RGB components to HSV. + hsv[0] is Hue [0 .. 360) + hsv[1] is Saturation [0...1] + hsv[2] is Value [0...1] + @param red red component value [0..255] + @param green green component value [0..255] + @param blue blue component value [0..255] + @param hsv 3 element array which holds the resulting HSV components. +*/ +void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]); + +/** Convert the argb color to its HSV components. + hsv[0] is Hue [0 .. 360) + hsv[1] is Saturation [0...1] + hsv[2] is Value [0...1] + @param color the argb color to convert. Note: the alpha component is ignored. + @param hsv 3 element array which holds the resulting HSV components. +*/ +static inline void SkColorToHSV(SkColor color, SkScalar hsv[3]) +{ + SkRGBToHSV(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), hsv); +} + +/** Convert HSV components to an ARGB color. The alpha component is passed through unchanged. + hsv[0] is Hue [0 .. 360) + hsv[1] is Saturation [0...1] + hsv[2] is Value [0...1] + If hsv values are out of range, they are pinned. + @param alpha the alpha component of the returned argb color. + @param hsv 3 element array which holds the input HSV components. + @return the resulting argb color +*/ +SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]); + +/** Convert HSV components to an ARGB color. The alpha component set to 0xFF. + hsv[0] is Hue [0 .. 360) + hsv[1] is Saturation [0...1] + hsv[2] is Value [0...1] + If hsv values are out of range, they are pinned. + @param hsv 3 element array which holds the input HSV components. + @return the resulting argb color +*/ +static inline SkColor SkHSVToColor(const SkScalar hsv[3]) +{ + return SkHSVToColor(0xFF, hsv); +} + +//////////////////////////////////////////////////////////////////////// + +/** 32 bit ARGB color value, premultiplied. The byte order for this value is + configuration dependent, matching the format of kARGB32 bitmaps. This is different + from SkColor, which is nonpremultiplied, and is always in the same byte order. +*/ +typedef uint32_t SkPMColor; + +/** Return a SkPMColor value from unpremultiplied 8 bit component values +*/ +SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); +/** Return a SkPMColor value from a SkColor value. This is done by multiplying the color + components by the color's alpha, and by arranging the bytes in a configuration + dependent order, to match the format of kARGB32 bitmaps. +*/ +SkPMColor SkPreMultiplyColor(SkColor c); + +/** Define a function pointer type for combining two premultiplied colors +*/ +typedef SkPMColor (*SkXfermodeProc)(SkPMColor src, SkPMColor dst); + +/** Define a function pointer type for combining a premultiplied src color + and a 16bit device color. +*/ +typedef uint16_t (*SkXfermodeProc16)(SkPMColor src, uint16_t dst); + +#endif + diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h new file mode 100644 index 0000000000..a1b3171fdd --- /dev/null +++ b/include/core/SkColorFilter.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkColorFilter_DEFINED +#define SkColorFilter_DEFINED + +#include "SkColor.h" +#include "SkFlattenable.h" +#include "SkPorterDuff.h" + +class SkColorFilter : public SkFlattenable { +public: + /** Called with a scanline of colors, as if there was a shader installed. + The implementation writes out its filtered version into result[]. + Note: shader and result may be the same buffer. + @param src array of colors, possibly generated by a shader + @param count the number of entries in the src[] and result[] arrays + @param result written by the filter + */ + virtual void filterSpan(const SkPMColor src[], int count, + SkPMColor result[]) = 0; + /** Called with a scanline of colors, as if there was a shader installed. + The implementation writes out its filtered version into result[]. + Note: shader and result may be the same buffer. + @param src array of colors, possibly generated by a shader + @param count the number of entries in the src[] and result[] arrays + @param result written by the filter + */ + virtual void filterSpan16(const uint16_t shader[], int count, + uint16_t result[]); + + enum Flags { + /** If set the filter methods will not change the alpha channel of the + colors. + */ + kAlphaUnchanged_Flag = 0x01, + /** If set, this subclass implements filterSpan16(). If this flag is + set, then kAlphaUnchanged_Flag must also be set. + */ + kHasFilter16_Flag = 0x02 + }; + + /** Returns the flags for this filter. Override in subclasses to return + custom flags. + */ + virtual uint32_t getFlags() { return 0; } + + /** Create a colorfilter that uses the specified color and porter-duff mode. + If porterDuffMode is DST, this function will return NULL (since that + mode will have no effect on the result). + @param srcColor The source color used with the specified mode + @param mode The porter-duff mode that is applied to each color in + the colorfilter's filterSpan[16,32] methods + @return colorfilter object that applies the src color and porter-duff + mode, or NULL if the mode will have no effect. + */ + static SkColorFilter* CreatePorterDuffFilter(SkColor srcColor, + SkPorterDuff::Mode mode); + + /** Create a colorfilter that calls through to the specified procs to + filter the colors. The SkXfermodeProc parameter must be non-null, but + the SkXfermodeProc16 is optional, and may be null. + */ + static SkColorFilter* CreatXfermodeProcFilter(SkColor srcColor, + SkXfermodeProc proc, + SkXfermodeProc16 proc16 = NULL); + + /** Create a colorfilter that multiplies the RGB channels by one color, and + then adds a second color, pinning the result for each component to + [0..255]. The alpha components of the mul and add arguments + are ignored. + */ + static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add); + +protected: + SkColorFilter() {} + SkColorFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {} + +private: + typedef SkFlattenable INHERITED; +}; + +#include "SkShader.h" + +class SkFilterShader : public SkShader { +public: + SkFilterShader(SkShader* shader, SkColorFilter* filter); + virtual ~SkFilterShader(); + + // override + virtual uint32_t getFlags(); + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix); + virtual void shadeSpan(int x, int y, SkPMColor result[], int count); + virtual void shadeSpan16(int x, int y, uint16_t result[], int count); + virtual void beginSession(); + virtual void endSession(); + +protected: + SkFilterShader(SkFlattenableReadBuffer& ); + virtual void flatten(SkFlattenableWriteBuffer& ); + virtual Factory getFactory() { return CreateProc; } +private: + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkFilterShader, (buffer)); } + SkShader* fShader; + SkColorFilter* fFilter; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/include/core/SkColorPriv.h b/include/core/SkColorPriv.h new file mode 100644 index 0000000000..041c0380a0 --- /dev/null +++ b/include/core/SkColorPriv.h @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkColorPriv_DEFINED +#define SkColorPriv_DEFINED + +// turn this own for extra debug checking when blending onto 565 +#ifdef SK_DEBUG + #define CHECK_FOR_565_OVERFLOW +#endif + +#include "SkColor.h" +#include "SkMath.h" + +/** Turn 0..255 into 0..256 by adding 1 at the half-way point. Used to turn a + byte into a scale value, so that we can say scale * value >> 8 instead of + alpha * value / 255. + + In debugging, asserts that alpha is 0..255 +*/ +static inline unsigned SkAlpha255To256(U8CPU alpha) { + SkASSERT(SkToU8(alpha) == alpha); + return alpha + (alpha >> 7); +} + +/** Multiplify value by 0..256, and shift the result down 8 + (i.e. return (value * alpha256) >> 8) + */ +#define SkAlphaMul(value, alpha256) (SkMulS16(value, alpha256) >> 8) + +// The caller may want negative values, so keep all params signed (int) +// so we don't accidentally slip into unsigned math and lose the sign +// extension when we shift (in SkAlphaMul) +inline int SkAlphaBlend(int src, int dst, int scale256) { + SkASSERT((unsigned)scale256 <= 256); + return dst + SkAlphaMul(src - dst, scale256); +} + +#define SK_R16_BITS 5 +#define SK_G16_BITS 6 +#define SK_B16_BITS 5 + +#define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS) +#define SK_G16_SHIFT (SK_B16_BITS) +#define SK_B16_SHIFT 0 + +#define SK_R16_MASK ((1 << SK_R16_BITS) - 1) +#define SK_G16_MASK ((1 << SK_G16_BITS) - 1) +#define SK_B16_MASK ((1 << SK_B16_BITS) - 1) + +#define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK) +#define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK) +#define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK) + +#define SkR16Assert(r) SkASSERT((unsigned)(r) <= SK_R16_MASK) +#define SkG16Assert(g) SkASSERT((unsigned)(g) <= SK_G16_MASK) +#define SkB16Assert(b) SkASSERT((unsigned)(b) <= SK_B16_MASK) + +static inline uint16_t SkPackRGB16(unsigned r, unsigned g, unsigned b) { + SkASSERT(r <= SK_R16_MASK); + SkASSERT(g <= SK_G16_MASK); + SkASSERT(b <= SK_B16_MASK); + + return SkToU16((r << SK_R16_SHIFT) | (g << SK_G16_SHIFT) | (b << SK_B16_SHIFT)); +} + +#define SK_R16_MASK_IN_PLACE (SK_R16_MASK << SK_R16_SHIFT) +#define SK_G16_MASK_IN_PLACE (SK_G16_MASK << SK_G16_SHIFT) +#define SK_B16_MASK_IN_PLACE (SK_B16_MASK << SK_B16_SHIFT) + +/** Expand the 16bit color into a 32bit value that can be scaled all at once + by a value up to 32. Used in conjunction with SkCompact_rgb_16. +*/ +static inline uint32_t SkExpand_rgb_16(U16CPU c) { + SkASSERT(c == (uint16_t)c); + + return ((c & SK_G16_MASK_IN_PLACE) << 16) | (c & ~SK_G16_MASK_IN_PLACE); +} + +/** Compress an expanded value (from SkExpand_rgb_16) back down to a 16bit + color value. The computation yields only 16bits of valid data, but we claim + to return 32bits, so that the compiler won't generate extra instructions to + "clean" the top 16bits. However, the top 16 can contain garbage, so it is + up to the caller to safely ignore them. +*/ +static inline U16CPU SkCompact_rgb_16(uint32_t c) { + return ((c >> 16) & SK_G16_MASK_IN_PLACE) | (c & ~SK_G16_MASK_IN_PLACE); +} + +/** Scale the 16bit color value by the 0..256 scale parameter. + The computation yields only 16bits of valid data, but we claim + to return 32bits, so that the compiler won't generate extra instructions to + "clean" the top 16bits. +*/ +static inline U16CPU SkAlphaMulRGB16(U16CPU c, unsigned scale) { + return SkCompact_rgb_16(SkExpand_rgb_16(c) * (scale >> 3) >> 5); +} + +// this helper explicitly returns a clean 16bit value (but slower) +#define SkAlphaMulRGB16_ToU16(c, s) (uint16_t)SkAlphaMulRGB16(c, s) + +/** Blend src and dst 16bit colors by the 0..256 scale parameter. + The computation yields only 16bits of valid data, but we claim + to return 32bits, so that the compiler won't generate extra instructions to + "clean" the top 16bits. +*/ +static inline U16CPU SkBlendRGB16(U16CPU src, U16CPU dst, int srcScale) { + SkASSERT((unsigned)srcScale <= 256); + + srcScale >>= 3; + + uint32_t src32 = SkExpand_rgb_16(src); + uint32_t dst32 = SkExpand_rgb_16(dst); + return SkCompact_rgb_16(dst32 + ((src32 - dst32) * srcScale >> 5)); +} + +static inline void SkBlendRGB16(const uint16_t src[], uint16_t dst[], + int srcScale, int count) { + SkASSERT(count > 0); + SkASSERT((unsigned)srcScale <= 256); + + srcScale >>= 3; + + do { + uint32_t src32 = SkExpand_rgb_16(*src++); + uint32_t dst32 = SkExpand_rgb_16(*dst); + *dst++ = SkCompact_rgb_16(dst32 + ((src32 - dst32) * srcScale >> 5)); + } while (--count > 0); +} + +#ifdef SK_DEBUG + static U16CPU SkRGB16Add(U16CPU a, U16CPU b) { + SkASSERT(SkGetPackedR16(a) + SkGetPackedR16(b) <= SK_R16_MASK); + SkASSERT(SkGetPackedG16(a) + SkGetPackedG16(b) <= SK_G16_MASK); + SkASSERT(SkGetPackedB16(a) + SkGetPackedB16(b) <= SK_B16_MASK); + + return a + b; + } +#else + #define SkRGB16Add(a, b) ((a) + (b)) +#endif + +///////////////////////////////////////////////////////////////////////////////////////////// + +#define SK_A32_BITS 8 +#define SK_R32_BITS 8 +#define SK_G32_BITS 8 +#define SK_B32_BITS 8 + +/* we check to see if the SHIFT value has already been defined (SkUserConfig.h) + if not, we define it ourself to some default values. We default to OpenGL + order (in memory: r,g,b,a) +*/ +#ifndef SK_A32_SHIFT + #ifdef SK_CPU_BENDIAN + #define SK_R32_SHIFT 24 + #define SK_G32_SHIFT 16 + #define SK_B32_SHIFT 8 + #define SK_A32_SHIFT 0 + #else + #define SK_R32_SHIFT 0 + #define SK_G32_SHIFT 8 + #define SK_B32_SHIFT 16 + #define SK_A32_SHIFT 24 + #endif +#endif + +#define SK_A32_MASK ((1 << SK_A32_BITS) - 1) +#define SK_R32_MASK ((1 << SK_R32_BITS) - 1) +#define SK_G32_MASK ((1 << SK_G32_BITS) - 1) +#define SK_B32_MASK ((1 << SK_B32_BITS) - 1) + +#define SkGetPackedA32(packed) ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24) +#define SkGetPackedR32(packed) ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24) +#define SkGetPackedG32(packed) ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24) +#define SkGetPackedB32(packed) ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24) + +#define SkA32Assert(a) SkASSERT((unsigned)(a) <= SK_A32_MASK) +#define SkR32Assert(r) SkASSERT((unsigned)(r) <= SK_R32_MASK) +#define SkG32Assert(g) SkASSERT((unsigned)(g) <= SK_G32_MASK) +#define SkB32Assert(b) SkASSERT((unsigned)(b) <= SK_B32_MASK) + +#ifdef SK_DEBUG + inline void SkPMColorAssert(SkPMColor c) { + unsigned a = SkGetPackedA32(c); + unsigned r = SkGetPackedR32(c); + unsigned g = SkGetPackedG32(c); + unsigned b = SkGetPackedB32(c); + + SkA32Assert(a); + SkASSERT(r <= a); + SkASSERT(g <= a); + SkASSERT(b <= a); + } +#else + #define SkPMColorAssert(c) +#endif + +inline SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkA32Assert(a); + SkASSERT(r <= a); + SkASSERT(g <= a); + SkASSERT(b <= a); + + return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) | + (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT); +} + +extern const uint32_t gMask_00FF00FF; + +inline uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) { + uint32_t mask = gMask_00FF00FF; +// uint32_t mask = 0xFF00FF; + + uint32_t rb = ((c & mask) * scale) >> 8; + uint32_t ag = ((c >> 8) & mask) * scale; + return (rb & mask) | (ag & ~mask); +} + +inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) { + return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); +} + +inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { + SkASSERT((unsigned)aa <= 255); + + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlpha255To256(255 - SkAlphaMul(SkGetPackedA32(src), src_scale)); + + return SkAlphaMulQ(src, src_scale) + SkAlphaMulQ(dst, dst_scale); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 32bit pixel to a 16bit pixel (no dither) + +#define SkR32ToR16_MACRO(r) ((unsigned)(r) >> (SK_R32_BITS - SK_R16_BITS)) +#define SkG32ToG16_MACRO(g) ((unsigned)(g) >> (SK_G32_BITS - SK_G16_BITS)) +#define SkB32ToB16_MACRO(b) ((unsigned)(b) >> (SK_B32_BITS - SK_B16_BITS)) + +#ifdef SK_DEBUG + inline unsigned SkR32ToR16(unsigned r) + { + SkR32Assert(r); + return SkR32ToR16_MACRO(r); + } + inline unsigned SkG32ToG16(unsigned g) + { + SkG32Assert(g); + return SkG32ToG16_MACRO(g); + } + inline unsigned SkB32ToB16(unsigned b) + { + SkB32Assert(b); + return SkB32ToB16_MACRO(b); + } +#else + #define SkR32ToR16(r) SkR32ToR16_MACRO(r) + #define SkG32ToG16(g) SkG32ToG16_MACRO(g) + #define SkB32ToB16(b) SkB32ToB16_MACRO(b) +#endif + +#define SkPacked32ToR16(c) (((unsigned)(c) >> (SK_R32_SHIFT + SK_R32_BITS - SK_R16_BITS)) & SK_R16_MASK) +#define SkPacked32ToG16(c) (((unsigned)(c) >> (SK_G32_SHIFT + SK_G32_BITS - SK_G16_BITS)) & SK_G16_MASK) +#define SkPacked32ToB16(c) (((unsigned)(c) >> (SK_B32_SHIFT + SK_B32_BITS - SK_B16_BITS)) & SK_B16_MASK) + +inline U16CPU SkPixel32ToPixel16(SkPMColor c) +{ + unsigned r = ((c >> (SK_R32_SHIFT + (8 - SK_R16_BITS))) & SK_R16_MASK) << SK_R16_SHIFT; + unsigned g = ((c >> (SK_G32_SHIFT + (8 - SK_G16_BITS))) & SK_G16_MASK) << SK_G16_SHIFT; + unsigned b = ((c >> (SK_B32_SHIFT + (8 - SK_B16_BITS))) & SK_B16_MASK) << SK_B16_SHIFT; + return r | g | b; +} + +inline U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b) +{ + return (SkR32ToR16(r) << SK_R16_SHIFT) | + (SkG32ToG16(g) << SK_G16_SHIFT) | + (SkB32ToB16(b) << SK_B16_SHIFT); +} + +#define SkPixel32ToPixel16_ToU16(src) SkToU16(SkPixel32ToPixel16(src)) + +///////////////////////////////////////////////////////////////////////////////////////// +// Fast dither from 32->16 + +#define SkShouldDitherXY(x, y) (((x) ^ (y)) & 1) + +inline uint16_t SkDitherPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b) +{ + r = ((r << 1) - ((r >> (8 - SK_R16_BITS) << (8 - SK_R16_BITS)) | (r >> SK_R16_BITS))) >> (8 - SK_R16_BITS); + g = ((g << 1) - ((g >> (8 - SK_G16_BITS) << (8 - SK_G16_BITS)) | (g >> SK_G16_BITS))) >> (8 - SK_G16_BITS); + b = ((b << 1) - ((b >> (8 - SK_B16_BITS) << (8 - SK_B16_BITS)) | (b >> SK_B16_BITS))) >> (8 - SK_B16_BITS); + + return SkPackRGB16(r, g, b); +} + +inline uint16_t SkDitherPixel32ToPixel16(SkPMColor c) +{ + return SkDitherPack888ToRGB16(SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c)); +} + +/* Return c in expanded_rgb_16 format, but also scaled up by 32 (5 bits) + It is now suitable for combining with a scaled expanded_rgb_16 color + as in SkSrcOver32To16(). + We must do this 565 high-bit replication, in order for the subsequent add + to saturate properly (and not overflow). If we take the 8 bits as is, it is + possible to overflow. +*/ +static inline uint32_t SkPMColorToExpanded16x5(SkPMColor c) +{ + unsigned sr = SkPacked32ToR16(c); + unsigned sg = SkPacked32ToG16(c); + unsigned sb = SkPacked32ToB16(c); + + sr = (sr << 5) | sr; + sg = (sg << 5) | (sg >> 1); + sb = (sb << 5) | sb; + return (sr << 11) | (sg << 21) | (sb << 0); +} + +/* SrcOver the 32bit src color with the 16bit dst, returning a 16bit value + (with dirt in the high 16bits, so caller beware). +*/ +static inline U16CPU SkSrcOver32To16(SkPMColor src, uint16_t dst) { + unsigned sr = SkGetPackedR32(src); + unsigned sg = SkGetPackedG32(src); + unsigned sb = SkGetPackedB32(src); + + unsigned dr = SkGetPackedR16(dst); + unsigned dg = SkGetPackedG16(dst); + unsigned db = SkGetPackedB16(dst); + + unsigned isa = 255 - SkGetPackedA32(src); + + dr = (sr + SkMul16ShiftRound(dr, isa, SK_R16_BITS)) >> (8 - SK_R16_BITS); + dg = (sg + SkMul16ShiftRound(dg, isa, SK_G16_BITS)) >> (8 - SK_G16_BITS); + db = (sb + SkMul16ShiftRound(db, isa, SK_B16_BITS)) >> (8 - SK_B16_BITS); + + return SkPackRGB16(dr, dg, db); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 16bit pixel to a 32bit pixel + +inline unsigned SkR16ToR32(unsigned r) +{ + return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); +} +inline unsigned SkG16ToG32(unsigned g) +{ + return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); +} +inline unsigned SkB16ToB32(unsigned b) +{ + return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8)); +} + +#define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c)) +#define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c)) +#define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c)) + +inline SkPMColor SkPixel16ToPixel32(U16CPU src) +{ + SkASSERT(src == SkToU16(src)); + + unsigned r = SkPacked16ToR32(src); + unsigned g = SkPacked16ToG32(src); + unsigned b = SkPacked16ToB32(src); + + SkASSERT((r >> (8 - SK_R16_BITS)) == SkGetPackedR16(src)); + SkASSERT((g >> (8 - SK_G16_BITS)) == SkGetPackedG16(src)); + SkASSERT((b >> (8 - SK_B16_BITS)) == SkGetPackedB16(src)); + + return SkPackARGB32(0xFF, r, g, b); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint16_t SkPMColor16; + +// Put in OpenGL order (r g b a) +#define SK_A4444_SHIFT 0 +#define SK_R4444_SHIFT 12 +#define SK_G4444_SHIFT 8 +#define SK_B4444_SHIFT 4 + +#define SkA32To4444(a) ((unsigned)(a) >> 4) +#define SkR32To4444(r) ((unsigned)(r) >> 4) +#define SkG32To4444(g) ((unsigned)(g) >> 4) +#define SkB32To4444(b) ((unsigned)(b) >> 4) + +static U8CPU SkReplicateNibble(unsigned nib) +{ + SkASSERT(nib <= 0xF); + return (nib << 4) | nib; +} + +#define SkA4444ToA32(a) SkReplicateNibble(a) +#define SkR4444ToR32(r) SkReplicateNibble(r) +#define SkG4444ToG32(g) SkReplicateNibble(g) +#define SkB4444ToB32(b) SkReplicateNibble(b) + +#define SkGetPackedA4444(c) (((unsigned)(c) >> SK_A4444_SHIFT) & 0xF) +#define SkGetPackedR4444(c) (((unsigned)(c) >> SK_R4444_SHIFT) & 0xF) +#define SkGetPackedG4444(c) (((unsigned)(c) >> SK_G4444_SHIFT) & 0xF) +#define SkGetPackedB4444(c) (((unsigned)(c) >> SK_B4444_SHIFT) & 0xF) + +#define SkPacked4444ToA32(c) SkReplicateNibble(SkGetPackedA4444(c)) +#define SkPacked4444ToR32(c) SkReplicateNibble(SkGetPackedR4444(c)) +#define SkPacked4444ToG32(c) SkReplicateNibble(SkGetPackedG4444(c)) +#define SkPacked4444ToB32(c) SkReplicateNibble(SkGetPackedB4444(c)) + +#ifdef SK_DEBUG +static inline void SkPMColor16Assert(U16CPU c) +{ + unsigned a = SkGetPackedA4444(c); + unsigned r = SkGetPackedR4444(c); + unsigned g = SkGetPackedG4444(c); + unsigned b = SkGetPackedB4444(c); + + SkASSERT(a <= 0xF); + SkASSERT(r <= a); + SkASSERT(g <= a); + SkASSERT(b <= a); +} +#else +#define SkPMColor16Assert(c) +#endif + +static inline unsigned SkAlpha15To16(unsigned a) +{ + SkASSERT(a <= 0xF); + return a + (a >> 3); +} + +#ifdef SK_DEBUG + static inline int SkAlphaMul4(int value, int scale) + { + SkASSERT((unsigned)scale <= 0x10); + return value * scale >> 4; + } +#else + #define SkAlphaMul4(value, scale) ((value) * (scale) >> 4) +#endif + +static inline unsigned SkR4444ToR565(unsigned r) +{ + SkASSERT(r <= 0xF); + return (r << (SK_R16_BITS - 4)) | (r >> (8 - SK_R16_BITS)); +} + +static inline unsigned SkG4444ToG565(unsigned g) +{ + SkASSERT(g <= 0xF); + return (g << (SK_G16_BITS - 4)) | (g >> (8 - SK_G16_BITS)); +} + +static inline unsigned SkB4444ToB565(unsigned b) +{ + SkASSERT(b <= 0xF); + return (b << (SK_B16_BITS - 4)) | (b >> (8 - SK_B16_BITS)); +} + +static inline SkPMColor16 SkPackARGB4444(unsigned a, unsigned r, + unsigned g, unsigned b) +{ + SkASSERT(a <= 0xF); + SkASSERT(r <= a); + SkASSERT(g <= a); + SkASSERT(b <= a); + + return (SkPMColor16)((a << SK_A4444_SHIFT) | (r << SK_R4444_SHIFT) | + (g << SK_G4444_SHIFT) | (b << SK_B4444_SHIFT)); +} + +extern const uint16_t gMask_0F0F; + +inline U16CPU SkAlphaMulQ4(U16CPU c, unsigned scale) +{ + SkASSERT(scale <= 16); + + const unsigned mask = 0xF0F; //gMask_0F0F; + +#if 0 + unsigned rb = ((c & mask) * scale) >> 4; + unsigned ag = ((c >> 4) & mask) * scale; + return (rb & mask) | (ag & ~mask); +#else + c = (c & mask) | ((c & (mask << 4)) << 12); + c = c * scale >> 4; + return (c & mask) | ((c >> 12) & (mask << 4)); +#endif +} + +/** Expand the SkPMColor16 color into a 32bit value that can be scaled all at + once by a value up to 16. Used in conjunction with SkCompact_4444. +*/ +inline uint32_t SkExpand_4444(U16CPU c) +{ + SkASSERT(c == (uint16_t)c); + + const unsigned mask = 0xF0F; //gMask_0F0F; + return (c & mask) | ((c & ~mask) << 12); +} + +/** Compress an expanded value (from SkExpand_4444) back down to a SkPMColor16. + NOTE: this explicitly does not clean the top 16 bits (which may be garbage). + It does this for speed, since if it is being written directly to 16bits of + memory, the top 16bits will be ignored. Casting the result to uint16_t here + would add 2 more instructions, slow us down. It is up to the caller to + perform the cast if needed. +*/ +static inline U16CPU SkCompact_4444(uint32_t c) +{ + const unsigned mask = 0xF0F; //gMask_0F0F; + return (c & mask) | ((c >> 12) & ~mask); +} + +static inline uint16_t SkSrcOver4444To16(SkPMColor16 s, uint16_t d) +{ + unsigned sa = SkGetPackedA4444(s); + unsigned sr = SkR4444ToR565(SkGetPackedR4444(s)); + unsigned sg = SkG4444ToG565(SkGetPackedG4444(s)); + unsigned sb = SkB4444ToB565(SkGetPackedB4444(s)); + + // To avoid overflow, we have to clear the low bit of the synthetic sg + // if the src alpha is <= 7. + // to see why, try blending 0x4444 on top of 565-white and watch green + // overflow (sum == 64) + sg &= ~(~(sa >> 3) & 1); + + unsigned scale = SkAlpha15To16(15 - sa); + unsigned dr = SkAlphaMul4(SkGetPackedR16(d), scale); + unsigned dg = SkAlphaMul4(SkGetPackedG16(d), scale); + unsigned db = SkAlphaMul4(SkGetPackedB16(d), scale); + +#if 0 + if (sg + dg > 63) { + SkDebugf("---- SkSrcOver4444To16 src=%x dst=%x scale=%d, sg=%d dg=%d\n", s, d, scale, sg, dg); + } +#endif + return SkPackRGB16(sr + dr, sg + dg, sb + db); +} + +static inline uint16_t SkBlend4444To16(SkPMColor16 src, uint16_t dst, int scale16) +{ + SkASSERT((unsigned)scale16 <= 16); + + return SkSrcOver4444To16(SkAlphaMulQ4(src, scale16), dst); +} + +static inline uint16_t SkBlend4444(SkPMColor16 src, SkPMColor16 dst, int scale16) +{ + SkASSERT((unsigned)scale16 <= 16); + + uint32_t src32 = SkExpand_4444(src) * scale16; + // the scaled srcAlpha is the bottom byte +#ifdef SK_DEBUG + { + unsigned srcA = SkGetPackedA4444(src) * scale16; + SkASSERT(srcA == (src32 & 0xFF)); + } +#endif + unsigned dstScale = SkAlpha255To256(255 - (src32 & 0xFF)) >> 4; + uint32_t dst32 = SkExpand_4444(dst) * dstScale; + return SkCompact_4444((src32 + dst32) >> 4); +} + +static inline SkPMColor SkPixel4444ToPixel32(U16CPU c) +{ + uint32_t d = (SkGetPackedA4444(c) << SK_A32_SHIFT) | + (SkGetPackedR4444(c) << SK_R32_SHIFT) | + (SkGetPackedG4444(c) << SK_G32_SHIFT) | + (SkGetPackedB4444(c) << SK_B32_SHIFT); + return d | (d << 4); +} + +static inline SkPMColor16 SkPixel32ToPixel4444(SkPMColor c) +{ + return (((c >> (SK_A32_SHIFT + 4)) & 0xF) << SK_A4444_SHIFT) | + (((c >> (SK_R32_SHIFT + 4)) & 0xF) << SK_R4444_SHIFT) | + (((c >> (SK_G32_SHIFT + 4)) & 0xF) << SK_G4444_SHIFT) | + (((c >> (SK_B32_SHIFT + 4)) & 0xF) << SK_B4444_SHIFT); +} + +// cheap 2x2 dither +static inline SkPMColor16 SkDitherARGB32To4444(U8CPU a, U8CPU r, + U8CPU g, U8CPU b) +{ + a = ((a << 1) - ((a >> 4 << 4) | (a >> 4))) >> 4; + r = ((r << 1) - ((r >> 4 << 4) | (r >> 4))) >> 4; + g = ((g << 1) - ((g >> 4 << 4) | (g >> 4))) >> 4; + b = ((b << 1) - ((b >> 4 << 4) | (b >> 4))) >> 4; + + return SkPackARGB4444(a, r, g, b); +} + +static inline SkPMColor16 SkDitherPixel32To4444(SkPMColor c) +{ + return SkDitherARGB32To4444(SkGetPackedA32(c), SkGetPackedR32(c), + SkGetPackedG32(c), SkGetPackedB32(c)); +} + +/* Assumes 16bit is in standard RGBA order. + Transforms a normal ARGB_8888 into the same byte order as + expanded ARGB_4444, but keeps each component 8bits +*/ +static uint32_t SkExpand_8888(SkPMColor c) +{ + return (((c >> SK_R32_SHIFT) & 0xFF) << 24) | + (((c >> SK_G32_SHIFT) & 0xFF) << 8) | + (((c >> SK_B32_SHIFT) & 0xFF) << 16) | + (((c >> SK_A32_SHIFT) & 0xFF) << 0); +} + +/* Undo the operation of SkExpand_8888, turning the argument back into + a SkPMColor. +*/ +static SkPMColor SkCompact_8888(uint32_t c) +{ + return (((c >> 24) & 0xFF) << SK_R32_SHIFT) | + (((c >> 8) & 0xFF) << SK_G32_SHIFT) | + (((c >> 16) & 0xFF) << SK_B32_SHIFT) | + (((c >> 0) & 0xFF) << SK_A32_SHIFT); +} + +/* Like SkExpand_8888, this transforms a pmcolor into the expanded 4444 format, + but this routine just keeps the high 4bits of each component in the low + 4bits of the result (just like a newly expanded PMColor16). +*/ +static uint32_t SkExpand32_4444(SkPMColor c) +{ + return (((c >> (SK_R32_SHIFT + 4)) & 0xF) << 24) | + (((c >> (SK_G32_SHIFT + 4)) & 0xF) << 8) | + (((c >> (SK_B32_SHIFT + 4)) & 0xF) << 16) | + (((c >> (SK_A32_SHIFT + 4)) & 0xF) << 0); +} + +// takes two values and alternamtes them as part of a memset16 +// used for cheap 2x2 dithering when the colors are opaque +void sk_dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, int n); + +#endif + diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h new file mode 100644 index 0000000000..f9c3dc33d2 --- /dev/null +++ b/include/core/SkColorShader.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkColorShader_DEFINED +#define SkColorShader_DEFINED + +#include "SkShader.h" + +/** \class SkColorShader + A Shader that represents a single color. In general, this effect can be + accomplished by just using the color field on the paint, but if an + actual shader object is needed, this provides that feature. +*/ +class SkColorShader : public SkShader { +public: + /** Create a ColorShader that will inherit its color from the Paint + at draw time. + */ + SkColorShader() : fInheritColor(true) {} + /** Create a ColorShader that ignores the color in the paint, and uses the + specified color. Note: like all shaders, at draw time the paint's alpha + will be respected, and is applied to the specified color. + */ + SkColorShader(SkColor c) : fColor(c), fInheritColor(false) {} + + virtual uint32_t getFlags(); + virtual uint8_t getSpan16Alpha() const; + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix); + virtual void shadeSpan(int x, int y, SkPMColor span[], int count); + virtual void shadeSpan16(int x, int y, uint16_t span[], int count); + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); + +protected: + SkColorShader(SkFlattenableReadBuffer& ); + virtual void flatten(SkFlattenableWriteBuffer& ); + virtual Factory getFactory() { return CreateProc; } +private: + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkColorShader, (buffer)); + } + SkColor fColor; // ignored if fInheritColor is true + SkPMColor fPMColor; // cached after setContext() + uint16_t fColor16; // cached after setContext() + SkBool8 fInheritColor; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/include/core/SkComposeShader.h b/include/core/SkComposeShader.h new file mode 100644 index 0000000000..0b198f61da --- /dev/null +++ b/include/core/SkComposeShader.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkComposeShader_DEFINED +#define SkComposeShader_DEFINED + +#include "SkShader.h" + +class SkXfermode; + +/////////////////////////////////////////////////////////////////////////////////////////// + +/** \class SkComposeShader + This subclass of shader returns the coposition of two other shaders, combined by + a xfermode. +*/ +class SkComposeShader : public SkShader { +public: + /** Create a new compose shader, given shaders A, B, and a combining xfermode mode. + When the xfermode is called, it will be given the result from shader A as its + "dst", and the result of from shader B as its "src". + mode->xfer32(sA_result, sB_result, ...) + @param shaderA The colors from this shader are seen as the "dst" by the xfermode + @param shaderB The colors from this shader are seen as the "src" by the xfermode + @param mode The xfermode that combines the colors from the two shaders. If mode + is null, then SRC_OVER is assumed. + */ + SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode = NULL); + virtual ~SkComposeShader(); + + // override + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix); + virtual void shadeSpan(int x, int y, SkPMColor result[], int count); + virtual void beginSession(); + virtual void endSession(); + +protected: + SkComposeShader(SkFlattenableReadBuffer& ); + virtual void flatten(SkFlattenableWriteBuffer& ); + virtual Factory getFactory() { return CreateProc; } + +private: + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkComposeShader, (buffer)); } + + SkShader* fShaderA; + SkShader* fShaderB; + SkXfermode* fMode; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/include/core/SkDeque.h b/include/core/SkDeque.h new file mode 100644 index 0000000000..cbed930088 --- /dev/null +++ b/include/core/SkDeque.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDeque_DEFINED +#define SkDeque_DEFINED + +#include "SkTypes.h" + +class SkDeque : SkNoncopyable { +public: + explicit SkDeque(size_t elemSize); + SkDeque(size_t elemSize, void* storage, size_t storageSize); + ~SkDeque(); + + bool empty() const { return 0 == fCount; } + int count() const { return fCount; } + size_t elemSize() const { return fElemSize; } + + const void* front() const; + const void* back() const; + + void* front() { + return (void*)((const SkDeque*)this)->front(); + } + + void* back() { + return (void*)((const SkDeque*)this)->back(); + } + + void* push_front(); + void* push_back(); + + void pop_front(); + void pop_back(); + +private: + struct Head; + +public: + class Iter { + public: + Iter(const SkDeque& d); + void* next(); + + private: + SkDeque::Head* fHead; + char* fPos; + size_t fElemSize; + }; + +private: + Head* fFront; + Head* fBack; + size_t fElemSize; + void* fInitialStorage; + int fCount; + + friend class Iter; +}; + +#endif diff --git a/include/core/SkDescriptor.h b/include/core/SkDescriptor.h new file mode 100644 index 0000000000..8074cff2b8 --- /dev/null +++ b/include/core/SkDescriptor.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDescriptor_DEFINED +#define SkDescriptor_DEFINED + +#include "SkTypes.h" + +class SkDescriptor : SkNoncopyable { +public: + static size_t ComputeOverhead(int entryCount) + { + SkASSERT(entryCount >= 0); + return sizeof(SkDescriptor) + entryCount * sizeof(Entry); + } + + static SkDescriptor* Alloc(size_t length) + { + SkASSERT(SkAlign4(length) == length); + SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length); + return desc; + } + + static void Free(SkDescriptor* desc) + { + sk_free(desc); + } + + void init() + { + fLength = sizeof(SkDescriptor); + fCount = 0; + } + + uint32_t getLength() const { return fLength; } + + void* addEntry(uint32_t tag, uint32_t length, const void* data = NULL) + { + SkASSERT(tag); + SkASSERT(SkAlign4(length) == length); + SkASSERT(this->findEntry(tag, NULL) == NULL); + + Entry* entry = (Entry*)((char*)this + fLength); + entry->fTag = tag; + entry->fLen = length; + if (data) + memcpy(entry + 1, data, length); + + fCount += 1; + fLength += sizeof(Entry) + length; + return (entry + 1); // return its data + } + + void computeChecksum() + { + fChecksum = SkDescriptor::ComputeChecksum(this); + } + +#ifdef SK_DEBUG + void assertChecksum() const + { + SkASSERT(fChecksum == SkDescriptor::ComputeChecksum(this)); + } +#endif + + const void* findEntry(uint32_t tag, uint32_t* length) const + { + const Entry* entry = (const Entry*)(this + 1); + int count = fCount; + + while (--count >= 0) + { + if (entry->fTag == tag) + { + if (length) + *length = entry->fLen; + return entry + 1; + } + entry = (const Entry*)((const char*)(entry + 1) + entry->fLen); + } + return NULL; + } + + SkDescriptor* copy() const + { + SkDescriptor* desc = SkDescriptor::Alloc(fLength); + memcpy(desc, this, fLength); + return desc; + } + + bool equals(const SkDescriptor& other) const + { + // probe to see if we have a good checksum algo +// SkASSERT(a.fChecksum != b.fChecksum || memcmp(&a, &b, a.fLength) == 0); + + // the first value we should look at is the checksum, so this loop + // should terminate early if they descriptors are different. + // NOTE: if we wrote a sentinel value at the end of each, we chould + // remove the aa < stop test in the loop... + const uint32_t* aa = (const uint32_t*)this; + const uint32_t* bb = (const uint32_t*)&other; + const uint32_t* stop = (const uint32_t*)((const char*)aa + fLength); + do { + if (*aa++ != *bb++) + return false; + } while (aa < stop); + return true; + } + + struct Entry { + uint32_t fTag; + uint32_t fLen; + }; + +#ifdef SK_DEBUG + uint32_t getChecksum() const { return fChecksum; } + uint32_t getCount() const { return fCount; } +#endif + +private: + uint32_t fChecksum; // must be first + uint32_t fLength; // must be second + uint32_t fCount; + + static uint32_t ComputeChecksum(const SkDescriptor* desc) + { + const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field + const uint32_t* stop = (const uint32_t*)((const char*)desc + desc->fLength); + uint32_t sum = 0; + + SkASSERT(ptr < stop); + do { + sum = (sum << 1) | (sum >> 31); + sum ^= *ptr++; + } while (ptr < stop); + + return sum; + } + + // private so no one can create one except our factories + SkDescriptor() {} +}; + +#include "SkScalerContext.h" + +class SkAutoDescriptor : SkNoncopyable { +public: + SkAutoDescriptor(size_t size) + { + if (size <= sizeof(fStorage)) + fDesc = (SkDescriptor*)(void*)fStorage; + else + fDesc = SkDescriptor::Alloc(size); + } + ~SkAutoDescriptor() + { + if (fDesc != (SkDescriptor*)(void*)fStorage) + SkDescriptor::Free(fDesc); + } + SkDescriptor* getDesc() const { return fDesc; } +private: + enum { + kStorageSize = sizeof(SkDescriptor) + + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec) // for rec + + sizeof(SkDescriptor::Entry) + sizeof(void*) // for typeface + + 32 // slop for occational small extras + }; + SkDescriptor* fDesc; + uint32_t fStorage[(kStorageSize + 3) >> 2]; +}; + + +#endif + diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h new file mode 100644 index 0000000000..4d678c6a40 --- /dev/null +++ b/include/core/SkDevice.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDevice_DEFINED +#define SkDevice_DEFINED + +#include "SkRefCnt.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColor.h" + +class SkDraw; +struct SkIRect; +class SkMatrix; +class SkRegion; + +class SkDevice : public SkRefCnt { +public: + SkDevice(); + /** Construct a new device, extracting the width/height/config/isOpaque values from + the bitmap. If transferPixelOwnership is true, and the bitmap claims to own its + own pixels (getOwnsPixels() == true), then transfer this responsibility to the + device, and call setOwnsPixels(false) on the bitmap. + + Subclasses may override the destructor, which is virtual, even though this class + doesn't have one. SkRefCnt does. + + @param bitmap A copy of this bitmap is made and stored in the device + */ + SkDevice(const SkBitmap& bitmap); + + /** Return the width of the device (in pixels). + */ + int width() const { return fBitmap.width(); } + /** Return the height of the device (in pixels). + */ + int height() const { return fBitmap.height(); } + /** Return the bitmap config of the device's pixels + */ + SkBitmap::Config config() const { return fBitmap.getConfig(); } + /** Returns true if the device's bitmap's config treats every pixels as + implicitly opaque. + */ + bool isOpaque() const { return fBitmap.isOpaque(); } + + /** Return the bounds of the device + */ + void getBounds(SkIRect* bounds) const; + + /** Return true if the specified rectangle intersects the bounds of the + device. If sect is not NULL and there is an intersection, sect returns + the intersection. + */ + bool intersects(const SkIRect& r, SkIRect* sect = NULL) const; + + /** Return the bitmap associated with this device. Call this each time you need + to access the bitmap, as it notifies the subclass to perform any flushing + etc. before you examine the pixels. + @param changePixels set to true if the caller plans to change the pixels + @return the device's bitmap + */ + const SkBitmap& accessBitmap(bool changePixels); + + /** Helper to erase the entire device to the specified color (including + alpha). + */ + void eraseColor(SkColor eraseColor); + + /** Called when this device is installed into a Canvas. Balanaced by a call + to unlockPixels() when the device is removed from a Canvas. + */ + virtual void lockPixels(); + virtual void unlockPixels(); + + /** Called with the correct matrix and clip before this device is drawn + to using those settings. If your subclass overrides this, be sure to + call through to the base class as well. + */ + virtual void setMatrixClip(const SkMatrix&, const SkRegion&); + + /** Called when this device gains focus (i.e becomes the current device + for drawing). + */ + virtual void gainFocus(SkCanvas*) {} + + /** These are called inside the per-device-layer loop for each draw call. + When these are called, we have already applied any saveLayer operations, + and are handling any looping from the paint, and any effects from the + DrawFilter. + */ + virtual void drawPaint(const SkDraw&, const SkPaint& paint); + virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, + const SkPoint[], const SkPaint& paint); + virtual void drawRect(const SkDraw&, const SkRect& r, + const SkPaint& paint); + virtual void drawPath(const SkDraw&, const SkPath& path, + const SkPaint& paint); + virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + const SkMatrix& matrix, const SkPaint& paint); + virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, + int x, int y, const SkPaint& paint); + virtual void drawText(const SkDraw&, const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint); + virtual void drawPosText(const SkDraw&, const void* text, size_t len, + const SkScalar pos[], SkScalar constY, + int scalarsPerPos, const SkPaint& paint); + virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint); + virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, + const SkPoint verts[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint); + virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&); + +protected: + /** Update as needed the pixel value in the bitmap, so that the caller can access + the pixels directly. Note: only the pixels field should be altered. The config/width/height/rowbytes + must remain unchanged. + */ + virtual void onAccessBitmap(SkBitmap*); + +private: + SkBitmap fBitmap; +}; + +#endif diff --git a/include/core/SkDither.h b/include/core/SkDither.h new file mode 100644 index 0000000000..5b2552d1c1 --- /dev/null +++ b/include/core/SkDither.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDither_DEFINED +#define SkDither_DEFINED + +#include "SkColorPriv.h" + +#define SK_DitherValueMax4444 15 +#define SK_DitherValueMax565 7 + +/* need to use macros for bit-counts for each component, and then + move these into SkColorPriv.h +*/ + +#define SkDITHER_R32_FOR_565_MACRO(r, d) (r + d - (r >> 5)) +#define SkDITHER_G32_FOR_565_MACRO(g, d) (g + (d >> 1) - (g >> 6)) +#define SkDITHER_B32_FOR_565_MACRO(b, d) (b + d - (b >> 5)) + +#define SkDITHER_A32_FOR_4444_MACRO(a, d) (a + 15 - (a >> 4)) +#define SkDITHER_R32_FOR_4444_MACRO(r, d) (r + d - (r >> 4)) +#define SkDITHER_G32_FOR_4444_MACRO(g, d) (g + d - (g >> 4)) +#define SkDITHER_B32_FOR_4444_MACRO(b, d) (b + d - (b >> 4)) + +#ifdef SK_DEBUG + inline unsigned SkDITHER_R32_FOR_565(unsigned r, unsigned d) + { + SkASSERT(d <= SK_DitherValueMax565); + SkA32Assert(r); + r = SkDITHER_R32_FOR_565_MACRO(r, d); + SkA32Assert(r); + return r; + } + inline unsigned SkDITHER_G32_FOR_565(unsigned g, unsigned d) + { + SkASSERT(d <= SK_DitherValueMax565); + SkG32Assert(g); + g = SkDITHER_G32_FOR_565_MACRO(g, d); + SkG32Assert(g); + return g; + } + inline unsigned SkDITHER_B32_FOR_565(unsigned b, unsigned d) + { + SkASSERT(d <= SK_DitherValueMax565); + SkB32Assert(b); + b = SkDITHER_B32_FOR_565_MACRO(b, d); + SkB32Assert(b); + return b; + } +#else + #define SkDITHER_R32_FOR_565(r, d) SkDITHER_R32_FOR_565_MACRO(r, d) + #define SkDITHER_G32_FOR_565(g, d) SkDITHER_G32_FOR_565_MACRO(g, d) + #define SkDITHER_B32_FOR_565(b, d) SkDITHER_B32_FOR_565_MACRO(b, d) +#endif + +#define SkDITHER_R32To565(r, d) SkR32ToR16(SkDITHER_R32_FOR_565(r, d)) +#define SkDITHER_G32To565(g, d) SkG32ToG16(SkDITHER_G32_FOR_565(g, d)) +#define SkDITHER_B32To565(b, d) SkB32ToB16(SkDITHER_B32_FOR_565(b, d)) + +#define SkDITHER_A32To4444(a, d) SkA32To4444(SkDITHER_A32_FOR_4444_MACRO(a, d)) +#define SkDITHER_R32To4444(r, d) SkR32To4444(SkDITHER_R32_FOR_4444_MACRO(r, d)) +#define SkDITHER_G32To4444(g, d) SkG32To4444(SkDITHER_G32_FOR_4444_MACRO(g, d)) +#define SkDITHER_B32To4444(b, d) SkB32To4444(SkDITHER_B32_FOR_4444_MACRO(b, d)) + +static inline SkPMColor SkDitherARGB32For565(SkPMColor c, unsigned dither) +{ + SkASSERT(dither <= SK_DitherValueMax565); + + unsigned sa = SkGetPackedA32(c); + dither = SkAlphaMul(dither, SkAlpha255To256(sa)); + + unsigned sr = SkGetPackedR32(c); + unsigned sg = SkGetPackedG32(c); + unsigned sb = SkGetPackedB32(c); + sr = SkDITHER_R32_FOR_565(sr, dither); + sg = SkDITHER_G32_FOR_565(sg, dither); + sb = SkDITHER_B32_FOR_565(sb, dither); + + return SkPackARGB32(sa, sr, sg, sb); +} + +static inline SkPMColor SkDitherRGB32For565(SkPMColor c, unsigned dither) +{ + SkASSERT(dither <= SK_DitherValueMax565); + + unsigned sr = SkGetPackedR32(c); + unsigned sg = SkGetPackedG32(c); + unsigned sb = SkGetPackedB32(c); + sr = SkDITHER_R32_FOR_565(sr, dither); + sg = SkDITHER_G32_FOR_565(sg, dither); + sb = SkDITHER_B32_FOR_565(sb, dither); + + return SkPackARGB32(0xFF, sr, sg, sb); +} + +static inline uint16_t SkDitherRGBTo565(U8CPU r, U8CPU g, U8CPU b, + unsigned dither) +{ + SkASSERT(dither <= SK_DitherValueMax565); + r = SkDITHER_R32To565(r, dither); + g = SkDITHER_G32To565(g, dither); + b = SkDITHER_B32To565(b, dither); + return SkPackRGB16(r, g, b); +} + +static inline uint16_t SkDitherRGB32To565(SkPMColor c, unsigned dither) +{ + SkASSERT(dither <= SK_DitherValueMax565); + + unsigned sr = SkGetPackedR32(c); + unsigned sg = SkGetPackedG32(c); + unsigned sb = SkGetPackedB32(c); + sr = SkDITHER_R32To565(sr, dither); + sg = SkDITHER_G32To565(sg, dither); + sb = SkDITHER_B32To565(sb, dither); + + return SkPackRGB16(sr, sg, sb); +} + +static inline uint16_t SkDitherARGB32To565(U8CPU sa, SkPMColor c, unsigned dither) +{ + SkASSERT(dither <= SK_DitherValueMax565); + dither = SkAlphaMul(dither, SkAlpha255To256(sa)); + + unsigned sr = SkGetPackedR32(c); + unsigned sg = SkGetPackedG32(c); + unsigned sb = SkGetPackedB32(c); + sr = SkDITHER_R32To565(sr, dither); + sg = SkDITHER_G32To565(sg, dither); + sb = SkDITHER_B32To565(sb, dither); + + return SkPackRGB16(sr, sg, sb); +} + +///////////////////////// 4444 + +static inline SkPMColor16 SkDitherARGB32To4444(U8CPU a, U8CPU r, U8CPU g, + U8CPU b, unsigned dither) +{ + dither = SkAlphaMul(dither, SkAlpha255To256(a)); + + a = SkDITHER_A32To4444(a, dither); + r = SkDITHER_R32To4444(r, dither); + g = SkDITHER_G32To4444(g, dither); + b = SkDITHER_B32To4444(b, dither); + + return SkPackARGB4444(a, r, g, b); +} + +static inline SkPMColor16 SkDitherARGB32To4444(SkPMColor c, unsigned dither) +{ + unsigned a = SkGetPackedA32(c); + unsigned r = SkGetPackedR32(c); + unsigned g = SkGetPackedG32(c); + unsigned b = SkGetPackedB32(c); + + dither = SkAlphaMul(dither, SkAlpha255To256(a)); + + a = SkDITHER_A32To4444(a, dither); + r = SkDITHER_R32To4444(r, dither); + g = SkDITHER_G32To4444(g, dither); + b = SkDITHER_B32To4444(b, dither); + + return SkPackARGB4444(a, r, g, b); +} + +// TODO: need dither routines for 565 -> 4444 + +// this toggles between a 4x4 and a 1x4 array +//#define ENABLE_DITHER_MATRIX_4X4 + +#ifdef ENABLE_DITHER_MATRIX_4X4 + extern const uint8_t gDitherMatrix_4Bit_4X4[4][4]; + extern const uint8_t gDitherMatrix_3Bit_4X4[4][4]; + + #define DITHER_4444_SCAN(y) const uint8_t* dither_scan = gDitherMatrix_4Bit_4X4[(y) & 3] + #define DITHER_565_SCAN(y) const uint8_t* dither_scan = gDitherMatrix_3Bit_4X4[(y) & 3] + + #define DITHER_VALUE(x) dither_scan[(x) & 3] +#else + extern const uint16_t gDitherMatrix_4Bit_16[4]; + extern const uint16_t gDitherMatrix_3Bit_16[4]; + + #define DITHER_4444_SCAN(y) const uint16_t dither_scan = gDitherMatrix_4Bit_16[(y) & 3] + #define DITHER_565_SCAN(y) const uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3] + + #define DITHER_VALUE(x) ((dither_scan >> (((x) & 3) << 2)) & 0xF) +#endif + +#define DITHER_INC_X(x) ++(x) + +#endif diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h new file mode 100644 index 0000000000..2d775a4272 --- /dev/null +++ b/include/core/SkDraw.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDraw_DEFINED +#define SkDraw_DEFINED + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkMask.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkRect.h" +#include "SkAutoKern.h" + +class SkBounder; +class SkDevice; +class SkPath; +class SkRegion; +struct SkDrawProcs; + +class SkDraw { +public: + SkDraw() : fDevice(NULL), fBounder(NULL), fProcs(NULL) {} + SkDraw(const SkDraw& src); + + void drawPaint(const SkPaint&) const; + void drawPoints(SkCanvas::PointMode, size_t count, const SkPoint[], + const SkPaint&) const; + void drawRect(const SkRect&, const SkPaint&) const; + /* To save on mallocs, we allow a flag that tells us that srcPath is + mutable, so that we don't have to make copies of it as we transform it. + */ + void drawPath(const SkPath& srcPath, const SkPaint&, + const SkMatrix* prePathMatrix, bool pathIsMutable) const; + void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) const; + void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const; + void drawText(const char text[], size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) const; + void drawPosText(const char text[], size_t byteLength, + const SkScalar pos[], SkScalar constY, + int scalarsPerPosition, const SkPaint& paint) const; + void drawTextOnPath(const char text[], size_t byteLength, + const SkPath&, const SkMatrix*, const SkPaint&) const; + void drawVertices(SkCanvas::VertexMode mode, int count, + const SkPoint vertices[], const SkPoint textures[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int ptCount, + const SkPaint& paint) const; + + void drawPath(const SkPath& src, const SkPaint& paint) const { + this->drawPath(src, paint, NULL, false); + } + + /** Helper function that creates a mask from a path and an optional maskfilter. + Note however, that the resulting mask will not have been actually filtered, + that must be done afterwards (by calling filterMask). The maskfilter is provided + solely to assist in computing the mask's bounds (if the mode requests that). + */ + static bool DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, + SkMaskFilter* filter, const SkMatrix* filterMatrix, + SkMask* mask, SkMask::CreateMode mode); + +private: + void drawText_asPaths(const char text[], size_t byteLength, + SkScalar x, SkScalar y, const SkPaint&) const; + void drawDevMask(const SkMask& mask, const SkPaint&) const; + void drawBitmapAsMask(const SkBitmap&, const SkPaint&) const; + +public: + const SkBitmap* fBitmap; // required + const SkMatrix* fMatrix; // required + const SkRegion* fClip; // required + SkDevice* fDevice; // optional + SkBounder* fBounder; // optional + SkDrawProcs* fProcs; // optional + +#ifdef SK_DEBUG + void validate() const; +#endif +}; + +#include "SkGlyphCache.h" + +class SkTextToPathIter { +public: + SkTextToPathIter(const char text[], size_t length, const SkPaint&, + bool applyStrokeAndPathEffects, bool forceLinearTextOn); + ~SkTextToPathIter(); + + const SkPaint& getPaint() const { return fPaint; } + SkScalar getPathScale() const { return fScale; } + + const SkPath* next(SkScalar* xpos); //!< returns nil when there are no more paths + +private: + SkGlyphCache* fCache; + SkPaint fPaint; + SkScalar fScale; + SkFixed fPrevAdvance; + const char* fText; + const char* fStop; + SkMeasureCacheProc fGlyphCacheProc; + + const SkPath* fPath; // returned in next + SkScalar fXPos; // accumulated xpos, returned in next + SkAutoKern fAutoKern; +}; + +#endif + + diff --git a/include/core/SkDrawFilter.h b/include/core/SkDrawFilter.h new file mode 100644 index 0000000000..db5a685191 --- /dev/null +++ b/include/core/SkDrawFilter.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDrawFilter_DEFINED +#define SkDrawFilter_DEFINED + +#include "SkRefCnt.h" + +////////////////// EXPERIMENTAL ////////////////////////// + +class SkCanvas; +class SkPaint; + +/** Right before something is being draw, filter() is called with the + current canvas and paint. If it returns true, then drawing proceeds + with the (possibly modified) canvas/paint, and then restore() is called + to restore the canvas/paint to their state before filter() was called. + If filter returns false, canvas/paint should not have been changed, and + restore() will not be called. +*/ +class SkDrawFilter : public SkRefCnt { +public: + enum Type { + kPaint_Type, + kPoint_Type, + kLine_Type, + kBitmap_Type, + kRect_Type, + kPath_Type, + kText_Type + }; + + /** Return true to allow the draw to continue (with possibly modified + canvas/paint). If true is returned, then restore() will be called. + */ + virtual bool filter(SkCanvas*, SkPaint*, Type) = 0; + /** If filter() returned true, then restore() will be called to restore the + canvas/paint to their previous states + */ + virtual void restore(SkCanvas*, SkPaint*, Type) = 0; +}; + +#endif diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h new file mode 100644 index 0000000000..333fb41105 --- /dev/null +++ b/include/core/SkDrawLooper.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkDrawLooper_DEFINED +#define SkDrawLooper_DEFINED + +#include "SkFlattenable.h" + +////////////////// EXPERIMENTAL ////////////////////////// + +class SkCanvas; +class SkPaint; + +/** \class SkDrawLooper + Subclasses of SkDrawLooper can be attached to a SkPaint. Where they are, + and something is drawn to a canvas with that paint, the looper subclass will + be called, allowing it to modify the canvas and/or paint for that draw call. + More than that, via the next() method, the looper can modify the draw to be + invoked multiple times (hence the name loop-er), allow it to perform effects + like shadows or frame/fills, that require more than one pass. +*/ +class SkDrawLooper : public SkFlattenable { +public: + /** Called right before something is being drawn to the specified canvas + with the specified paint. Subclass that want to modify either parameter + can do so now. + */ + virtual void init(SkCanvas*, SkPaint*) {} + /** Called in a loop (after init()). Each time true is returned, the object + is drawn (possibly with a modified canvas and/or paint). When false is + finally returned, drawing for the object stops. + */ + virtual bool next() { return false; } + /** Called after the looper has finally returned false from next(), allowing + the looper to restore the canvas/paint to their original states. + is this required, since the subclass knows when it is done??? + should we pass the canvas/paint here, and/or to the next call + so that subclasses don't need to retain pointers to them during the + loop? + */ + virtual void restore() {} + +protected: + SkDrawLooper() {} + SkDrawLooper(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/include/core/SkEndian.h b/include/core/SkEndian.h new file mode 100644 index 0000000000..f08a9a990b --- /dev/null +++ b/include/core/SkEndian.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkEndian_DEFINED +#define SkEndian_DEFINED + +#include "SkTypes.h" + +/** \file SkEndian.h + + Macros and helper functions for handling 16 and 32 bit values in + big and little endian formats. +*/ + +#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN) + #error "can't have both LENDIAN and BENDIAN defined" +#endif + +#if !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN) + #error "need either LENDIAN or BENDIAN defined" +#endif + +/** Swap the two bytes in the low 16bits of the parameters. + e.g. 0x1234 -> 0x3412 +*/ +inline uint16_t SkEndianSwap16(U16CPU value) +{ + SkASSERT(value == (uint16_t)value); + return (uint16_t)((value >> 8) | (value << 8)); +} + +/** Vector version of SkEndianSwap16(), which swaps the + low two bytes of each value in the array. +*/ +inline void SkEndianSwap16s(uint16_t array[], int count) +{ + SkASSERT(count == 0 || array != NULL); + + while (--count >= 0) + { + *array = SkEndianSwap16(*array); + array += 1; + } +} + +/** Reverse all 4 bytes in a 32bit value. + e.g. 0x12345678 -> 0x78563412 +*/ +inline uint32_t SkEndianSwap32(uint32_t value) +{ + return ((value & 0xFF) << 24) | + ((value & 0xFF00) << 8) | + ((value & 0xFF0000) >> 8) | + (value >> 24); +} + +/** Vector version of SkEndianSwap16(), which swaps the + bytes of each value in the array. +*/ +inline void SkEndianSwap32s(uint32_t array[], int count) +{ + SkASSERT(count == 0 || array != NULL); + + while (--count >= 0) + { + *array = SkEndianSwap32(*array); + array += 1; + } +} + +#ifdef SK_CPU_LENDIAN + #define SkEndian_SwapBE16(n) SkEndianSwap16(n) + #define SkEndian_SwapBE32(n) SkEndianSwap32(n) + #define SkEndian_SwapLE16(n) (n) + #define SkEndian_SwapLE32(n) (n) +#else // SK_CPU_BENDIAN + #define SkEndian_SwapBE16(n) (n) + #define SkEndian_SwapBE32(n) (n) + #define SkEndian_SwapLE16(n) SkEndianSwap16(n) + #define SkEndian_SwapLE32(n) SkEndianSwap32(n) +#endif + + +#endif + diff --git a/include/core/SkFDot6.h b/include/core/SkFDot6.h new file mode 100644 index 0000000000..a4b9cf759b --- /dev/null +++ b/include/core/SkFDot6.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFDot6_DEFINED +#define SkFDot6_DEFINED + +#include "SkMath.h" + +typedef int32_t SkFDot6; + +#define SK_FDot61 (64) +#define SK_FDot6Half (32) + +#ifdef SK_DEBUG + inline SkFDot6 SkIntToFDot6(S16CPU x) + { + SkASSERT(SkToS16(x) == x); + return x << 6; + } +#else + #define SkIntToFDot6(x) ((x) << 6) +#endif + +#define SkFDot6Floor(x) ((x) >> 6) +#define SkFDot6Ceil(x) (((x) + 63) >> 6) +#define SkFDot6Round(x) (((x) + 32) >> 6) + +#define SkFixedToFDot6(x) ((x) >> 10) + +inline SkFixed SkFDot6ToFixed(SkFDot6 x) +{ + SkASSERT((x << 10 >> 10) == x); + + return x << 10; +} + +#ifdef SK_SCALAR_IS_FLOAT + #define SkScalarToFDot6(x) (SkFDot6)((x) * 64) +#else + #define SkScalarToFDot6(x) ((x) >> 10) +#endif + +inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) +{ + SkASSERT(b != 0); + + if (a == (int16_t)a) + return (a << 16) / b; + else + return SkFixedDiv(a, b); +} + +#endif + diff --git a/include/core/SkFixed.h b/include/core/SkFixed.h new file mode 100644 index 0000000000..be4bf99788 --- /dev/null +++ b/include/core/SkFixed.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFixed_DEFINED +#define SkFixed_DEFINED + +#include "SkTypes.h" + +/** \file SkFixed.h + + Types and macros for 16.16 fixed point +*/ + +/** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point +*/ +typedef int32_t SkFixed; +#define SK_Fixed1 (1 << 16) +#define SK_FixedHalf (1 << 15) +#define SK_FixedMax (0x7FFFFFFF) +#define SK_FixedMin (0x1) +#define SK_FixedNaN ((int) 0x80000000) +#define SK_FixedPI (0x3243F) +#define SK_FixedSqrt2 (92682) +#define SK_FixedTanPIOver8 (0x6A0A) +#define SK_FixedRoot2Over2 (0xB505) + +#ifdef SK_CAN_USE_FLOAT + #define SkFixedToFloat(x) ((x) * 1.5258789e-5f) + #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1)) + + #define SkFixedToDouble(x) ((x) * 1.5258789e-5) + #define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) +#endif + +/** 32 bit signed integer used to represent fractions values with 30 bits to the right of the decimal point +*/ +typedef int32_t SkFract; +#define SK_Fract1 (1 << 30) +#define Sk_FracHalf (1 << 29) +#define SK_FractPIOver180 (0x11DF46A) + +#ifdef SK_CAN_USE_FLOAT + #define SkFractToFloat(x) ((float)(x) * 0.00000000093132257f) + #define SkFloatToFract(x) ((SkFract)((x) * SK_Fract1)) +#endif + +/** Converts an integer to a SkFixed, asserting that the result does not overflow + a 32 bit signed integer +*/ +#ifdef SK_DEBUG + inline SkFixed SkIntToFixed(int n) + { + SkASSERT(n >= -32768 && n <= 32767); + return n << 16; + } +#else + // force the cast to SkFixed to ensure that the answer is signed (like the debug version) + #define SkIntToFixed(n) (SkFixed)((n) << 16) +#endif + +/** Converts a SkFixed to a SkFract, asserting that the result does not overflow + a 32 bit signed integer +*/ +#ifdef SK_DEBUG + inline SkFract SkFixedToFract(SkFixed x) + { + SkASSERT(x >= (-2 << 16) && x <= (2 << 16) - 1); + return x << 14; + } +#else + #define SkFixedToFract(x) ((x) << 14) +#endif + +/** Returns the signed fraction of a SkFixed +*/ +inline SkFixed SkFixedFraction(SkFixed x) +{ + SkFixed mask = x >> 31 << 16; + return (x & 0xFFFF) | mask; +} + +/** Converts a SkFract to a SkFixed +*/ +#define SkFractToFixed(x) ((x) >> 14) +/** Round a SkFixed to an integer +*/ +#define SkFixedRound(x) (((x) + SK_FixedHalf) >> 16) +#define SkFixedCeil(x) (((x) + SK_Fixed1 - 1) >> 16) +#define SkFixedFloor(x) ((x) >> 16) +#define SkFixedAbs(x) SkAbs32(x) +#define SkFixedAve(a, b) (((a) + (b)) >> 1) + +SkFixed SkFixedMul_portable(SkFixed, SkFixed); +SkFract SkFractMul_portable(SkFract, SkFract); +inline SkFixed SkFixedSquare_portable(SkFixed value) +{ + uint32_t a = SkAbs32(value); + uint32_t ah = a >> 16; + uint32_t al = a & 0xFFFF; + return ah * a + al * ah + (al * al >> 16); +} + +#define SkFixedDiv(numer, denom) SkDivBits(numer, denom, 16) +SkFixed SkFixedDivInt(int32_t numer, int32_t denom); +SkFixed SkFixedMod(SkFixed numer, SkFixed denom); +#define SkFixedInvert(n) SkDivBits(SK_Fixed1, n, 16) +SkFixed SkFixedFastInvert(SkFixed n); +#define SkFixedSqrt(n) SkSqrtBits(n, 23) +SkFixed SkFixedMean(SkFixed a, SkFixed b); //*< returns sqrt(x*y) +int SkFixedMulCommon(SkFixed, int , int bias); // internal used by SkFixedMulFloor, SkFixedMulCeil, SkFixedMulRound + +#define SkFractDiv(numer, denom) SkDivBits(numer, denom, 30) +#define SkFractSqrt(n) SkSqrtBits(n, 30) + +SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValueOrNull); +#define SkFixedSin(radians) SkFixedSinCos(radians, NULL) +inline SkFixed SkFixedCos(SkFixed radians) +{ + SkFixed cosValue; + (void)SkFixedSinCos(radians, &cosValue); + return cosValue; +} +SkFixed SkFixedTan(SkFixed radians); +SkFixed SkFixedASin(SkFixed); +SkFixed SkFixedACos(SkFixed); +SkFixed SkFixedATan2(SkFixed y, SkFixed x); +SkFixed SkFixedExp(SkFixed); +SkFixed SkFixedLog(SkFixed); + +#define SK_FixedNearlyZero (SK_Fixed1 >> 12) + +inline bool SkFixedNearlyZero(SkFixed x, SkFixed tolerance = SK_FixedNearlyZero) +{ + SkASSERT(tolerance > 0); + return SkAbs32(x) < tolerance; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Now look for ASM overrides for our portable versions (should consider putting this in its own file) + +#ifdef SkLONGLONG + inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) + { + return (SkFixed)((SkLONGLONG)a * b >> 16); + } + inline SkFract SkFractMul_longlong(SkFract a, SkFract b) + { + return (SkFixed)((SkLONGLONG)a * b >> 30); + } + inline SkFixed SkFixedSquare_longlong(SkFixed value) + { + return (SkFixed)((SkLONGLONG)value * value >> 16); + } + #define SkFixedMul(a,b) SkFixedMul_longlong(a,b) + #define SkFractMul(a,b) SkFractMul_longlong(a,b) + #define SkFixedSquare(a) SkFixedSquare_longlong(a) +#endif + +#if defined(__arm__) && !defined(__thumb__) + /* This guy does not handle NaN or other obscurities, but is faster than + than (int)(x*65536) when we only have software floats + */ + inline SkFixed SkFloatToFixed_arm(float x) + { + register int32_t y, z; + asm("movs %1, %3, lsl #1 \n" + "mov %2, #0x8E \n" + "sub %1, %2, %1, lsr #24 \n" + "mov %2, %3, lsl #8 \n" + "orr %2, %2, #0x80000000 \n" + "mov %1, %2, lsr %1 \n" + "rsbcs %1, %1, #0 \n" + : "=r"(x), "=&r"(y), "=&r"(z) + : "r"(x) + : "cc" + ); + return y; + } + inline SkFixed SkFixedMul_arm(SkFixed x, SkFixed y) + { + register int32_t t; + asm("smull %0, %2, %1, %3 \n" + "mov %0, %0, lsr #16 \n" + "orr %0, %0, %2, lsl #16 \n" + : "=r"(x), "=&r"(y), "=r"(t) + : "r"(x), "1"(y) + : + ); + return x; + } + inline SkFixed SkFixedMulAdd_arm(SkFixed x, SkFixed y, SkFixed a) + { + register int32_t t; + asm("smull %0, %3, %1, %4 \n" + "add %0, %2, %0, lsr #16 \n" + "add %0, %0, %3, lsl #16 \n" + : "=r"(x), "=&r"(y), "=&r"(a), "=r"(t) + : "%r"(x), "1"(y), "2"(a) + : + ); + return x; + } + inline SkFixed SkFractMul_arm(SkFixed x, SkFixed y) + { + register int32_t t; + asm("smull %0, %2, %1, %3 \n" + "mov %0, %0, lsr #30 \n" + "orr %0, %0, %2, lsl #2 \n" + : "=r"(x), "=&r"(y), "=r"(t) + : "r"(x), "1"(y) + : + ); + return x; + } + #undef SkFixedMul + #undef SkFractMul + #define SkFixedMul(x, y) SkFixedMul_arm(x, y) + #define SkFractMul(x, y) SkFractMul_arm(x, y) + #define SkFixedMulAdd(x, y, a) SkFixedMulAdd_arm(x, y, a) + + #undef SkFloatToFixed + #define SkFloatToFixed(x) SkFloatToFixed_arm(x) +#endif + +/////////////////////// Now define our macros to the portable versions if they weren't overridden + +#ifndef SkFixedSquare + #define SkFixedSquare(x) SkFixedSquare_portable(x) +#endif +#ifndef SkFixedMul + #define SkFixedMul(x, y) SkFixedMul_portable(x, y) +#endif +#ifndef SkFractMul + #define SkFractMul(x, y) SkFractMul_portable(x, y) +#endif +#ifndef SkFixedMulAdd + #define SkFixedMulAdd(x, y, a) (SkFixedMul(x, y) + (a)) +#endif + +#endif diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h new file mode 100644 index 0000000000..6958462033 --- /dev/null +++ b/include/core/SkFlattenable.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFlattenable_DEFINED +#define SkFlattenable_DEFINED + +#include "SkRefCnt.h" +#include "SkBitmap.h" +#include "SkReader32.h" +#include "SkTDArray.h" +#include "SkWriter32.h" + +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; +class SkString; + +/** \class SkFlattenable + + SkFlattenable is the base class for objects that need to be flattened + into a data stream for either transport or as part of the key to the + font cache. + */ +class SkFlattenable : public SkRefCnt { +public: + typedef SkFlattenable* (*Factory)(SkFlattenableReadBuffer&); + + SkFlattenable() {} + + /** Implement this to return a factory function pointer that can be called + to recreate your class given a buffer (previously written to by your + override of flatten(). + */ + virtual Factory getFactory() = 0; + /** Override this to write data specific to your subclass into the buffer, + being sure to call your super-class' version first. This data will later + be passed to your Factory function, returned by getFactory(). + */ + virtual void flatten(SkFlattenableWriteBuffer&); + + /** Set the string to describe the sublass and return true. If this is not + overridden, ignore the string param and return false. + */ + virtual bool toDumpString(SkString*) const; + + static Factory NameToFactory(const char name[]); + static const char* FactoryToName(Factory); + static void Register(const char name[], Factory); + + class Registrar { + public: + Registrar(const char name[], Factory factory) { + SkFlattenable::Register(name, factory); + } + }; + +protected: + SkFlattenable(SkFlattenableReadBuffer&) {} +}; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +class SkTypeface; + +class SkFlattenableReadBuffer : public SkReader32 { +public: + SkFlattenableReadBuffer(); + explicit SkFlattenableReadBuffer(const void* data); + SkFlattenableReadBuffer(const void* data, size_t size); + + void setRefCntArray(SkRefCnt* array[], int count) { + fRCArray = array; + fRCCount = count; + } + + void setTypefaceArray(SkTypeface* array[], int count) { + fTFArray = array; + fTFCount = count; + } + + void setFactoryPlayback(SkFlattenable::Factory array[], int count) { + fFactoryArray = array; + fFactoryCount = count; + } + + SkTypeface* readTypeface(); + SkRefCnt* readRefCnt(); + void* readFunctionPtr(); + SkFlattenable* readFlattenable(); + +private: + SkRefCnt** fRCArray; + int fRCCount; + + SkTypeface** fTFArray; + int fTFCount; + + SkFlattenable::Factory* fFactoryArray; + int fFactoryCount; + + typedef SkReader32 INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkPtrRecorder.h" + +class SkRefCntRecorder : public SkPtrRecorder { +public: + virtual ~SkRefCntRecorder(); + + /** Add a refcnt object to the set and ref it if not already present, + or if it is already present, do nothing. Either way, returns 0 if obj + is null, or a base-1 index if obj is not null. + */ + uint32_t record(SkRefCnt* ref) { + return this->recordPtr(ref); + } + + // This does not change the owner counts on the objects + void get(SkRefCnt* array[]) const { + this->getPtrs((void**)array); + } + +protected: + // overrides + virtual void incPtr(void*); + virtual void decPtr(void*); + +private: + typedef SkPtrRecorder INHERITED; +}; + +class SkFactoryRecorder : public SkPtrRecorder { +public: + /** Add a factory to the set. If it is null return 0, otherwise return a + base-1 index for the factory. + */ + uint32_t record(SkFlattenable::Factory fact) { + return this->recordPtr((void*)fact); + } + + void get(SkFlattenable::Factory array[]) const { + this->getPtrs((void**)array); + } + +private: + typedef SkPtrRecorder INHERITED; +}; + +class SkFlattenableWriteBuffer : public SkWriter32 { +public: + SkFlattenableWriteBuffer(size_t minSize); + virtual ~SkFlattenableWriteBuffer(); + + void writeTypeface(SkTypeface*); + void writeRefCnt(SkRefCnt*); + void writeFunctionPtr(void*); + void writeFlattenable(SkFlattenable* flattenable); + + SkRefCntRecorder* getTypefaceRecorder() const { return fTFRecorder; } + SkRefCntRecorder* setTypefaceRecorder(SkRefCntRecorder*); + + SkRefCntRecorder* getRefCntRecorder() const { return fRCRecorder; } + SkRefCntRecorder* setRefCntRecorder(SkRefCntRecorder*); + + SkFactoryRecorder* getFactoryRecorder() const { return fFactoryRecorder; } + SkFactoryRecorder* setFactoryRecorder(SkFactoryRecorder*); + + enum Flags { + kCrossProcess_Flag = 0x01 + }; + Flags getFlags() const { return fFlags; } + void setFlags(Flags flags) { fFlags = flags; } + + bool isCrossProcess() const { return (fFlags & kCrossProcess_Flag) != 0; } + + bool persistBitmapPixels() const { + return (fFlags & kCrossProcess_Flag) != 0; + } + + bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; } + +private: + Flags fFlags; + SkRefCntRecorder* fTFRecorder; + SkRefCntRecorder* fRCRecorder; + SkFactoryRecorder* fFactoryRecorder; + + typedef SkWriter32 INHERITED; +}; + +#endif + diff --git a/include/core/SkFloatBits.h b/include/core/SkFloatBits.h new file mode 100644 index 0000000000..1628f6e753 --- /dev/null +++ b/include/core/SkFloatBits.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFloatBits_DEFINED +#define SkFloatBits_DEFINED + +#include "SkTypes.h" + +/** Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement + int. This also converts -0 (0x80000000) to 0. Doing this to a float allows + it to be compared using normal C operators (<, <=, etc.) +*/ +static inline int32_t SkSignBitTo2sCompliment(int32_t x) { + if (x < 0) { + x &= 0x7FFFFFFF; + x = -x; + } + return x; +} + +/** Convert a 2s compliment int to a sign-bit (i.e. int interpreted as float). + This undoes the result of SkSignBitTo2sCompliment(). + */ +static inline int32_t Sk2sComplimentToSignBit(int32_t x) { + int sign = x >> 31; + // make x positive + x = (x ^ sign) - sign; + // set the sign bit as needed + x |= sign << 31; + return x; +} + +/** Given the bit representation of a float, return its value cast to an int. + If the value is out of range, or NaN, return return +/- SK_MaxS32 +*/ +int32_t SkFloatBits_toIntCast(int32_t floatBits); + +/** Given the bit representation of a float, return its floor as an int. + If the value is out of range, or NaN, return return +/- SK_MaxS32 + */ +int32_t SkFloatBits_toIntFloor(int32_t floatBits); + +/** Given the bit representation of a float, return it rounded to an int. + If the value is out of range, or NaN, return return +/- SK_MaxS32 + */ +int32_t SkFloatBits_toIntRound(int32_t floatBits); + +/** Given the bit representation of a float, return its ceiling as an int. + If the value is out of range, or NaN, return return +/- SK_MaxS32 + */ +int32_t SkFloatBits_toIntCeil(int32_t floatBits); + + +#ifdef SK_CAN_USE_FLOAT + +union SkFloatIntUnion { + float fFloat; + int32_t fSignBitInt; +}; + +// Helper to see a float as its bit pattern (w/o aliasing warnings) +static inline int32_t SkFloat2Bits(float x) { + SkFloatIntUnion data; + data.fFloat = x; + return data.fSignBitInt; +} + +// Helper to see a bit pattern as a float (w/o aliasing warnings) +static inline float SkBits2Float(int32_t floatAsBits) { + SkFloatIntUnion data; + data.fSignBitInt = floatAsBits; + return data.fFloat; +} + +/** Return the float as a 2s compliment int. Just to be used to compare floats + to each other or against positive float-bit-constants (like 0). This does + not return the int equivalent of the float, just something cheaper for + compares-only. + */ +static inline int32_t SkFloatAs2sCompliment(float x) { + return SkSignBitTo2sCompliment(SkFloat2Bits(x)); +} + +/** Return the 2s compliment int as a float. This undos the result of + SkFloatAs2sCompliment + */ +static inline float Sk2sComplimentAsFloat(int32_t x) { + return SkBits2Float(Sk2sComplimentToSignBit(x)); +} + +/** Return x cast to a float (i.e. (float)x) +*/ +float SkIntToFloatCast(int x); +float SkIntToFloatCast_NoOverflowCheck(int x); + +/** Return the float cast to an int. + If the value is out of range, or NaN, return +/- SK_MaxS32 +*/ +static inline int32_t SkFloatToIntCast(float x) { + return SkFloatBits_toIntCast(SkFloat2Bits(x)); +} + +/** Return the floor of the float as an int. + If the value is out of range, or NaN, return +/- SK_MaxS32 +*/ +static inline int32_t SkFloatToIntFloor(float x) { + return SkFloatBits_toIntFloor(SkFloat2Bits(x)); +} + +/** Return the float rounded to an int. + If the value is out of range, or NaN, return +/- SK_MaxS32 +*/ +static inline int32_t SkFloatToIntRound(float x) { + return SkFloatBits_toIntRound(SkFloat2Bits(x)); +} + +/** Return the ceiling of the float as an int. + If the value is out of range, or NaN, return +/- SK_MaxS32 +*/ +static inline int32_t SkFloatToIntCeil(float x) { + return SkFloatBits_toIntCeil(SkFloat2Bits(x)); +} + +#endif + +// Scalar wrappers for float-bit routines + +#ifdef SK_SCALAR_IS_FLOAT + #define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x) + #define Sk2sComplimentAsScalar(x) Sk2sComplimentAsFloat(x) +#else + #define SkScalarAs2sCompliment(x) (x) + #define Sk2sComplimentAsScalar(x) (x) +#endif + +#endif + diff --git a/include/core/SkFloatingPoint.h b/include/core/SkFloatingPoint.h new file mode 100644 index 0000000000..d3a6fc5f80 --- /dev/null +++ b/include/core/SkFloatingPoint.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFloatingPoint_DEFINED +#define SkFloatingPoint_DEFINED + +#include "SkTypes.h" + +#ifdef SK_CAN_USE_FLOAT + +#include <math.h> +#include <float.h> +#include "SkFloatBits.h" + +#ifdef SK_BUILD_FOR_WINCE + #define sk_float_sqrt(x) (float)::sqrt(x) + #define sk_float_sin(x) (float)::sin(x) + #define sk_float_cos(x) (float)::cos(x) + #define sk_float_tan(x) (float)::tan(x) + #define sk_float_acos(x) (float)::acos(x) + #define sk_float_asin(x) (float)::asin(x) + #define sk_float_atan2(y,x) (float)::atan2(y,x) + #define sk_float_abs(x) (float)::fabs(x) + #define sk_float_mod(x,y) (float)::fmod(x,y) + #define sk_float_exp(x) (float)::exp(x) + #define sk_float_log(x) (float)::log(x) + #define sk_float_floor(x) (float)::floor(x) + #define sk_float_ceil(x) (float)::ceil(x) +#else + #define sk_float_sqrt(x) sqrtf(x) + #define sk_float_sin(x) sinf(x) + #define sk_float_cos(x) cosf(x) + #define sk_float_tan(x) tanf(x) + #define sk_float_floor(x) floorf(x) + #define sk_float_ceil(x) ceilf(x) +#ifdef SK_BUILD_FOR_MAC + #define sk_float_acos(x) acos(x) + #define sk_float_asin(x) asin(x) +#else + #define sk_float_acos(x) acosf(x) + #define sk_float_asin(x) asinf(x) +#endif + #define sk_float_atan2(y,x) atan2f(y,x) + #define sk_float_abs(x) fabsf(x) + #define sk_float_mod(x,y) fmodf(x,y) + #define sk_float_exp(x) expf(x) + #define sk_float_log(x) logf(x) + #define sk_float_isNaN(x) _isnan(x) +#endif + +#ifdef SK_USE_FLOATBITS + #define sk_float_floor2int(x) SkFloatToIntFloor(x) + #define sk_float_round2int(x) SkFloatToIntRound(x) + #define sk_float_ceil2int(x) SkFloatToIntCeil(x) +#else + #define sk_float_floor2int(x) (int)sk_float_floor(x) + #define sk_float_round2int(x) (int)sk_float_floor((x) + 0.5f) + #define sk_float_ceil2int(x) (int)sk_float_ceil(x) +#endif + +#endif +#endif diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h new file mode 100644 index 0000000000..ede40b7a31 --- /dev/null +++ b/include/core/SkFontHost.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkFontHost_DEFINED +#define SkFontHost_DEFINED + +#include "SkScalerContext.h" +#include "SkTypeface.h" + +class SkDescriptor; +class SkStream; +class SkWStream; + +/** \class SkFontHost + + This class is ported to each environment. It is responsible for bridging the gap + between SkTypeface and the resulting platform-specific instance of SkScalerContext. +*/ +class SkFontHost { +public: + /** Return the closest matching typeface given either an existing family + (specified by a typeface in that family) or by a familyName, and a + requested style. + 1) If familyFace is null, use famillyName. + 2) If famillyName is null, use familyFace. + 3) If both are null, return the default font that best matches style + + NOTE: this does not return a new typeface, nor does it affect the + owner count of an existing one, so the caller is free to ignore the + return result, or just compare it against null. + */ + static SkTypeface* FindTypeface(const SkTypeface* familyFace, + const char famillyName[], + SkTypeface::Style style); + + /** Return the typeface associated with the uniqueID, or null if that ID + does not match any faces. + + NOTE: this does not return a new typeface, nor does it affect the + owner count of an existing one, so the caller is free to ignore the + return result, or just compare it against null. + */ + static SkTypeface* ResolveTypeface(uint32_t uniqueID); + + /** Return a new stream to read the font data, or null if the uniqueID does + not match an existing typeface. The caller must call CloseStream() when + it is finished reading the stream. + */ + static SkStream* OpenStream(uint32_t uniqueID); + + /** Call this when finished reading from the stream returned by OpenStream. + The caller should NOT try to delete the stream. + */ + static void CloseStream(uint32_t uniqueID, SkStream*); + + /** Return a new typeface given the data buffer (owned by the caller). + If the data does not represent a valid font, return null. The caller is + responsible for unref-ing the returned typeface (if it is not null). + */ + static SkTypeface* CreateTypeface(SkStream*); + + /////////////////////////////////////////////////////////////////////////// + + /** Write a unique identifier to the stream, so that the same typeface can + be retrieved with Deserialize(). + */ + static void Serialize(const SkTypeface*, SkWStream*); + + /** Given a stream created by Serialize(), return the corresponding typeface + or null if no match is found. + + NOTE: this does not return a new typeface, nor does it affect the + owner count of an existing one, so the caller is free to ignore the + return result, or just compare it against null. + */ + static SkTypeface* Deserialize(SkStream*); + + /////////////////////////////////////////////////////////////////////////// + + /** Return a subclass of SkScalarContext + */ + static SkScalerContext* CreateScalerContext(const SkDescriptor* desc); + + /** Return a scalercontext using the "fallback" font. If there is no designated + fallback, return null. + */ + static SkScalerContext* CreateFallbackScalerContext(const SkScalerContext::Rec&); + + /** Return the number of bytes (approx) that should be purged from the font + cache. The input parameter is the cache's estimate of how much as been + allocated by the cache so far. + To purge (basically) everything, return the input parameter. + To purge nothing, return 0 + */ + static size_t ShouldPurgeFontCache(size_t sizeAllocatedSoFar); + + /** Return SkScalerContext gamma flag, or 0, based on the paint that will be + used to draw something with antialiasing. + */ + static int ComputeGammaFlag(const SkPaint& paint); + + /** Return NULL or a pointer to 256 bytes for the black (table[0]) and + white (table[1]) gamma tables. + */ + static void GetGammaTables(const uint8_t* tables[2]); +}; + +#endif + diff --git a/include/core/SkGlobals.h b/include/core/SkGlobals.h new file mode 100644 index 0000000000..8e28290379 --- /dev/null +++ b/include/core/SkGlobals.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkGlobals_DEFINED +#define SkGlobals_DEFINED + +#include "SkThread.h" + +class SkGlobals { +public: + class Rec { + public: + virtual ~Rec(); + private: + Rec* fNext; + uint32_t fTag; + + friend class SkGlobals; + }; + + /** Look for a matching Rec for the specified tag. If one is found, return it. + If one is not found, if create_proc is null, return null, else + call the proc, and if it returns a Rec, add it to the global list + and return it. + + create_proc can NOT call back into SkGlobals::Find (it would deadlock) + */ + static Rec* Find(uint32_t tag, Rec* (*create_proc)()); + /** Helper for Find, when you want to assert that the Rec is already in the list + */ + static Rec* Get(uint32_t tag) + { + Rec* rec = SkGlobals::Find(tag, NULL); + SkASSERT(rec); + return rec; + } + + // used by porting layer + struct BootStrap { + SkMutex fMutex; + Rec* fHead; + }; + +private: + static void Init(); + static void Term(); + friend class SkGraphics; + + // This last function is implemented in the porting layer + static BootStrap& GetBootStrap(); +}; + +#endif + diff --git a/include/core/SkGraphics.h b/include/core/SkGraphics.h new file mode 100644 index 0000000000..cb06128306 --- /dev/null +++ b/include/core/SkGraphics.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkGraphics_DEFINED +#define SkGraphics_DEFINED + +#include "SkTypes.h" + +class SkGraphics { +public: + static void Init(bool runUnitTests); + static void Term(); + + /** Return the (approximate) number of bytes used by the font cache. + */ + static size_t GetFontCacheUsed(); + + /** Attempt to purge the font cache until <= the specified amount remains + in the cache. Specifying 0 will attempt to purge the entire cache. + Returns true if some amount was purged from the font cache. + */ + static bool SetFontCacheUsed(size_t usageInBytes); + +private: + /** This is automatically called by SkGraphics::Init(), and must be + implemented by the host OS. This allows the host OS to register a callback + with the C++ runtime to call SkGraphics::FreeCaches() + */ + static void InstallNewHandler(); +}; + +#endif + diff --git a/include/core/SkMMapStream.h b/include/core/SkMMapStream.h new file mode 100644 index 0000000000..600c6212f7 --- /dev/null +++ b/include/core/SkMMapStream.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMMapStream_DEFINED +#define SkMMapStream_DEFINED + +#include "SkStream.h" + +class SkMMAPStream : public SkMemoryStream { +public: + SkMMAPStream(const char filename[]); + virtual ~SkMMAPStream(); + + virtual void setMemory(const void* data, size_t length); +private: + int fFildes; + void* fAddr; + size_t fSize; + + void closeMMap(); + + typedef SkMemoryStream INHERITED; +}; + +#endif diff --git a/include/core/SkMallocPixelRef.h b/include/core/SkMallocPixelRef.h new file mode 100644 index 0000000000..b6a013d787 --- /dev/null +++ b/include/core/SkMallocPixelRef.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMallocPixelRef_DEFINED +#define SkMallocPixelRef_DEFINED + +#include "SkPixelRef.h" + +/** We explicitly use the same allocator for our pixels that SkMask does, + so that we can freely assign memory allocated by one class to the other. +*/ +class SkMallocPixelRef : public SkPixelRef { +public: + /** Allocate the specified buffer for pixels. The memory is freed when the + last owner of this pixelref is gone. + */ + SkMallocPixelRef(void* addr, size_t size, SkColorTable* ctable); + virtual ~SkMallocPixelRef(); + + //! Return the allocation size for the pixels + size_t getSize() const { return fSize; } + + // overrides from SkPixelRef + virtual void flatten(SkFlattenableWriteBuffer&) const; + virtual Factory getFactory() const { + return Create; + } + static SkPixelRef* Create(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkMallocPixelRef, (buffer)); + } + +protected: + // overrides from SkPixelRef + virtual void* onLockPixels(SkColorTable**); + virtual void onUnlockPixels(); + + SkMallocPixelRef(SkFlattenableReadBuffer& buffer); + +private: + void* fStorage; + size_t fSize; + SkColorTable* fCTable; + + typedef SkPixelRef INHERITED; +}; + +#endif diff --git a/include/core/SkMask.h b/include/core/SkMask.h new file mode 100644 index 0000000000..764ead68e1 --- /dev/null +++ b/include/core/SkMask.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMask_DEFINED +#define SkMask_DEFINED + +#include "SkRect.h" + +/** \class SkMask + SkMask is used to describe alpha bitmaps, either 1bit, 8bit, or + the 3-channel 3D format. These are passed to SkMaskFilter objects. +*/ +struct SkMask { + enum Format { + kBW_Format, //!< 1bit per pixel mask (e.g. monochrome) + kA8_Format, //!< 8bits per pixel mask (e.g. antialiasing) + k3D_Format, //!< 3 8bit per pixl planes: alpha, mul, add + kLCD_Format //!< 3 bytes/pixel: r/g/b + }; + + enum { + kCountMaskFormats = kLCD_Format + 1 + }; + + uint8_t* fImage; + SkIRect fBounds; + uint16_t fRowBytes; + uint8_t fFormat; // Format + + /** Return the byte size of the mask, assuming only 1 plane. + Does not account for k3D_Format. For that, use computeFormatImageSize() + */ + size_t computeImageSize() const; + /** Return the byte size of the mask, taking into account + any extra planes (e.g. k3D_Format). + */ + size_t computeTotalImageSize() const; + + /** Returns the address of the byte that holds the specified bit. + Asserts that the mask is kBW_Format, and that x,y are in range. + x,y are in the same coordiate space as fBounds. + */ + uint8_t* getAddr1(int x, int y) const + { + SkASSERT(fFormat == kBW_Format); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + return fImage + ((x - fBounds.fLeft) >> 3) + (y - fBounds.fTop) * fRowBytes; + } + /** Returns the address of the specified byte. + Asserts that the mask is kA8_Format, and that x,y are in range. + x,y are in the same coordiate space as fBounds. + */ + uint8_t* getAddr(int x, int y) const + { + SkASSERT(fFormat != kBW_Format); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes; + } + + static uint8_t* AllocImage(size_t bytes); + static void FreeImage(void* image); + + enum CreateMode { + kJustComputeBounds_CreateMode, //!< compute bounds and return + kJustRenderImage_CreateMode, //!< render into preallocate mask + kComputeBoundsAndRenderImage_CreateMode //!< compute bounds, alloc image and render into it + }; +}; + +#endif + diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h new file mode 100644 index 0000000000..749a73a651 --- /dev/null +++ b/include/core/SkMaskFilter.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMaskFilter_DEFINED +#define SkMaskFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkMask.h" + +class SkBlitter; +class SkBounder; +class SkMatrix; +class SkPath; +class SkRegion; + +/** \class SkMaskFilter + + SkMaskFilter is the base class for object that perform transformations on + an alpha-channel mask before drawing it. A subclass of SkMaskFilter may be + installed into a SkPaint. Once there, each time a primitive is drawn, it + is first scan converted into a SkMask::kA8_Format mask, and handed to the + filter, calling its filterMask() method. If this returns true, then the + new mask is used to render into the device. + + Blur and emboss are implemented as subclasses of SkMaskFilter. +*/ +class SkMaskFilter : public SkFlattenable { +public: + SkMaskFilter() {} + + /** Returns the format of the resulting mask that this subclass will return + when its filterMask() method is called. + */ + virtual SkMask::Format getFormat() = 0; + + /** Create a new mask by filter the src mask. + If src.fImage == null, then do not allocate or create the dst image + but do fill out the other fields in dstMask. + If you do allocate a dst image, use SkMask::AllocImage() + If this returns false, dst mask is ignored. + @param dst the result of the filter. If src.fImage == null, dst should not allocate its image + @param src the original image to be filtered. + @param matrix the CTM + @param margin if not null, return the buffer dx/dy need when calculating the effect. Used when + drawing a clipped object to know how much larger to allocate the src before + applying the filter. If returning false, ignore this parameter. + @return true if the dst mask was correctly created. + */ + virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint* margin); + + /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask + and then call filterMask(). If this returns true, the specified blitter will be called + to render that mask. Returns false if filterMask() returned false. + This method is not exported to java. + */ + bool filterPath(const SkPath& devPath, const SkMatrix& devMatrix, + const SkRegion& devClip, SkBounder*, SkBlitter* blitter); + + virtual void flatten(SkFlattenableWriteBuffer& ) {} +protected: + // empty for now, but lets get our subclass to remember to init us for the future + SkMaskFilter(SkFlattenableReadBuffer&) {} +}; + +/** \class SkAutoMaskImage + + Stack class used to manage the fImage buffer in a SkMask. + When this object loses scope, the buffer is freed with SkMask::FreeImage(). +*/ +class SkAutoMaskImage { +public: + SkAutoMaskImage(SkMask* mask, bool alloc) + { + if (alloc) + mask->fImage = SkMask::AllocImage(mask->computeImageSize()); + fImage = mask->fImage; + } + ~SkAutoMaskImage() + { + SkMask::FreeImage(fImage); + } +private: + uint8_t* fImage; +}; + +#endif + diff --git a/include/core/SkMath.h b/include/core/SkMath.h new file mode 100644 index 0000000000..5c2b475ef9 --- /dev/null +++ b/include/core/SkMath.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMath_DEFINED +#define SkMath_DEFINED + +#include "SkTypes.h" + +//! Returns the number of leading zero bits (0...32) +int SkCLZ_portable(uint32_t); + +/** Computes the 64bit product of a * b, and then shifts the answer down by + shift bits, returning the low 32bits. shift must be [0..63] + e.g. to perform a fixedmul, call SkMulShift(a, b, 16) +*/ +int32_t SkMulShift(int32_t a, int32_t b, unsigned shift); + +/** Computes numer1 * numer2 / denom in full 64 intermediate precision. + It is an error for denom to be 0. There is no special handling if + the result overflows 32bits. +*/ +int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom); + +/** Computes (numer1 << shift) / denom in full 64 intermediate precision. + It is an error for denom to be 0. There is no special handling if + the result overflows 32bits. +*/ +int32_t SkDivBits(int32_t numer, int32_t denom, int shift); + +/** Return the integer square root of value, with a bias of bitBias +*/ +int32_t SkSqrtBits(int32_t value, int bitBias); + +/** Return the integer square root of n, treated as a SkFixed (16.16) +*/ +#define SkSqrt32(n) SkSqrtBits(n, 15) + +/** Return the integer cube root of value, with a bias of bitBias + */ +int32_t SkCubeRootBits(int32_t value, int bitBias); + +/** Returns -1 if n < 0, else returns 0 +*/ +#define SkExtractSign(n) ((int32_t)(n) >> 31) + +/** If sign == -1, returns -n, else sign must be 0, and returns n. + Typically used in conjunction with SkExtractSign(). +*/ +static inline int32_t SkApplySign(int32_t n, int32_t sign) { + SkASSERT(sign == 0 || sign == -1); + return (n ^ sign) - sign; +} + +/** Returns (value < 0 ? 0 : value) efficiently (i.e. no compares or branches) +*/ +static inline int SkClampPos(int value) { + return value & ~(value >> 31); +} + +/** Given an integer and a positive (max) integer, return the value + pinned against 0 and max, inclusive. + Note: only works as long as max - value doesn't wrap around + @param value The value we want returned pinned between [0...max] + @param max The positive max value + @return 0 if value < 0, max if value > max, else value +*/ +static inline int SkClampMax(int value, int max) { + // ensure that max is positive + SkASSERT(max >= 0); + // ensure that if value is negative, max - value doesn't wrap around + SkASSERT(value >= 0 || max - value > 0); + +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (value < 0) { + value = 0; + } + if (value > max) { + value = max; + } + return value; +#else + + int diff = max - value; + // clear diff if diff is positive + diff &= diff >> 31; + + // clear the result if value < 0 + return (value + diff) & ~(value >> 31); +#endif +} + +/** Given a positive value and a positive max, return the value + pinned against max. + Note: only works as long as max - value doesn't wrap around + @return max if value >= max, else value +*/ +static inline unsigned SkClampUMax(unsigned value, unsigned max) { +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (value > max) { + value = max; + } + return value; +#else + int diff = max - value; + // clear diff if diff is positive + diff &= diff >> 31; + + return value + diff; +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(__arm__) && !defined(__thumb__) + #define SkCLZ(x) __builtin_clz(x) +#endif + +#ifndef SkCLZ + #define SkCLZ(x) SkCLZ_portable(x) +#endif + +/////////////////////////////////////////////////////////////////////////////// + +/** Returns the smallest power-of-2 that is >= the specified value. If value + is already a power of 2, then it is returned unchanged. It is undefined + if value is <= 0. +*/ +static inline int SkNextPow2(int value) { + SkASSERT(value > 0); + return 1 << (32 - SkCLZ(value - 1)); +} + +/** Returns the log2 of the specified value, were that value to be rounded up + to the next power of 2. It is undefined to pass 0. Examples: + SkNextLog2(1) -> 0 + SkNextLog2(2) -> 1 + SkNextLog2(3) -> 2 + SkNextLog2(4) -> 2 + SkNextLog2(5) -> 3 +*/ +static inline int SkNextLog2(uint32_t value) { + SkASSERT(value != 0); + return 32 - SkCLZ(value - 1); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** SkMulS16(a, b) multiplies a * b, but requires that a and b are both int16_t. + With this requirement, we can generate faster instructions on some + architectures. +*/ +#if defined(__arm__) && !defined(__thumb__) + static inline int32_t SkMulS16(S16CPU x, S16CPU y) { + SkASSERT((int16_t)x == x); + SkASSERT((int16_t)y == y); + int32_t product; + asm("smulbb %0, %1, %2 \n" + : "=r"(product) + : "r"(x), "r"(y) + : + ); + return product; + } +#else + #ifdef SK_DEBUG + static inline int32_t SkMulS16(S16CPU x, S16CPU y) { + SkASSERT((int16_t)x == x); + SkASSERT((int16_t)y == y); + return x * y; + } + #else + #define SkMulS16(x, y) ((x) * (y)) + #endif +#endif + +/** Return a*b/255, truncating away any fractional bits. Only valid if both + a and b are 0..255 +*/ +static inline U8CPU SkMulDiv255Trunc(U8CPU a, U8CPU b) { + SkASSERT((uint8_t)a == a); + SkASSERT((uint8_t)b == b); + unsigned prod = SkMulS16(a, b) + 1; + return (prod + (prod >> 8)) >> 8; +} + +/** Return a*b/255, rounding any fractional bits. Only valid if both + a and b are 0..255 + */ +static inline U8CPU SkMulDiv255Round(U8CPU a, U8CPU b) { + SkASSERT((uint8_t)a == a); + SkASSERT((uint8_t)b == b); + unsigned prod = SkMulS16(a, b) + 128; + return (prod + (prod >> 8)) >> 8; +} + +/** Return a*b/((1 << shift) - 1), rounding any fractional bits. + Only valid if a and b are unsigned and <= 32767 and shift is > 0 and <= 8 +*/ +static inline unsigned SkMul16ShiftRound(unsigned a, unsigned b, int shift) { + SkASSERT(a <= 32767); + SkASSERT(b <= 32767); + SkASSERT(shift > 0 && shift <= 8); + unsigned prod = SkMulS16(a, b) + (1 << (shift - 1)); + return (prod + (prod >> shift)) >> shift; +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + class SkMath { + public: + static void UnitTest(); + }; +#endif + +#endif + diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h new file mode 100644 index 0000000000..2b25dcada3 --- /dev/null +++ b/include/core/SkMatrix.h @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkMatrix_DEFINED +#define SkMatrix_DEFINED + +#include "SkRect.h" + +class SkString; + +/** \class SkMatrix + + 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.). +*/ +class SkMatrix { +public: + /** Enum of bit fields for the mask return by getType(). + Use this to identify the complexity of the matrix. + */ + 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 + }; + + /** Returns a mask bitfield describing the types of transformations + that the matrix will perform. This information is used by routines + like mapPoints, to optimize its inner loops to only perform as much + arithmetic as is necessary. + */ + TypeMask getType() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + // only return the public masks + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if the matrix is identity. + */ + bool isIdentity() const { + return this->getType() == 0; + } + + /** 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. + */ + bool rectStaysRect() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + return (fTypeMask & kRectStaysRect_Mask) != 0; + } + + enum { + kMScaleX, + kMSkewX, + kMTransX, + kMSkewY, + kMScaleY, + kMTransY, + kMPersp0, + kMPersp1, + kMPersp2 + }; + + SkScalar operator[](int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + SkScalar get(int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + SkScalar getScaleX() const { return fMat[kMScaleX]; } + SkScalar getScaleY() const { return fMat[kMScaleY]; } + SkScalar getSkewY() const { return fMat[kMSkewY]; } + SkScalar getSkewX() const { return fMat[kMSkewX]; } + SkScalar getTranslateX() const { return fMat[kMTransX]; } + SkScalar getTranslateY() const { return fMat[kMTransY]; } + SkScalar getPerspX() const { return fMat[kMPersp0]; } + SkScalar getPerspY() const { return fMat[kMPersp1]; } + + void set(int index, SkScalar value) { + SkASSERT((unsigned)index < 9); + fMat[index] = value; + this->setTypeMask(kUnknown_Mask); + } + + void setScaleX(SkScalar v) { this->set(kMScaleX, v); } + void setScaleY(SkScalar v) { this->set(kMScaleY, v); } + void setSkewY(SkScalar v) { this->set(kMSkewY, v); } + void setSkewX(SkScalar v) { this->set(kMSkewX, v); } + void setTranslateX(SkScalar v) { this->set(kMTransX, v); } + void setTranslateY(SkScalar v) { this->set(kMTransY, v); } + void setPerspX(SkScalar v) { this->set(kMPersp0, v); } + void setPerspY(SkScalar v) { this->set(kMPersp1, v); } + + /** Set the matrix to identity + */ + void reset(); + + /** Set the matrix to translate by (dx, dy). + */ + void setTranslate(SkScalar dx, SkScalar dy); + /** 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. + */ + void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Set the matrix to scale by sx and sy. + */ + void setScale(SkScalar sx, SkScalar sy); + /** Set the matrix to rotate by the specified number of degrees, with a + pivot point at (px, py). The pivot point is the coordinate that should + remain unchanged by the specified transformation. + */ + void setRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Set the matrix to rotate about (0,0) by the specified number of degrees. + */ + 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. + */ + void setSinCos(SkScalar sinValue, SkScalar cosValue, + SkScalar px, SkScalar py); + /** Set the matrix to rotate by the specified sine and cosine values. + */ + void setSinCos(SkScalar sinValue, SkScalar cosValue); + /** 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. + */ + void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Set the matrix to skew by sx and sy. + */ + void setSkew(SkScalar kx, SkScalar ky); + /** Set the matrix to the concatenation of the two specified matrices, + returning true if the the result can be represented. Either of the + two matrices may also be the target matrix. *this = a * b; + */ + bool setConcat(const SkMatrix& a, const SkMatrix& b); + + /** Preconcats the matrix with the specified translation. + M' = M * T(dx, dy) + */ + bool preTranslate(SkScalar dx, SkScalar dy); + /** Preconcats the matrix with the specified scale. + M' = M * S(sx, sy, px, py) + */ + bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified scale. + M' = M * S(sx, sy) + */ + bool preScale(SkScalar sx, SkScalar sy); + /** Preconcats the matrix with the specified rotation. + M' = M * R(degrees, px, py) + */ + bool preRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified rotation. + M' = M * R(degrees) + */ + bool preRotate(SkScalar degrees); + /** Preconcats the matrix with the specified skew. + M' = M * K(kx, ky, px, py) + */ + bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Preconcats the matrix with the specified skew. + M' = M * K(kx, ky) + */ + bool preSkew(SkScalar kx, SkScalar ky); + /** Preconcats the matrix with the specified matrix. + M' = M * other + */ + bool preConcat(const SkMatrix& other); + + /** Postconcats the matrix with the specified translation. + M' = T(dx, dy) * M + */ + bool postTranslate(SkScalar dx, SkScalar dy); + /** Postconcats the matrix with the specified scale. + M' = S(sx, sy, px, py) * M + */ + bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified scale. + M' = S(sx, sy) * M + */ + bool postScale(SkScalar sx, SkScalar sy); + /** Postconcats the matrix by dividing it by the specified integers. + M' = S(1/divx, 1/divy, 0, 0) * M + */ + bool postIDiv(int divx, int divy); + /** Postconcats the matrix with the specified rotation. + M' = R(degrees, px, py) * M + */ + bool postRotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified rotation. + M' = R(degrees) * M + */ + bool postRotate(SkScalar degrees); + /** Postconcats the matrix with the specified skew. + M' = K(kx, ky, px, py) * M + */ + bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + /** Postconcats the matrix with the specified skew. + M' = K(kx, ky) * M + */ + bool postSkew(SkScalar kx, SkScalar ky); + /** Postconcats the matrix with the specified matrix. + M' = other * M + */ + bool postConcat(const SkMatrix& other); + + enum ScaleToFit { + /** + * Scale in X and Y independently, so that src matches dst exactly. + * This may change the aspect ratio of the src. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); + + /** 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 + */ + 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 + */ + bool invert(SkMatrix* inverse) const; + + /** 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. + */ + void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; + + /** 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. + */ + void mapPoints(SkPoint pts[], int count) const { + this->mapPoints(pts, pts, count); + } + + void mapXY(SkScalar x, SkScalar y, SkPoint* result) const { + SkASSERT(result); + this->getMapXYProc()(*this, x, y, 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. + */ + 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. + */ + void mapVectors(SkVector vecs[], int count) const { + this->mapVectors(vecs, vecs, count); + } + + /** 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() + */ + 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() + */ + bool mapRect(SkRect* rect) const { + return this->mapRect(rect, *rect); + } + + /** 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. + */ + SkScalar mapRadius(SkScalar radius) const; + + typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, + SkPoint* result); + + static MapXYProc GetMapXYProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapXYProcs[mask & kAllMasks]; + } + + MapXYProc getMapXYProc() const { + return GetMapXYProc(this->getType()); + } + + typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], + const SkPoint src[], int count); + + static MapPtsProc GetMapPtsProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapPtsProcs[mask & kAllMasks]; + } + + MapPtsProc getMapPtsProc() const { + return GetMapPtsProc(this->getType()); + } + + /** If the matrix can be stepped in X (not complex perspective) + then return true and if step[XY] is not null, return the step[XY] value. + If it cannot, return false and ignore step. + */ + bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const; + + friend bool operator==(const SkMatrix& a, const SkMatrix& b) { + return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0; + } + + friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { + return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0; + } + + void dump() const; + void toDumpString(SkString*) const; + +#ifdef SK_DEBUG + /** @cond UNIT_TEST */ + + static void UnitTest(); + /** @endcond */ +#endif + +private: + enum { + /** Set if the matrix will map a rectangle to another rectangle. This + can be true if the matrix is scale-only, or rotates a multiple of + 90 degrees. This bit is not set if the matrix is identity. + + This bit will be set on identity matrices + */ + kRectStaysRect_Mask = 0x10, + + kUnknown_Mask = 0x80, + + kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask + }; + + SkScalar fMat[9]; + mutable uint8_t fTypeMask; + + uint8_t computeTypeMask() const; + + void setTypeMask(int mask) { + // allow kUnknown or a valid mask + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask); + fTypeMask = SkToU8(mask); + } + + void clearTypeMask(int mask) { + // only allow a valid mask + SkASSERT((mask & kAllMasks) == mask); + fTypeMask &= ~mask; + } + + static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale); + + static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + + static const MapXYProc gMapXYProcs[]; + + static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); + static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static const MapPtsProc gMapPtsProcs[]; + + friend class SkPerspIter; +}; + +#endif + diff --git a/include/core/SkPackBits.h b/include/core/SkPackBits.h new file mode 100644 index 0000000000..c11231bd48 --- /dev/null +++ b/include/core/SkPackBits.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPackBits_DEFINED +#define SkPackBits_DEFINED + +#include "SkTypes.h" + +class SkPackBits { +public: + /** Given the number of 16bit values that will be passed to Pack16, + returns the worst-case size needed for the dst[] buffer. + */ + static size_t ComputeMaxSize16(int count); + + /** Given the number of 8bit values that will be passed to Pack8, + returns the worst-case size needed for the dst[] buffer. + */ + static size_t ComputeMaxSize8(int count); + + /** Write the src array into a packed format. The packing process may end + up writing more bytes than it read, so dst[] must be large enough. + @param src Input array of 16bit values + @param count Number of entries in src[] + @param dst Buffer (allocated by caller) to write the packed data + into + @return the number of bytes written to dst[] + */ + static size_t Pack16(const uint16_t src[], int count, uint8_t dst[]); + + /** Write the src array into a packed format. The packing process may end + up writing more bytes than it read, so dst[] must be large enough. + @param src Input array of 8bit values + @param count Number of entries in src[] + @param dst Buffer (allocated by caller) to write the packed data + into + @return the number of bytes written to dst[] + */ + static size_t Pack8(const uint8_t src[], int count, uint8_t dst[]); + + /** Unpack the data in src[], and expand it into dst[]. The src[] data was + written by a previous call to Pack16. + @param src Input data to unpack, previously created by Pack16. + @param srcSize Number of bytes of src to unpack + @param dst Buffer (allocated by caller) to expand the src[] into. + @return the number of dst elements (not bytes) written into dst. + */ + static int Unpack16(const uint8_t src[], size_t srcSize, uint16_t dst[]); + + /** Unpack the data in src[], and expand it into dst[]. The src[] data was + written by a previous call to Pack8. + @param src Input data to unpack, previously created by Pack8. + @param srcSize Number of bytes of src to unpack + @param dst Buffer (allocated by caller) to expand the src[] into. + @return the number of bytes written into dst. + */ + static int Unpack8(const uint8_t src[], size_t srcSize, uint8_t dst[]); + + /** Unpack the data from src[], skip the first dstSkip bytes, then write + dstWrite bytes into dst[]. The src[] data was written by a previous + call to Pack8. Return the number of bytes actually writtten into dst[] + @param src Input data to unpack, previously created by Pack8. + @param dst Buffer (allocated by caller) to expand the src[] into. + @param dstSkip Number of bytes of unpacked src to skip before writing + into dst + @param dstWrite Number of bytes of unpacked src to write into dst (after + skipping dstSkip bytes) + */ + static void Unpack8(uint8_t dst[], size_t dstSkip, size_t dstWrite, + const uint8_t src[]); +}; + +#endif diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h new file mode 100644 index 0000000000..fc390ab819 --- /dev/null +++ b/include/core/SkPaint.h @@ -0,0 +1,814 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPaint_DEFINED +#define SkPaint_DEFINED + +#include "SkColor.h" +#include "SkMath.h" +#include "SkPorterDuff.h" + +class SkAutoGlyphCache; +class SkColorFilter; +class SkDescriptor; +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; +struct SkGlyph; +struct SkRect; +class SkGlyphCache; +class SkMaskFilter; +class SkMatrix; +class SkPath; +class SkPathEffect; +class SkRasterizer; +class SkShader; +class SkDrawLooper; +class SkTypeface; +class SkXfermode; + +typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**, + SkFixed x, SkFixed y); + +typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**); + +/** \class SkPaint + + The SkPaint class holds the style and color information about how to draw + geometries, text and bitmaps. +*/ +class SkPaint { +public: + SkPaint(); + SkPaint(const SkPaint& paint); + ~SkPaint(); + + SkPaint& operator=(const SkPaint&); + + friend int operator==(const SkPaint& a, const SkPaint& b); + friend int operator!=(const SkPaint& a, const SkPaint& b) + { + return !(a == b); + } + + void flatten(SkFlattenableWriteBuffer&) const; + void unflatten(SkFlattenableReadBuffer&); + + /** Restores the paint to its initial settings. + */ + void reset(); + + /** Specifies the bit values that are stored in the paint's flags. + */ + enum Flags { + kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing + kFilterBitmap_Flag = 0x02, //!< mask to enable bitmap filtering + kDither_Flag = 0x04, //!< mask to enable dithering + kUnderlineText_Flag = 0x08, //!< mask to enable underline text + kStrikeThruText_Flag = 0x10, //!< mask to enable strike-thru text + kFakeBoldText_Flag = 0x20, //!< mask to enable fake-bold text + kLinearText_Flag = 0x40, //!< mask to enable linear-text + kSubpixelText_Flag = 0x80, //!< mask to enable subpixel-text + kDevKernText_Flag = 0x100, //!< mask to enable device kerning text + + kAllFlags = 0x1FF + }; + + /** Return the paint's flags. Use the Flag enum to test flag values. + @return the paint's flags (see enums ending in _Flag for bit masks) + */ + uint32_t getFlags() const { return fFlags; } + + /** Set the paint's flags. Use the Flag enum to specific flag values. + @param flags The new flag bits for the paint (see Flags enum) + */ + void setFlags(uint32_t flags); + + /** Helper for getFlags(), returning true if kAntiAlias_Flag bit is set + @return true if the antialias bit is set in the paint's flags. + */ + bool isAntiAlias() const + { + return SkToBool(this->getFlags() & kAntiAlias_Flag); + } + + /** Helper for setFlags(), setting or clearing the kAntiAlias_Flag bit + @param aa true to enable antialiasing, false to disable it + */ + void setAntiAlias(bool aa); + + /** Helper for getFlags(), returning true if kDither_Flag bit is set + @return true if the dithering bit is set in the paint's flags. + */ + bool isDither() const + { + return SkToBool(this->getFlags() & kDither_Flag); + } + + /** Helper for setFlags(), setting or clearing the kDither_Flag bit + @param dither true to enable dithering, false to disable it + */ + void setDither(bool dither); + + /** Helper for getFlags(), returning true if kLinearText_Flag bit is set + @return true if the lineartext bit is set in the paint's flags + */ + bool isLinearText() const + { + return SkToBool(this->getFlags() & kLinearText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kLinearText_Flag bit + @param linearText true to set the linearText bit in the paint's flags, + false to clear it. + */ + void setLinearText(bool linearText); + + /** Helper for getFlags(), returning true if kSubpixelText_Flag bit is set + @return true if the lineartext bit is set in the paint's flags + */ + bool isSubpixelText() const + { + return SkToBool(this->getFlags() & kSubpixelText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kSubpixelText_Flag bit + @param subpixelText true to set the subpixelText bit in the paint's + flags, false to clear it. + */ + void setSubpixelText(bool subpixelText); + + /** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set + @return true if the underlineText bit is set in the paint's flags. + */ + bool isUnderlineText() const + { + return SkToBool(this->getFlags() & kUnderlineText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kUnderlineText_Flag bit + @param underlineText true to set the underlineText bit in the paint's + flags, false to clear it. + */ + void setUnderlineText(bool underlineText); + + /** Helper for getFlags(), returns true if kStrikeThruText_Flag bit is set + @return true if the strikeThruText bit is set in the paint's flags. + */ + bool isStrikeThruText() const + { + return SkToBool(this->getFlags() & kStrikeThruText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kStrikeThruText_Flag bit + @param strikeThruText true to set the strikeThruText bit in the + paint's flags, false to clear it. + */ + void setStrikeThruText(bool strikeThruText); + + /** Helper for getFlags(), returns true if kFakeBoldText_Flag bit is set + @return true if the kFakeBoldText_Flag bit is set in the paint's flags. + */ + bool isFakeBoldText() const + { + return SkToBool(this->getFlags() & kFakeBoldText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kFakeBoldText_Flag bit + @param fakeBoldText true to set the kFakeBoldText_Flag bit in the paint's + flags, false to clear it. + */ + void setFakeBoldText(bool fakeBoldText); + + /** Helper for getFlags(), returns true if kDevKernText_Flag bit is set + @return true if the kernText bit is set in the paint's flags. + */ + bool isDevKernText() const + { + return SkToBool(this->getFlags() & kDevKernText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kKernText_Flag bit + @param kernText true to set the kKernText_Flag bit in the paint's + flags, false to clear it. + */ + void setDevKernText(bool devKernText); + + bool isFilterBitmap() const + { + return SkToBool(this->getFlags() & kFilterBitmap_Flag); + } + + void setFilterBitmap(bool filterBitmap); + + /** Styles apply to rect, oval, path, and text. + Bitmaps are always drawn in "fill", and lines are always drawn in + "stroke". + */ + enum Style { + kFill_Style, //!< fill with the paint's color + kStroke_Style, //!< stroke with the paint's color + kStrokeAndFill_Style, //!< fill and stroke with the paint's color + + kStyleCount, + }; + + /** Return the paint's style, used for controlling how primitives' + geometries are interpreted (except for drawBitmap, which always assumes + kFill_Style). + @return the paint's Style + */ + Style getStyle() const { return (Style)fStyle; } + + /** Set the paint's style, used for controlling how primitives' + geometries are interpreted (except for drawBitmap, which always assumes + Fill). + @param style The new style to set in the paint + */ + void setStyle(Style style); + + /** Return the paint's color. Note that the color is a 32bit value + containing alpha as well as r,g,b. This 32bit value is not + premultiplied, meaning that its alpha can be any value, regardless of + the values of r,g,b. + @return the paint's color (and alpha). + */ + SkColor getColor() const { return fColor; } + + /** Set the paint's color. Note that the color is a 32bit value containing + alpha as well as r,g,b. This 32bit value is not premultiplied, meaning + that its alpha can be any value, regardless of the values of r,g,b. + @param color The new color (including alpha) to set in the paint. + */ + void setColor(SkColor color); + + /** Helper to getColor() that just returns the color's alpha value. + @return the alpha component of the paint's color. + */ + uint8_t getAlpha() const { return SkToU8(SkColorGetA(fColor)); } + + /** Helper to setColor(), that only assigns the color's alpha value, + leaving its r,g,b values unchanged. + @param a set the alpha component (0..255) of the paint's color. + */ + void setAlpha(U8CPU a); + + /** Helper to setColor(), that takes a,r,g,b and constructs the color value + using SkColorSetARGB() + @param a The new alpha component (0..255) of the paint's color. + @param r The new red component (0..255) of the paint's color. + @param g The new green component (0..255) of the paint's color. + @param b The new blue component (0..255) of the paint's color. + */ + void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); + + /** Return the width for stroking. + <p /> + A value of 0 strokes in hairline mode. + Hairlines always draw 1-pixel wide, regardless of the matrix. + @return the paint's stroke width, used whenever the paint's style is + Stroke or StrokeAndFill. + */ + SkScalar getStrokeWidth() const { return fWidth; } + + /** Set the width for stroking. + Pass 0 to stroke in hairline mode. + Hairlines always draw 1-pixel wide, regardless of the matrix. + @param width set the paint's stroke width, used whenever the paint's + style is Stroke or StrokeAndFill. + */ + void setStrokeWidth(SkScalar width); + + /** Return the paint's stroke miter value. This is used to control the + behavior of miter joins when the joins angle is sharp. + @return the paint's miter limit, used whenever the paint's style is + Stroke or StrokeAndFill. + */ + SkScalar getStrokeMiter() const { return fMiterLimit; } + + /** Set the paint's stroke miter value. This is used to control the + behavior of miter joins when the joins angle is sharp. This value must + be >= 0. + @param miter set the miter limit on the paint, used whenever the + paint's style is Stroke or StrokeAndFill. + */ + void setStrokeMiter(SkScalar miter); + + /** Cap enum specifies the settings for the paint's strokecap. This is the + treatment that is applied to the beginning and end of each non-closed + contour (e.g. lines). + */ + enum Cap { + kButt_Cap, //!< begin/end contours with no extension + kRound_Cap, //!< begin/end contours with a semi-circle extension + kSquare_Cap, //!< begin/end contours with a half square extension + + kCapCount, + kDefault_Cap = kButt_Cap + }; + + /** Join enum specifies the settings for the paint's strokejoin. This is + the treatment that is applied to corners in paths and rectangles. + */ + enum Join { + kMiter_Join, //!< connect path segments with a sharp join + kRound_Join, //!< connect path segments with a round join + kBevel_Join, //!< connect path segments with a flat bevel join + + kJoinCount, + kDefault_Join = kMiter_Join + }; + + /** Return the paint's stroke cap type, controlling how the start and end + of stroked lines and paths are treated. + @return the line cap style for the paint, used whenever the paint's + style is Stroke or StrokeAndFill. + */ + Cap getStrokeCap() const { return (Cap)fCapType; } + + /** Set the paint's stroke cap type. + @param cap set the paint's line cap style, used whenever the paint's + style is Stroke or StrokeAndFill. + */ + void setStrokeCap(Cap cap); + + /** Return the paint's stroke join type. + @return the paint's line join style, used whenever the paint's style is + Stroke or StrokeAndFill. + */ + Join getStrokeJoin() const { return (Join)fJoinType; } + + /** Set the paint's stroke join type. + @param join set the paint's line join style, used whenever the paint's + style is Stroke or StrokeAndFill. + */ + void setStrokeJoin(Join join); + + /** Applies any/all effects (patheffect, stroking) to src, returning the + result in dst. The result is that drawing src with this paint will be + the same as drawing dst with a default paint (at least from the + geometric perspective). + @param src input path + @param dst output path (may be the same as src) + @return true if the path should be filled, or false if it should be + drawn with a hairline (width == 0) + */ + bool getFillPath(const SkPath& src, SkPath* dst) const; + + /** Returns true if the current paint settings allow for fast computation of + bounds (i.e. there is nothing complex like a patheffect that would make + the bounds computation expensive. + */ + bool canComputeFastBounds() const; + + /** Only call this if canComputeFastBounds() returned true. This takes a + raw rectangle (the raw bounds of a shape), and adjusts it for stylistic + effects in the paint (e.g. stroking). If needed, it uses the storage + rect parameter. It returns the adjusted bounds that can then be used + for quickReject tests. + + The returned rect will either be orig or storage, thus the caller + should not rely on storage being set to the result, but should always + use the retured value. It is legal for orig and storage to be the same + rect. + + e.g. + if (paint.canComputeFastBounds()) { + SkRect r, storage; + path.computeBounds(&r, SkPath::kFast_BoundsType); + const SkRect& fastR = paint.computeFastBounds(r, &storage); + if (canvas->quickReject(fastR, ...)) { + // don't draw the path + } + } + */ + const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const; + + /** Get the paint's shader object. + <p /> + The shader's reference count is not affected. + @return the paint's shader (or NULL) + */ + SkShader* getShader() const { return fShader; } + + /** Set or clear the shader object. + <p /> + Pass NULL to clear any previous shader. + As a convenience, the parameter passed is also returned. + If a previous shader exists, its reference count is decremented. + If shader is not NULL, its reference count is incremented. + @param shader May be NULL. The shader to be installed in the paint + @return shader + */ + SkShader* setShader(SkShader* shader); + + /** Get the paint's colorfilter. If there is a colorfilter, its reference + count is not changed. + @return the paint's colorfilter (or NULL) + */ + SkColorFilter* getColorFilter() const { return fColorFilter; } + + /** Set or clear the paint's colorfilter, returning the parameter. + <p /> + If the paint already has a filter, its reference count is decremented. + If filter is not NULL, its reference count is incremented. + @param filter May be NULL. The filter to be installed in the paint + @return filter + */ + SkColorFilter* setColorFilter(SkColorFilter* filter); + + /** Get the paint's xfermode object. + <p /> + The xfermode's reference count is not affected. + @return the paint's xfermode (or NULL) + */ + SkXfermode* getXfermode() const { return fXfermode; } + + /** Set or clear the xfermode object. + <p /> + Pass NULL to clear any previous xfermode. + As a convenience, the parameter passed is also returned. + If a previous xfermode exists, its reference count is decremented. + If xfermode is not NULL, its reference count is incremented. + @param xfermode May be NULL. The new xfermode to be installed in the + paint + @return xfermode + */ + SkXfermode* setXfermode(SkXfermode* xfermode); + + /** Helper for setXfermode, passing the corresponding xfermode object + returned from the PorterDuff factory. + @param mode The porter-duff mode used to create an xfermode for the + paint. + @return the resulting xfermode object (or NULL if the mode is + SrcOver) + */ + SkXfermode* setPorterDuffXfermode(SkPorterDuff::Mode mode); + + /** Get the paint's patheffect object. + <p /> + The patheffect reference count is not affected. + @return the paint's patheffect (or NULL) + */ + SkPathEffect* getPathEffect() const { return fPathEffect; } + + /** Set or clear the patheffect object. + <p /> + Pass NULL to clear any previous patheffect. + As a convenience, the parameter passed is also returned. + If a previous patheffect exists, its reference count is decremented. + If patheffect is not NULL, its reference count is incremented. + @param effect May be NULL. The new patheffect to be installed in the + paint + @return effect + */ + SkPathEffect* setPathEffect(SkPathEffect* effect); + + /** Get the paint's maskfilter object. + <p /> + The maskfilter reference count is not affected. + @return the paint's maskfilter (or NULL) + */ + SkMaskFilter* getMaskFilter() const { return fMaskFilter; } + + /** Set or clear the maskfilter object. + <p /> + Pass NULL to clear any previous maskfilter. + As a convenience, the parameter passed is also returned. + If a previous maskfilter exists, its reference count is decremented. + If maskfilter is not NULL, its reference count is incremented. + @param maskfilter May be NULL. The new maskfilter to be installed in + the paint + @return maskfilter + */ + SkMaskFilter* setMaskFilter(SkMaskFilter* maskfilter); + + // These attributes are for text/fonts + + /** Get the paint's typeface object. + <p /> + The typeface object identifies which font to use when drawing or + measuring text. The typeface reference count is not affected. + @return the paint's typeface (or NULL) + */ + SkTypeface* getTypeface() const { return fTypeface; } + + /** Set or clear the typeface object. + <p /> + Pass NULL to clear any previous typeface. + As a convenience, the parameter passed is also returned. + If a previous typeface exists, its reference count is decremented. + If typeface is not NULL, its reference count is incremented. + @param typeface May be NULL. The new typeface to be installed in the + paint + @return typeface + */ + SkTypeface* setTypeface(SkTypeface* typeface); + + /** Get the paint's rasterizer (or NULL). + <p /> + The raster controls how paths/text are turned into alpha masks. + @return the paint's rasterizer (or NULL) + */ + SkRasterizer* getRasterizer() const { return fRasterizer; } + + /** Set or clear the rasterizer object. + <p /> + Pass NULL to clear any previous rasterizer. + As a convenience, the parameter passed is also returned. + If a previous rasterizer exists in the paint, its reference count is + decremented. If rasterizer is not NULL, its reference count is + incremented. + @param rasterizer May be NULL. The new rasterizer to be installed in + the paint. + @return rasterizer + */ + SkRasterizer* setRasterizer(SkRasterizer* rasterizer); + + SkDrawLooper* getLooper() const { return fLooper; } + SkDrawLooper* setLooper(SkDrawLooper*); + + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + + kAlignCount + }; + /** Return the paint's Align value for drawing text. + @return the paint's Align value for drawing text. + */ + Align getTextAlign() const { return (Align)fTextAlign; } + /** Set the paint's text alignment. + @param align set the paint's Align value for drawing text. + */ + void setTextAlign(Align align); + + /** Return the paint's text size. + @return the paint's text size. + */ + SkScalar getTextSize() const { return fTextSize; } + + /** Set the paint's text size. This value must be > 0 + @param textSize set the paint's text size. + */ + void setTextSize(SkScalar textSize); + + /** Return the paint's horizontal scale factor for text. The default value + is 1.0. + @return the paint's scale factor in X for drawing/measuring text + */ + SkScalar getTextScaleX() const { return fTextScaleX; } + + /** Set the paint's horizontal scale factor for text. The default value + is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will + stretch the text narrower. + @param scaleX set the paint's scale factor in X for drawing/measuring + text. + */ + void setTextScaleX(SkScalar scaleX); + + /** Return the paint's horizontal skew factor for text. The default value + is 0. + @return the paint's skew factor in X for drawing text. + */ + SkScalar getTextSkewX() const { return fTextSkewX; } + + /** Set the paint's horizontal skew factor for text. The default value + is 0. For approximating oblique text, use values around -0.25. + @param skewX set the paint's skew factor in X for drawing text. + */ + void setTextSkewX(SkScalar skewX); + + /** Describes how to interpret the text parameters that are passed to paint + methods like measureText() and getTextWidths(). + */ + enum TextEncoding { + kUTF8_TextEncoding, //!< the text parameters are UTF8 + kUTF16_TextEncoding, //!< the text parameters are UTF16 + kGlyphID_TextEncoding //!< the text parameters are glyph indices + }; + + TextEncoding getTextEncoding() const + { + return (TextEncoding)fTextEncoding; + } + + void setTextEncoding(TextEncoding encoding); + + struct FontMetrics { + SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0) + SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0) + SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0) + SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0) + SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0) + }; + + /** Return the recommend spacing between lines (which will be + fDescent - fAscent + fLeading). + If metrics is not null, return in it the font metrics for the + typeface/pointsize/etc. currently set in the paint. + @param metrics If not null, returns the font metrics for the + current typeface/pointsize/etc setting in this + paint. + @param scale If not 0, return width as if the canvas were scaled + by this value + @param return the recommended spacing between lines + */ + SkScalar getFontMetrics(FontMetrics* metrics, SkScalar scale = 0) const; + + /** Return the recommend line spacing. This will be + fDescent - fAscent + fLeading + */ + SkScalar getFontSpacing() const { return this->getFontMetrics(NULL, 0); } + + /** Convert the specified text into glyph IDs, returning the number of + glyphs ID written. If glyphs is NULL, it is ignore and only the count + is returned. + */ + int textToGlyphs(const void* text, size_t byteLength, + uint16_t glyphs[]) const; + + /** Return the number of drawable units in the specified text buffer. + This looks at the current TextEncoding field of the paint. If you also + want to have the text converted into glyph IDs, call textToGlyphs + instead. + */ + int countText(const void* text, size_t byteLength) const + { + return this->textToGlyphs(text, byteLength, NULL); + } + + /** Return the width of the text. + @param text The text to be measured + @param length Number of bytes of text to measure + @param bounds If not NULL, returns the bounds of the text, + relative to (0, 0). + @param scale If not 0, return width as if the canvas were scaled + by this value + @return The advance width of the text + */ + SkScalar measureText(const void* text, size_t length, + SkRect* bounds, SkScalar scale = 0) const; + + /** Return the width of the text. + @param text Address of the text + @param length Number of bytes of text to measure + @return The width of the text + */ + SkScalar measureText(const void* text, size_t length) const + { + return this->measureText(text, length, NULL, 0); + } + + /** Specify the direction the text buffer should be processed in breakText() + */ + enum TextBufferDirection { + /** When measuring text for breakText(), begin at the start of the text + buffer and proceed forward through the data. This is the default. + */ + kForward_TextBufferDirection, + /** When measuring text for breakText(), begin at the end of the text + buffer and proceed backwards through the data. + */ + kBackward_TextBufferDirection + }; + + /** Return the width of the text. + @param text The text to be measured + @param length Number of bytes of text to measure + @param maxWidth Maximum width. Only the subset of text whose accumulated + widths are <= maxWidth are measured. + @param measuredWidth Optional. If non-null, this returns the actual + width of the measured text. + @param tbd Optional. The direction the text buffer should be + traversed during measuring. + @return The number of bytes of text that were measured. Will be + <= length. + */ + size_t breakText(const void* text, size_t length, SkScalar maxWidth, + SkScalar* measuredWidth = NULL, + TextBufferDirection tbd = kForward_TextBufferDirection) + const; + + /** Return the advance widths for the characters in the string. + @param text the text + @param byteLength number of bytes to of text + @param widths If not null, returns the array of advance widths of + the glyphs. If not NULL, must be at least a large + as the number of unichars in the specified text. + @param bounds If not null, returns the bounds for each of + character, relative to (0, 0) + @return the number of unichars in the specified text. + */ + int getTextWidths(const void* text, size_t byteLength, SkScalar widths[], + SkRect bounds[] = NULL) const; + + /** Return the path (outline) for the specified text. + Note: just like SkCanvas::drawText, this will respect the Align setting + in the paint. + */ + void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y, + SkPath* path) const; + +private: + SkTypeface* fTypeface; + SkScalar fTextSize; + SkScalar fTextScaleX; + SkScalar fTextSkewX; + + SkPathEffect* fPathEffect; + SkShader* fShader; + SkXfermode* fXfermode; + SkMaskFilter* fMaskFilter; + SkColorFilter* fColorFilter; + SkRasterizer* fRasterizer; + SkDrawLooper* fLooper; + + SkColor fColor; + SkScalar fWidth; + SkScalar fMiterLimit; + unsigned fFlags : 9; + unsigned fTextAlign : 2; + unsigned fCapType : 2; + unsigned fJoinType : 2; + unsigned fStyle : 2; + unsigned fTextEncoding : 2; // 3 values + + SkDrawCacheProc getDrawCacheProc() const; + SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir, + bool needFullMetrics) const; + + SkScalar measure_text(SkGlyphCache*, const char* text, size_t length, + int* count, SkRect* bounds) const; + + SkGlyphCache* detachCache(const SkMatrix*) const; + + void descriptorProc(const SkMatrix* deviceMatrix, + void (*proc)(const SkDescriptor*, void*), + void* context) const; + + enum { + kCanonicalTextSizeForPaths = 64 + }; + friend class SkCanvas; + friend class SkDraw; + friend class SkAutoGlyphCache; + friend class SkTextToPathIter; +}; + +////////////////////////////////////////////////////////////////////////// + +#include "SkPathEffect.h" + +/** \class SkStrokePathEffect + + SkStrokePathEffect simulates stroking inside a patheffect, allowing the + caller to have explicit control of when to stroke a path. Typically this is + used if the caller wants to stroke before another patheffect is applied + (using SkComposePathEffect or SkSumPathEffect). +*/ +class SkStrokePathEffect : public SkPathEffect { +public: + SkStrokePathEffect(const SkPaint&); + SkStrokePathEffect(SkScalar width, SkPaint::Style, SkPaint::Join, + SkPaint::Cap, SkScalar miterLimit = -1); + + // overrides + // This method is not exported to java. + virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width); + + // overrides for SkFlattenable + // This method is not exported to java. + virtual void flatten(SkFlattenableWriteBuffer&); + // This method is not exported to java. + virtual Factory getFactory(); + +private: + SkScalar fWidth, fMiter; + uint8_t fStyle, fJoin, fCap; + + static SkFlattenable* CreateProc(SkFlattenableReadBuffer&); + SkStrokePathEffect(SkFlattenableReadBuffer&); + + typedef SkPathEffect INHERITED; + + // illegal + SkStrokePathEffect(const SkStrokePathEffect&); + SkStrokePathEffect& operator=(const SkStrokePathEffect&); +}; + +#endif + diff --git a/include/core/SkPath.h b/include/core/SkPath.h new file mode 100644 index 0000000000..e2409ad6ba --- /dev/null +++ b/include/core/SkPath.h @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPath_DEFINED +#define SkPath_DEFINED + +#include "SkMatrix.h" +#include "SkTDArray.h" + +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; +class SkAutoPathBoundsUpdate; +class SkString; + +/** \class SkPath + + The SkPath class encapsulates compound (multiple contour) geometric paths + consisting of straight line segments, quadratic curves, and cubic curves. +*/ +class SkPath { +public: + SkPath(); + SkPath(const SkPath&); + ~SkPath(); + + SkPath& operator=(const SkPath&); + + enum FillType { + /** Specifies that "inside" is computed by a non-zero sum of signed + edge crossings + */ + kWinding_FillType, + /** Specifies that "inside" is computed by an odd number of edge + crossings + */ + kEvenOdd_FillType, + /** Same as Winding, but draws outside of the path, rather than inside + */ + kInverseWinding_FillType, + /** Same as EvenOdd, but draws outside of the path, rather than inside + */ + kInverseEvenOdd_FillType + }; + + /** Return the path's fill type. This is used to define how "inside" is + computed. The default value is kWinding_FillType. + + @return the path's fill type + */ + FillType getFillType() const { return (FillType)fFillType; } + + /** Set the path's fill type. This is used to define how "inside" is + computed. The default value is kWinding_FillType. + + @param ft The new fill type for this path + */ + void setFillType(FillType ft) { fFillType = SkToU8(ft); } + + /** Returns true if the filltype is one of the Inverse variants */ + bool isInverseFillType() const { return (fFillType & 2) != 0; } + + /** Toggle between inverse and normal filltypes. This reverse the return + value of isInverseFillType() + */ + void toggleInverseFillType() { fFillType ^= 2; } + + /** Clear any lines and curves from the path, making it empty. This frees up + internal storage associated with those segments. + This does NOT change the fill-type setting. + */ + void reset(); + + /** Similar to reset(), in that all lines and curves are removed from the + path. However, any internal storage for those lines/curves is retained, + making reuse of the path potentially faster. + This does NOT change the fill-type setting. + */ + void rewind(); + + /** Returns true if the path is empty (contains no lines or curves) + + @return true if the path is empty (contains no lines or curves) + */ + bool isEmpty() const; + + /** Returns true if the path specifies a rectangle. If so, and if rect is + not null, set rect to the bounds of the path. If the path does not + specify a rectangle, return false and ignore rect. + + @param rect If not null, returns the bounds of the path if it specifies + a rectangle + @return true if the path specifies a rectangle + */ + bool isRect(SkRect* rect) const; + + /** Returns the number of points in the path. Up to max points are copied. + + @param points If not null, receives up to max points + @param max The maximum number of points to copy into points + @return the actual number of points in the path + */ + int getPoints(SkPoint points[], int max) const; + + //! Swap contents of this and other. Guaranteed not to throw + void swap(SkPath& other); + + enum BoundsType { + /** compute the bounds of the path's control points, may be larger than + with kExact_BoundsType, but may be faster to compute + */ + kFast_BoundsType, + /** compute the exact bounds of the path, may be smaller than with + kFast_BoundsType, but may be slower to compute + */ + kExact_BoundsType + }; + + /** Compute the bounds of the path, and write the answer into bounds. If the + path contains 0 or 1 points, the bounds is set to (0,0,0,0) + + @param bounds Returns the computed bounds of the path + @param btype Specifies if the computed bounds should be exact + (slower) or approximate (faster) + */ + void computeBounds(SkRect* bounds, BoundsType btype) const; + + /** Calling this will, if the internal cache of the bounds is out of date, + update it so that subsequent calls to computeBounds will be instanteous. + This also means that any copies or simple transformations of the path + will inherit the cached bounds. + */ + void updateBoundsCache() const; + + // Construction methods + + /** Hint to the path to prepare for adding more points. This can allow the + path to more efficiently grow its storage. + + @param extraPtCount The number of extra points the path should + preallocate for. + */ + void incReserve(unsigned extraPtCount); + + /** Set the beginning of the next contour to the point (x,y). + + @param x The x-coordinate of the start of a new contour + @param y The y-coordinate of the start of a new contour + */ + void moveTo(SkScalar x, SkScalar y); + + /** Set the beginning of the next contour to the point + + @param p The start of a new contour + */ + void moveTo(const SkPoint& p) { + this->moveTo(p.fX, p.fY); + } + + /** Set the beginning of the next contour relative to the last point on the + previous contour. If there is no previous contour, this is treated the + same as moveTo(). + + @param dx The amount to add to the x-coordinate of the end of the + previous contour, to specify the start of a new contour + @param dy The amount to add to the y-coordinate of the end of the + previous contour, to specify the start of a new contour + */ + void rMoveTo(SkScalar dx, SkScalar dy); + + /** Add a line from the last point to the specified point (x,y). If no + moveTo() call has been made for this contour, the first point is + automatically set to (0,0). + + @param x The x-coordinate of the end of a line + @param y The y-coordinate of the end of a line + */ + void lineTo(SkScalar x, SkScalar y); + + /** Add a line from the last point to the specified point. If no moveTo() + call has been made for this contour, the first point is automatically + set to (0,0). + + @param p The end of a line + */ + void lineTo(const SkPoint& p) { + this->lineTo(p.fX, p.fY); + } + + /** Same as lineTo, but the coordinates are considered relative to the last + point on this contour. If there is no previous point, then a moveTo(0,0) + is inserted automatically. + + @param dx The amount to add to the x-coordinate of the previous point + on this contour, to specify a line + @param dy The amount to add to the y-coordinate of the previous point + on this contour, to specify a line + */ + void rLineTo(SkScalar dx, SkScalar dy); + + /** Add a quadratic bezier from the last point, approaching control point + (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for + this contour, the first point is automatically set to (0,0). + + @param x1 The x-coordinate of the control point on a quadratic curve + @param y1 The y-coordinate of the control point on a quadratic curve + @param x2 The x-coordinate of the end point on a quadratic curve + @param y2 The y-coordinate of the end point on a quadratic curve + */ + void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); + + /** Add a quadratic bezier from the last point, approaching control point + p1, and ending at p2. If no moveTo() call has been made for this + contour, the first point is automatically set to (0,0). + + @param p1 The control point on a quadratic curve + @param p2 The end point on a quadratic curve + */ + void quadTo(const SkPoint& p1, const SkPoint& p2) { + this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); + } + + /** Same as quadTo, but the coordinates are considered relative to the last + point on this contour. If there is no previous point, then a moveTo(0,0) + is inserted automatically. + + @param dx1 The amount to add to the x-coordinate of the last point on + this contour, to specify the control point of a quadratic curve + @param dy1 The amount to add to the y-coordinate of the last point on + this contour, to specify the control point of a quadratic curve + @param dx2 The amount to add to the x-coordinate of the last point on + this contour, to specify the end point of a quadratic curve + @param dy2 The amount to add to the y-coordinate of the last point on + this contour, to specify the end point of a quadratic curve + */ + void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); + + /** Add a cubic bezier from the last point, approaching control points + (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been + made for this contour, the first point is automatically set to (0,0). + + @param x1 The x-coordinate of the 1st control point on a cubic curve + @param y1 The y-coordinate of the 1st control point on a cubic curve + @param x2 The x-coordinate of the 2nd control point on a cubic curve + @param y2 The y-coordinate of the 2nd control point on a cubic curve + @param x3 The x-coordinate of the end point on a cubic curve + @param y3 The y-coordinate of the end point on a cubic curve + */ + void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar x3, SkScalar y3); + + /** Add a cubic bezier from the last point, approaching control points p1 + and p2, and ending at p3. If no moveTo() call has been made for this + contour, the first point is automatically set to (0,0). + + @param p1 The 1st control point on a cubic curve + @param p2 The 2nd control point on a cubic curve + @param p3 The end point on a cubic curve + */ + void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { + this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); + } + + /** Same as cubicTo, but the coordinates are considered relative to the + current point on this contour. If there is no previous point, then a + moveTo(0,0) is inserted automatically. + + @param dx1 The amount to add to the x-coordinate of the last point on + this contour, to specify the 1st control point of a cubic curve + @param dy1 The amount to add to the y-coordinate of the last point on + this contour, to specify the 1st control point of a cubic curve + @param dx2 The amount to add to the x-coordinate of the last point on + this contour, to specify the 2nd control point of a cubic curve + @param dy2 The amount to add to the y-coordinate of the last point on + this contour, to specify the 2nd control point of a cubic curve + @param dx3 The amount to add to the x-coordinate of the last point on + this contour, to specify the end point of a cubic curve + @param dy3 The amount to add to the y-coordinate of the last point on + this contour, to specify the end point of a cubic curve + */ + void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar x3, SkScalar y3); + + /** Append the specified arc to the path as a new contour. If the start of + the path is different from the path's current last point, then an + automatic lineTo() is added to connect the current contour to the start + of the arc. However, if the path is empty, then we call moveTo() with + the first point of the arc. The sweep angle is treated mod 360. + + @param oval The bounding oval defining the shape and size of the arc + @param startAngle Starting angle (in degrees) where the arc begins + @param sweepAngle Sweep angle (in degrees) measured clockwise. This is + treated mod 360. + @param forceMoveTo If true, always begin a new contour with the arc + */ + void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool forceMoveTo); + + /** Append a line and arc to the current path. This is the same as the + PostScript call "arct". + */ + void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar radius); + + /** Append a line and arc to the current path. This is the same as the + PostScript call "arct". + */ + void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { + this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); + } + + /** Close the current contour. If the current point is not equal to the + first point of the contour, a line segment is automatically added. + */ + void close(); + + enum Direction { + /** clockwise direction for adding closed contours */ + kCW_Direction, + /** counter-clockwise direction for adding closed contours */ + kCCW_Direction + }; + + /** Add a closed rectangle contour to the path + @param rect The rectangle to add as a closed contour to the path + @param dir The direction to wind the rectangle's contour + */ + void addRect(const SkRect& rect, Direction dir = kCW_Direction); + + /** Add a closed rectangle contour to the path + + @param left The left side of a rectangle to add as a closed contour + to the path + @param top The top of a rectangle to add as a closed contour to the + path + @param right The right side of a rectangle to add as a closed contour + to the path + @param bottom The bottom of a rectangle to add as a closed contour to + the path + @param dir The direction to wind the rectangle's contour + */ + void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, + Direction dir = kCW_Direction); + + /** Add a closed oval contour to the path + + @param oval The bounding oval to add as a closed contour to the path + @param dir The direction to wind the oval's contour + */ + void addOval(const SkRect& oval, Direction dir = kCW_Direction); + + /** Add a closed circle contour to the path + + @param x The x-coordinate of the center of a circle to add as a + closed contour to the path + @param y The y-coordinate of the center of a circle to add as a + closed contour to the path + @param radius The radius of a circle to add as a closed contour to the + path + @param dir The direction to wind the circle's contour + */ + void addCircle(SkScalar x, SkScalar y, SkScalar radius, + Direction dir = kCW_Direction); + + /** Add the specified arc to the path as a new contour. + + @param oval The bounds of oval used to define the size of the arc + @param startAngle Starting angle (in degrees) where the arc begins + @param sweepAngle Sweep angle (in degrees) measured clockwise + */ + void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); + + /** Add a closed round-rectangle contour to the path + @param rect The bounds of a round-rectangle to add as a closed contour + @param rx The x-radius of the rounded corners on the round-rectangle + @param ry The y-radius of the rounded corners on the round-rectangle + @param dir The direction to wind the round-rectangle's contour + */ + void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, + Direction dir = kCW_Direction); + + /** Add a closed round-rectangle contour to the path. Each corner receives + two radius values [X, Y]. The corners are ordered top-left, top-right, + bottom-right, bottom-left. + @param rect The bounds of a round-rectangle to add as a closed contour + @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner + @param dir The direction to wind the round-rectangle's contour + */ + void addRoundRect(const SkRect& rect, const SkScalar radii[], + Direction dir = kCW_Direction); + + /** Add a copy of src to the path, offset by (dx,dy) + @param src The path to add as a new contour + @param dx The amount to translate the path in X as it is added + @param dx The amount to translate the path in Y as it is added + */ + void addPath(const SkPath& src, SkScalar dx, SkScalar dy); + + /** Add a copy of src to the path + */ + void addPath(const SkPath& src) { + SkMatrix m; + m.reset(); + this->addPath(src, m); + } + + /** Add a copy of src to the path, transformed by matrix + @param src The path to add as a new contour + */ + void addPath(const SkPath& src, const SkMatrix& matrix); + + /** Offset the path by (dx,dy), returning true on success + + @param dx The amount in the X direction to offset the entire path + @param dy The amount in the Y direction to offset the entire path + @param dst The translated path is written here + */ + void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; + + /** Offset the path by (dx,dy), returning true on success + + @param dx The amount in the X direction to offset the entire path + @param dy The amount in the Y direction to offset the entire path + */ + void offset(SkScalar dx, SkScalar dy) { + this->offset(dx, dy, this); + } + + /** Transform the points in this path by matrix, and write the answer into + dst. + + @param matrix The matrix to apply to the path + @param dst The transformed path is written here + */ + void transform(const SkMatrix& matrix, SkPath* dst) const; + + /** Transform the points in this path by matrix + + @param matrix The matrix to apply to the path + */ + void transform(const SkMatrix& matrix) { + this->transform(matrix, this); + } + + /** Return the last point on the path. If no points have been added, (0,0) + is returned. + + @param lastPt The last point on the path is returned here + */ + void getLastPt(SkPoint* lastPt) const; + + /** Set the last point on the path. If no points have been added, + moveTo(x,y) is automatically called. + + @param x The new x-coordinate for the last point + @param y The new y-coordinate for the last point + */ + void setLastPt(SkScalar x, SkScalar y); + + /** Set the last point on the path. If no points have been added, moveTo(p) + is automatically called. + + @param p The new location for the last point + */ + void setLastPt(const SkPoint& p) { + this->setLastPt(p.fX, p.fY); + } + + enum Verb { + kMove_Verb, //!< iter.next returns 1 point + kLine_Verb, //!< iter.next returns 2 points + kQuad_Verb, //!< iter.next returns 3 points + kCubic_Verb, //!< iter.next returns 4 points + kClose_Verb, //!< iter.next returns 1 point (the last point) + kDone_Verb //!< iter.next returns 0 points + }; + + /** Iterate through all of the segments (lines, quadratics, cubics) of + each contours in a path. + */ + class Iter { + public: + Iter(); + Iter(const SkPath&, bool forceClose); + + void setPath(const SkPath&, bool forceClose); + + /** Return the next verb in this iteration of the path. When all + segments have been visited, return kDone_Verb. + + @param pts The points representing the current verb and/or segment + @return The verb for the current segment + */ + Verb next(SkPoint pts[4]); + + /** If next() returns kLine_Verb, then this query returns true if the + line was the result of a close() command (i.e. the end point is the + initial moveto for this contour). If next() returned a different + verb, this returns an undefined value. + + @return If the last call to next() returned kLine_Verb, return true + if it was the result of an explicit close command. + */ + bool isCloseLine() const { return SkToBool(fCloseLine); } + + /** Returns true if the current contour is closed (has a kClose_Verb) + @return true if the current contour is closed (has a kClose_Verb) + */ + bool isClosedContour() const; + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + SkPoint fMoveTo; + SkPoint fLastPt; + SkBool8 fForceClose; + SkBool8 fNeedClose; + SkBool8 fNeedMoveTo; + SkBool8 fCloseLine; + + bool cons_moveTo(SkPoint pts[1]); + Verb autoClose(SkPoint pts[2]); + }; + +#ifdef SK_DEBUG + /** @cond UNIT_TEST */ + void dump(bool forceClose, const char title[] = NULL) const; + static void UnitTest(); + /** @endcond */ +#endif + + void flatten(SkFlattenableWriteBuffer&) const; + void unflatten(SkFlattenableReadBuffer&); + + /** Subdivide the path so that no segment is longer that dist. + If bendLines is true, then turn all line segments into curves. + If dst == null, then the original path itself is modified (not const!) + */ + void subdivide(SkScalar dist, bool bendLines, SkPath* dst = NULL) const; + + /** Return an SVG-compatible string of the path. + */ + void toString(SkString*) const; + + SkDEBUGCODE(void validate() const;) + +private: + SkTDArray<SkPoint> fPts; + SkTDArray<uint8_t> fVerbs; + mutable SkRect fFastBounds; + mutable uint8_t fFastBoundsIsDirty; + uint8_t fFillType; + + friend class Iter; + void cons_moveto(); + + friend class SkPathStroker; + /* Append the first contour of path, ignoring path's initial point. If no + moveTo() call has been made for this contour, the first point is + automatically set to (0,0). + */ + void pathTo(const SkPath& path); + + /* Append, in reverse order, the first contour of path, ignoring path's + last point. If no moveTo() call has been made for this contour, the + first point is automatically set to (0,0). + */ + void reversePathTo(const SkPath&); + + friend const SkPoint* sk_get_path_points(const SkPath&, int index); + friend class SkAutoPathBoundsUpdate; +}; + +#endif + diff --git a/include/core/SkPathEffect.h b/include/core/SkPathEffect.h new file mode 100644 index 0000000000..f97adb7904 --- /dev/null +++ b/include/core/SkPathEffect.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPathEffect_DEFINED +#define SkPathEffect_DEFINED + +#include "SkFlattenable.h" + +class SkPath; + +/** \class SkPathEffect + + SkPathEffect is the base class for objects in the SkPaint that affect + the geometry of a drawing primitive before it is transformed by the + canvas' matrix and drawn. + + Dashing is implemented as a subclass of SkPathEffect. +*/ +class SkPathEffect : public SkFlattenable { +public: + // This method is not exported to java. + SkPathEffect() {} + + /** Given a src path and a width value, return true if the patheffect + has produced a new path (dst) and a new width value. If false is returned, + ignore dst and width. + On input, width >= 0 means the src should be stroked + On output, width >= 0 means the dst should be stroked + */ + virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) = 0; + +private: + // illegal + SkPathEffect(const SkPathEffect&); + SkPathEffect& operator=(const SkPathEffect&); +}; + +/** \class SkPairPathEffect + + Common baseclass for Compose and Sum. This subclass manages two pathEffects, + including flattening them. It does nothing in filterPath, and is only useful + for managing the lifetimes of its two arguments. +*/ +class SkPairPathEffect : public SkPathEffect { +public: + SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1); + virtual ~SkPairPathEffect(); + +protected: + SkPairPathEffect(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&); + // these are visible to our subclasses + SkPathEffect* fPE0, *fPE1; + +private: + typedef SkPathEffect INHERITED; +}; + +/** \class SkComposePathEffect + + This subclass of SkPathEffect composes its two arguments, to create + a compound pathEffect. +*/ +class SkComposePathEffect : public SkPairPathEffect { +public: + /** Construct a pathEffect whose effect is to apply first the inner pathEffect + and the the outer pathEffect (e.g. outer(inner(path))) + The reference counts for outer and inner are both incremented in the constructor, + and decremented in the destructor. + */ + SkComposePathEffect(SkPathEffect* outer, SkPathEffect* inner) + : INHERITED(outer, inner) {} + + // overrides + + // This method is not exported to java. + virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width); + +protected: + virtual Factory getFactory() { return CreateProc; } + +private: + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkComposePathEffect, (buffer)); + } + SkComposePathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + + // illegal + SkComposePathEffect(const SkComposePathEffect&); + SkComposePathEffect& operator=(const SkComposePathEffect&); + + typedef SkPairPathEffect INHERITED; +}; + +/** \class SkSumPathEffect + + This subclass of SkPathEffect applies two pathEffects, one after the other. + Its filterPath() returns true if either of the effects succeeded. +*/ +class SkSumPathEffect : public SkPairPathEffect { +public: + /** Construct a pathEffect whose effect is to apply two effects, in sequence. + (e.g. first(path) + second(path)) + The reference counts for first and second are both incremented in the constructor, + and decremented in the destructor. + */ + SkSumPathEffect(SkPathEffect* first, SkPathEffect* second) + : INHERITED(first, second) {} + + // overrides + // This method is not exported to java. + virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width); + +protected: + virtual Factory getFactory() { return CreateProc; } + +private: + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkSumPathEffect, (buffer)); + } + SkSumPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + + // illegal + SkSumPathEffect(const SkSumPathEffect&); + SkSumPathEffect& operator=(const SkSumPathEffect&); + + typedef SkPairPathEffect INHERITED; +}; + +#endif + diff --git a/include/core/SkPathMeasure.h b/include/core/SkPathMeasure.h new file mode 100644 index 0000000000..5ab97cacfd --- /dev/null +++ b/include/core/SkPathMeasure.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPathMeasure_DEFINED +#define SkPathMeasure_DEFINED + +#include "SkPath.h" +#include "SkTDArray.h" + +class SkPathMeasure : SkNoncopyable { +public: + SkPathMeasure(); + /** Initialize the pathmeasure with the specified path. The path must remain valid + for the lifetime of the measure object, or until setPath() is called with + a different path (or null), since the measure object keeps a pointer to the + path object (does not copy its data). + */ + SkPathMeasure(const SkPath& path, bool forceClosed); + ~SkPathMeasure(); + + /** Reset the pathmeasure with the specified path. The path must remain valid + for the lifetime of the measure object, or until setPath() is called with + a different path (or null), since the measure object keeps a pointer to the + path object (does not copy its data). + */ + void setPath(const SkPath*, bool forceClosed); + + /** Return the total length of the current contour, or 0 if no path + is associated (e.g. resetPath(null)) + */ + SkScalar getLength(); + + /** Pins distance to 0 <= distance <= getLength(), and then computes + the corresponding position and tangent. + Returns false if there is no path, or a zero-length path was specified, in which case + position and tangent are unchanged. + */ + bool getPosTan(SkScalar distance, SkPoint* position, SkVector* tangent); + + enum MatrixFlags { + kGetPosition_MatrixFlag = 0x01, + kGetTangent_MatrixFlag = 0x02, + kGetPosAndTan_MatrixFlag = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag + }; + /** Pins distance to 0 <= distance <= getLength(), and then computes + the corresponding matrix (by calling getPosTan). + Returns false if there is no path, or a zero-length path was specified, in which case + matrix is unchanged. + */ + bool getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags = kGetPosAndTan_MatrixFlag); + /** Given a start and stop distance, return in dst the intervening segment(s). + If the segment is zero-length, return false, else return true. + startD and stopD are pinned to legal values (0..getLength()). If startD <= stopD + then return false (and leave dst untouched). + Begin the segment with a moveTo if startWithMoveTo is true + */ + bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo); + + /** Return true if the current contour is closed() + */ + bool isClosed(); + + /** Move to the next contour in the path. Return true if one exists, or false if + we're done with the path. + */ + bool nextContour(); + +#ifdef SK_DEBUG + void dump(); + static void UnitTest(); +#endif + +private: + SkPath::Iter fIter; + const SkPath* fPath; + SkScalar fLength; // relative to the current contour + int fFirstPtIndex; // relative to the current contour + bool fIsClosed; // relative to the current contour + bool fForceClosed; + + struct Segment { + SkScalar fDistance; // total distance up to this point + unsigned fPtIndex : 15; + unsigned fTValue : 15; + unsigned fType : 2; + + SkScalar getScalarT() const; + }; + SkTDArray<Segment> fSegments; + + static const Segment* NextSegment(const Segment*); + + void buildSegments(); + SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance, + int mint, int maxt, int ptIndex); + SkScalar compute_cubic_segs(const SkPoint pts[3], SkScalar distance, + int mint, int maxt, int ptIndex); + const Segment* distanceToSegment(SkScalar distance, SkScalar* t); +}; + +#endif + diff --git a/include/core/SkPerspIter.h b/include/core/SkPerspIter.h new file mode 100644 index 0000000000..81ce7c8fac --- /dev/null +++ b/include/core/SkPerspIter.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPerspIter_DEFINED +#define SkPerspIter_DEFINED + +#include "SkMatrix.h" + +class SkPerspIter { +public: + /** Iterate a line through the matrix [x,y] ... [x+count-1, y]. + @param m The matrix we will be iterating a line through + @param x The initial X coordinate to be mapped through the matrix + @param y The initial Y coordinate to be mapped through the matrix + @param count The number of points (x,y) (x+1,y) (x+2,y) ... we will eventually map + */ + SkPerspIter(const SkMatrix& m, SkScalar x, SkScalar y, int count); + + /** Return the buffer of [x,y] fixed point values we will be filling. + This always returns the same value, so it can be saved across calls to + next(). + */ + const SkFixed* getXY() const { return fStorage; } + + /** Return the number of [x,y] pairs that have been filled in the getXY() buffer. + When this returns 0, the iterator is finished. + */ + int next(); + +private: + enum { + kShift = 4, + kCount = (1 << kShift) + }; + const SkMatrix& fMatrix; + SkFixed fStorage[kCount * 2]; + SkFixed fX, fY; + SkScalar fSX, fSY; + int fCount; +}; + +#endif diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h new file mode 100644 index 0000000000..fa614c9516 --- /dev/null +++ b/include/core/SkPicture.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPicture_DEFINED +#define SkPicture_DEFINED + +#include "SkRefCnt.h" + +class SkCanvas; +class SkPicturePlayback; +class SkPictureRecord; +class SkStream; +class SkWStream; + +/** \class SkPicture + + The SkPicture class records the drawing commands made to a canvas, to + be played back at a later time. +*/ +class SkPicture : public SkRefCnt { +public: + /** The constructor prepares the picture to record. + @param width the width of the virtual device the picture records. + @param height the height of the virtual device the picture records. + */ + SkPicture(); + /** Make a copy of the contents of src. If src records more drawing after + this call, those elements will not appear in this picture. + */ + SkPicture(const SkPicture& src); + explicit SkPicture(SkStream*); + virtual ~SkPicture(); + + /** + * Swap the contents of the two pictures. Guaranteed to succeed. + */ + void swap(SkPicture& other); + + /** Returns the canvas that records the drawing commands. + @return the picture canvas. + */ + SkCanvas* beginRecording(int width, int height); + /** Returns the recording canvas if one is active, or NULL if recording is + not active. This does not alter the refcnt on the canvas (if present). + */ + SkCanvas* getRecordingCanvas() const; + /** Signal that the caller is done recording. This invalidates the canvas + returned by beginRecording/getRecordingCanvas, and prepares the picture + for drawing. Note: this happens implicitly the first time the picture + is drawn. + */ + void endRecording(); + + /** Replays the drawing commands on the specified canvas. This internally + calls endRecording() if that has not already been called. + @param surface the canvas receiving the drawing commands. + */ + void draw(SkCanvas* surface); + + /** Return the width of the picture's recording canvas. This + value reflects what was passed to setSize(), and does not necessarily + reflect the bounds of what has been recorded into the picture. + @return the width of the picture's recording canvas + */ + int width() const { return fWidth; } + + /** Return the height of the picture's recording canvas. This + value reflects what was passed to setSize(), and does not necessarily + reflect the bounds of what has been recorded into the picture. + @return the height of the picture's recording canvas + */ + int height() const { return fHeight; } + + void serialize(SkWStream*) const; + + /** Signals that the caller is prematurely done replaying the drawing + commands. This can be called from a canvas virtual while the picture + is drawing. Has no effect if the picture is not drawing. + */ + void abortPlayback(); + +private: + int fWidth, fHeight; + SkPictureRecord* fRecord; + SkPicturePlayback* fPlayback; + + friend class SkFlatPicture; + friend class SkPicturePlayback; +}; + +class SkAutoPictureRecord : SkNoncopyable { +public: + SkAutoPictureRecord(SkPicture* pict, int width, int height) { + fPicture = pict; + fCanvas = pict->beginRecording(width, height); + } + ~SkAutoPictureRecord() { + fPicture->endRecording(); + } + + /** Return the canvas to draw into for recording into the picture. + */ + SkCanvas* getRecordingCanvas() const { return fCanvas; } + +private: + SkPicture* fPicture; + SkCanvas* fCanvas; +}; + + +#endif diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h new file mode 100644 index 0000000000..82e5ca7b5e --- /dev/null +++ b/include/core/SkPixelRef.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPixelRef_DEFINED +#define SkPixelRef_DEFINED + +#include "SkRefCnt.h" +#include "SkString.h" + +class SkColorTable; +class SkMutex; +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; + +/** \class SkPixelRef + + This class is the smart container for pixel memory, and is used with + SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can + access the actual pixel memory by calling lockPixels/unlockPixels. + + This class can be shared/accessed between multiple threads. +*/ +class SkPixelRef : public SkRefCnt { +public: + explicit SkPixelRef(SkMutex* mutex = NULL); + + /** Return the pixel memory returned from lockPixels, or null if the + lockCount is 0. + */ + void* pixels() const { return fPixels; } + + /** Return the current colorTable (if any) if pixels are locked, or null. + */ + SkColorTable* colorTable() const { return fColorTable; } + + /** Return the current lockcount (defaults to 0) + */ + int getLockCount() const { return fLockCount; } + + /** Call to access the pixel memory, which is returned. Balance with a call + to unlockPixels(). + */ + void lockPixels(); + /** Call to balanace a previous call to lockPixels(). Returns the pixels + (or null) after the unlock. NOTE: lock calls can be nested, but the + matching number of unlock calls must be made in order to free the + memory (if the subclass implements caching/deferred-decoding.) + */ + void unlockPixels(); + + /** Returns a non-zero, unique value corresponding to the pixels in this + pixelref. Each time the pixels are changed (and notifyPixelsChanged is + called), a different generation ID will be returned. + */ + 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(). + */ + void notifyPixelsChanged(); + + /** Returns true if this pixelref is marked as immutable, meaning that the + contents of its pixels will not change for the lifetime of the pixelref. + */ + bool isImmutable() const { return fIsImmutable; } + + /** Marks this pixelref is immutable, meaning that the contents of its + pixels will not change for the lifetime of the pixelref. This state can + be set on a pixelref, but it cannot be cleared once it is set. + */ + void setImmutable(); + + /** Return the optional URI string associated with this pixelref. May be + null. + */ + const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; } + + /** Copy a URI string to this pixelref, or clear the URI if the uri is null + */ + void setURI(const char uri[]) { + fURI.set(uri); + } + + /** Copy a URI string to this pixelref + */ + void setURI(const char uri[], size_t len) { + fURI.set(uri, len); + } + + /** Assign a URI string to this pixelref. + */ + void setURI(const SkString& uri) { fURI = uri; } + + // serialization + + typedef SkPixelRef* (*Factory)(SkFlattenableReadBuffer&); + + virtual Factory getFactory() const { return NULL; } + virtual void flatten(SkFlattenableWriteBuffer&) const; + + static Factory NameToFactory(const char name[]); + static const char* FactoryToName(Factory); + static void Register(const char name[], Factory); + + class Registrar { + public: + Registrar(const char name[], Factory factory) { + SkPixelRef::Register(name, factory); + } + }; + +protected: + /** Called when the lockCount goes from 0 to 1. The caller will have already + acquire a mutex for thread safety, so this method need not do that. + */ + virtual void* onLockPixels(SkColorTable**) = 0; + /** Called when the lock count goes from 1 to 0. The caller will have + already acquire a mutex for thread safety, so this method need not do + that. + */ + virtual void onUnlockPixels() = 0; + + /** Return the mutex associated with this pixelref. This value is assigned + in the constructor, and cannot change during the lifetime of the object. + */ + SkMutex* mutex() const { return fMutex; } + + SkPixelRef(SkFlattenableReadBuffer&, SkMutex*); + +private: + SkMutex* fMutex; // must remain in scope for the life of this object + void* fPixels; + SkColorTable* fColorTable; // we do not track ownership, subclass does + int fLockCount; + + mutable uint32_t fGenerationID; + + SkString fURI; + + // can go from false to true, but never from true to false + bool fIsImmutable; +}; + +#endif diff --git a/include/core/SkPoint.h b/include/core/SkPoint.h new file mode 100644 index 0000000000..f038afb443 --- /dev/null +++ b/include/core/SkPoint.h @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPoint_DEFINED +#define SkPoint_DEFINED + +#include "SkMath.h" +#include "SkScalar.h" + +/** \struct SkIPoint + + SkIPoint holds two 32 bit integer coordinates +*/ +struct SkIPoint { + int32_t fX, fY; + + /** Set the x and y values of the point. */ + void set(int32_t x, int32_t y) { fX = x; fY = y; } + + /** Rotate the point clockwise, writing the new point into dst + It is legal for dst == this + */ + void rotateCW(SkIPoint* dst) const; + + /** Rotate the point clockwise, writing the new point back into the point + */ + + void rotateCW() { this->rotateCW(this); } + + /** Rotate the point counter-clockwise, writing the new point into dst. + It is legal for dst == this + */ + void rotateCCW(SkIPoint* dst) const; + + /** Rotate the point counter-clockwise, writing the new point back into + the point + */ + void rotateCCW() { this->rotateCCW(this); } + + /** Negate the X and Y coordinates of the point. + */ + void negate() { fX = -fX; fY = -fY; } + + /** Return a new point whose X and Y coordinates are the negative of the + original point's + */ + SkIPoint operator-() const { + SkIPoint neg; + neg.fX = -fX; + neg.fY = -fY; + return neg; + } + + /** Add v's coordinates to this point's */ + void operator+=(const SkIPoint& v) { + fX += v.fX; + fY += v.fY; + } + + /** Subtract v's coordinates from this point's */ + void operator-=(const SkIPoint& v) { + fX -= v.fX; + fY -= v.fY; + } + + /** Returns true if the point's coordinates equal (x,y) */ + bool equals(int32_t x, int32_t y) const { + return fX == x && fY == y; + } + + friend bool operator==(const SkIPoint& a, const SkIPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns a new point whose coordinates are the difference between + a and b (i.e. a - b) + */ + friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) { + SkIPoint v; + v.set(a.fX - b.fX, a.fY - b.fY); + return v; + } + + /** Returns a new point whose coordinates are the sum of a and b (a + b) + */ + friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) { + SkIPoint v; + v.set(a.fX + b.fX, a.fY + b.fY); + return v; + } + + /** Returns the dot product of a and b, treating them as 2D vectors + */ + static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) { + return a.fX * b.fX + a.fY * b.fY; + } + + /** Returns the cross product of a and b, treating them as 2D vectors + */ + static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) { + return a.fX * b.fY - a.fY * b.fX; + } +}; + +struct SkPoint { + SkScalar fX, fY; + + /** Set the point's X and Y coordinates */ + void set(SkScalar x, SkScalar y) { fX = x; fY = y; } + + /** Set the point's X and Y coordinates by automatically promoting (x,y) to + SkScalar values. + */ + void iset(int32_t x, int32_t y) { + fX = SkIntToScalar(x); + fY = SkIntToScalar(y); + } + + /** Set the point's X and Y coordinates by automatically promoting p's + coordinates to SkScalar values. + */ + void iset(const SkIPoint& p) { + fX = SkIntToScalar(p.fX); + fY = SkIntToScalar(p.fY); + } + + /** Return the euclidian distance from (0,0) to the point + */ + SkScalar length() const { return SkPoint::Length(fX, fY); } + + /** Set the point (vector) to be unit-length in the same direction as it + currently is, and return its old length. If the old length is + degenerately small (nearly zero), do nothing and return false, otherwise + return true. + */ + bool normalize(); + + /** Set the point (vector) to be unit-length in the same direction as the + x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0) + then return false and do nothing, otherwise return true. + */ + bool setNormalize(SkScalar x, SkScalar y); + + /** Scale the point (vector) to have the specified length, and return that + length. If the original length is degenerately small (nearly zero), + do nothing and return false, otherwise return true. + */ + bool setLength(SkScalar length); + + /** Set the point (vector) to have the specified length in the same + direction as (x,y). If the vector (x,y) has a degenerate length + (i.e. nearly 0) then return false and do nothing, otherwise return true. + */ + bool setLength(SkScalar x, SkScalar y, SkScalar length); + + /** Scale the point's coordinates by scale, writing the answer into dst. + It is legal for dst == this. + */ + void scale(SkScalar scale, SkPoint* dst) const; + + /** Scale the point's coordinates by scale, writing the answer back into + the point. + */ + void scale(SkScalar scale) { this->scale(scale, this); } + + /** Rotate the point clockwise by 90 degrees, writing the answer into dst. + It is legal for dst == this. + */ + void rotateCW(SkPoint* dst) const; + + /** Rotate the point clockwise by 90 degrees, writing the answer back into + the point. + */ + void rotateCW() { this->rotateCW(this); } + + /** Rotate the point counter-clockwise by 90 degrees, writing the answer + into dst. It is legal for dst == this. + */ + void rotateCCW(SkPoint* dst) const; + + /** Rotate the point counter-clockwise by 90 degrees, writing the answer + back into the point. + */ + void rotateCCW() { this->rotateCCW(this); } + + /** Negate the point's coordinates + */ + void negate() { + fX = -fX; + fY = -fY; + } + + /** Returns a new point whose coordinates are the negative of the point's + */ + SkPoint operator-() const { + SkPoint neg; + neg.fX = -fX; + neg.fY = -fY; + return neg; + } + + /** Add v's coordinates to the point's + */ + void operator+=(const SkPoint& v) { + fX += v.fX; + fY += v.fY; + } + + /** Subtract v's coordinates from the point's + */ + void operator-=(const SkPoint& v) { + fX -= v.fX; + fY -= v.fY; + } + + /** Returns true if the point's coordinates equal (x,y) + */ + bool equals(SkScalar x, SkScalar y) const { return fX == x && fY == y; } + + friend bool operator==(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + friend bool operator!=(const SkPoint& a, const SkPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns a new point whose coordinates are the difference between + a's and b's (a - b) + */ + friend SkPoint operator-(const SkPoint& a, const SkPoint& b) { + SkPoint v; + v.set(a.fX - b.fX, a.fY - b.fY); + return v; + } + + /** Returns a new point whose coordinates are the sum of a's and b's (a + b) + */ + friend SkPoint operator+(const SkPoint& a, const SkPoint& b) { + SkPoint v; + v.set(a.fX + b.fX, a.fY + b.fY); + return v; + } + + /** Returns the euclidian distance from (0,0) to (x,y) + */ + static SkScalar Length(SkScalar x, SkScalar y); + + /** Returns the euclidian distance between a and b + */ + static SkScalar Distance(const SkPoint& a, const SkPoint& b) { + return Length(a.fX - b.fX, a.fY - b.fY); + } + + /** Returns the dot product of a and b, treating them as 2D vectors + */ + static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) { + return SkScalarMul(a.fX, b.fX) + SkScalarMul(a.fY, b.fY); + } + + /** Returns the cross product of a and b, treating them as 2D vectors + */ + static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { + return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX); + } +}; + +typedef SkPoint SkVector; + +#endif + diff --git a/include/core/SkPorterDuff.h b/include/core/SkPorterDuff.h new file mode 100644 index 0000000000..f03e9cbb0e --- /dev/null +++ b/include/core/SkPorterDuff.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPorterDuff_DEFINED +#define SkPorterDuff_DEFINED + +#include "SkColor.h" + +class SkXfermode; + +class SkPorterDuff { +public: + /** List of predefined xfermodes. In general, the algebra for the modes + uses the following symbols: + Sa, Sc - source alpha and color + Da, Dc - destination alpha and color (before compositing) + [a, c] - Resulting (alpha, color) values + For these equations, the colors are in premultiplied state. + If no xfermode is specified, kSrcOver is assumed. + */ + enum Mode { + kClear_Mode, //!< [0, 0] + kSrc_Mode, //!< [Sa, Sc] + kDst_Mode, //!< [Da, Dc] + kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc] + kDstOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc] + kSrcIn_Mode, //!< [Sa * Da, Sc * Da] + kDstIn_Mode, //!< [Sa * Da, Sa * Dc] + kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)] + kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] + kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc] + kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] + kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] + kDarken_Mode, //!< [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] + kLighten_Mode, //!< [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] + kMultiply_Mode, //!< [Sa * Da, Sc * Dc] + kScreen_Mode, //!< [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] + + kModeCount + }; + /** Return an SkXfermode object for the specified mode. + */ + static SkXfermode* CreateXfermode(Mode mode); + + /** Return a function pointer to a routine that applies the specified + porter-duff transfer mode. + */ + static SkXfermodeProc GetXfermodeProc(Mode mode); + + /** Return a function pointer to a routine that applies the specified + porter-duff transfer mode and srcColor to a 16bit device color. Note, + if the mode+srcColor might return a non-opaque color, then there is not + 16bit proc, and this will return NULL. + */ + static SkXfermodeProc16 GetXfermodeProc16(Mode mode, SkColor srcColor); + + /** If the specified xfermode advertises itself as one of the porterduff + modes (via SkXfermode::Coeff), return true and if not null, set mode + to the corresponding porterduff mode. If it is not recognized as a one, + return false and ignore the mode parameter. + */ + static bool IsMode(SkXfermode*, Mode* mode); +}; + +#endif + diff --git a/include/core/SkPostConfig.h b/include/core/SkPostConfig.h new file mode 100644 index 0000000000..e32d6a10b2 --- /dev/null +++ b/include/core/SkPostConfig.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPostConfig_DEFINED +#define SkPostConfig_DEFINED + +#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_WINCE) + #define SK_BUILD_FOR_WIN +#endif + +#if defined(SK_DEBUG) && defined(SK_RELEASE) + #error "cannot define both SK_DEBUG and SK_RELEASE" +#elif !defined(SK_DEBUG) && !defined(SK_RELEASE) + #error "must define either SK_DEBUG or SK_RELEASE" +#endif + +#if defined SK_SUPPORT_UNITTEST && !defined(SK_DEBUG) + #error "can't have unittests without debug" +#endif + +#if defined(SK_SCALAR_IS_FIXED) && defined(SK_SCALAR_IS_FLOAT) + #error "cannot define both SK_SCALAR_IS_FIXED and SK_SCALAR_IS_FLOAT" +#elif !defined(SK_SCALAR_IS_FIXED) && !defined(SK_SCALAR_IS_FLOAT) + #ifdef SK_CAN_USE_FLOAT + #define SK_SCALAR_IS_FLOAT + #else + #define SK_SCALAR_IS_FIXED + #endif +#endif + +#if defined(SK_SCALAR_IS_FLOAT) && !defined(SK_CAN_USE_FLOAT) + #define SK_CAN_USE_FLOAT + // we do nothing in the else case: fixed-scalars can have floats or not +#endif + +#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN) + #error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN" +#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN) + #error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN" +#endif + +// ensure the port has defined all of these, or none of them +#ifdef SK_A32_SHIFT + #if !defined(SK_R32_SHIFT) || !defined(SK_G32_SHIFT) || !defined(SK_B32_SHIFT) + #error "all or none of the 32bit SHIFT amounts must be defined" + #endif +#else + #if defined(SK_R32_SHIFT) || defined(SK_G32_SHIFT) || defined(SK_B32_SHIFT) + #error "all or none of the 32bit SHIFT amounts must be defined" + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#ifndef SkNEW + #define SkNEW(type_name) new type_name + #define SkNEW_ARGS(type_name, args) new type_name args + #define SkNEW_ARRAY(type_name, count) new type_name[count] + #define SkDELETE(obj) delete obj + #define SkDELETE_ARRAY(array) delete[] array +#endif + +#ifndef SK_CRASH +#if 1 // set to 0 for infinite loop, which can help connecting gdb + #define SK_CRASH() *(int *)(uintptr_t)0xbbadbeef = 0 +#else + #define SK_CRASH() do {} while (true) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(SK_SOFTWARE_FLOAT) && defined(SK_SCALAR_IS_FLOAT) + // if this is defined, we convert floats to 2scompliment ints for compares + #ifndef SK_SCALAR_SLOW_COMPARES + #define SK_SCALAR_SLOW_COMPARES + #endif +#endif + +#ifdef SK_BUILD_FOR_WIN + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #undef WIN32_LEAN_AND_MEAN + + #ifndef SK_DEBUGBREAK + #define SK_DEBUGBREAK(cond) do { if (!(cond)) DebugBreak(); } while (false) + #endif + + #ifdef SK_BUILD_FOR_WIN32 + #define strcasecmp(a, b) stricmp(a, b) + #define strncasecmp(a, b, c) strnicmp(a, b, c) + #elif defined(SK_BUILD_FOR_WINCE) + #define strcasecmp(a, b) _stricmp(a, b) + #define strncasecmp(a, b, c) _strnicmp(a, b, c) + #endif +#elif defined(SK_BUILD_FOR_MAC) + #ifndef SK_DEBUGBREAK + #define SK_DEBUGBREAK(cond) do { if (!(cond)) SK_CRASH(); } while (false) + #endif +#else + #ifdef SK_DEBUG + #include <stdio.h> + #ifndef SK_DEBUGBREAK + #define SK_DEBUGBREAK(cond) do { if (cond) break; \ + SkDebugf("%s:%d: failed assertion \"%s\"\n", \ + __FILE__, __LINE__, #cond); SK_CRASH(); } while (false) + #endif + #endif +#endif + +// stdlib macros + +#if 0 +#if !defined(strlen) && defined(SK_DEBUG) + extern size_t sk_strlen(const char*); + #define strlen(s) sk_strlen(s) +#endif +#ifndef sk_strcpy + #define sk_strcpy(dst, src) strcpy(dst, src) +#endif +#ifndef sk_strchr + #define sk_strchr(s, c) strchr(s, c) +#endif +#ifndef sk_strrchr + #define sk_strrchr(s, c) strrchr(s, c) +#endif +#ifndef sk_strcmp + #define sk_strcmp(s, t) strcmp(s, t) +#endif +#ifndef sk_strncmp + #define sk_strncmp(s, t, n) strncmp(s, t, n) +#endif +#ifndef sk_memcpy + #define sk_memcpy(dst, src, n) memcpy(dst, src, n) +#endif +#ifndef memmove + #define memmove(dst, src, n) memmove(dst, src, n) +#endif +#ifndef sk_memset + #define sk_memset(dst, val, n) memset(dst, val, n) +#endif +#ifndef sk_memcmp + #define sk_memcmp(s, t, n) memcmp(s, t, n) +#endif + +#define sk_strequal(s, t) (!sk_strcmp(s, t)) +#define sk_strnequal(s, t, n) (!sk_strncmp(s, t, n)) +#endif + +////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef SK_BUILD_FOR_WINCE +#include <string.h> +#include <stdlib.h> +#else +#define _CMNINTRIN_DECLARE_ONLY +#include "cmnintrin.h" +#endif + +#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN32 +//#define _CRTDBG_MAP_ALLOC +#ifdef free +#undef free +#endif +#include <crtdbg.h> +#undef free + +#ifdef SK_DEBUGx +#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(__cplusplus) + void * operator new( + size_t cb, + int nBlockUse, + const char * szFileName, + int nLine, + int foo + ); + void * operator new[]( + size_t cb, + int nBlockUse, + const char * szFileName, + int nLine, + int foo + ); + void operator delete( + void *pUserData, + int, const char*, int, int + ); + void operator delete( + void *pUserData + ); + void operator delete[]( void * p ); + #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__, 0) +#else + #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) +#endif + #define new DEBUG_CLIENTBLOCK +#else +#define DEBUG_CLIENTBLOCK +#endif // _DEBUG + +#endif + +#endif + diff --git a/include/core/SkPreConfig.h b/include/core/SkPreConfig.h new file mode 100644 index 0000000000..04f1987738 --- /dev/null +++ b/include/core/SkPreConfig.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPreConfig_DEFINED +#define SkPreConfig_DEFINED + +#ifdef ANDROID + #define SK_BUILD_FOR_UNIX + #define SkLONGLONG int64_t +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) + + #if defined(PALMOS_SDK_VERSION) + #define SK_BUILD_FOR_PALM + #elif defined(UNDER_CE) + #define SK_BUILD_FOR_WINCE + #elif defined(WIN32) + #define SK_BUILD_FOR_WIN32 + #elif defined(__SYMBIAN32__) + #define SK_BUILD_FOR_WIN32 + #elif defined(linux) + #define SK_BUILD_FOR_UNIX + #else + #define SK_BUILD_FOR_MAC + #endif + +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_DEBUG) && !defined(SK_RELEASE) + #ifdef NDEBUG + #define SK_RELEASE + #else + #define SK_DEBUG + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +// define to blank or change this in SkUserConfig.h as needed +#define SK_RESTRICT __restrict__ + +////////////////////////////////////////////////////////////////////// + +#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC) + #ifndef SK_CAN_USE_FLOAT + #define SK_CAN_USE_FLOAT + #endif + #if !defined(SK_SCALAR_IS_FIXED) && !defined(SK_SCALAR_IS_FLOAT) + #define SK_SCALAR_IS_FIXED + #endif + + #ifndef SkLONGLONG + #ifdef SK_BUILD_FOR_WIN32 + #define SkLONGLONG __int64 + #else + #define SkLONGLONG long long + #endif + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN) + #if defined (__ppc__) || defined(__ppc64__) + #define SK_CPU_BENDIAN + #else + #define SK_CPU_LENDIAN + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if (defined(__arm__) && !defined(__thumb__)) || defined(SK_BUILD_FOR_BREW) || defined(SK_BUILD_FOR_WINCE) || (defined(SK_BUILD_FOR_SYMBIAN) && !defined(__MARM_THUMB__)) + /* e.g. the ARM instructions have conditional execution, making tiny branches cheap */ + #define SK_CPU_HAS_CONDITIONAL_INSTR +#endif + +////////////////////////////////////////////////////////////////////// +// Conditional features based on build target + +#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) + #ifndef SK_BUILD_NO_IMAGE_ENCODE + #define SK_SUPPORT_IMAGE_ENCODE + #endif +#endif + +#ifdef SK_BUILD_FOR_SYMBIAN + #define SK_USE_RUNTIME_GLOBALS +#endif + +#endif + diff --git a/include/core/SkPtrRecorder.h b/include/core/SkPtrRecorder.h new file mode 100644 index 0000000000..ff1e14dcb7 --- /dev/null +++ b/include/core/SkPtrRecorder.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkPtrRecorder_DEFINED +#define SkPtrRecorder_DEFINED + +#include "SkRefCnt.h" +#include "SkTDArray.h" + +class SkPtrRecorder : public SkRefCnt { +public: + uint32_t recordPtr(void*); + + int count() const { return fList.count(); } + void getPtrs(void* array[]) const; + + void reset(); + +protected: + virtual void incPtr(void* ptr) {} + virtual void decPtr(void* ptr) {} + +private: + struct Pair { + void* fPtr; + uint32_t fIndex; + }; + SkTDArray<Pair> fList; + + static int Cmp(const Pair& a, const Pair& b); + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/include/core/SkRandom.h b/include/core/SkRandom.h new file mode 100644 index 0000000000..33b563af5e --- /dev/null +++ b/include/core/SkRandom.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkRandom_DEFINED +#define SkRandom_DEFINED + +#include "Sk64.h" +#include "SkScalar.h" + +/** \class SkRandom + + Utility class that implements pseudo random 32bit numbers using a fast + linear equation. Unlike rand(), this class holds its own seed (initially + set to 0), so that multiple instances can be used with no side-effects. +*/ +class SkRandom { +public: + SkRandom() : fSeed(0) {} + SkRandom(uint32_t seed) : fSeed(seed) {} + + /** Return the next pseudo random number as an unsigned 32bit value. + */ + uint32_t nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; } + + /** Return the next pseudo random number as a signed 32bit value. + */ + int32_t nextS() { return (int32_t)this->nextU(); } + + /** Return the next pseudo random number as an unsigned 16bit value. + */ + U16CPU nextU16() { return this->nextU() >> 16; } + + /** Return the next pseudo random number as a signed 16bit value. + */ + S16CPU nextS16() { return this->nextS() >> 16; } + + /** Return the next pseudo random number, as an unsigned value of + at most bitCount bits. + @param bitCount The maximum number of bits to be returned + */ + uint32_t nextBits(unsigned bitCount) { + SkASSERT(bitCount > 0 && bitCount <= 32); + return this->nextU() >> (32 - bitCount); + } + + /** Return the next pseudo random unsigned number, mapped to lie within + [min, max] inclusive. + */ + uint32_t nextRangeU(uint32_t min, uint32_t max) { + SkASSERT(min <= max); + return min + this->nextU() % (max - min + 1); + } + + /** Return the next pseudo random number expressed as an unsigned SkFixed + in the range [0..SK_Fixed1). + */ + SkFixed nextUFixed1() { return this->nextU() >> 16; } + + /** Return the next pseudo random number expressed as a signed SkFixed + in the range (-SK_Fixed1..SK_Fixed1). + */ + SkFixed nextSFixed1() { return this->nextS() >> 15; } + + /** Return the next pseudo random number expressed as a SkScalar + in the range [0..SK_Scalar1). + */ + SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); } + + /** Return the next pseudo random number expressed as a SkScalar + in the range (-SK_Scalar1..SK_Scalar1). + */ + SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); } + + /** Return the next pseudo random number as a signed 64bit value. + */ + void next64(Sk64* a) { + SkASSERT(a); + a->set(this->nextS(), this->nextU()); + } + + /** Set the seed of the random object. The seed is initialized to 0 when the + object is first created, and is updated each time the next pseudo random + number is requested. + */ + void setSeed(int32_t seed) { fSeed = (uint32_t)seed; } + +private: + // See "Numerical Recipes in C", 1992 page 284 for these constants + enum { + kMul = 1664525, + kAdd = 1013904223 + }; + uint32_t fSeed; +}; + +#endif + diff --git a/include/core/SkRasterizer.h b/include/core/SkRasterizer.h new file mode 100644 index 0000000000..d81e613f0b --- /dev/null +++ b/include/core/SkRasterizer.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkRasterizer_DEFINED +#define SkRasterizer_DEFINED + +#include "SkFlattenable.h" +#include "SkMask.h" + +class SkMaskFilter; +class SkMatrix; +class SkPath; +struct SkIRect; + +class SkRasterizer : public SkFlattenable { +public: + SkRasterizer() {} + + /** Turn the path into a mask, respecting the specified local->device matrix. + */ + bool rasterize(const SkPath& path, const SkMatrix& matrix, + const SkIRect* clipBounds, SkMaskFilter* filter, + SkMask* mask, SkMask::CreateMode mode); + + virtual void flatten(SkFlattenableWriteBuffer& ) {} +protected: + SkRasterizer(SkFlattenableReadBuffer&); + + virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix, + const SkIRect* clipBounds, + SkMask* mask, SkMask::CreateMode mode); + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h new file mode 100644 index 0000000000..1c72a87eb7 --- /dev/null +++ b/include/core/SkReader32.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkReader32_DEFINED +#define SkReader32_DEFINED + +#include "SkTypes.h" + +#include "SkScalar.h" +#include "SkPoint.h" +#include "SkRect.h" + +class SkReader32 : SkNoncopyable { +public: + SkReader32() : fCurr(NULL), fStop(NULL), fBase(NULL) {} + SkReader32(const void* data, size_t size) { + this->setMemory(data, size); + } + + void setMemory(const void* data, size_t size) { + SkASSERT(ptr_align_4(data)); + SkASSERT(SkAlign4(size) == size); + + fBase = fCurr = (const char*)data; + fStop = (const char*)data + size; + } + + uint32_t size() const { return fStop - fBase; } + uint32_t offset() const { return fCurr - fBase; } + bool eof() const { return fCurr >= fStop; } + const void* base() const { return fBase; } + const void* peek() const { return fCurr; } + void rewind() { fCurr = fBase; } + + void setOffset(size_t offset) { + SkASSERT(SkAlign4(offset) == offset); + SkASSERT(offset <= this->size()); + fCurr = fBase + offset; + } + + bool readBool() { return this->readInt() != 0; } + + int32_t readInt() { + SkASSERT(ptr_align_4(fCurr)); + int32_t value = *(const int32_t*)fCurr; + fCurr += sizeof(value); + SkASSERT(fCurr <= fStop); + return value; + } + + SkScalar readScalar() { + SkASSERT(ptr_align_4(fCurr)); + SkScalar value = *(const SkScalar*)fCurr; + fCurr += sizeof(value); + SkASSERT(fCurr <= fStop); + return value; + } + + const SkPoint* skipPoint() { + return (const SkPoint*)this->skip(sizeof(SkPoint)); + } + + const SkRect* skipRect() { + return (const SkRect*)this->skip(sizeof(SkRect)); + } + + const void* skip(size_t size) { + SkASSERT(ptr_align_4(fCurr)); + const void* addr = fCurr; + fCurr += SkAlign4(size); + SkASSERT(fCurr <= fStop); + return addr; + } + + void read(void* dst, size_t size) { + SkASSERT(dst != NULL); + SkASSERT(ptr_align_4(fCurr)); + memcpy(dst, fCurr, size); + fCurr += SkAlign4(size); + SkASSERT(fCurr <= fStop); + } + + uint8_t readU8() { return (uint8_t)this->readInt(); } + uint16_t readU16() { return (uint16_t)this->readInt(); } + int32_t readS32() { return this->readInt(); } + uint32_t readU32() { return this->readInt(); } + +private: + // these are always 4-byte aligned + const char* fCurr; // current position within buffer + const char* fStop; // end of buffer + const char* fBase; // beginning of buffer + +#ifdef SK_DEBUG + static bool ptr_align_4(const void* ptr) + { + return (((const char*)ptr - (const char*)NULL) & 3) == 0; + } +#endif +}; + +#endif diff --git a/include/core/SkRect.h b/include/core/SkRect.h new file mode 100644 index 0000000000..a9f25aa9f5 --- /dev/null +++ b/include/core/SkRect.h @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkRect_DEFINED +#define SkRect_DEFINED + +#include "SkPoint.h" + +/** \struct SkIRect + + SkIRect holds four 32 bit integer coordinates for a rectangle +*/ +struct SkIRect { + int32_t fLeft, fTop, fRight, fBottom; + + /** Return true if the rectangle's width or height are <= 0 + */ + bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + + /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right) + so the result may be negative. + */ + int width() const { return fRight - fLeft; } + + /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom) + so the result may be negative. + */ + int height() const { return fBottom - fTop; } + + friend int operator==(const SkIRect& a, const SkIRect& b) + { + return !memcmp(&a, &b, sizeof(a)); + } + friend int operator!=(const SkIRect& a, const SkIRect& b) + { + return memcmp(&a, &b, sizeof(a)); + } + + /** Set the rectangle to (0,0,0,0) + */ + void setEmpty() { memset(this, 0, sizeof(*this)); } + + void set(int32_t left, int32_t top, int32_t right, int32_t bottom) + { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Offset set the rectangle by adding dx to its left and right, + and adding dy to its top and bottom. + */ + void offset(int32_t dx, int32_t dy) + { + fLeft += dx; + fTop += dy; + fRight += dx; + fBottom += dy; + } + + /** 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 hods true for dy and the top and bottom. + */ + void inset(int32_t dx, int32_t dy) + { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + /** 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. + */ + 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. + */ + 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 + fLeft <= left && fTop <= top && + fRight >= right && fBottom >= bottom; + } + + /** Returns true if the specified rectangle r is inside or equal to this rectangle. + */ + bool contains(const SkIRect& r) const + { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** 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. + */ + bool containsNoEmptyCheck(int32_t left, int32_t top, + int32_t right, int32_t bottom) const + { + SkASSERT(fLeft < fRight && fTop < fBottom); + SkASSERT(left < right && top < bottom); + + return fLeft <= left && fTop <= top && + fRight >= right && fBottom >= bottom; + } + + /** 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. + */ + bool intersect(const SkIRect& r) + { + SkASSERT(&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. + */ + bool intersect(const SkIRect& a, const SkIRect& b) + { + SkASSERT(&a && &b); + + if (!a.isEmpty() && !b.isEmpty() && + a.fLeft < b.fRight && b.fLeft < a.fRight && + a.fTop < b.fBottom && b.fTop < a.fBottom) + { + fLeft = SkMax32(a.fLeft, b.fLeft); + fTop = SkMax32(a.fTop, b.fTop); + fRight = SkMin32(a.fRight, b.fRight); + fBottom = SkMin32(a.fBottom, b.fBottom); + return true; + } + 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. + */ + bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) + { + SkASSERT(&a && &b); + SkASSERT(!a.isEmpty() && !b.isEmpty()); + + if (a.fLeft < b.fRight && b.fLeft < a.fRight && + a.fTop < b.fBottom && b.fTop < a.fBottom) + { + fLeft = SkMax32(a.fLeft, b.fLeft); + fTop = SkMax32(a.fTop, b.fTop); + fRight = SkMin32(a.fRight, b.fRight); + fBottom = SkMin32(a.fBottom, b.fBottom); + return true; + } + 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. + */ + bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) + { + if (left < right && top < bottom && !this->isEmpty() && + fLeft < right && left < fRight && fTop < bottom && top < fBottom) + { + if (fLeft < left) fLeft = left; + if (fTop < top) fTop = top; + if (fRight > right) fRight = right; + if (fBottom > bottom) fBottom = bottom; + return true; + } + return false; + } + + /** Returns true if a and b are not empty, and they intersect + */ + 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; + } + + /** 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. + */ + 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. + */ + 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 + */ + void sort(); +}; + +/** \struct SkRect +*/ +struct SkRect { + SkScalar fLeft, fTop, fRight, fBottom; + + /** Return true if the rectangle's width or height are <= 0 + */ + bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + SkScalar width() const { return fRight - fLeft; } + SkScalar height() const { return fBottom - fTop; } + SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } + SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } + + friend int operator==(const SkRect& a, const SkRect& b) + { + return !memcmp(&a, &b, sizeof(a)); + } + friend int operator!=(const SkRect& a, const SkRect& b) + { + return memcmp(&a, &b, sizeof(a)); + } + + /** return the 4 points that enclose the rectangle + */ + void toQuad(SkPoint quad[4]) const; + + /** Set this rectangle to the empty rectangle (0,0,0,0) + */ + void setEmpty() { memset(this, 0, sizeof(*this)); } + + void set(const SkIRect& src) + { + fLeft = SkIntToScalar(src.fLeft); + fTop = SkIntToScalar(src.fTop); + fRight = SkIntToScalar(src.fRight); + fBottom = SkIntToScalar(src.fBottom); + } + + void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) + { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Initialize the rect with the 4 specified integers. The routine handles + converting them to scalars (by calling SkIntToScalar) + */ + void iset(int left, int top, int right, int bottom) { + fLeft = SkIntToScalar(left); + fTop = SkIntToScalar(top); + fRight = SkIntToScalar(right); + fBottom = SkIntToScalar(bottom); + } + + /** 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) + */ + void set(const SkPoint pts[], int count); + + /** Offset set the rectangle by adding dx to its left and right, + and adding dy to its top and bottom. + */ + void offset(SkScalar dx, SkScalar dy) + { + fLeft += dx; + fTop += dy; + fRight += dx; + fBottom += dy; + } + + /** 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 hods true for dy and the top and bottom. + */ + void inset(SkScalar dx, SkScalar dy) + { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= 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. + */ + 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. + */ + bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); + + /** Return true if this rectangle is not empty, and the specified sides of + a rectangle are not empty, and they intersect. + */ + bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const + { + return // first check that both are not empty + left < right && top < bottom && + fLeft < fRight && fTop < fBottom && + // now check for intersection + fLeft < right && left < fRight && + fTop < bottom && top < fBottom; + } + + /** Return true if rectangles a and b are not empty and intersect. + */ + static bool Intersects(const SkRect& a, const SkRect& 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; + } + + /** 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. + */ + 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. + */ + void join(const SkRect& r) + { + this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of + the rectangle are considered to be inside, while the right and bottom coordinates + 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. + If this rectangle is empty, return false. + */ + bool contains(const SkPoint& p) const + { + return !this->isEmpty() && + fLeft <= p.fX && p.fX < fRight && + fTop <= p.fY && p.fY < fBottom; + } + + /** Returns true if (x,y) is inside the rectangle. The left and top coordinates of + the rectangle are considered to be inside, while the right and bottom coordinates + 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. + If this rectangle is empty, return false. + */ + bool contains(SkScalar x, SkScalar y) const + { + return !this->isEmpty() && + fLeft <= x && x < fRight && + fTop <= y && y < fBottom; + } + + /** Return true if this rectangle contains r. + If either rectangle is empty, return false. + */ + bool contains(const SkRect& r) const + { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Set the dst integer rectangle by rounding this rectangle's coordinates + to their nearest integer values. + */ + void round(SkIRect* dst) const + { + SkASSERT(dst); + dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom)); + } + + /** Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left, + and the ceiling of right and bototm. + */ + void roundOut(SkIRect* dst) const + { + SkASSERT(dst); + dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(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 + */ + void sort(); +}; + +#endif + diff --git a/include/core/SkRefCnt.h b/include/core/SkRefCnt.h new file mode 100644 index 0000000000..adb59ddc18 --- /dev/null +++ b/include/core/SkRefCnt.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkRefCnt_DEFINED +#define SkRefCnt_DEFINED + +#include "SkThread.h" + +/** \class SkRefCnt + + SkRefCnt is the base class for objects that may be shared by multiple + objects. When a new owner wants a reference, it calls ref(). When an owner + wants to release its reference, it calls unref(). When the shared object's + reference count goes to zero as the result of an unref() call, its (virtual) + destructor is called. It is an error for the destructor to be called + explicitly (or via the object going out of scope on the stack or calling + delete) if getRefCnt() > 1. +*/ +class SkRefCnt : SkNoncopyable { +public: + /** Default construct, initializing the reference count to 1. + */ + SkRefCnt() : fRefCnt(1) {} + + /** Destruct, asserting that the reference count is 1. + */ + virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); } + + /** Return the reference count. + */ + int32_t getRefCnt() const { return fRefCnt; } + + /** Increment the reference count. Must be balanced by a call to unref(). + */ + void ref() const { + SkASSERT(fRefCnt > 0); + sk_atomic_inc(&fRefCnt); + } + + /** Decrement the reference count. If the reference count is 1 before the + decrement, then call delete on the object. Note that if this is the + case, then the object needs to have been allocated via new, and not on + the stack. + */ + void unref() const { + SkASSERT(fRefCnt > 0); + if (sk_atomic_dec(&fRefCnt) == 1) { + fRefCnt = 1; // so our destructor won't complain + SkDELETE(this); + } + } + + /** Helper version of ref(), that first checks to see if this is not null. + If this is null, then do nothing. + */ + void safeRef() const { + if (this) { + this->ref(); + } + } + + /** Helper version of unref(), that first checks to see if this is not null. + If this is null, then do nothing. + */ + void safeUnref() const { + if (this) { + this->unref(); + } + } + +private: + mutable int32_t fRefCnt; +}; + +/** \class SkAutoUnref + + SkAutoUnref is a stack-helper class that will automatically call unref() on + the object it points to when the SkAutoUnref object goes out of scope. + If obj is null, do nothing. +*/ +class SkAutoUnref : SkNoncopyable { +public: + SkAutoUnref(SkRefCnt* obj) : fObj(obj) {} + ~SkAutoUnref(); + + SkRefCnt* get() const { return fObj; } + + /** If the hosted object is null, do nothing and return false, else call + ref() on it and return true + */ + bool ref(); + + /** If the hosted object is null, do nothing and return false, else call + unref() on it, set its reference to null, and return true + */ + bool unref(); + + /** If the hosted object is null, do nothing and return NULL, else call + unref() on it, set its reference to null, and return the object + */ + SkRefCnt* detach(); + +private: + SkRefCnt* fObj; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for + null in on each side of the assignment, and ensuring that ref() is called + before unref(), in case the two pointers point to the same object. +*/ +#define SkRefCnt_SafeAssign(dst, src) \ + do { \ + if (src) src->ref(); \ + if (dst) dst->unref(); \ + dst = src; \ + } while (0) + +#endif + diff --git a/include/core/SkRegion.h b/include/core/SkRegion.h new file mode 100644 index 0000000000..8b15a893c8 --- /dev/null +++ b/include/core/SkRegion.h @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkRegion_DEFINED +#define SkRegion_DEFINED + +#include "SkRect.h" + +class SkPath; +class SkRgnBuilder; + +namespace android { + class Region; +} + +#define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1) +#define SkRegion_gRectRunHeadPtr 0 + +/** \class SkRegion + + The SkRegion class encapsulates the geometric region used to specify + clipping areas for drawing. +*/ +class SkRegion { +public: + typedef int32_t RunType; + enum { + kRunTypeSentinel = 0x7FFFFFFF + }; + + SkRegion(); + SkRegion(const SkRegion&); + explicit SkRegion(const SkIRect&); + ~SkRegion(); + + SkRegion& operator=(const SkRegion&); + + friend int operator==(const SkRegion& a, const SkRegion& b); + friend int operator!=(const SkRegion& a, const SkRegion& b) { + return !(a == b); + } + + /** Replace this region with the specified region, and return true if the + resulting region is non-empty. + */ + bool set(const SkRegion& src) { + SkASSERT(&src); + *this = src; + return !this->isEmpty(); + } + + /** Swap the contents of this and the specified region. This operation + is gauarenteed to never fail. + */ + void swap(SkRegion&); + + /** Return true if this region is empty */ + bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } + /** Return true if this region is a single, non-empty rectangle */ + bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } + /** Return true if this region consists of more than 1 rectangular area */ + bool isComplex() const { return !this->isEmpty() && !this->isRect(); } + /** Return the bounds of this region. If the region is empty, returns an + empty rectangle. + */ + const SkIRect& getBounds() const { return fBounds; } + + /** Returns true if the region is non-empty, and if so, sets the specified + path to the boundary(s) of the region. + */ + bool getBoundaryPath(SkPath* path) const; + + /** Set the region to be empty, and return false, since the resulting + region is empty + */ + bool setEmpty(); + + /** If rect is non-empty, set this region to that rectangle and return true, + otherwise set this region to empty and return false. + */ + bool setRect(const SkIRect&); + + /** If left < right and top < bottom, set this region to that rectangle and + return true, otherwise set this region to empty and return false. + */ + bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); + + /** Set this region to the specified region, and return true if it is + non-empty. */ + bool setRegion(const SkRegion&); + + /** Set this region to the area described by the path, clipped. + Return true if the resulting region is non-empty. + This produces a region that is identical to the pixels that would be + drawn by the path (with no antialiasing) with the specified clip. + */ + bool setPath(const SkPath&, const SkRegion& clip); + + /** Returns true if the specified rectangle has a non-empty intersection + with this region. + */ + bool intersects(const SkIRect&) const; + + /** Returns true if the specified region has a non-empty intersection + with this region. + */ + bool intersects(const SkRegion&) const; + + /** Return true if the specified x,y coordinate is inside the region. + */ + bool contains(int32_t x, int32_t y) const; + + /** Return true if the specified rectangle is completely inside the region. + This works for simple (rectangular) and complex regions, and always + returns the correct result. Note: if either this region or the rectangle + is empty, contains() returns false. + */ + bool contains(const SkIRect&) const; + + /** Return true if the specified region is completely inside the region. + This works for simple (rectangular) and complex regions, and always + returns the correct result. Note: if either region is empty, contains() + returns false. + */ + bool contains(const SkRegion&) const; + + /** Return true if this region is a single rectangle (not complex) and the + specified rectangle is contained by this region. Returning false is not + a guarantee that the rectangle is not contained by this region, but + return true is a guarantee that the rectangle is contained by this region. + */ + bool quickContains(const SkIRect& r) const { + return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Return true if this region is a single rectangle (not complex) and the + specified rectangle is contained by this region. Returning false is not + a guarantee that the rectangle is not contained by this region, but + return true is a guarantee that the rectangle is contained by this + region. + */ + bool quickContains(int32_t left, int32_t top, int32_t right, + int32_t bottom) const { + SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region + + return left < right && top < bottom && + fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() + /* fBounds.contains(left, top, right, bottom); */ + fBounds.fLeft <= left && fBounds.fTop <= top && + fBounds.fRight >= right && fBounds.fBottom >= bottom; + } + + /** Return true if this region is empty, or if the specified rectangle does + not intersect the region. Returning false is not a guarantee that they + intersect, but returning true is a guarantee that they do not. + */ + bool quickReject(const SkIRect& rect) const + { + return this->isEmpty() || rect.isEmpty() || + !SkIRect::Intersects(fBounds, rect); + } + + /** Return true if this region, or rgn, is empty, or if their bounds do not + intersect. Returning false is not a guarantee that they intersect, but + returning true is a guarantee that they do not. + */ + bool quickReject(const SkRegion& rgn) const { + return this->isEmpty() || rgn.isEmpty() || + !SkIRect::Intersects(fBounds, rgn.fBounds); + } + + /** Translate the region by the specified (dx, dy) amount. + */ + void translate(int dx, int dy) { this->translate(dx, dy, this); } + + /** Translate the region by the specified (dx, dy) amount, writing the + resulting region into dst. Note: it is legal to pass this region as the + dst parameter, effectively translating the region in place. If dst is + null, nothing happens. + */ + void translate(int dx, int dy, SkRegion* dst) const; + + /** The logical operations that can be performed when combining two regions. + */ + enum Op { + kDifference_Op, //!< subtract the op region from the first region + kIntersect_Op, //!< intersect the two regions + kUnion_Op, //!< union (inclusive-or) the two regions + kXOR_Op, //!< exclusive-or the two regions + /** subtract the first region from the op region */ + kReverseDifference_Op, + kReplace_Op //!< replace the dst region with the op region + }; + + /** Set this region to the result of applying the Op to this region and the + specified rectangle: this = (this op rect). + Return true if the resulting region is non-empty. + */ + bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } + + /** Set this region to the result of applying the Op to this region and the + specified rectangle: this = (this op rect). + Return true if the resulting region is non-empty. + */ + bool op(int left, int top, int right, int bottom, Op op) { + SkIRect rect; + rect.set(left, top, right, bottom); + return this->op(*this, rect, op); + } + + /** Set this region to the result of applying the Op to this region and the + specified region: this = (this op rgn). + Return true if the resulting region is non-empty. + */ + bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } + /** Set this region to the result of applying the Op to the specified + rectangle and region: this = (rect op rgn). + Return true if the resulting region is non-empty. + */ + bool op(const SkIRect& rect, const SkRegion& rgn, Op); + /** Set this region to the result of applying the Op to the specified + region and rectangle: this = (rgn op rect). + Return true if the resulting region is non-empty. + */ + bool op(const SkRegion& rgn, const SkIRect& rect, Op); + /** Set this region to the result of applying the Op to the specified + regions: this = (rgna op rgnb). + Return true if the resulting region is non-empty. + */ + bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); + + /** Returns the sequence of rectangles, sorted in Y and X, that make up + this region. + */ + class Iterator { + public: + Iterator() : fRgn(NULL), fDone(true) {} + Iterator(const SkRegion&); + // if we have a region, reset to it and return true, else return false + bool rewind(); + // reset the iterator, using the new region + void reset(const SkRegion&); + bool done() { return fDone; } + void next(); + const SkIRect& rect() const { return fRect; } + + private: + const SkRegion* fRgn; + const RunType* fRuns; + SkIRect fRect; + bool fDone; + }; + + /** Returns the sequence of rectangles, sorted in Y and X, that make up + this region intersected with the specified clip rectangle. + */ + class Cliperator { + public: + Cliperator(const SkRegion&, const SkIRect& clip); + bool done() { return fDone; } + void next(); + const SkIRect& rect() const { return fRect; } + + private: + Iterator fIter; + SkIRect fClip; + SkIRect fRect; + bool fDone; + }; + + /** Returns the sequence of runs that make up this region for the specified + Y scanline, clipped to the specified left and right X values. + */ + class Spanerator { + public: + Spanerator(const SkRegion&, int y, int left, int right); + bool next(int* left, int* right); + + private: + const SkRegion::RunType* fRuns; + int fLeft, fRight; + bool fDone; + }; + + /** Write the region to the buffer, and return the number of bytes written. + If buffer is NULL, it still returns the number of bytes. + */ + uint32_t flatten(void* buffer) const; + /** Initialized the region from the buffer, returning the number + of bytes actually read. + */ + uint32_t unflatten(const void* buffer); + + SkDEBUGCODE(void dump() const;) + SkDEBUGCODE(void validate() const;) + SkDEBUGCODE(static void UnitTest();) + + // expose this to allow for regression test on complex regions + SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) + +private: + enum { + kOpCount = kReplace_Op + 1 + }; + + enum { + kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S] + }; + + friend class android::Region; // needed for marshalling efficiently + void allocateRuns(int count); // allocate space for count runs + + struct RunHead; + + SkIRect fBounds; + RunHead* fRunHead; + + void freeRuns(); + const RunType* getRuns(RunType tmpStorage[], int* count) const; + bool setRuns(RunType runs[], int count); + + int count_runtype_values(int* itop, int* ibot) const; + + static void BuildRectRuns(const SkIRect& bounds, + RunType runs[kRectRegionRuns]); + // returns true if runs are just a rect + static bool ComputeRunBounds(const RunType runs[], int count, + SkIRect* bounds); + + friend struct RunHead; + friend class Iterator; + friend class Spanerator; + friend class SkRgnBuilder; + friend class SkFlatRegion; +}; + + +#endif + diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h new file mode 100644 index 0000000000..86341eb996 --- /dev/null +++ b/include/core/SkScalar.h @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkScalar_DEFINED +#define SkScalar_DEFINED + +#include "SkFixed.h" + +/** \file SkScalar.h + + Types and macros for the data type SkScalar. This is the fractional numeric type + that, depending on the compile-time flag SK_SCALAR_IS_FLOAT, may be implemented + either as an IEEE float, or as a 16.16 SkFixed. The macros in this file are written + to allow the calling code to manipulate SkScalar values without knowing which representation + is in effect. +*/ + +#ifdef SK_SCALAR_IS_FLOAT + #include "SkFloatingPoint.h" + + /** SkScalar is our type for fractional values and coordinates. Depending on + compile configurations, it is either represented as an IEEE float, or + as a 16.16 fixed point integer. + */ + typedef float SkScalar; + extern const uint32_t gIEEENotANumber; + extern const uint32_t gIEEEInfinity; + + /** SK_Scalar1 is defined to be 1.0 represented as an SkScalar + */ + #define SK_Scalar1 (1.0f) + /** SK_Scalar1 is defined to be 1/2 represented as an SkScalar + */ + #define SK_ScalarHalf (0.5f) + /** SK_ScalarInfinity is defined to be infinity as an SkScalar + */ + #define SK_ScalarInfinity (*(const float*)&gIEEEInfinity) + /** SK_ScalarMax is defined to be the largest value representable as an SkScalar + */ + #define SK_ScalarMax (3.4028235e+38f) + /** SK_ScalarMin is defined to be the smallest value representable as an SkScalar + */ + #define SK_ScalarMin (1.1754944e-38f) + /** SK_ScalarNaN is defined to be 'Not a Number' as an SkScalar + */ + #define SK_ScalarNaN (*(const float*)(const void*)&gIEEENotANumber) + /** SkScalarIsNaN(n) returns true if argument is not a number + */ + static inline bool SkScalarIsNaN(float x) { return x != x; } + /** SkIntToScalar(n) returns its integer argument as an SkScalar + */ + #define SkIntToScalar(n) ((float)(n)) + /** SkFixedToScalar(n) returns its SkFixed argument as an SkScalar + */ + #define SkFixedToScalar(x) SkFixedToFloat(x) + /** SkScalarToFixed(n) returns its SkScalar argument as an SkFixed + */ + #define SkScalarToFixed(x) SkFloatToFixed(x) + + #define SkScalarToFloat(n) (n) + #define SkFloatToScalar(n) (n) + + #define SkScalarToDouble(n) (double)(n) + #define SkDoubleToScalar(n) (float)(n) + + /** SkScalarFraction(x) returns the signed fractional part of the argument + */ + #define SkScalarFraction(x) sk_float_mod(x, 1.0f) + /** Rounds the SkScalar to the nearest integer value + */ + #define SkScalarRound(x) sk_float_round2int(x) + /** Returns the smallest integer that is >= the specified SkScalar + */ + #define SkScalarCeil(x) sk_float_ceil2int(x) + /** Returns the largest integer that is <= the specified SkScalar + */ + #define SkScalarFloor(x) sk_float_floor2int(x) + /** Returns the absolute value of the specified SkScalar + */ + #define SkScalarAbs(x) sk_float_abs(x) + /** Returns the value pinned between 0 and max inclusive + */ + inline SkScalar SkScalarClampMax(SkScalar x, SkScalar max) { + return x < 0 ? 0 : x > max ? max : x; + } + /** Returns the value pinned between min and max inclusive + */ + inline SkScalar SkScalarPin(SkScalar x, SkScalar min, SkScalar max) { + return x < min ? min : x > max ? max : x; + } + /** Returns the specified SkScalar squared (x*x) + */ + inline SkScalar SkScalarSquare(SkScalar x) { return x * x; } + /** Returns the product of two SkScalars + */ + #define SkScalarMul(a, b) ((float)(a) * (b)) + /** Returns the product of two SkScalars plus a third SkScalar + */ + #define SkScalarMulAdd(a, b, c) ((float)(a) * (b) + (c)) + /** Returns the product of a SkScalar and an int rounded to the nearest integer value + */ + #define SkScalarMulRound(a, b) SkScalarRound((float)(a) * (b)) + /** Returns the product of a SkScalar and an int promoted to the next larger int + */ + #define SkScalarMulCeil(a, b) SkScalarCeil((float)(a) * (b)) + /** Returns the product of a SkScalar and an int truncated to the next smaller int + */ + #define SkScalarMulFloor(a, b) SkScalarFloor((float)(a) * (b)) + /** Returns the quotient of two SkScalars (a/b) + */ + #define SkScalarDiv(a, b) ((float)(a) / (b)) + /** Returns the mod of two SkScalars (a mod b) + */ + #define SkScalarMod(x,y) sk_float_mod(x,y) + /** Returns the product of the first two arguments, divided by the third argument + */ + #define SkScalarMulDiv(a, b, c) ((float)(a) * (b) / (c)) + /** Returns the multiplicative inverse of the SkScalar (1/x) + */ + #define SkScalarInvert(x) (SK_Scalar1 / (x)) + #define SkScalarFastInvert(x) (SK_Scalar1 / (x)) + /** Returns the square root of the SkScalar + */ + #define SkScalarSqrt(x) sk_float_sqrt(x) + /** Returns the average of two SkScalars (a+b)/2 + */ + #define SkScalarAve(a, b) (((a) + (b)) * 0.5f) + /** Returns the geometric mean of two SkScalars + */ + #define SkScalarMean(a, b) sk_float_sqrt((float)(a) * (b)) + /** Returns one half of the specified SkScalar + */ + #define SkScalarHalf(a) ((a) * 0.5f) + + #define SK_ScalarSqrt2 1.41421356f + #define SK_ScalarPI 3.14159265f + #define SK_ScalarTanPIOver8 0.414213562f + #define SK_ScalarRoot2Over2 0.707106781f + + #define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180)) + float SkScalarSinCos(SkScalar radians, SkScalar* cosValue); + #define SkScalarSin(radians) (float)sk_float_sin(radians) + #define SkScalarCos(radians) (float)sk_float_cos(radians) + #define SkScalarTan(radians) (float)sk_float_tan(radians) + #define SkScalarASin(val) (float)sk_float_asin(val) + #define SkScalarACos(val) (float)sk_float_acos(val) + #define SkScalarATan2(y, x) (float)sk_float_atan2(y,x) + #define SkScalarExp(x) (float)sk_float_exp(x) + #define SkScalarLog(x) (float)sk_float_log(x) + + inline SkScalar SkMaxScalar(SkScalar a, SkScalar b) { return a > b ? a : b; } + inline SkScalar SkMinScalar(SkScalar a, SkScalar b) { return a < b ? a : b; } + +#else + typedef SkFixed SkScalar; + + #define SK_Scalar1 SK_Fixed1 + #define SK_ScalarHalf SK_FixedHalf + #define SK_ScalarInfinity SK_FixedMax + #define SK_ScalarMax SK_FixedMax + #define SK_ScalarMin SK_FixedMin + #define SK_ScalarNaN SK_FixedNaN + #define SkScalarIsNaN(x) ((x) == SK_FixedNaN) + #define SkIntToScalar(n) SkIntToFixed(n) + #define SkFixedToScalar(x) (x) + #define SkScalarToFixed(x) (x) + #ifdef SK_CAN_USE_FLOAT + #define SkScalarToFloat(n) SkFixedToFloat(n) + #define SkFloatToScalar(n) SkFloatToFixed(n) + + #define SkScalarToDouble(n) SkFixedToDouble(n) + #define SkDoubleToScalar(n) SkDoubleToFixed(n) + #endif + #define SkScalarFraction(x) SkFixedFraction(x) + #define SkScalarRound(x) SkFixedRound(x) + #define SkScalarCeil(x) SkFixedCeil(x) + #define SkScalarFloor(x) SkFixedFloor(x) + #define SkScalarAbs(x) SkFixedAbs(x) + #define SkScalarClampMax(x, max) SkClampMax(x, max) + #define SkScalarPin(x, min, max) SkPin32(x, min, max) + #define SkScalarSquare(x) SkFixedSquare(x) + #define SkScalarMul(a, b) SkFixedMul(a, b) + #define SkScalarMulAdd(a, b, c) SkFixedMulAdd(a, b, c) + #define SkScalarMulRound(a, b) SkFixedMulCommon(a, b, SK_FixedHalf) + #define SkScalarMulCeil(a, b) SkFixedMulCommon(a, b, SK_Fixed1 - 1) + #define SkScalarMulFloor(a, b) SkFixedMulCommon(a, b, 0) + #define SkScalarDiv(a, b) SkFixedDiv(a, b) + #define SkScalarMod(a, b) SkFixedMod(a, b) + #define SkScalarMulDiv(a, b, c) SkMulDiv(a, b, c) + #define SkScalarInvert(x) SkFixedInvert(x) + #define SkScalarFastInvert(x) SkFixedFastInvert(x) + #define SkScalarSqrt(x) SkFixedSqrt(x) + #define SkScalarAve(a, b) SkFixedAve(a, b) + #define SkScalarMean(a, b) SkFixedMean(a, b) + #define SkScalarHalf(a) ((a) >> 1) + + #define SK_ScalarSqrt2 SK_FixedSqrt2 + #define SK_ScalarPI SK_FixedPI + #define SK_ScalarTanPIOver8 SK_FixedTanPIOver8 + #define SK_ScalarRoot2Over2 SK_FixedRoot2Over2 + + #define SkDegreesToRadians(degrees) SkFractMul(degrees, SK_FractPIOver180) + #define SkScalarSinCos(radians, cosPtr) SkFixedSinCos(radians, cosPtr) + #define SkScalarSin(radians) SkFixedSin(radians) + #define SkScalarCos(radians) SkFixedCos(radians) + #define SkScalarTan(val) SkFixedTan(val) + #define SkScalarASin(val) SkFixedASin(val) + #define SkScalarACos(val) SkFixedACos(val) + #define SkScalarATan2(y, x) SkFixedATan2(y,x) + #define SkScalarExp(x) SkFixedExp(x) + #define SkScalarLog(x) SkFixedLog(x) + + #define SkMaxScalar(a, b) SkMax32(a, b) + #define SkMinScalar(a, b) SkMin32(a, b) +#endif + +#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) + +/* <= is slower than < for floats, so we use < for our tolerance test +*/ + +inline bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) +{ + SkASSERT(tolerance > 0); + return SkScalarAbs(x) < tolerance; +} + +/** Linearly interpolate between A and B, based on t. + If t is 0, return A + If t is 1, return B + else interpolate. + t must be [0..SK_Scalar1] +*/ +inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) +{ + SkASSERT(t >= 0 && t <= SK_Scalar1); + return A + SkScalarMul(B - A, t); +} + +#endif + diff --git a/include/core/SkScalarCompare.h b/include/core/SkScalarCompare.h new file mode 100644 index 0000000000..fee554cd2b --- /dev/null +++ b/include/core/SkScalarCompare.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkScalarCompare_DEFINED +#define SkScalarCompare_DEFINED + +#include "SkFloatBits.h" +#include "SkRect.h" + +#ifdef SK_SCALAR_SLOW_COMPARES + typedef int32_t SkScalarCompareType; + typedef SkIRect SkRectCompareType; + #define SkScalarToCompareType(x) SkScalarAs2sCompliment(x) +#else + typedef SkScalar SkScalarCompareType; + typedef SkRect SkRectCompareType; + #define SkScalarToCompareType(x) (x) +#endif + +#endif + diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h new file mode 100644 index 0000000000..ec2cd0db44 --- /dev/null +++ b/include/core/SkScalerContext.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkScalerContext_DEFINED +#define SkScalerContext_DEFINED + +#include "SkMask.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPoint.h" + +class SkDescriptor; +class SkMaskFilter; +class SkPathEffect; +class SkRasterizer; + +// needs to be != to any valid SkMask::Format +#define MASK_FORMAT_JUST_ADVANCE (0xFF) + +struct SkGlyph { + void* fImage; + SkPath* fPath; + SkFixed fAdvanceX, fAdvanceY; + + uint32_t fID; + uint16_t fWidth, fHeight; + int16_t fTop, fLeft; + + uint8_t fMaskFormat; + int8_t fRsbDelta, fLsbDelta; // used by auto-kerning + + unsigned rowBytes() const { + unsigned rb = fWidth; + if (SkMask::kBW_Format == fMaskFormat) { + rb = (rb + 7) >> 3; + } else { + rb = SkAlign4(rb); + } + return rb; + } + + bool isJustAdvance() const { + return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; + } + + bool isFullMetrics() const { + return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; + } + + uint16_t getGlyphID() const { + return ID2Code(fID); + } + + unsigned getGlyphID(unsigned baseGlyphCount) const { + unsigned code = ID2Code(fID); + SkASSERT(code >= baseGlyphCount); + return code - baseGlyphCount; + } + + unsigned getSubX() const { + return ID2SubX(fID); + } + + SkFixed getSubXFixed() const { + return SubToFixed(ID2SubX(fID)); + } + + SkFixed getSubYFixed() const { + return SubToFixed(ID2SubY(fID)); + } + + size_t computeImageSize() const; + + enum { + kSubBits = 2, + kSubMask = ((1 << kSubBits) - 1), + kSubShift = 24, // must be large enough for glyphs and unichars + kCodeMask = ((1 << kSubShift) - 1), + // relative offsets for X and Y subpixel bits + kSubShiftX = kSubBits, + kSubShiftY = 0 + }; + + static unsigned ID2Code(uint32_t id) { + return id & kCodeMask; + } + + static unsigned ID2SubX(uint32_t id) { + return id >> (kSubShift + kSubShiftX); + } + + static unsigned ID2SubY(uint32_t id) { + return (id >> (kSubShift + kSubShiftY)) & kSubMask; + } + + static unsigned FixedToSub(SkFixed n) { + return (n >> (16 - kSubBits)) & kSubMask; + } + + static SkFixed SubToFixed(unsigned sub) { + SkASSERT(sub <= kSubMask); + return sub << (16 - kSubBits); + } + + static uint32_t MakeID(unsigned code) { + return code; + } + + static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) { + SkASSERT(code <= kCodeMask); + x = FixedToSub(x); + y = FixedToSub(y); + return (x << (kSubShift + kSubShiftX)) | + (y << (kSubShift + kSubShiftY)) | + code; + } + + void toMask(SkMask* mask) const; +}; + +class SkScalerContext { +public: + enum Hints { + kNo_Hints, + kSubpixel_Hints, + kNormal_Hints + }; + enum Flags { + kFrameAndFill_Flag = 0x01, + kDevKernText_Flag = 0x02, + kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags + kGammaForWhite_Flag = 0x08 // illegal to set both Gamma flags + }; + struct Rec { + uint32_t fFontID; + SkScalar fTextSize, fPreScaleX, fPreSkewX; + SkScalar fPost2x2[2][2]; + SkScalar fFrameWidth, fMiterLimit; + uint8_t fHints; + uint8_t fMaskFormat; + uint8_t fStrokeJoin; + uint8_t fFlags; + + void getMatrixFrom2x2(SkMatrix*) const; + void getLocalMatrix(SkMatrix*) const; + void getSingleMatrix(SkMatrix*) const; + }; + + SkScalerContext(const SkDescriptor* desc); + virtual ~SkScalerContext(); + + void setBaseGlyphCount(unsigned baseGlyphCount) { + fBaseGlyphCount = baseGlyphCount; + } + + uint16_t charToGlyphID(SkUnichar uni); + + unsigned getGlyphCount() const { return this->generateGlyphCount(); } + void getAdvance(SkGlyph*); + void getMetrics(SkGlyph*); + void getImage(const SkGlyph&); + void getPath(const SkGlyph&, SkPath*); + void getFontMetrics(SkPaint::FontMetrics* mX, + SkPaint::FontMetrics* mY); + + static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec); + static SkScalerContext* Create(const SkDescriptor*); + +protected: + Rec fRec; + unsigned fBaseGlyphCount; + + virtual unsigned generateGlyphCount() const = 0; + virtual uint16_t generateCharToGlyph(SkUnichar) = 0; + virtual void generateAdvance(SkGlyph*) = 0; + virtual void generateMetrics(SkGlyph*) = 0; + virtual void generateImage(const SkGlyph&) = 0; + virtual void generatePath(const SkGlyph&, SkPath*) = 0; + virtual void generateFontMetrics(SkPaint::FontMetrics* mX, + SkPaint::FontMetrics* mY) = 0; + +private: + SkPathEffect* fPathEffect; + SkMaskFilter* fMaskFilter; + SkRasterizer* fRasterizer; + SkScalar fDevFrameWidth; + + void internalGetPath(const SkGlyph& glyph, SkPath* fillPath, + SkPath* devPath, SkMatrix* fillToDevMatrix); + + mutable SkScalerContext* fAuxScalerContext; + + SkScalerContext* getGlyphContext(const SkGlyph& glyph) const; + + // return loaded fAuxScalerContext or NULL + SkScalerContext* loadAuxContext() const; +}; + +#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c') +#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e') +#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f') +#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't') + +#endif + diff --git a/include/core/SkShader.h b/include/core/SkShader.h new file mode 100644 index 0000000000..7c13e3d3e8 --- /dev/null +++ b/include/core/SkShader.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkShader_DEFINED +#define SkShader_DEFINED + +#include "SkBitmap.h" +#include "SkFlattenable.h" +#include "SkMask.h" +#include "SkMatrix.h" +#include "SkPaint.h" + +class SkPath; + +/** \class SkShader + + SkShader is the based class for objects that return horizontal spans of colors during drawing. + A subclass of SkShader is installed in a SkPaint calling paint.setShader(shader). After that + any object (other than a bitmap) that is drawn with that paint will get its color(s) from the + shader. +*/ +class SkShader : public SkFlattenable { +public: + SkShader(); + virtual ~SkShader(); + + /** Return true if the shader has a non-identity local matrix. + @param localM Optional: If not null, return the shader's local matrix + @return true if the shader has a non-identity local matrix. + */ + bool getLocalMatrix(SkMatrix* localM) const; + /** Set the shader's local matrix. + @param localM The shader's new local matrix. + */ + void setLocalMatrix(const SkMatrix& localM); + /** Reset the shader's local matrix to identity. + */ + void resetLocalMatrix(); + + enum TileMode { + kClamp_TileMode, //!< replicate the edge color if the shader draws outside of its original bounds + kRepeat_TileMode, //!< repeat the shader's image horizontally and vertically + kMirror_TileMode, //!< repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam + + kTileModeCount + }; + + // override these in your subclass + + enum Flags { + //!< set if all of the colors will be opaque + kOpaqueAlpha_Flag = 0x01, + //! set if this shader's shadeSpan16() method can be called + kHasSpan16_Flag = 0x02, + /** Set this bit if the shader's native data type is instrinsically 16 + bit, meaning that calling the 32bit shadeSpan() entry point will + mean the the impl has to up-sample 16bit data into 32bit. Used as a + a means of clearing a dither request if the it will have no effect + */ + kIntrinsicly16_Flag = 0x04 + }; + + /** Called sometimes before drawing with this shader. + Return the type of alpha your shader will return. + The default implementation returns 0. Your subclass should override if it can + (even sometimes) report a non-zero value, since that will enable various blitters + to perform faster. + */ + virtual uint32_t getFlags() { return 0; } + + /** Return the alpha associated with the data returned by shadeSpan16(). If + kHasSpan16_Flag is not set, this value is meaningless. + */ + virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; } + + /** Called once before drawing, with the current paint and + device matrix. Return true if your shader supports these + parameters, or false if not. If false is returned, nothing + will be drawn. + */ + virtual bool setContext( const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix); + + /** Called for each span of the object being drawn. Your subclass + should set the appropriate colors (with premultiplied alpha) that + correspond to the specified device coordinates. + */ + virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; + /** Called only for 16bit devices when getFlags() returns kOpaqueAlphaFlag | kHasSpan16_Flag + */ + virtual void shadeSpan16(int x, int y, uint16_t[], int count); + /** Similar to shadeSpan, but only returns the alpha-channel for a span. + The default implementation calls shadeSpan() and then extracts the alpha + values from the returned colors. + */ + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); + + /** Helper function that returns true if this shader's shadeSpan16() method can + be called. + */ + bool canCallShadeSpan16() + { + return SkShader::CanCallShadeSpan16(this->getFlags()); + } + + /** Helper to check the flags to know if it is legal to call shadeSpan16() + */ + static bool CanCallShadeSpan16(uint32_t flags) { + return (flags & kHasSpan16_Flag) != 0; + } + + /** Called before a session using the shader begins. Some shaders override + this to defer some of their work (like calling bitmap.lockPixels()). + Must be balanced by a call to endSession. + */ + virtual void beginSession(); + virtual void endSession(); + + /** Optional methods for shaders that can pretend to be a bitmap/texture + to play along with opengl. Default just returns false and ignores + the out parameters. + */ + virtual bool asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, + TileMode xy[2]); + + ////////////////////////////////////////////////////////////////////////// + // Factory methods for stock shaders + + /** Call this to create a new shader that will draw with the specified bitmap. + @param src The bitmap to use inside the shader + @param tmx The tiling mode to use when sampling the bitmap in the x-direction. + @param tmy The tiling mode to use when sampling the bitmap in the y-direction. + @return Returns a new shader object. Note: this function never returns null. + */ + static SkShader* CreateBitmapShader(const SkBitmap& src, + TileMode tmx, TileMode tmy); + + virtual void flatten(SkFlattenableWriteBuffer& ); +protected: + enum MatrixClass { + kLinear_MatrixClass, // no perspective + kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each scanline + kPerspective_MatrixClass // slow perspective, need to mappoints each pixel + }; + static MatrixClass ComputeMatrixClass(const SkMatrix&); + + // These can be called by your subclass after setContext() has been called + uint8_t getPaintAlpha() const { return fPaintAlpha; } + SkBitmap::Config getDeviceConfig() const { return (SkBitmap::Config)fDeviceConfig; } + const SkMatrix& getTotalInverse() const { return fTotalInverse; } + MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; } + + SkShader(SkFlattenableReadBuffer& ); +private: + SkMatrix* fLocalMatrix; + SkMatrix fTotalInverse; + uint8_t fPaintAlpha; + uint8_t fDeviceConfig; + uint8_t fTotalInverseClass; + SkDEBUGCODE(SkBool8 fInSession;) + + static SkShader* CreateBitmapShader(const SkBitmap& src, + TileMode, TileMode, + void* storage, size_t storageSize); + friend class SkAutoBitmapShaderInstall; + typedef SkFlattenable INHERITED; +}; + +#endif + diff --git a/include/core/SkStream.h b/include/core/SkStream.h new file mode 100644 index 0000000000..26ef43f624 --- /dev/null +++ b/include/core/SkStream.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkStream_DEFINED +#define SkStream_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" + +class SkStream : public SkRefCnt { +public: + virtual ~SkStream(); + /** Called to rewind to the beginning of the stream. If this cannot be + done, return false. + */ + virtual bool rewind() = 0; + /** If this stream represents a file, this method returns the file's name. + If it does not, it returns NULL (the default behavior). + */ + virtual const char* getFileName(); + /** Called to read or skip size number of bytes. + If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped. + If buffer is NULL and size == 0, return the total length of the stream. + If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied. + @param buffer If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer + @param size The number of bytes to skip or copy + @return bytes read on success + */ + virtual size_t read(void* buffer, size_t size) = 0; + + /** Return the total length of the stream. + */ + size_t getLength() { return this->read(NULL, 0); } + + /** Skip the specified number of bytes, returning the actual number + of bytes that could be skipped. + */ + size_t skip(size_t bytes); + + /** If the stream is backed by RAM, this method returns the starting + address for the data. If not (i.e. it is backed by a file or other + structure), this method returns NULL. + The default implementation returns NULL. + */ + virtual const void* getMemoryBase(); + + int8_t readS8(); + int16_t readS16(); + int32_t readS32(); + + uint8_t readU8() { return (uint8_t)this->readS8(); } + uint16_t readU16() { return (uint16_t)this->readS16(); } + uint32_t readU32() { return (uint32_t)this->readS32(); } + + bool readBool() { return this->readU8() != 0; } + SkScalar readScalar(); + size_t readPackedUInt(); + + static void UnitTest(); +}; + +class SkWStream : SkNoncopyable { +public: + virtual ~SkWStream(); + + /** Called to write bytes to a SkWStream. Returns true on success + @param buffer the address of at least size bytes to be written to the stream + @param size The number of bytes in buffer to write to the stream + @return true on success + */ + virtual bool write(const void* buffer, size_t size) = 0; + virtual void newline(); + virtual void flush(); + + // helpers + + bool write8(U8CPU); + bool write16(U16CPU); + bool write32(uint32_t); + + bool writeText(const char text[]); + bool writeDecAsText(int32_t); + bool writeHexAsText(uint32_t, int minDigits = 0); + bool writeScalarAsText(SkScalar); + + bool writeBool(bool v) { return this->write8(v); } + bool writeScalar(SkScalar); + bool writePackedUInt(size_t); + + bool writeStream(SkStream* input, size_t length); + + static void UnitTest(); +}; + +//////////////////////////////////////////////////////////////////////////////////////// + +#include "SkString.h" + +struct SkFILE; + +/** A stream that reads from a FILE*, which is opened in the constructor and + closed in the destructor + */ +class SkFILEStream : public SkStream { +public: + /** Initialize the stream by calling fopen on the specified path. Will be + closed in the destructor. + */ + explicit SkFILEStream(const char path[] = NULL); + virtual ~SkFILEStream(); + + /** Returns true if the current path could be opened. + */ + bool isValid() const { return fFILE != NULL; } + /** Close the current file, and open a new file with the specified + path. If path is NULL, just close the current file. + */ + void setPath(const char path[]); + + virtual bool rewind(); + virtual size_t read(void* buffer, size_t size); + virtual const char* getFileName(); + +private: + SkFILE* fFILE; + SkString fName; +}; + +/** A stream that reads from a file descriptor + */ +class SkFDStream : public SkStream { +public: + /** Initialize the stream with a dup() of the specified file descriptor. + If closeWhenDone is true, then the descriptor will be closed in the + destructor. + */ + SkFDStream(int fileDesc, bool closeWhenDone); + virtual ~SkFDStream(); + + /** Returns true if the current path could be opened. + */ + bool isValid() const { return fFD >= 0; } + + virtual bool rewind(); + virtual size_t read(void* buffer, size_t size); + virtual const char* getFileName() { return NULL; } + +private: + int fFD; + bool fCloseWhenDone; +}; + +class SkMemoryStream : public SkStream { +public: + SkMemoryStream(); + /** We allocate (and free) the memory. Write to it via getMemoryBase() + */ + SkMemoryStream(size_t length); + /** if copyData is true, the stream makes a private copy of the data + */ + SkMemoryStream(const void* data, size_t length, bool copyData = false); + virtual ~SkMemoryStream(); + + /** Resets the stream to the specified data and length, + just like the constructor. + if copyData is true, the stream makes a private copy of the data + */ + virtual void setMemory(const void* data, size_t length, + bool copyData = false); + void skipToAlign4(); + virtual bool rewind(); + virtual size_t read(void* buffer, size_t size); + virtual const void* getMemoryBase(); + const void* getAtPos(); + size_t seek(size_t offset); + size_t peek() const { return fOffset; } + +private: + const void* fSrc; + size_t fSize, fOffset; + SkBool8 fWeOwnTheData; +}; + +/** \class SkBufferStream + This is a wrapper class that adds buffering to another stream. + The caller can provide the buffer, or ask SkBufferStream to allocated/free + it automatically. +*/ +class SkBufferStream : public SkStream { +public: + /** Provide the stream to be buffered (proxy), and the size of the buffer that + should be used. This will be allocated and freed automatically. If bufferSize is 0, + a default buffer size will be used. + The proxy stream is referenced, and will be unreferenced in when the + bufferstream is destroyed. + */ + SkBufferStream(SkStream* proxy, size_t bufferSize = 0); + /** Provide the stream to be buffered (proxy), and a buffer and size to be used. + This buffer is owned by the caller, and must be at least bufferSize bytes big. + Passing NULL for buffer will cause the buffer to be allocated/freed automatically. + If buffer is not NULL, it is an error for bufferSize to be 0. + The proxy stream is referenced, and will be unreferenced in when the + bufferstream is destroyed. + */ + SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize); + virtual ~SkBufferStream(); + + virtual bool rewind(); + virtual const char* getFileName(); + virtual size_t read(void* buffer, size_t size); + virtual const void* getMemoryBase(); + +private: + enum { + kDefaultBufferSize = 128 + }; + // illegal + SkBufferStream(const SkBufferStream&); + SkBufferStream& operator=(const SkBufferStream&); + + SkStream* fProxy; + char* fBuffer; + size_t fOrigBufferSize, fBufferSize, fBufferOffset; + bool fWeOwnTheBuffer; + + void init(void*, size_t); +}; + +///////////////////////////////////////////////////////////////////////////////////////////// + +class SkFILEWStream : public SkWStream { +public: + SkFILEWStream(const char path[]); + virtual ~SkFILEWStream(); + + /** Returns true if the current path could be opened. + */ + bool isValid() const { return fFILE != NULL; } + + virtual bool write(const void* buffer, size_t size); + virtual void flush(); +private: + SkFILE* fFILE; +}; + +class SkMemoryWStream : public SkWStream { +public: + SkMemoryWStream(void* buffer, size_t size); + virtual bool write(const void* buffer, size_t size); + +private: + char* fBuffer; + size_t fMaxLength; + size_t fBytesWritten; +}; + +class SkDynamicMemoryWStream : public SkWStream { +public: + SkDynamicMemoryWStream(); + virtual ~SkDynamicMemoryWStream(); + virtual bool write(const void* buffer, size_t size); + // random access write + // modifies stream and returns true if offset + size is less than or equal to getOffset() + bool write(const void* buffer, size_t offset, size_t size); + bool read(void* buffer, size_t offset, size_t size); + size_t getOffset() { return fBytesWritten; } + + // copy what has been written to the stream into dst + void copyTo(void* dst) const; + /* return a cache of the flattened data returned by copyTo(). + This copy is only valid until the next call to write(). + The memory is managed by the stream class. + */ + const char* getStream() const; + + // same as getStream, but additionally detach the flattened datat + const char* detach(); + + // reset the stream to its original state + void reset(); + void padToAlign4(); +private: + struct Block; + Block* fHead; + Block* fTail; + size_t fBytesWritten; + mutable char* fCopyToCache; +}; + + +class SkDebugWStream : public SkWStream { +public: + // overrides + virtual bool write(const void* buffer, size_t size); + virtual void newline(); +}; + +// for now +typedef SkFILEStream SkURLStream; + +#endif + diff --git a/include/core/SkString.h b/include/core/SkString.h new file mode 100644 index 0000000000..743b093207 --- /dev/null +++ b/include/core/SkString.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkString_DEFINED +#define SkString_DEFINED + +#include "SkScalar.h" + +/* Some helper functions for C strings +*/ + +bool SkStrStartsWith(const char string[], const char prefix[]); +bool SkStrEndsWith(const char string[], const char suffix[]); +int SkStrStartsWithOneOf(const char string[], const char prefixes[]); + +#define SkStrAppendS32_MaxSize 11 +char* SkStrAppendS32(char buffer[], int32_t); +#define SkStrAppendScalar_MaxSize 11 +char* SkStrAppendScalar(char buffer[], SkScalar); + +/** \class SkString + + Light weight class for managing strings. Uses reference + counting to make string assignments and copies very fast + with no extra RAM cost. Assumes UTF8 encoding. +*/ +class SkString { +public: + SkString(); + explicit SkString(size_t len); + explicit SkString(const char text[]); + SkString(const char text[], size_t len); + explicit SkString(const SkString&); + ~SkString(); + + bool isEmpty() const { return fRec->fLength == 0; } + size_t size() const { return (size_t) fRec->fLength; } + const char* c_str() const { return fRec->data(); } + + bool equals(const SkString&) const; + bool equals(const char text[]) const; + bool equals(const char text[], size_t len) const; + + bool startsWith(const char prefix[]) const + { + return SkStrStartsWith(fRec->data(), prefix); + } + bool endsWith(const char suffix[]) const + { + return SkStrEndsWith(fRec->data(), suffix); + } + + friend int operator==(const SkString& a, const SkString& b) + { + return a.equals(b); + } + friend int operator!=(const SkString& a, const SkString& b) + { + return !a.equals(b); + } + + // these methods edit the string + + SkString& operator=(const SkString&); + + char* writable_str(); + + void reset(); + void resize(size_t len) { this->set(NULL, len); } + void set(const SkString& src) { *this = src; } + void set(const char text[]); + void set(const char text[], size_t len); + void setUTF16(const uint16_t[]); + void setUTF16(const uint16_t[], size_t len); + + void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); } + void insert(size_t offset, const char text[]); + void insert(size_t offset, const char text[], size_t len); + void insertUnichar(size_t offset, SkUnichar); + void insertS32(size_t offset, int32_t value); + void insertHex(size_t offset, uint32_t value, int minDigits = 0); + void insertScalar(size_t offset, SkScalar); + + void append(const SkString& str) { this->insert((size_t)-1, str); } + void append(const char text[]) { this->insert((size_t)-1, text); } + void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); } + void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); } + void appendS32(int32_t value) { this->insertS32((size_t)-1, value); } + void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); } + void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void prepend(const SkString& str) { this->insert(0, str); } + void prepend(const char text[]) { this->insert(0, text); } + void prepend(const char text[], size_t len) { this->insert(0, text, len); } + void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); } + void prependS32(int32_t value) { this->insertS32(0, value); } + void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); } + void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void printf(const char format[], ...); + void appendf(const char format[], ...); + void prependf(const char format[], ...); + + void remove(size_t offset, size_t length); + + /** Swap contents between this and other. This function is guaranteed + to never fail or throw. + */ + void swap(SkString& other); + + /** @cond UNIT_TEST */ + SkDEBUGCODE(static void UnitTest();) + /** @endcond */ + +private: + struct Rec { + public: + uint16_t fLength; + uint16_t fRefCnt; + char fBeginningOfData; + + char* data() { return &fBeginningOfData; } + const char* data() const { return &fBeginningOfData; } + }; + Rec* fRec; + +#ifdef SK_DEBUG + const char* fStr; + void validate() const; +#else + void validate() const {} +#endif + + static const Rec gEmptyRec; + static Rec* AllocRec(const char text[], U16CPU len); + static Rec* RefRec(Rec*); +}; + +class SkAutoUCS2 { +public: + SkAutoUCS2(const char utf8[]); + ~SkAutoUCS2(); + + /** This returns the number of ucs2 characters + */ + int count() const { return fCount; } + /** This returns a null terminated ucs2 string + */ + const uint16_t* getUCS2() const { return fUCS2; } + +private: + int fCount; + uint16_t* fUCS2; +}; + +#endif + diff --git a/include/core/SkStroke.h b/include/core/SkStroke.h new file mode 100644 index 0000000000..b593b69e8d --- /dev/null +++ b/include/core/SkStroke.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkStroke_DEFINED +#define SkStroke_DEFINED + +#include "SkPoint.h" +#include "SkPaint.h" + +struct SkRect; +class SkPath; + +#define SK_DefaultStrokeWidth SK_Scalar1 +#define SK_DefaultMiterLimit SkIntToScalar(4) + + +/** \class SkStroke + SkStroke is the utility class that constructs paths by stroking + geometries (lines, rects, ovals, roundrects, paths). This is + invoked when a geometry or text is drawn in a canvas with the + kStroke_Mask bit set in the paint. +*/ +class SkStroke { +public: + SkStroke(); + SkStroke(const SkPaint&); + SkStroke(const SkPaint&, SkScalar width); // width overrides paint.getStrokeWidth() + + SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; } + void setCap(SkPaint::Cap); + + SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; } + void setJoin(SkPaint::Join); + + void setMiterLimit(SkScalar); + void setWidth(SkScalar); + + bool getDoFill() const { return SkToBool(fDoFill); } + void setDoFill(bool doFill) { fDoFill = SkToU8(doFill); } + + void strokeLine(const SkPoint& start, const SkPoint& end, SkPath*) const; + void strokeRect(const SkRect& rect, SkPath*) const; + void strokeOval(const SkRect& oval, SkPath*) const; + void strokeRRect(const SkRect& rect, SkScalar rx, SkScalar ry, SkPath*) const; + void strokePath(const SkPath& path, SkPath*) const; + + //////////////////////////////////////////////////////////////// + +private: + SkScalar fWidth, fMiterLimit; + uint8_t fCap, fJoin; + SkBool8 fDoFill; + + friend class SkPaint; +}; + +#endif + diff --git a/include/core/SkTDArray.h b/include/core/SkTDArray.h new file mode 100644 index 0000000000..4d2d7f7ed3 --- /dev/null +++ b/include/core/SkTDArray.h @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTDArray_DEFINED +#define SkTDArray_DEFINED + +#include "SkTypes.h" + +template <typename T> class SkTDArray { +public: + SkTDArray() { + fReserve = fCount = 0; + fArray = NULL; +#ifdef SK_DEBUG + fData = NULL; +#endif + } + SkTDArray(const T src[], size_t count) { + SkASSERT(src || count == 0); + + fReserve = fCount = 0; + fArray = NULL; +#ifdef SK_DEBUG + fData = NULL; +#endif + if (count) { + fArray = (T*)sk_malloc_throw(count * sizeof(T)); +#ifdef SK_DEBUG + fData = (ArrayT*)fArray; +#endif + memcpy(fArray, src, sizeof(T) * count); + fReserve = fCount = count; + } + } + SkTDArray(const SkTDArray<T>& src) { + fReserve = fCount = 0; + fArray = NULL; +#ifdef SK_DEBUG + fData = NULL; +#endif + SkTDArray<T> tmp(src.fArray, src.fCount); + this->swap(tmp); + } + ~SkTDArray() { + sk_free(fArray); + } + + SkTDArray<T>& operator=(const SkTDArray<T>& src) { + if (this != &src) { + if (src.fCount > fReserve) { + SkTDArray<T> tmp(src.fArray, src.fCount); + this->swap(tmp); + } else { + memcpy(fArray, src.fArray, sizeof(T) * src.fCount); + fCount = src.fCount; + } + } + return *this; + } + + friend int operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) { + return a.fCount == b.fCount && + (a.fCount == 0 || + !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T))); + } + + void swap(SkTDArray<T>& other) { + SkTSwap(fArray, other.fArray); +#ifdef SK_DEBUG + SkTSwap(fData, other.fData); +#endif + SkTSwap(fReserve, other.fReserve); + SkTSwap(fCount, other.fCount); + } + + bool isEmpty() const { return fCount == 0; } + int count() const { return fCount; } + T* begin() const { return fArray; } + T* end() const { return fArray ? fArray + fCount : NULL; } + T& operator[](int index) const { + SkASSERT((unsigned)index < fCount); + return fArray[index]; + } + + void reset() { + if (fArray) { + sk_free(fArray); + fArray = NULL; +#ifdef SK_DEBUG + fData = NULL; +#endif + fReserve = fCount = 0; + } else { + SkASSERT(fReserve == 0 && fCount == 0); + } + } + + void rewind() { + // same as setCount(0) + fCount = 0; + } + + void setCount(size_t count) { + if (count > fReserve) { + this->growBy(count - fCount); + } else { + fCount = count; + } + } + + void setReserve(size_t reserve) { + if (reserve > fReserve) { + SkASSERT(reserve > fCount); + size_t count = fCount; + this->growBy(reserve - fCount); + fCount = count; + } + } + + T* prepend() { + this->growBy(1); + memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T)); + return fArray; + } + + T* append() { + return this->append(1, NULL); + } + T* append(size_t count, const T* src = NULL) { + unsigned oldCount = fCount; + if (count) { + SkASSERT(src == NULL || fArray == NULL || + src + count <= fArray || fArray + oldCount <= src); + + this->growBy(count); + if (src) { + memcpy(fArray + oldCount, src, sizeof(T) * count); + } + } + return fArray + oldCount; + } + + T* appendClear() { + T* result = this->append(); + *result = 0; + return result; + } + + T* insert(size_t index) { + return this->insert(index, 1, NULL); + } + T* insert(size_t index, size_t count, const T* src = NULL) { + SkASSERT(count); + SkASSERT(index <= fCount); + int oldCount = fCount; + this->growBy(count); + T* dst = fArray + index; + memmove(dst + count, dst, sizeof(T) * (oldCount - index)); + if (src) { + memcpy(dst, src, sizeof(T) * count); + } + return dst; + } + + void remove(size_t index, size_t count = 1) { + SkASSERT(index + count <= fCount); + fCount = fCount - count; + memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index)); + } + + void removeShuffle(size_t index) { + SkASSERT(index < fCount); + unsigned newCount = fCount - 1; + fCount = newCount; + if (index != newCount) { + memcpy(fArray + index, fArray + newCount, sizeof(T)); + } + } + + int find(const T& elem) const { + const T* iter = fArray; + const T* stop = fArray + fCount; + + for (; iter < stop; iter++) { + if (*iter == elem) { + return (int) (iter - fArray); + } + } + return -1; + } + + int rfind(const T& elem) const { + const T* iter = fArray + fCount; + const T* stop = fArray; + + while (iter > stop) { + if (*--iter == elem) { + return iter - stop; + } + } + return -1; + } + + // routines to treat the array like a stack + T* push() { return this->append(); } + void push(const T& elem) { *this->append() = elem; } + const T& top() const { return (*this)[fCount - 1]; } + T& top() { return (*this)[fCount - 1]; } + void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; } + void pop() { --fCount; } + + void deleteAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + delete (*iter); + iter += 1; + } + this->reset(); + } + + void freeAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + sk_free(*iter); + iter += 1; + } + this->reset(); + } + + void unrefAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + (*iter)->unref(); + iter += 1; + } + this->reset(); + } + +#ifdef SK_DEBUG + void validate() const { + SkASSERT((fReserve == 0 && fArray == NULL) || + (fReserve > 0 && fArray != NULL)); + SkASSERT(fCount <= fReserve); + SkASSERT(fData == (ArrayT*)fArray); + } +#endif + +private: +#ifdef SK_DEBUG + enum { + kDebugArraySize = 16 + }; + typedef T ArrayT[kDebugArraySize]; + ArrayT* fData; +#endif + T* fArray; + size_t fReserve, fCount; + + void growBy(size_t extra) { + SkASSERT(extra); + + if (fCount + extra > fReserve) { + size_t size = fCount + extra + 4; + size += size >> 2; + + fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T)); +#ifdef SK_DEBUG + fData = (ArrayT*)fArray; +#endif + fReserve = size; + } + fCount += extra; + } +}; + +#endif + diff --git a/include/core/SkTDStack.h b/include/core/SkTDStack.h new file mode 100644 index 0000000000..5bc10ee9cb --- /dev/null +++ b/include/core/SkTDStack.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTDStack_DEFINED +#define SkTDStack_DEFINED + +#include "SkTypes.h" + +template <typename T> class SkTDStack : SkNoncopyable { +public: + SkTDStack() : fCount(0), fTotalCount(0) + { + fInitialRec.fNext = NULL; + fRec = &fInitialRec; + + // fCount = kSlotCount; + } + ~SkTDStack() + { + Rec* rec = fRec; + while (rec != &fInitialRec) + { + Rec* next = rec->fNext; + sk_free(rec); + rec = next; + } + } + + int count() const { return fTotalCount; } + + T* push() + { + SkASSERT(fCount <= kSlotCount); + if (fCount == kSlotCount) + { + Rec* rec = (Rec*)sk_malloc_throw(sizeof(Rec)); + rec->fNext = fRec; + fRec = rec; + fCount = 0; + } + ++fTotalCount; + return &fRec->fSlots[fCount++]; + } + void push(const T& elem) { *this->push() = elem; } + const T& index(int idx) const + { + SkASSERT(fRec && fCount > idx); + return fRec->fSlots[fCount - idx - 1]; + } + T& index(int idx) + { + SkASSERT(fRec && fCount > idx); + return fRec->fSlots[fCount - idx - 1]; + } + const T& top() const + { + SkASSERT(fRec && fCount > 0); + return fRec->fSlots[fCount - 1]; + } + T& top() + { + SkASSERT(fRec && fCount > 0); + return fRec->fSlots[fCount - 1]; + } + void pop(T* elem) + { + if (elem) + *elem = fRec->fSlots[fCount - 1]; + this->pop(); + } + void pop() + { + SkASSERT(fCount > 0 && fRec); + --fTotalCount; + if (--fCount == 0) + { + if (fRec != &fInitialRec) + { + Rec* rec = fRec->fNext; + sk_free(fRec); + fCount = kSlotCount; + fRec = rec; + } + else + SkASSERT(fTotalCount == 0); + } + } + +private: + enum { + kSlotCount = 8 + }; + + struct Rec; + friend struct Rec; + + struct Rec { + Rec* fNext; + T fSlots[kSlotCount]; + }; + Rec fInitialRec; + Rec* fRec; + int fCount, fTotalCount; +}; + +#endif + diff --git a/include/core/SkTDict.h b/include/core/SkTDict.h new file mode 100644 index 0000000000..0b92779ce3 --- /dev/null +++ b/include/core/SkTDict.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTDict_DEFINED +#define SkTDict_DEFINED + +#include "SkChunkAlloc.h" +#include "SkTSearch.h" +#include "SkTDArray.h" + +template <typename T> class SkTDict : SkNoncopyable { +public: + SkTDict(size_t minStringAlloc) : fStrings(minStringAlloc) {} + + void reset() + { + fArray.reset(); + fStrings.reset(); + } + + int count() const { return fArray.count(); } + + bool set(const char name[], const T& value) + { + return set(name, strlen(name), value); + } + + bool set(const char name[], size_t len, const T& value) + { + SkASSERT(name); + + int index = this->find_index(name, len); + + if (index >= 0) + { + fArray[index].fValue = value; + return false; + } + else + { + Pair* pair = fArray.insert(~index); + char* copy = (char*)fStrings.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType); + memcpy(copy, name, len); + copy[len] = '\0'; + pair->fName = copy; + pair->fValue = value; + return true; + } + } + + bool find(const char name[]) const + { + return this->find_index(name) >= 0; + } + + bool find(const char name[], size_t len) const + { + return this->find_index(name, len) >= 0; + } + + bool find(const char name[], T* value) const + { + return find(name, strlen(name), value); + } + + bool find(const char name[], size_t len, T* value) const + { + int index = this->find_index(name, len); + + if (index >= 0) + { + if (value) + *value = fArray[index].fValue; + return true; + } + return false; + } + + bool findKey(T& value, const char** name) const + { + Pair* end = fArray.end(); + for (Pair* pair = fArray.begin(); pair < end; pair++) { + if (pair->fValue != value) + continue; + *name = pair->fName; + return true; + } + return false; + } + +public: + struct Pair { + const char* fName; + T fValue; + + friend int operator<(const Pair& a, const Pair& b) + { + return strcmp(a.fName, b.fName); + } + friend int operator!=(const Pair& a, const Pair& b) + { + return strcmp(a.fName, b.fName); + } + }; + friend class Iter; + +public: + class Iter { + public: + Iter(const SkTDict<T>& dict) + { + fIter = dict.fArray.begin(); + fStop = dict.fArray.end(); + } + const char* next(T* value) + { + const char* name = NULL; + if (fIter < fStop) + { + name = fIter->fName; + if (value) + *value = fIter->fValue; + fIter += 1; + } + return name; + } + private: + Pair* fIter; + Pair* fStop; + }; + +private: + SkTDArray<Pair> fArray; + SkChunkAlloc fStrings; + + int find_index(const char name[]) const + { + return find_index(name, strlen(name)); + } + + int find_index(const char name[], size_t len) const + { + SkASSERT(name); + + int count = fArray.count(); + int index = ~0; + + if (count) + index = SkStrSearch(&fArray.begin()->fName, count, name, len, sizeof(Pair)); + return index; + } + friend class Iter; +}; + +#endif + diff --git a/include/core/SkTSearch.h b/include/core/SkTSearch.h new file mode 100644 index 0000000000..f29e6f5e77 --- /dev/null +++ b/include/core/SkTSearch.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTSearch_DEFINED +#define SkTSearch_DEFINED + +#include "SkTypes.h" + +template <typename T> +int SkTSearch(const T* base, int count, const T& target, size_t elemSize) +{ + SkASSERT(count >= 0); + if (count <= 0) + return ~0; + + SkASSERT(base != NULL); // base may be NULL if count is zero + + int lo = 0; + int hi = count - 1; + + while (lo < hi) + { + int mid = (hi + lo) >> 1; + const T* elem = (const T*)((const char*)base + mid * elemSize); + + if (*elem < target) + lo = mid + 1; + else + hi = mid; + } + + const T* elem = (const T*)((const char*)base + hi * elemSize); + if (*elem != target) + { + if (*elem < target) + hi += 1; + hi = ~hi; + } + return hi; +} + +template <typename T> +int SkTSearch(const T* base, int count, const T& target, size_t elemSize, + int (*compare)(const T&, const T&)) +{ + SkASSERT(count >= 0); + if (count <= 0) { + return ~0; + } + + SkASSERT(base != NULL); // base may be NULL if count is zero + + int lo = 0; + int hi = count - 1; + + while (lo < hi) { + int mid = (hi + lo) >> 1; + const T* elem = (const T*)((const char*)base + mid * elemSize); + + if ((*compare)(*elem, target) < 0) + lo = mid + 1; + else + hi = mid; + } + + const T* elem = (const T*)((const char*)base + hi * elemSize); + int pred = (*compare)(*elem, target); + if (pred != 0) { + if (pred < 0) + hi += 1; + hi = ~hi; + } + return hi; +} + +template <typename T> +int SkTSearch(const T** base, int count, const T* target, size_t elemSize, + int (*compare)(const T*, const T*)) +{ + SkASSERT(count >= 0); + if (count <= 0) + return ~0; + + SkASSERT(base != NULL); // base may be NULL if count is zero + + int lo = 0; + int hi = count - 1; + + while (lo < hi) + { + int mid = (hi + lo) >> 1; + const T* elem = *(const T**)((const char*)base + mid * elemSize); + + if ((*compare)(elem, target) < 0) + lo = mid + 1; + else + hi = mid; + } + + const T* elem = *(const T**)((const char*)base + hi * elemSize); + int pred = (*compare)(elem, target); + if (pred != 0) + { + if (pred < 0) + hi += 1; + hi = ~hi; + } + return hi; +} + +int SkStrSearch(const char*const* base, int count, const char target[], + size_t target_len, size_t elemSize); +int SkStrSearch(const char*const* base, int count, const char target[], + size_t elemSize); + +/** Like SkStrSearch, but treats target as if it were all lower-case. Assumes that + base points to a table of lower-case strings. +*/ +int SkStrLCSearch(const char*const* base, int count, const char target[], + size_t target_len, size_t elemSize); +int SkStrLCSearch(const char*const* base, int count, const char target[], + size_t elemSize); + +/** Helper class to convert a string to lower-case, but only modifying the ascii + characters. This makes the routine very fast and never changes the string + length, but it is not suitable for linguistic purposes. Normally this is + used for buiding and searching string tables. +*/ +class SkAutoAsciiToLC { +public: + SkAutoAsciiToLC(const char str[], size_t len = (size_t)-1); + ~SkAutoAsciiToLC(); + + const char* lc() const { return fLC; } + size_t length() const { return fLength; } + +private: + char* fLC; // points to either the heap or fStorage + size_t fLength; + enum { + STORAGE = 64 + }; + char fStorage[STORAGE+1]; +}; + +extern "C" { + typedef int (*SkQSortCompareProc)(const void*, const void*); + void SkQSort(void* base, size_t count, size_t elemSize, SkQSortCompareProc); +} + +SkDEBUGCODE(void SkQSort_UnitTest();) + +#endif + diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h new file mode 100644 index 0000000000..27ebd416df --- /dev/null +++ b/include/core/SkTemplates.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTemplates_DEFINED +#define SkTemplates_DEFINED + +#include "SkTypes.h" + +/** \file SkTemplates.h + + This file contains light-weight template classes for type-safe and exception-safe + resource management. +*/ + +/** \class SkAutoTCallVProc + + Call a function when this goes out of scope. The template uses two + parameters, the object, and a function that is to be called in the destructor. + If detach() is called, the object reference is set to null. If the object + reference is null when the destructor is called, we do not call the + function. +*/ +template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { +public: + SkAutoTCallVProc(T* obj): fObj(obj) {} + ~SkAutoTCallVProc() { if (fObj) P(fObj); } + T* detach() { T* obj = fObj; fObj = NULL; return obj; } +private: + T* fObj; +}; + +/** \class SkAutoTCallIProc + +Call a function when this goes out of scope. The template uses two +parameters, the object, and a function that is to be called in the destructor. +If detach() is called, the object reference is set to null. If the object +reference is null when the destructor is called, we do not call the +function. +*/ +template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { +public: + SkAutoTCallIProc(T* obj): fObj(obj) {} + ~SkAutoTCallIProc() { if (fObj) P(fObj); } + T* detach() { T* obj = fObj; fObj = NULL; return obj; } +private: + T* fObj; +}; + +template <typename T> class SkAutoTDelete : SkNoncopyable { +public: + SkAutoTDelete(T* obj) : fObj(obj) {} + ~SkAutoTDelete() { delete fObj; } + + T* get() const { return fObj; } + void free() { delete fObj; fObj = NULL; } + T* detach() { T* obj = fObj; fObj = NULL; return obj; } + +private: + T* fObj; +}; + +template <typename T> class SkAutoTDeleteArray : SkNoncopyable { +public: + SkAutoTDeleteArray(T array[]) : fArray(array) {} + ~SkAutoTDeleteArray() { delete[] fArray; } + + T* get() const { return fArray; } + void free() { delete[] fArray; fArray = NULL; } + T* detach() { T* array = fArray; fArray = NULL; return array; } + +private: + T* fArray; +}; + +/** Allocate an array of T elements, and free the array in the destructor + */ +template <typename T> class SkAutoTArray : SkNoncopyable { +public: + /** Allocate count number of T elements + */ + SkAutoTArray(size_t count) { + fArray = NULL; + if (count) { + fArray = new T[count]; + } + SkDEBUGCODE(fCount = count;) + } + + ~SkAutoTArray() { + delete[] fArray; + } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray; } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT((unsigned)index < fCount); + return fArray[index]; + } + +private: + T* fArray; + SkDEBUGCODE(size_t fCount;) +}; + +/** Wraps SkAutoTArray, with room for up to N elements preallocated + */ +template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { +public: + /** Allocate count number of T elements + */ + SkAutoSTArray(size_t count) { + if (count > N) { + fArray = new T[count]; + } else if (count) { + fArray = new (fStorage) T[count]; + } else { + fArray = NULL; + } + fCount = count; + } + + ~SkAutoSTArray() { + if (fCount > N) { + delete[] fArray; + } else { + T* start = fArray; + T* iter = start + fCount; + while (iter > start) { + (--iter)->~T(); + } + } + } + + /** Return the number of T elements in the array + */ + size_t count() const { return fCount; } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray; } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT((unsigned)index < fCount); + return fArray[index]; + } + +private: + size_t fCount; + T* fArray; + // since we come right after fArray, fStorage should be properly aligned + char fStorage[N * sizeof(T)]; +}; + +/** Allocate a temp array on the stack/heap. + Does NOT call any constructors/destructors on T (i.e. T must be POD) +*/ +template <typename T> class SkAutoTMalloc : SkNoncopyable { +public: + SkAutoTMalloc(size_t count) + { + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + ~SkAutoTMalloc() + { + sk_free(fPtr); + } + T* get() const { return fPtr; } + +private: + T* fPtr; +}; + +template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable { +public: + SkAutoSTMalloc(size_t count) + { + if (count <= N) + fPtr = fTStorage; + else + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + ~SkAutoSTMalloc() + { + if (fPtr != fTStorage) + sk_free(fPtr); + } + T* get() const { return fPtr; } + +private: + T* fPtr; + union { + uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; + T fTStorage[1]; // do NOT want to invoke T::T() + }; +}; + +#endif + diff --git a/include/core/SkThread.h b/include/core/SkThread.h new file mode 100644 index 0000000000..637492dc43 --- /dev/null +++ b/include/core/SkThread.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkThread_DEFINED +#define SkThread_DEFINED + +#include "SkTypes.h" +#include "SkThread_platform.h" + +/****** SkThread_platform needs to define the following... + +int32_t sk_atomic_inc(int32_t*); +int32_t sk_atomic_dec(int32_t*); + +class SkMutex { +public: + SkMutex(); + ~SkMutex(); + + void acquire(); + void release(); +}; + +****************/ + +class SkAutoMutexAcquire : SkNoncopyable { +public: + explicit SkAutoMutexAcquire(SkMutex& mutex) : fMutex(&mutex) + { + SkASSERT(fMutex != NULL); + mutex.acquire(); + } + /** If the mutex has not been release, release it now. + */ + ~SkAutoMutexAcquire() + { + if (fMutex) + fMutex->release(); + } + /** If the mutex has not been release, release it now. + */ + void release() + { + if (fMutex) + { + fMutex->release(); + fMutex = NULL; + } + } + +private: + SkMutex* fMutex; +}; + +#endif diff --git a/include/core/SkThread_platform.h b/include/core/SkThread_platform.h new file mode 100644 index 0000000000..825b737554 --- /dev/null +++ b/include/core/SkThread_platform.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkThread_platform_DEFINED +#define SkThread_platform_DEFINED + +#ifdef ANDROID + +#include <utils/threads.h> +#include <utils/Atomic.h> + +#define sk_atomic_inc(addr) android_atomic_inc(addr) +#define sk_atomic_dec(addr) android_atomic_dec(addr) + +class SkMutex : android::Mutex { +public: + // if isGlobal is true, then ignore any errors in the platform-specific + // destructor + SkMutex(bool isGlobal = true) {} + ~SkMutex() {} + + void acquire() { this->lock(); } + void release() { this->unlock(); } +}; + +#else + +/** Implemented by the porting layer, this function adds 1 to the int specified + by the address (in a thread-safe manner), and returns the previous value. +*/ +int32_t sk_atomic_inc(int32_t* addr); +/** Implemented by the porting layer, this function subtracts 1 to the int + specified by the address (in a thread-safe manner), and returns the previous + value. +*/ +int32_t sk_atomic_dec(int32_t* addr); + +class SkMutex { +public: + // if isGlobal is true, then ignore any errors in the platform-specific + // destructor + SkMutex(bool isGlobal = true); + ~SkMutex(); + + void acquire(); + void release(); + +private: + bool fIsGlobal; + enum { + kStorageIntCount = 12 + }; + uint32_t fStorage[kStorageIntCount]; +}; + +#endif + +#endif diff --git a/include/core/SkTime.h b/include/core/SkTime.h new file mode 100644 index 0000000000..9ee7110029 --- /dev/null +++ b/include/core/SkTime.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTime_DEFINED +#define SkTime_DEFINED + +#include "SkTypes.h" + +/** \class SkTime + Platform-implemented utilities to return time of day, and millisecond counter. +*/ +class SkTime { +public: + struct DateTime { + uint16_t fYear; //!< e.g. 2005 + uint8_t fMonth; //!< 1..12 + uint8_t fDayOfWeek; //!< 0..6, 0==Sunday + uint8_t fDay; //!< 1..31 + uint8_t fHour; //!< 0..23 + uint8_t fMinute; //!< 0..59 + uint8_t fSecond; //!< 0..59 + }; + static void GetDateTime(DateTime*); + + static SkMSec GetMSecs(); +}; + +#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN32) + extern SkMSec gForceTickCount; +#endif + +#define SK_TIME_FACTOR 1 + +/////////////////////////////////////////////////////////////////////////////// + +class SkAutoTime { +public: + // The label is not deep-copied, so its address must remain valid for the + // lifetime of this object + SkAutoTime(const char* label = NULL, SkMSec minToDump = 0) : fLabel(label) + { + fNow = SkTime::GetMSecs(); + fMinToDump = minToDump; + } + ~SkAutoTime() + { + SkMSec dur = SkTime::GetMSecs() - fNow; + if (dur >= fMinToDump) { + SkDebugf("%s %d\n", fLabel ? fLabel : "", dur); + } + } +private: + const char* fLabel; + SkMSec fNow; + SkMSec fMinToDump; +}; + +#endif + diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h new file mode 100644 index 0000000000..546edcaae8 --- /dev/null +++ b/include/core/SkTypeface.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTypeface_DEFINED +#define SkTypeface_DEFINED + +#include "SkRefCnt.h" + +class SkStream; +class SkWStream; + +/** \class SkTypeface + + The SkTypeface class specifies the typeface and intrinsic style of a font. + This is used in the paint, along with optionally algorithmic settings like + textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify + how text appears when drawn (and measured). + + Typeface objects are immutable, and so they can be shred between threads. + To enable this, Typeface inherits from the thread-safe version of SkRefCnt. +*/ +class SkTypeface : public SkRefCnt { +public: + /** Style specifies the intrinsic style attributes of a given typeface + */ + enum Style { + kNormal = 0, + kBold = 0x01, + kItalic = 0x02, + + // helpers + kBoldItalic = 0x03 + }; + + /** Returns the typeface's intrinsic style attributes + */ + Style style() const { return fStyle; } + + /** DEPRECATED */ + Style getStyle() const { return this->style(); } + + /** Returns true if getStyle() has the kBold bit set. + */ + bool isBold() const { return (fStyle & kBold) != 0; } + + /** Returns true if getStyle() has the kItalic bit set. + */ + bool isItalic() const { return (fStyle & kItalic) != 0; } + + uint32_t uniqueID() const { return fUniqueID; } + + /** Return the uniqueID for the specified typeface. If the face is null, + resolve it to the default font and return its uniqueID. + */ + static uint32_t UniqueID(const SkTypeface* face); + + /** Return a new reference to the typeface that most closely matches the + requested familyName and style. Pass null as the familyName to return + the default font for the requested style. Will never return null + + @param familyName May be NULL. The name of the font family. + @param style The style (normal, bold, italic) of the typeface. + @return reference to the closest-matching typeface. Call must call + unref() when they are done. + */ + static SkTypeface* Create(const char familyName[], Style style = kNormal); + + /** Return a new reference to the typeface that most closely matches the + requested typeface and specified Style. Use this call if you want to + pick a new style from the same family of the existing typeface. + If family is NULL, this selects from the default font's family. + + @param family May be NULL. The name of the existing type face. + @param s The style (normal, bold, italic) of the type face. + @return reference to the closest-matching typeface. Call must call + unref() when they are done. + */ + static SkTypeface* CreateFromTypeface(const SkTypeface* family, Style s); + + /** Returns true if the two typefaces reference the same underlying font, + even if one is null (which maps to the default font). + */ + static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); + + /** Returns a 32bit hash value for the typeface. Takes care of mapping null + to the default typeface. + */ + static uint32_t Hash(const SkTypeface* face); + + /** Return a new typeface given a file. If the file does not exist, or is + not a valid font file, returns null. + */ + static SkTypeface* CreateFromFile(const char path[]); + + /** Return a new typeface given a stream. If the stream is + not a valid font file, returns null. Ownership of the stream is + transferred, so the caller must not reference it again. + */ + static SkTypeface* CreateFromStream(SkStream* stream); + + // Serialization + void serialize(SkWStream*) const; + static SkTypeface* Deserialize(SkStream*); + +protected: + /** uniqueID must be unique (please!) and non-zero + */ + SkTypeface(Style style, uint32_t uniqueID) + : fUniqueID(uniqueID), fStyle(style) {} + +private: + uint32_t fUniqueID; + Style fStyle; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h new file mode 100644 index 0000000000..0554c73d12 --- /dev/null +++ b/include/core/SkTypes.h @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkTypes_DEFINED +#define SkTypes_DEFINED + +#include "SkPreConfig.h" +#include "SkUserConfig.h" +#include "SkPostConfig.h" + +#ifndef SK_IGNORE_STDINT_DOT_H + #include <stdint.h> +#endif + +#include <stdio.h> + +/** \file SkTypes.h +*/ + +/* + memory wrappers to be implemented by the porting layer (platform) +*/ + +/** Called internally if we run out of memory. The platform implementation must + not return, but should either throw an exception or otherwise exit. +*/ +extern void sk_out_of_memory(void); +/** Called internally if we hit an unrecoverable error. + The platform implementation must not return, but should either throw + an exception or otherwise exit. +*/ +extern void sk_throw(void); + +enum { + SK_MALLOC_TEMP = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame + SK_MALLOC_THROW = 0x02 //!< instructs sk_malloc to call sk_throw if the memory cannot be allocated. +}; +/** Return a block of memory (at least 4-byte aligned) of at least the + specified size. If the requested memory cannot be returned, either + return null (if SK_MALLOC_TEMP bit is clear) or call sk_throw() + (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free(). +*/ +extern void* sk_malloc_flags(size_t size, unsigned flags); +/** Same as sk_malloc(), but hard coded to pass SK_MALLOC_THROW as the flag +*/ +extern void* sk_malloc_throw(size_t size); +/** Same as standard realloc(), but this one never returns null on failure. It will throw + an exception if it fails. +*/ +extern void* sk_realloc_throw(void* buffer, size_t size); +/** Free memory returned by sk_malloc(). It is safe to pass null. +*/ +extern void sk_free(void*); + +/////////////////////////////////////////////////////////////////////// + +#define SK_INIT_TO_AVOID_WARNING = 0 + +#ifndef SkDebugf + void SkDebugf(const char format[], ...); +#endif + +#ifdef SK_DEBUG + #define SkASSERT(cond) SK_DEBUGBREAK(cond) + #define SkDEBUGCODE(code) code + #define SkDECLAREPARAM(type, var) , type var + #define SkPARAM(var) , var +// #define SkDEBUGF(args ) SkDebugf##args + #define SkDEBUGF(args ) SkDebugf args + #define SkAssertResult(cond) SkASSERT(cond) +#else + #define SkASSERT(cond) + #define SkDEBUGCODE(code) + #define SkDEBUGF(args) + #define SkDECLAREPARAM(type, var) + #define SkPARAM(var) + + // unlike SkASSERT, this guy executes its condition in the non-debug build + #define SkAssertResult(cond) cond +#endif + +/////////////////////////////////////////////////////////////////////// + +/** Fast type for signed 8 bits. Use for parameter passing and local variables, not for storage +*/ +typedef int S8CPU; +/** Fast type for unsigned 8 bits. Use for parameter passing and local variables, not for storage +*/ +typedef int S16CPU; +/** Fast type for signed 16 bits. Use for parameter passing and local variables, not for storage +*/ +typedef unsigned U8CPU; +/** Fast type for unsigned 16 bits. Use for parameter passing and local variables, not for storage +*/ +typedef unsigned U16CPU; + +/** Meant to be faster than bool (doesn't promise to be 0 or 1, just 0 or non-zero +*/ +typedef int SkBool; +/** Meant to be a small version of bool, for storage purposes. Will be 0 or 1 +*/ +typedef uint8_t SkBool8; + +#ifdef SK_DEBUG + int8_t SkToS8(long); + uint8_t SkToU8(size_t); + int16_t SkToS16(long); + uint16_t SkToU16(size_t); + int32_t SkToS32(long); + uint32_t SkToU32(size_t); +#else + #define SkToS8(x) ((int8_t)(x)) + #define SkToU8(x) ((uint8_t)(x)) + #define SkToS16(x) ((int16_t)(x)) + #define SkToU16(x) ((uint16_t)(x)) + #define SkToS32(x) ((int32_t)(x)) + #define SkToU32(x) ((uint32_t)(x)) +#endif + +/** Returns 0 or 1 based on the condition +*/ +#define SkToBool(cond) ((cond) != 0) + +#define SK_MaxS16 32767 +#define SK_MinS16 -32767 +#define SK_MaxU16 0xFFFF +#define SK_MinU16 0 +#define SK_MaxS32 0x7FFFFFFF +#define SK_MinS32 0x80000001 +#define SK_MaxU32 0xFFFFFFFF +#define SK_MinU32 0 +#define SK_NaN32 0x80000000 + +#ifndef SK_OFFSETOF + #define SK_OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) +#endif + +/** Returns the number of entries in an array (not a pointer) +*/ +#define SK_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) + +/** Returns x rounded up to a multiple of 2 +*/ +#define SkAlign2(x) (((x) + 1) >> 1 << 1) +/** Returns x rounded up to a multiple of 4 +*/ +#define SkAlign4(x) (((x) + 3) >> 2 << 2) + +typedef uint32_t SkFourByteTag; +#define SkSetFourByteTag(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +/** 32 bit integer to hold a unicode value +*/ +typedef int32_t SkUnichar; +/** 32 bit value to hold a millisecond count +*/ +typedef uint32_t SkMSec; +/** 1 second measured in milliseconds +*/ +#define SK_MSec1 1000 +/** maximum representable milliseconds +*/ +#define SK_MSecMax 0x7FFFFFFF +/** Returns a < b for milliseconds, correctly handling wrap-around from 0xFFFFFFFF to 0 +*/ +#define SkMSec_LT(a, b) ((int32_t)(a) - (int32_t)(b) < 0) +/** Returns a <= b for milliseconds, correctly handling wrap-around from 0xFFFFFFFF to 0 +*/ +#define SkMSec_LE(a, b) ((int32_t)(a) - (int32_t)(b) <= 0) + + +/**************************************************************************** + The rest of these only build with C++ +*/ +#ifdef __cplusplus + +/** Faster than SkToBool for integral conditions. Returns 0 or 1 +*/ +inline int Sk32ToBool(uint32_t n) +{ + return (n | (0-n)) >> 31; +} + +template <typename T> inline void SkTSwap(T& a, T& b) +{ + T c(a); + a = b; + b = c; +} + +inline int32_t SkAbs32(int32_t value) +{ +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (value < 0) + value = -value; + return value; +#else + int32_t mask = value >> 31; + return (value ^ mask) - mask; +#endif +} + +inline int32_t SkMax32(int32_t a, int32_t b) +{ + if (a < b) + a = b; + return a; +} + +inline int32_t SkMin32(int32_t a, int32_t b) +{ + if (a > b) + a = b; + return a; +} + +inline int32_t SkSign32(int32_t a) +{ + return (a >> 31) | ((unsigned) -a >> 31); +} + +inline int32_t SkFastMin32(int32_t value, int32_t max) +{ +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (value > max) + value = max; + return value; +#else + int diff = max - value; + // clear diff if it is negative (clear if value > max) + diff &= (diff >> 31); + return value + diff; +#endif +} + +/** Returns signed 32 bit value pinned between min and max, inclusively +*/ +inline int32_t SkPin32(int32_t value, int32_t min, int32_t max) +{ +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (value < min) + value = min; + if (value > max) + value = max; +#else + if (value < min) + value = min; + else if (value > max) + value = max; +#endif + return value; +} + +inline uint32_t SkSetClearShift(uint32_t bits, bool cond, unsigned shift) +{ + SkASSERT((int)cond == 0 || (int)cond == 1); + return (bits & ~(1 << shift)) | ((int)cond << shift); +} + +inline uint32_t SkSetClearMask(uint32_t bits, bool cond, uint32_t mask) +{ + return cond ? bits | mask : bits & ~mask; +} + +////////////////////////////////////////////////////////////////////////////// + +/** \class SkNoncopyable + +SkNoncopyable is the base class for objects that may do not want to +be copied. It hides its copy-constructor and its assignment-operator. +*/ +class SkNoncopyable { +public: + SkNoncopyable() {} + +private: + SkNoncopyable(const SkNoncopyable&); + SkNoncopyable& operator=(const SkNoncopyable&); +}; + +class SkAutoFree : SkNoncopyable { +public: + SkAutoFree() : fPtr(NULL) {} + explicit SkAutoFree(void* ptr) : fPtr(ptr) {} + ~SkAutoFree() { sk_free(fPtr); } + + /** Return the currently allocate buffer, or null + */ + void* get() const { return fPtr; } + + /** Assign a new ptr allocated with sk_malloc (or null), and return the + previous ptr. Note it is the caller's responsibility to sk_free the + returned ptr. + */ + void* set(void* ptr) { + void* prev = fPtr; + fPtr = ptr; + return prev; + } + + /** Transfer ownership of the current ptr to the caller, setting the + internal reference to null. Note the caller is reponsible for calling + sk_free on the returned address. + */ + void* detach() { return this->set(NULL); } + + /** Free the current buffer, and set the internal reference to NULL. Same + as calling sk_free(detach()) + */ + void free() { + sk_free(fPtr); + fPtr = NULL; + } + +private: + void* fPtr; + // illegal + SkAutoFree(const SkAutoFree&); + SkAutoFree& operator=(const SkAutoFree&); +}; + +class SkAutoMalloc : public SkAutoFree { +public: + explicit SkAutoMalloc(size_t size) + : SkAutoFree(sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP)) {} + + SkAutoMalloc(size_t size, unsigned flags) + : SkAutoFree(sk_malloc_flags(size, flags)) {} + SkAutoMalloc() {} + + void* alloc(size_t size, + unsigned flags = (SK_MALLOC_THROW | SK_MALLOC_TEMP)) { + sk_free(set(sk_malloc_flags(size, flags))); + return get(); + } +}; + +template <size_t kSize> class SkAutoSMalloc : SkNoncopyable { +public: + explicit SkAutoSMalloc(size_t size) + { + if (size <= kSize) + fPtr = fStorage; + else + fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + ~SkAutoSMalloc() + { + if (fPtr != (void*)fStorage) + sk_free(fPtr); + } + void* get() const { return fPtr; } +private: + void* fPtr; + uint32_t fStorage[(kSize + 3) >> 2]; + // illegal + SkAutoSMalloc(const SkAutoSMalloc&); + SkAutoSMalloc& operator=(const SkAutoSMalloc&); +}; + +#endif /* C++ */ + +#endif + diff --git a/include/core/SkUnPreMultiply.h b/include/core/SkUnPreMultiply.h new file mode 100644 index 0000000000..4bdb9802e0 --- /dev/null +++ b/include/core/SkUnPreMultiply.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + +#ifndef SkUnPreMultiply_DEFINED +#define SkUnPreMultiply_DEFINED + +#include "SkColor.h" + +class SkUnPreMultiply { +public: + typedef uint32_t Scale; + + // index this table with alpha [0..255] + static const Scale* GetScaleTable() { + return gTable; + } + + static Scale GetScale(U8CPU alpha) { + SkASSERT(alpha <= 255); + return gTable[alpha]; + } + + /** Usage: + + const Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (...) { + unsigned a = ... + SkUnPreMultiply::Scale scale = table[a]; + + red = SkUnPreMultiply::ApplyScale(scale, red); + ... + // now red is unpremultiplied + } + */ + static U8CPU ApplyScale(Scale scale, U8CPU component) { + SkASSERT(component <= 255); + return (scale * component + (1 << 23)) >> 24; + } + + static SkColor PMColorToColor(SkPMColor c); + +private: + static const uint32_t gTable[256]; +}; + +#endif diff --git a/include/core/SkUnitMapper.h b/include/core/SkUnitMapper.h new file mode 100644 index 0000000000..5d1ea35882 --- /dev/null +++ b/include/core/SkUnitMapper.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkUnitMapper_DEFINED +#define SkUnitMapper_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" + +#include "SkFlattenable.h" + +class SkUnitMapper : public SkFlattenable { +public: + SkUnitMapper() {} + + /** Given a value in [0..0xFFFF], return a value in the same range. + */ + virtual uint16_t mapUnit16(uint16_t x) = 0; + +protected: + SkUnitMapper(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {} +}; + +#endif + diff --git a/include/core/SkUserConfig.h b/include/core/SkUserConfig.h new file mode 100644 index 0000000000..85cda1cb58 --- /dev/null +++ b/include/core/SkUserConfig.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkUserConfig_DEFINED +#define SkUserConfig_DEFINED + +// for floats +#ifdef SK_SCALAR_IS_FIXED +#undef SK_SCALAR_IS_FIXED +#endif +#define SK_SCALAR_IS_FLOAT + +// remove the x if you want to force us into SK_DEBUG mode +#ifdef SK_RELEASE + #undef SK_RELEASE + #define SK_DEBUG +#endif + +// remove the x if you want to force us into SK_RELEASE mode +#ifdef SK_DEBUGx + #undef SK_DEBUG + #define SK_RELEASE +#endif + +#ifdef ANDROID + #include <utils/misc.h> + #include <assert.h> + + #define SK_CRASH() *(int *)(uintptr_t)0 = 0 +// #define SK_CRASH() assert(0) + +#if 0 + // force fixed + #define SK_SCALAR_IS_FIXED + #undef SK_SCALAR_IS_FLOAT +#else + // force floats + #ifdef SK_SCALAR_IS_FIXED + #undef SK_SCALAR_IS_FIXED + #endif + #define SK_SCALAR_IS_FLOAT +#endif + + #define SK_CAN_USE_FLOAT + #define SK_SOFTWARE_FLOAT + #define SkLONGLONG int64_t + + // replace some sw float routines (floor, ceil, etc.) + #define SK_USE_FLOATBITS + + #if __BYTE_ORDER == __BIG_ENDIAN + #define SK_CPU_BENDIAN + #undef SK_CPU_LENDIAN + #else + #define SK_CPU_LENDIAN + #undef SK_CPU_BENDIAN + #endif + + // define SkDebugf to record file/line + #define SkDebugf(...) Android_SkDebugf(__FILE__, __LINE__, \ + __FUNCTION__, __VA_ARGS__) + void Android_SkDebugf(const char* file, int line, + const char* function, const char* format, ...); +#endif + +/* This file is included before all other headers, except for SkPreConfig.h. + That file uses various heuristics to make a "best guess" at settings for + the following build defines. + + However, in this file you can override any of those decisions by either + defining new symbols, or #undef symbols that were already set. +*/ + +// experimental for now +#define SK_SUPPORT_MIPMAP + +#ifdef SK_DEBUG + #define SK_SUPPORT_UNITTEST + /* Define SK_SIMULATE_FAILED_MALLOC to have + * sk_malloc throw an exception. Use this to + * detect unhandled memory leaks. */ + //#define SK_SIMULATE_FAILED_MALLOC + //#define SK_FIND_MEMORY_LEAKS +#endif + +#ifdef SK_BUILD_FOR_BREW + #include "SkBrewUserConfig.h" +#endif + +#endif + diff --git a/include/core/SkUtils.h b/include/core/SkUtils.h new file mode 100644 index 0000000000..f3e33417f1 --- /dev/null +++ b/include/core/SkUtils.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkUtils_DEFINED +#define SkUtils_DEFINED + +#include "SkTypes.h" + +/////////////////////////////////////////////////////////////////////////// + +/** Similar to memset(), but it assigns a 16bit value into the buffer. + @param buffer The memory to have value copied into it + @param value The 16bit value to be copied into buffer + @param count The number of times value should be copied into the buffer. +*/ +void sk_memset16_portable(uint16_t dst[], uint16_t value, int count); + +/** Similar to memset(), but it assigns a 32bit value into the buffer. + @param buffer The memory to have value copied into it + @param value The 32bit value to be copied into buffer + @param count The number of times value should be copied into the buffer. +*/ +void sk_memset32_portable(uint32_t dst[], uint32_t value, int count); + +#ifdef ANDROID + #include "cutils/memory.h" + + #define sk_memset16(dst, value, count) android_memset16(dst, value, (count) << 1) + #define sk_memset32(dst, value, count) android_memset32(dst, value, (count) << 2) +#endif + +#ifndef sk_memset16 + #define sk_memset16(dst, value, count) sk_memset16_portable(dst, value, count) +#endif + +#ifndef sk_memset32 + #define sk_memset32(dst, value, count) sk_memset32_portable(dst, value, count) +#endif + + +/////////////////////////////////////////////////////////////////////////// + +#define kMaxBytesInUTF8Sequence 4 + +#ifdef SK_DEBUG + int SkUTF8_LeadByteToCount(unsigned c); +#else + #define SkUTF8_LeadByteToCount(c) ((((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1) +#endif + +inline int SkUTF8_CountUTF8Bytes(const char utf8[]) +{ + SkASSERT(utf8); + return SkUTF8_LeadByteToCount(*(const uint8_t*)utf8); +} + +int SkUTF8_CountUnichars(const char utf8[]); +int SkUTF8_CountUnichars(const char utf8[], size_t byteLength); +SkUnichar SkUTF8_ToUnichar(const char utf8[]); +SkUnichar SkUTF8_NextUnichar(const char**); +SkUnichar SkUTF8_PrevUnichar(const char**); + +/** Return the number of bytes need to convert a unichar + into a utf8 sequence. Will be 1..kMaxBytesInUTF8Sequence, + or 0 if uni is illegal. +*/ +size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[] = NULL); + +/////////////////////////////////////////////////////////////////////////////// + +#define SkUTF16_IsHighSurrogate(c) (((c) & 0xFC00) == 0xD800) +#define SkUTF16_IsLowSurrogate(c) (((c) & 0xFC00) == 0xDC00) + +int SkUTF16_CountUnichars(const uint16_t utf16[]); +int SkUTF16_CountUnichars(const uint16_t utf16[], + int numberOf16BitValues); +// returns the current unichar and then moves past it (*p++) +SkUnichar SkUTF16_NextUnichar(const uint16_t**); +// this guy backs up to the previus unichar value, and returns it (*--p) +SkUnichar SkUTF16_PrevUnichar(const uint16_t**); +size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = NULL); + +size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues, + char utf8[] = NULL); + +class SkUtils { +public: +#ifdef SK_DEBUG + static void UnitTest(); +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkAutoTrace { +public: + /** NOTE: label contents are not copied, just the ptr is + retained, so DON'T DELETE IT. + */ + SkAutoTrace(const char label[]) : fLabel(label) { + SkDebugf("--- trace: %s Enter\n", fLabel); + } + ~SkAutoTrace() { + SkDebugf("--- trace: %s Leave\n", fLabel); + } +private: + const char* fLabel; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkAutoMemoryUsageProbe { +public: + /** Record memory usage in constructor, and dump the result + (delta and current total) in the destructor, with the optional + label. NOTE: label contents are not copied, just the ptr is + retained, so DON'T DELETE IT. + */ + SkAutoMemoryUsageProbe(const char label[]); + ~SkAutoMemoryUsageProbe(); +private: + const char* fLabel; + size_t fBytesAllocated; +}; + +#endif + diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h new file mode 100644 index 0000000000..aeeb37de4b --- /dev/null +++ b/include/core/SkWriter32.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkWriter32_DEFINED +#define SkWriter32_DEFINED + +#include "SkTypes.h" + +#include "SkScalar.h" +#include "SkPoint.h" +#include "SkRect.h" + +class SkStream; +class SkWStream; + +class SkWriter32 : SkNoncopyable { +public: + SkWriter32(size_t minSize) { + fMinSize = minSize; + fSize = 0; + fHead = fTail = NULL; + } + ~SkWriter32(); + + bool writeBool(bool value) { + this->writeInt(value); + return value; + } + + void writeInt(int32_t value) { + *(int32_t*)this->reserve(sizeof(value)) = value; + } + + void write8(int32_t value) { + *(int32_t*)this->reserve(sizeof(value)) = value & 0xFF; + } + + void write16(int32_t value) { + *(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF; + } + + void write32(int32_t value) { + *(int32_t*)this->reserve(sizeof(value)) = value; + } + + void writeScalar(SkScalar value) { + *(SkScalar*)this->reserve(sizeof(value)) = value; + } + + void writePoint(const SkPoint& pt) { + *(SkPoint*)this->reserve(sizeof(pt)) = pt; + } + + void writeRect(const SkRect& rect) { + *(SkRect*)this->reserve(sizeof(rect)) = rect; + } + + // write count bytes (must be a multiple of 4) + void writeMul4(const void* values, size_t size) { + SkASSERT(SkAlign4(size) == size); + // if we could query how much is avail in the current block, we might + // copy that much, and then alloc the rest. That would reduce the waste + // in the current block + memcpy(this->reserve(size), values, size); + } + + void writePad(const void* src, size_t size); + + // return the current offset (will always be a multiple of 4) + uint32_t size() const { return fSize; } + void reset(); + uint32_t* reserve(size_t size); // size MUST be multiple of 4 + + // return the address of the 4byte int at the specified offset (which must + // be a multiple of 4. This does not allocate any new space, so the returned + // address is only valid for 1 int. + uint32_t* peek32(size_t offset); + + // copy into a single buffer (allocated by caller). Must be at least size() + void flatten(void* dst) const; + + // read from the stream, and write up to length bytes. Return the actual + // number of bytes written. + size_t readFromStream(SkStream*, size_t length); + + bool writeToStream(SkWStream*); + +private: + size_t fMinSize; + uint32_t fSize; + + struct Block; + Block* fHead; + Block* fTail; + + Block* newBlock(size_t bytes); +}; + +#endif diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h new file mode 100644 index 0000000000..f7e6510f83 --- /dev/null +++ b/include/core/SkXfermode.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SkXfermode_DEFINED +#define SkXfermode_DEFINED + +#include "SkFlattenable.h" +#include "SkColor.h" + +/** \class SkXfermode + + SkXfermode is the base class for objects that are called to implement custom + "transfer-modes" in the drawing pipeline. The static function Create(Modes) + can be called to return an instance of any of the predefined subclasses as + specified in the Modes enum. When an SkXfermode is assigned to an SkPaint, + then objects drawn with that paint have the xfermode applied. +*/ +class SkXfermode : public SkFlattenable { +public: + SkXfermode() {} + + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xfer4444(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + + enum Coeff { + kZero_Coeff, + kOne_Coeff, + kSC_Coeff, + kISC_Coeff, + kDC_Coeff, + kIDC_Coeff, + kSA_Coeff, + kISA_Coeff, + kDA_Coeff, + kIDA_Coeff, + + kCoeffCount + }; + virtual bool asCoeff(Coeff* src, Coeff* dst); + +protected: + SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {} + + /** The default implementation of xfer32/xfer16/xferA8 in turn call this + method, 1 color at a time (upscaled to a SkPMColor). The default + implmentation of this method just returns dst. If performance is + important, your subclass should override xfer32/xfer16/xferA8 directly. + + This method will not be called directly by the client, so it need not + be implemented if your subclass has overridden xfer32/xfer16/xferA8 + */ + virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst); + +private: + typedef SkFlattenable INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** \class SkProcXfermode + + SkProcXfermode is a xfermode that applies the specified proc to its colors. + This class is not exported to java. +*/ +class SkProcXfermode : public SkXfermode { +public: + SkProcXfermode(SkXfermodeProc proc) : fProc(proc) {} + + // overrides from SkXfermode + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xfer4444(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]); + + // overrides from SkFlattenable + virtual Factory getFactory() { return CreateProc; } + virtual void flatten(SkFlattenableWriteBuffer&); + +protected: + SkProcXfermode(SkFlattenableReadBuffer&); + +private: + SkXfermodeProc fProc; + + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkProcXfermode, (buffer)); } + + typedef SkXfermode INHERITED; +}; + +#endif + |