diff options
author | Baligh Uddin <baligh@google.com> | 2013-11-01 16:01:52 -0700 |
---|---|---|
committer | Baligh Uddin <baligh@google.com> | 2013-11-01 16:01:52 -0700 |
commit | 658e3185acf0d232cb2a568a8430297369b59898 (patch) | |
tree | d3aa0c50c4c4b08d550b7b95061b12545c948d2a | |
parent | f0c91a53b03ff18d8c7fbd8a019a28c4331c6f3f (diff) | |
parent | 425017857b2c8efbc272d8a977d5c009ac6f7ec4 (diff) | |
download | include-idea133.tar.gz |
Merge remote-tracking branch 'origin/kitkat-dev'chromium_org-pre-replicationidea133
299 files changed, 43497 insertions, 0 deletions
diff --git a/animator/SkAnimator.h b/animator/SkAnimator.h new file mode 100644 index 0000000..9bb3642 --- /dev/null +++ b/animator/SkAnimator.h @@ -0,0 +1,500 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkAnimator_DEFINED +#define SkAnimator_DEFINED + +#include "SkScalar.h" +#include "SkKey.h" +#include "SkEventSink.h" + +class SkAnimateMaker; +class SkCanvas; +class SkDisplayable; +class SkEvent; +class SkExtras; +struct SkMemberInfo; +class SkPaint; +struct SkRect; +class SkStream; +class SkTypedArray; +class SkXMLParserError; +class SkDOM; +struct SkDOMNode; + +/** SkElementType is the type of element: a rectangle, a color, an animator, and so on. + This enum is incomplete and will be fleshed out in a future release */ +enum SkElementType { + kElementDummyType +}; +/** SkFieldType is the type of field: a scalar, a string, an integer, a boolean, and so on. + This enum is incomplete and will be fleshed out in a future release */ +enum SkFieldType { + kFieldDummyType +}; + +/** \class SkAnimator + + The SkAnimator class decodes an XML stream into a display list. The + display list can be drawn statically as a picture, or can drawn + different elements at different times to form a moving animation. + + SkAnimator does not read the system time on its own; it relies on the + caller to pass the current time. The caller can pause, speed up, or + reverse the animation by varying the time passed in. + + The XML describing the display list must conform to the schema + described by SkAnimateSchema.xsd. + + The XML must contain an <event> element to draw. Usually, it contains + an <event kind="onload" /> block to add some drawing elements to the + display list when the document is first decoded. + + Here's an "Hello World" XML sample: + + <screenplay> + <event kind="onload" > + <text text="Hello World" y="20" /> + </event> + </screenplay> + + To read and draw this sample: + + // choose one of these two + SkAnimator animator; // declare an animator instance on the stack + // SkAnimator* animator = new SkAnimator() // or one could instantiate the class + + // choose one of these three + animator.decodeMemory(buffer, size); // to read from RAM + animator.decodeStream(stream); // to read from a user-defined stream (e.g., a zip file) + animator.decodeURI(filename); // to read from a web location, or from a local text file + + // to draw to the current window: + SkCanvas canvas(getBitmap()); // create a canvas + animator.draw(canvas, &paint, 0); // draw the scene +*/ +class SkAnimator : public SkEventSink { +public: + SkAnimator(); + virtual ~SkAnimator(); + + /** Add a drawable extension to the graphics engine. Experimental. + @param extras A derived class that implements methods that identify and instantiate the class + */ + void addExtras(SkExtras* extras); + + /** Read in XML from a stream, and append it to the current + animator. Returns false if an error was encountered. + Error diagnostics are stored in fErrorCode and fLineNumber. + @param stream The stream to append. + @return true if the XML was parsed successfully. + */ + bool appendStream(SkStream* stream); + + /** Read in XML from memory. Returns true if the file can be + read without error. Returns false if an error was encountered. + Error diagnostics are stored in fErrorCode and fLineNumber. + @param buffer The XML text as UTF-8 characters. + @param size The XML text length in bytes. + @return true if the XML was parsed successfully. + */ + bool decodeMemory(const void* buffer, size_t size); + + /** Read in XML from a stream. Returns true if the file can be + read without error. Returns false if an error was encountered. + Error diagnostics are stored in fErrorCode and fLineNumber. + @param stream The stream containg the XML text as UTF-8 characters. + @return true if the XML was parsed successfully. + */ + virtual bool decodeStream(SkStream* stream); + + /** Parse the DOM tree starting at the specified node. Returns true if it can be + parsed without error. Returns false if an error was encountered. + Error diagnostics are stored in fErrorCode and fLineNumber. + @return true if the DOM was parsed successfully. + */ + virtual bool decodeDOM(const SkDOM&, const SkDOMNode*); + + /** Read in XML from a URI. Returns true if the file can be + read without error. Returns false if an error was encountered. + Error diagnostics are stored in fErrorCode and fLineNumber. + @param uri The complete url path to be read (either ftp, http or https). + @return true if the XML was parsed successfully. + */ + bool decodeURI(const char uri[]); + + /** Pass a char event, usually a keyboard symbol, to the animator. + This triggers events of the form <event kind="keyChar" key="... /> + @param ch The character to match against <event> element "key" + attributes. + @return true if the event was dispatched successfully. + */ + bool doCharEvent(SkUnichar ch); + + /** Experimental: + Pass a mouse click event along with the mouse coordinates to + the animator. This triggers events of the form <event kind="mouseDown" ... /> + and other mouse events. + @param state The mouse state, described by SkView::Click::State : values are + down == 0, moved == 1, up == 2 + @param x The x-position of the mouse + @param y The y-position of the mouse + @return true if the event was dispatched successfully. + */ + bool doClickEvent(int state, SkScalar x, SkScalar y); + + /** Pass a meta-key event, such as an arrow , to the animator. + This triggers events of the form <event kind="keyPress" code="... /> + @param code The key to match against <event> element "code" + attributes. + @return true if the event was dispatched successfully. + */ + bool doKeyEvent(SkKey code); + bool doKeyUpEvent(SkKey code); + + /** Send an event to the animator. The animator's clock is set + relative to the current time. + @return true if the event was dispatched successfully. + */ + bool doUserEvent(const SkEvent& evt); + + /** The possible results from the draw function. + */ + enum DifferenceType { + kNotDifferent, + kDifferent, + kPartiallyDifferent + }; + /** Draws one frame of the animation. The first call to draw always + draws the initial frame of the animation. Subsequent calls draw + the offset into the animation by + subtracting the initial time from the current time. + @param canvas The canvas to draw into. + @param paint The paint to draw with. + @param time The offset into the current animation. + @return kNotDifferent if there are no active animations; kDifferent if there are active animations; and + kPartiallyDifferent if the document contains an active <bounds> element that specifies a minimal + redraw area. + */ + DifferenceType draw(SkCanvas* canvas, SkPaint* paint, SkMSec time); + + /** Draws one frame of the animation, using a new Paint each time. + The first call to draw always + draws the initial frame of the animation. Subsequent calls draw + the offset into the animation by + subtracting the initial time from the current time. + @param canvas The canvas to draw into. + @param time The offset into the current animation. + @return kNotDifferent if there are no active animations; kDifferent if there are active animations; and + kPartiallyDifferent if the document contains an active <bounds> element that specifies a minimal + redraw area. + */ + DifferenceType draw(SkCanvas* canvas, SkMSec time); + + /** Experimental: + Helper to choose whether to return a SkView::Click handler. + @param x ignored + @param y ignored + @return true if a mouseDown event handler is enabled. + */ + bool findClickEvent(SkScalar x, SkScalar y); + + + /** Get the nested animator associated with this element, if any. + Use this to access a movie's event sink, to send events to movies. + @param element the value returned by getElement + @return the internal animator. + */ + const SkAnimator* getAnimator(const SkDisplayable* element) const; + + /** Returns the scalar value of the specified element's attribute[index] + @param element the value returned by getElement + @param field the value returned by getField + @param index the array entry + @return the integer value to retrieve, or SK_NaN32 if unsuccessful + */ + int32_t getArrayInt(const SkDisplayable* element, const SkMemberInfo* field, int index); + + /** Returns the scalar value of the specified element's attribute[index] + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param index the array entry + @return the integer value to retrieve, or SK_NaN32 if unsuccessful + */ + int32_t getArrayInt(const char* elementID, const char* fieldName, int index); + + /** Returns the scalar value of the specified element's attribute[index] + @param element the value returned by getElement + @param field the value returned by getField + @param index the array entry + @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful + */ + SkScalar getArrayScalar(const SkDisplayable* element, const SkMemberInfo* field, int index); + + /** Returns the scalar value of the specified element's attribute[index] + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param index the array entry + @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful + */ + SkScalar getArrayScalar(const char* elementID, const char* fieldName, int index); + + /** Returns the string value of the specified element's attribute[index] + @param element is a value returned by getElement + @param field is a value returned by getField + @param index the array entry + @return the string value to retrieve, or null if unsuccessful + */ + const char* getArrayString(const SkDisplayable* element, const SkMemberInfo* field, int index); + + /** Returns the string value of the specified element's attribute[index] + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param index the array entry + @return the string value to retrieve, or null if unsuccessful + */ + const char* getArrayString(const char* elementID, const char* fieldName, int index); + + /** Returns the XML element corresponding to the given ID. + @param elementID is the value of the id attribute in the XML of this element + @return the element matching the ID, or null if the element can't be found + */ + const SkDisplayable* getElement(const char* elementID); + + /** Returns the element type corresponding to the XML element. + The element type matches the element name; for instance, <line> returns kElement_LineType + @param element is a value returned by getElement + @return element type, or 0 if the element can't be found + */ + SkElementType getElementType(const SkDisplayable* element); + + /** Returns the element type corresponding to the given ID. + @param elementID is the value of the id attribute in the XML of this element + @return element type, or 0 if the element can't be found + */ + SkElementType getElementType(const char* elementID); + + /** Returns the XML field of the named attribute in the XML element. + @param element is a value returned by getElement + @param fieldName is the attribute to return + @return the attribute matching the fieldName, or null if the element can't be found + */ + const SkMemberInfo* getField(const SkDisplayable* element, const char* fieldName); + + /** Returns the XML field of the named attribute in the XML element matching the elementID. + @param elementID is the value of the id attribute in the XML of this element + @param fieldName is the attribute to return + @return the attribute matching the fieldName, or null if the element can't be found + */ + const SkMemberInfo* getField(const char* elementID, const char* fieldName); + + /** Returns the value type coresponding to the element's attribute. + The value type matches the XML schema: and may be kField_BooleanType, kField_ScalarType, etc. + @param field is a value returned by getField + @return the attribute type, or 0 if the element can't be found + */ + SkFieldType getFieldType(const SkMemberInfo* field); + + /** Returns the value type coresponding to the element's attribute. + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @return the attribute type, or 0 if the element can't be found + */ + SkFieldType getFieldType(const char* elementID, const char* fieldName); + + /** Returns the recommended animation interval. Returns zero if no + interval is specified. + */ + SkMSec getInterval(); + + /** Returns the partial rectangle to invalidate after drawing. Call after draw() returns + kIsPartiallyDifferent to do a mimimal inval(). */ + void getInvalBounds(SkRect* inval); + + /** Returns the details of any error encountered while parsing the XML. + */ + const SkXMLParserError* getParserError(); + + /** Returns the details of any error encountered while parsing the XML as string. + */ + const char* getParserErrorString(); + + /** Returns the scalar value of the specified element's attribute + @param element is a value returned by getElement + @param field is a value returned by getField + @return the integer value to retrieve, or SK_NaN32 if not found + */ + int32_t getInt(const SkDisplayable* element, const SkMemberInfo* field); + + /** Returns the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @return the integer value to retrieve, or SK_NaN32 if not found + */ + int32_t getInt(const char* elementID, const char* fieldName); + + /** Returns the scalar value of the specified element's attribute + @param element is a value returned by getElement + @param field is a value returned by getField + @return the scalar value to retrieve, or SK_ScalarNaN if not found + */ + SkScalar getScalar(const SkDisplayable* element, const SkMemberInfo* field); + + /** Returns the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @return the scalar value to retrieve, or SK_ScalarNaN if not found + */ + SkScalar getScalar(const char* elementID, const char* fieldName); + + /** Returns the string value of the specified element's attribute + @param element is a value returned by getElement + @param field is a value returned by getField + @return the string value to retrieve, or null if not found + */ + const char* getString(const SkDisplayable* element, const SkMemberInfo* field); + + /** Returns the string value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @return the string value to retrieve, or null if not found + */ + const char* getString(const char* elementID, const char* fieldName); + + /** Gets the file default directory of the URL base path set explicitly or by reading the last URL. */ + const char* getURIBase(); + + /** Resets the animator to a newly created state with no animation data. */ + void initialize(); + + /** Experimental. Resets any active animations so that the next time passed is treated as + time zero. */ + void reset(); + + /** Sets the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param array is the c-style array of integers + @param count is the length of the array + @return true if the value was set successfully + */ + bool setArrayInt(const char* elementID, const char* fieldName, const int* array, int count); + + /** Sets the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param array is the c-style array of strings + @param count is the length of the array + @return true if the value was set successfully + */ + bool setArrayString(const char* elementID, const char* fieldName, const char** array, int count); + + /** Sets the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param data the integer value to set + @return true if the value was set successfully + */ + bool setInt(const char* elementID, const char* fieldName, int32_t data); + + /** Sets the scalar value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param data the scalar value to set + @return true if the value was set successfully + */ + bool setScalar(const char* elementID, const char* fieldName, SkScalar data); + + /** Sets the string value of the specified element's attribute + @param elementID is the value of the id attribute in the XML of this element + @param fieldName specifies the name of the attribute + @param data the string value to set + @return true if the value was set successfully + */ + bool setString(const char* elementID, const char* fieldName, const char* data); + + /** Sets the file default directory of the URL base path + @param path the directory path + */ + void setURIBase(const char* path); + + typedef void* Handler; + // This guy needs to be exported to java, so don't make it virtual + void setHostHandler(Handler handler) { + this->onSetHostHandler(handler); + } + + /** \class Timeline + Returns current time to animator. To return a custom timeline, create a child + class and override the getMSecs method. + */ + class Timeline { + public: + virtual ~Timeline() {} + + /** Returns the current time in milliseconds */ + virtual SkMSec getMSecs() const = 0; + }; + + /** Sets a user class to return the current time to the animator. + Optional; if not called, the system clock will be used by calling SkTime::GetMSecs instead. + @param callBack the time function + */ + void setTimeline(const Timeline& ); + + static void Init(bool runUnitTests); + static void Term(); + + /** The event sink events generated by the animation are posted to. + Screenplay also posts an inval event to this event sink after processing an + event to force a redraw. + @param target the event sink id + */ + void setHostEventSinkID(SkEventSinkID hostID); + SkEventSinkID getHostEventSinkID() const; + + // helper + void setHostEventSink(SkEventSink* sink) { + this->setHostEventSinkID(sink ? sink->getSinkID() : 0); + } + + virtual void setJavaOwner(Handler owner); + +#ifdef SK_DEBUG + virtual void eventDone(const SkEvent& evt); + virtual bool isTrackingEvents(); + static bool NoLeaks(); +#endif + +protected: + virtual void onSetHostHandler(Handler handler); + virtual void onEventPost(SkEvent*, SkEventSinkID); + virtual void onEventPostTime(SkEvent*, SkEventSinkID, SkMSec time); + +private: +// helper functions for setters + bool setArray(SkDisplayable* element, const SkMemberInfo* field, SkTypedArray array); + bool setArray(const char* elementID, const char* fieldName, SkTypedArray array); + bool setInt(SkDisplayable* element, const SkMemberInfo* field, int32_t data); + bool setScalar(SkDisplayable* element, const SkMemberInfo* field, SkScalar data); + bool setString(SkDisplayable* element, const SkMemberInfo* field, const char* data); + + virtual bool onEvent(const SkEvent&); + SkAnimateMaker* fMaker; + friend class SkAnimateMaker; + friend class SkAnimatorScript; + friend class SkAnimatorScript2; + friend class SkApply; + friend class SkDisplayMovie; + friend class SkDisplayType; + friend class SkPost; + friend class SkXMLAnimatorWriter; +}; + +#endif diff --git a/animator/SkAnimatorView.h b/animator/SkAnimatorView.h new file mode 100644 index 0000000..2b2c61b --- /dev/null +++ b/animator/SkAnimatorView.h @@ -0,0 +1,39 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkAnimatorView_DEFINED +#define SkAnimatorView_DEFINED + +#include "SkView.h" +#include "SkAnimator.h" + +class SkAnimatorView : public SkView { +public: + SkAnimatorView(); + virtual ~SkAnimatorView(); + + SkAnimator* getAnimator() const { return fAnimator; } + + bool decodeFile(const char path[]); + bool decodeMemory(const void* buffer, size_t size); + bool decodeStream(SkStream* stream); + +protected: + // overrides + virtual bool onEvent(const SkEvent&); + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + +private: + SkAnimator* fAnimator; + + typedef SkView INHERITED; +}; + +#endif diff --git a/config/SkUserConfig.h b/config/SkUserConfig.h new file mode 100644 index 0000000..236a99a --- /dev/null +++ b/config/SkUserConfig.h @@ -0,0 +1,205 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkUserConfig_DEFINED +#define SkUserConfig_DEFINED + +/* SkTypes.h, the root of the public header files, does the following trick: + + #include "SkPreConfig.h" + #include "SkUserConfig.h" + #include "SkPostConfig.h" + + SkPreConfig.h runs first, and it is responsible for initializing certain + skia defines. + + SkPostConfig.h runs last, and its job is to just check that the final + defines are consistent (i.e. that we don't have mutually conflicting + defines). + + SkUserConfig.h (this file) runs in the middle. It gets to change or augment + the list of flags initially set in preconfig, and then postconfig checks + that everything still makes sense. + + Below are optional defines that add, subtract, or change default behavior + in Skia. Your port can locally edit this file to enable/disable flags as + you choose, or these can be delared on your command line (i.e. -Dfoo). + + By default, this include file will always default to having all of the flags + commented out, so including it will have no effect. +*/ + +/////////////////////////////////////////////////////////////////////////////// + +/* Scalars (the fractional value type in skia) can be implemented either as + floats or 16.16 integers (fixed). Exactly one of these two symbols must be + defined. +*/ +//#define SK_SCALAR_IS_FLOAT +//#define SK_SCALAR_IS_FIXED + + +/* For some performance-critical scalar operations, skia will optionally work + around the standard float operators if it knows that the CPU does not have + native support for floats. If your environment uses software floating point, + define this flag. + */ +//#define SK_SOFTWARE_FLOAT + + +/* Skia has lots of debug-only code. Often this is just null checks or other + parameter checking, but sometimes it can be quite intrusive (e.g. check that + each 32bit pixel is in premultiplied form). This code can be very useful + during development, but will slow things down in a shipping product. + + By default, these mutually exclusive flags are defined in SkPreConfig.h, + based on the presence or absence of NDEBUG, but that decision can be changed + here. + */ +//#define SK_DEBUG +//#define SK_RELEASE + +/* Skia has certain debug-only code that is extremely intensive even for debug + builds. This code is useful for diagnosing specific issues, but is not + generally applicable, therefore it must be explicitly enabled to avoid + the performance impact. By default these flags are undefined, but can be + enabled by uncommenting them below. + */ +//#define SK_DEBUG_GLYPH_CACHE +//#define SK_DEBUG_PATH + +/* To assist debugging, Skia provides an instance counting utility in + include/core/SkInstCount.h. This flag turns on and off that utility to + allow instance count tracking in either debug or release builds. By + default it is enabled in debug but disabled in release. + */ +//#define SK_ENABLE_INST_COUNT 1 + +/* If, in debugging mode, Skia needs to stop (presumably to invoke a debugger) + it will call SK_CRASH(). If this is not defined it, it is defined in + SkPostConfig.h to write to an illegal address + */ +//#define SK_CRASH() *(int *)(uintptr_t)0 = 0 + + +/* preconfig will have attempted to determine the endianness of the system, + but you can change these mutually exclusive flags here. + */ +//#define SK_CPU_BENDIAN +//#define SK_CPU_LENDIAN + +/* Most compilers use the same bit endianness for bit flags in a byte as the + system byte endianness, and this is the default. If for some reason this + needs to be overridden, specify which of the mutually exclusive flags to + use. For example, some atom processors in certain configurations have big + endian byte order but little endian bit orders. +*/ +//#define SK_UINT8_BITFIELD_BENDIAN +//#define SK_UINT8_BITFIELD_LENDIAN + + +/* Some compilers don't support long long for 64bit integers. If yours does + not, define this to the appropriate type. + */ +//#define SkLONGLONG int64_t + + +/* To write debug messages to a console, skia will call SkDebugf(...) following + printf conventions (e.g. const char* format, ...). If you want to redirect + this to something other than printf, define yours here + */ +//#define SkDebugf(...) MyFunction(__VA_ARGS__) + +/* + * To specify a different default font cache limit, define this. If this is + * undefined, skia will use a built-in value. + */ +//#define SK_DEFAULT_FONT_CACHE_LIMIT (1024 * 1024) + +/* + * To specify the default size of the image cache, undefine this and set it to + * the desired value (in bytes). SkGraphics.h as a runtime API to set this + * value as well. If this is undefined, a built-in value will be used. + */ +//#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024) + +/* If zlib is available and you want to support the flate compression + algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the + include path. Alternatively, define SK_SYSTEM_ZLIB to use the system zlib + library specified as "#include <zlib.h>". + */ +//#define SK_ZLIB_INCLUDE <zlib.h> +//#define SK_SYSTEM_ZLIB + +/* Define this to allow PDF scalars above 32k. The PDF/A spec doesn't allow + them, but modern PDF interpreters should handle them just fine. + */ +//#define SK_ALLOW_LARGE_PDF_SCALARS + +/* Define this to provide font subsetter in PDF generation. + */ +//#define SK_SFNTLY_SUBSETTER "sfntly/subsetter/font_subsetter.h" + +/* Define this to set the upper limit for text to support LCD. Values that + are very large increase the cost in the font cache and draw slower, without + improving readability. If this is undefined, Skia will use its default + value (e.g. 48) + */ +//#define SK_MAX_SIZE_FOR_LCDTEXT 48 + +/* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST + which will run additional self-tests at startup. These can take a long time, + so this flag is optional. + */ +#ifdef SK_DEBUG +//#define SK_SUPPORT_UNITTEST +#endif + +/* If your system embeds skia and has complex event logging, define this + symbol to name a file that maps the following macros to your system's + equivalents: + SK_TRACE_EVENT0(event) + SK_TRACE_EVENT1(event, name1, value1) + SK_TRACE_EVENT2(event, name1, value1, name2, value2) + src/utils/SkDebugTrace.h has a trivial implementation that writes to + the debug output stream. If SK_USER_TRACE_INCLUDE_FILE is not defined, + SkTrace.h will define the above three macros to do nothing. +*/ +//#undef SK_USER_TRACE_INCLUDE_FILE + +/* Change the ordering to work in X windows. + */ +#ifdef SK_SAMPLES_FOR_X + #define SK_R32_SHIFT 16 + #define SK_G32_SHIFT 8 + #define SK_B32_SHIFT 0 + #define SK_A32_SHIFT 24 +#endif + + +/* Determines whether to build code that supports the GPU backend. Some classes + that are not GPU-specific, such as SkShader subclasses, have optional code + that is used allows them to interact with the GPU backend. If you'd like to + omit this code set SK_SUPPORT_GPU to 0. This also allows you to omit the gpu + directories from your include search path when you're not building the GPU + backend. Defaults to 1 (build the GPU code). + */ +//#define SK_SUPPORT_GPU 1 + + +/* The PDF generation code uses Path Ops to generate inverse fills and complex + * clipping paths, but at this time, Path Ops is not release ready yet. So, + * the code is hidden behind this #define guard. If you are feeling adventurous + * and want the latest and greatest PDF generation code, uncomment the #define. + * When Path Ops is release ready, the define guards and this user config + * define should be removed entirely. + */ +//#define SK_PDF_USE_PATHOPS + +#endif diff --git a/config/sk_stdint.h b/config/sk_stdint.h new file mode 100644 index 0000000..360755e --- /dev/null +++ b/config/sk_stdint.h @@ -0,0 +1,23 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef sk_stdint_DEFINED +#define sk_stdint_DEFINED + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +#endif diff --git a/core/Sk64.h b/core/Sk64.h new file mode 100644 index 0000000..6db3001 --- /dev/null +++ b/core/Sk64.h @@ -0,0 +1,230 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef Sk64_DEFINED +#define Sk64_DEFINED + +#include "SkFixed.h" + +/** \class Sk64 + + Sk64 is a 64-bit math package that does not require long long support from the compiler. +*/ +struct SK_API 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 getSign() 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 +}; + +#endif diff --git a/core/SkAdvancedTypefaceMetrics.h b/core/SkAdvancedTypefaceMetrics.h new file mode 100755 index 0000000..acfd86e --- /dev/null +++ b/core/SkAdvancedTypefaceMetrics.h @@ -0,0 +1,157 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkAdvancedTypefaceMetrics_DEFINED +#define SkAdvancedTypefaceMetrics_DEFINED + +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkTDArray.h" +#include "SkTemplates.h" +#include "SkTScopedPtr.h" + +/** \class SkAdvancedTypefaceMetrics + + The SkAdvancedTypefaceMetrics class is used by the PDF backend to correctly + embed typefaces. This class is filled in with information about a given + typeface by the SkFontHost class. +*/ + +class SkAdvancedTypefaceMetrics : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkAdvancedTypefaceMetrics) + + SkString fFontName; + + enum FontType { + kType1_Font, + kType1CID_Font, + kCFF_Font, + kTrueType_Font, + kOther_Font, + kNotEmbeddable_Font + }; + // The type of the underlying font program. This field determines which + // of the following fields are valid. If it is kOther_Font or + // kNotEmbeddable_Font, the per glyph information will never be populated. + FontType fType; + + // fMultiMaster may be true for Type1_Font or CFF_Font. + bool fMultiMaster; + uint16_t fLastGlyphID; // The last valid glyph ID in the font. + uint16_t fEmSize; // The size of the em box (defines font units). + + // These enum values match the values used in the PDF file format. + enum StyleFlags { + kFixedPitch_Style = 0x00001, + kSerif_Style = 0x00002, + kScript_Style = 0x00008, + kItalic_Style = 0x00040, + kAllCaps_Style = 0x10000, + kSmallCaps_Style = 0x20000, + kForceBold_Style = 0x40000 + }; + uint16_t fStyle; // Font style characteristics. + int16_t fItalicAngle; // Counterclockwise degrees from vertical of the + // dominant vertical stroke for an Italic face. + // The following fields are all in font units. + int16_t fAscent; // Max height above baseline, not including accents. + int16_t fDescent; // Max depth below baseline (negative). + int16_t fStemV; // Thickness of dominant vertical stem. + int16_t fCapHeight; // Height (from baseline) of top of flat capitals. + + SkIRect fBBox; // The bounding box of all glyphs (in font units). + + // The type of advance data wanted. + enum PerGlyphInfo { + kNo_PerGlyphInfo = 0x0, // Don't populate any per glyph info. + kHAdvance_PerGlyphInfo = 0x1, // Populate horizontal advance data. + kVAdvance_PerGlyphInfo = 0x2, // Populate vertical advance data. + kGlyphNames_PerGlyphInfo = 0x4, // Populate glyph names (Type 1 only). + kToUnicode_PerGlyphInfo = 0x8 // Populate ToUnicode table, ignored + // for Type 1 fonts + }; + + template <typename Data> + struct AdvanceMetric { + enum MetricType { + kDefault, // Default advance: fAdvance.count = 1 + kRange, // Advances for a range: fAdvance.count = fEndID-fStartID + kRun // fStartID-fEndID have same advance: fAdvance.count = 1 + }; + MetricType fType; + uint16_t fStartId; + uint16_t fEndId; + SkTDArray<Data> fAdvance; + SkTScopedPtr<AdvanceMetric<Data> > fNext; + }; + + struct VerticalMetric { + int16_t fVerticalAdvance; + int16_t fOriginXDisp; // Horiz. displacement of the secondary origin. + int16_t fOriginYDisp; // Vert. displacement of the secondary origin. + }; + typedef AdvanceMetric<int16_t> WidthRange; + typedef AdvanceMetric<VerticalMetric> VerticalAdvanceRange; + + // This is indexed by glyph id. + SkTScopedPtr<WidthRange> fGlyphWidths; + // Only used for Vertical CID fonts. + SkTScopedPtr<VerticalAdvanceRange> fVerticalMetrics; + + // The names of each glyph, only populated for postscript fonts. + SkTScopedPtr<SkAutoTArray<SkString> > fGlyphNames; + + // The mapping from glyph to Unicode, only populated if + // kToUnicode_PerGlyphInfo is passed to GetAdvancedTypefaceMetrics. + SkTDArray<SkUnichar> fGlyphToUnicode; + +private: + typedef SkRefCnt INHERITED; +}; + +namespace skia_advanced_typeface_metrics_utils { + +template <typename Data> +void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range, + int startId); + +template <typename Data> +SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange( + SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> >* nextSlot, + int startId); + +template <typename Data> +void finishRange( + SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range, + int endId, + typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType + type); + +/** Retrieve advance data for glyphs. Used by the PDF backend. It calls + underlying platform dependent API getAdvance to acquire the data. + @param num_glyphs Total number of glyphs in the given font. + @param glyphIDs For per-glyph info, specify subset of the font by + giving glyph ids. Each integer represents a glyph + id. Passing NULL means all glyphs in the font. + @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if + glyphIDs is NULL. +*/ +template <typename Data, typename FontHandle> +SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( + FontHandle fontHandle, + int num_glyphs, + const uint32_t* glyphIDs, + uint32_t glyphIDsCount, + bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)); + +} // namespace skia_advanced_typeface_metrics_utils + +#endif diff --git a/core/SkAnnotation.h b/core/SkAnnotation.h new file mode 100644 index 0000000..18ee1cd --- /dev/null +++ b/core/SkAnnotation.h @@ -0,0 +1,128 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnnotation_DEFINED +#define SkAnnotation_DEFINED + +#include "SkFlattenable.h" + +class SkData; +class SkDataSet; +class SkStream; +class SkWStream; +struct SkPoint; + +/** + * Experimental class for annotating draws. Do not use directly yet. + * Use helper functions at the bottom of this file for now. + */ +class SkAnnotation : public SkFlattenable { +public: + enum Flags { + // If set, the associated drawing primitive should not be drawn + kNoDraw_Flag = 1 << 0, + }; + + SkAnnotation(SkDataSet*, uint32_t flags); + virtual ~SkAnnotation(); + + uint32_t getFlags() const { return fFlags; } + SkDataSet* getDataSet() const { return fDataSet; } + + bool isNoDraw() const { return SkToBool(fFlags & kNoDraw_Flag); } + + /** + * Helper for search the annotation's dataset. + */ + SkData* find(const char name[]) const; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAnnotation) + +protected: + SkAnnotation(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkDataSet* fDataSet; + uint32_t fFlags; + + void writeToStream(SkWStream*) const; + void readFromStream(SkStream*); + + typedef SkFlattenable INHERITED; +}; + +/** + * Experimental collection of predefined Keys into the Annotation dictionary + */ +class SkAnnotationKeys { +public: + /** + * Returns the canonical key whose payload is a URL + */ + static const char* URL_Key(); + + /** + * Returns the canonical key whose payload is the name of a destination to + * be defined. + */ + static const char* Define_Named_Dest_Key(); + + /** + * Returns the canonical key whose payload is the name of a destination to + * be linked to. + */ + static const char* Link_Named_Dest_Key(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Experimental helper functions to use Annotations +// + +struct SkRect; +class SkCanvas; + +/** + * Experimental! + * + * Annotate the canvas by associating the specified URL with the + * specified rectangle (in local coordinates, just like drawRect). If the + * backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*); + +/** + * Experimental! + * + * Annotate the canvas by associating a name with the specified point. + * + * If the backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*); + +/** + * Experimental! + * + * Annotate the canvas by making the specified rectangle link to a named + * destination. + * + * If the backend of this canvas does not support annotations, this call is + * safely ignored. + * + * The caller is responsible for managing its ownership of the SkData. + */ +SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*); + + +#endif diff --git a/core/SkBitmap.h b/core/SkBitmap.h new file mode 100644 index 0000000..887169c --- /dev/null +++ b/core/SkBitmap.h @@ -0,0 +1,820 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBitmap_DEFINED +#define SkBitmap_DEFINED + +#include "Sk64.h" +#include "SkColor.h" +#include "SkColorTable.h" +#include "SkPoint.h" +#include "SkRefCnt.h" + +struct SkIRect; +struct SkRect; +class SkPaint; +class SkPixelRef; +class SkRegion; +class SkString; + +class GrTexture; + +/** \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. + A const SkBitmap exposes getAddr(), which lets a caller write its pixels; + the constness is considered to apply to the bitmap's configuration, not + its contents. +*/ +class SK_API SkBitmap { +public: + class Allocator; + + enum Config { + kNo_Config, //!< bitmap has not been configured + /** + * 1-bit per pixel, (0 is transparent, 1 is opaque) + * Valid as a destination (target of a canvas), but not valid as a src. + * i.e. you can draw into a 1-bit bitmap, but you cannot draw from one. + */ + kA1_Config, + 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) + }; + + // do not add this to the Config enum, otherwise the compiler will let us + // pass this as a valid parameter for Config. + enum { + kConfigCount = kARGB_8888_Config + 1 + }; + + /** + * Default construct creates a bitmap with zero width and height, and no pixels. + * Its config is set to kNo_Config. + */ + SkBitmap(); + + /** + * Copy the settings from the src into this bitmap. If the src has pixels + * allocated, they will be shared, not copied, so that the two bitmaps will + * reference the same memory for the pixels. If a deep copy is needed, + * where the new bitmap has its own separate copy of the pixels, use + * deepCopyTo(). + */ + SkBitmap(const SkBitmap& src); + + ~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 pixelref. Note: this can return true even if the + dimensions of the bitmap are > 0 (see empty()). + */ + bool isNull() const { return 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. + */ + size_t 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 number of bytes from the pointer returned by getPixels() + to the end of the allocated space in the buffer. Required in + cases where extractSubset has been called. + */ + size_t getSafeSize() const ; + + /** 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; + } + + /** Same as getSafeSize(), but does not truncate the answer to 32bits. + */ + Sk64 getSafeSize64() const ; + + /** Returns true if this bitmap is marked as immutable, meaning that the + contents of its pixels will not change for the lifetime of the bitmap. + */ + bool isImmutable() const; + + /** Marks this bitmap as immutable, meaning that the contents of its + pixels will not change for the lifetime of the bitmap and of the + underlying pixelref. This state can be set, but it cannot be + cleared once it is set. This state propagates to all other bitmaps + that share the same pixelref. + */ + void setImmutable(); + + /** 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); + + /** Returns true if the bitmap is volatile (i.e. should not be cached by devices.) + */ + bool isVolatile() const; + + /** Specify whether this bitmap is volatile. Bitmaps are not volatile by + default. Temporary bitmaps that are discarded after use should be + marked as volatile. This provides a hint to the device that the bitmap + should not be cached. Providing this hint when appropriate can + improve performance by avoiding unnecessary overhead and resource + consumption on the device. + */ + void setIsVolatile(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 size_t 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); + + /** + * This will brute-force return true if all of the pixels in the bitmap + * are opaque. If it fails to read the pixels, or encounters an error, + * it will return false. + * + * Since this can be an expensive operation, the bitmap stores a flag for + * this (isOpaque, setIsOpaque). Only call this if you need to compute this + * value from "unknown" pixels. + */ + static bool ComputeIsOpaque(const SkBitmap&); + + /** + * Calls ComputeIsOpaque, and passes its result to setIsOpaque(). + */ + void computeAndSetOpaquePredicate() { + this->setIsOpaque(ComputeIsOpaque(*this)); + } + + /** + * Return the bitmap's bounds [0, 0, width, height] as an SkRect + */ + void getBounds(SkRect* bounds) const; + void getBounds(SkIRect* bounds) const; + + /** 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, size_t 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); + + /** Copies the bitmap's pixels to the location pointed at by dst and returns + true if possible, returns false otherwise. + + In the case when the dstRowBytes matches the bitmap's rowBytes, the copy + may be made faster by copying over the dst's per-row padding (for all + rows but the last). By setting preserveDstPad to true the caller can + disable this optimization and ensure that pixels in the padding are not + overwritten. + + Always returns false for RLE formats. + + @param dst Location of destination buffer. + @param dstSize Size of destination buffer. Must be large enough to hold + pixels using indicated stride. + @param dstRowBytes Width of each line in the buffer. If 0, uses + bitmap's internal stride. + @param preserveDstPad Must we preserve padding in the dst + */ + bool copyPixelsTo(void* const dst, size_t dstSize, size_t dstRowBytes = 0, + bool preserveDstPad = false) const; + + /** 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, if 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; + + /** + * Some bitmaps can return a copy of their pixels for lockPixels(), but + * that copy, if modified, will not be pushed back. These bitmaps should + * not be used as targets for a raster device/canvas (since all pixels + * modifications will be lost when unlockPixels() is called.) + */ + bool lockPixelsAreWritable() 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 || NULL != fColorTable); + } + + /** Returns the pixelRef's texture, or NULL + */ + GrTexture* getTexture() const; + + /** Return the bitmap's colortable, if it uses one (i.e. fConfig is + kIndex8_Config) and the pixels are locked. + Otherwise returns NULL. 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. Each time the pixels are changed (and notifyPixelsChanged + is called), a different generation ID will be returned. Finally, if + their is no pixelRef then zero is 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; + + /** + * Fill the entire bitmap with the specified color. + * If the bitmap's config does not support alpha (e.g. 565) then the alpha + * of the color is ignored (treated as opaque). If the config only supports + * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. + */ + void eraseColor(SkColor c) const { + this->eraseARGB(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), + SkColorGetB(c)); + } + + /** + * Fill the entire bitmap with the specified color. + * If the bitmap's config does not support alpha (e.g. 565) then the alpha + * of the color is ignored (treated as opaque). If the config only supports + * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. + */ + void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const; + + // DEPRECATED -- call eraseColor or eraseARGB + void eraseRGB(U8CPU r, U8CPU g, U8CPU b) const { + this->eraseARGB(0xFF, r, g, b); + } + + /** + * Fill the specified area of this bitmap with the specified color. + * If the bitmap's config does not support alpha (e.g. 565) then the alpha + * of the color is ignored (treated as opaque). If the config only supports + * alpha (e.g. A1 or A8) then the color's r,g,b components are ignored. + */ + void eraseArea(const SkIRect& area, SkColor c) const; + + /** 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). If the bitmap is immutable, + do nothing and return false. + + @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; + + /** + * Return the SkColor of the specified pixel. In most cases this will + * require un-premultiplying the color. Alpha only configs (A1 and A8) + * return black with the appropriate alpha set. The value is undefined + * for kNone_Config or if x or y are out of bounds, or if the bitmap + * does not have any pixels (or has not be locked with lockPixels()). + */ + SkColor getColor(int x, int y) 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. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 32-bit, however none of these checks are performed + * in the release build. + */ + inline uint32_t* getAddr32(int x, int y) const; + + /** Returns the address of the pixel specified by x,y for 16bit pixels. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 16-bit, however none of these checks are performed + * in the release build. + */ + inline uint16_t* getAddr16(int x, int y) const; + + /** Returns the address of the pixel specified by x,y for 8bit pixels. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 8-bit, however none of these checks are performed + * in the release build. + */ + 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. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 1-bit, however none of these checks are performed + * in the release build. + */ + inline uint8_t* getAddr1(int x, int y) const; + + /** Returns the color corresponding to the pixel specified by x,y for + * colortable based bitmaps. + * In debug build, this asserts that the pixels are allocated and locked, + * that the config is kIndex8, and that the colortable is allocated, + * however none of these checks are performed in the release build. + */ + inline SkPMColor getIndex8Color(int x, int y) const; + + /** Set dst to be a setset of this bitmap. If possible, it will share the + pixel memory, and just point into a subset of it. However, if the 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; + + /** Makes a deep copy of this bitmap, respecting the requested config, + * and allocating the dst pixels on the cpu. + * Returns false if either there is an error (i.e. the src does not have + * pixels) or the request cannot be satisfied (e.g. the src has per-pixel + * alpha, and the requested config does not support alpha). + * @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; + + /** Makes a deep copy of this bitmap, respecting the requested config, and + * with custom allocation logic that will keep the copied pixels + * in the same domain as the source: If the src pixels are allocated for + * the cpu, then so will the dst. If the src pixels are allocated on the + * gpu (typically as a texture), the it will do the same for the dst. + * If the request cannot be fulfilled, returns false and dst is unmodified. + */ + bool deepCopyTo(SkBitmap* dst, Config c) const; + + /** Returns true if this bitmap can be deep copied into the requested config + by calling copyTo(). + */ + bool canCopyTo(Config newConfig) const; + + /** + * DEPRECATED -- will be replaced with API on SkPaint + */ + void buildMipMap(bool forceRebuild = false); + +#ifdef SK_BUILD_FOR_ANDROID + bool hasHardwareMipMap() const { + return (fFlags & kHasHardwareMipMap_Flag) != 0; + } + + void setHasHardwareMipMap(bool hasHardwareMipMap) { + if (hasHardwareMipMap) { + fFlags |= kHasHardwareMipMap_Flag; + } else { + fFlags &= ~kHasHardwareMipMap_Flag; + } + } +#endif + + bool extractAlpha(SkBitmap* dst) const { + return this->extractAlpha(dst, NULL, NULL, NULL); + } + + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, + SkIPoint* offset) const { + return this->extractAlpha(dst, paint, NULL, offset); + } + + /** Set dst to contain alpha layer of this bitmap. If destination bitmap + fails to be initialized, e.g. because allocator can't allocate pixels + for it, dst will not be modified and false will be returned. + + @param dst The bitmap to be filled with alpha layer + @param paint The paint to draw with + @param allocator Allocator used to allocate the pixelref for the dst + bitmap. If this is null, the standard HeapAllocator + will be used. + @param offset If not null, it is set to top-left coordinate to position + the returned bitmap so that it visually lines up with the + original + */ + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, + SkIPoint* offset) const; + + /** The following two functions provide the means to both flatten and + unflatten the bitmap AND its pixels into the provided buffer. + It is recommended that you do not call these functions directly, + but instead call the write/readBitmap functions on the respective + buffers as they can optimize the recording process and avoid recording + duplicate bitmaps and pixelRefs. + */ + void flatten(SkFlattenableWriteBuffer&) const; + void unflatten(SkFlattenableReadBuffer&); + + SkDEBUGCODE(void validate() const;) + + class Allocator : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Allocator) + + /** 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; + private: + typedef SkRefCnt INHERITED; + }; + + /** Subclass of Allocator that returns a pixelref that allocates its pixel + memory from the heap. This is the default Allocator invoked by + 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; + }; + + SkDEVCODE(void toString(SkString* str) const;) + +private: + struct MipMap; + mutable MipMap* fMipMap; + + 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, + kImageIsVolatile_Flag = 0x02, + kImageIsImmutable_Flag = 0x04, +#ifdef SK_BUILD_FOR_ANDROID + /* A hint for the renderer responsible for drawing this bitmap + * indicating that it should attempt to use mipmaps when this bitmap + * is drawn scaled down. + */ + kHasHardwareMipMap_Flag = 0x08, +#endif + }; + + uint32_t fRowBytes; + uint32_t fWidth; + uint32_t fHeight; + uint8_t fConfig; + uint8_t fFlags; + uint8_t fBytesPerPixel; // based on config + + void internalErase(const SkIRect&, U8CPU a, U8CPU r, U8CPU g, U8CPU b)const; + + /* Internal computations for safe size. + */ + static Sk64 ComputeSafeSize64(Config config, + uint32_t width, + uint32_t height, + size_t rowBytes); + static size_t ComputeSafeSize(Config config, + uint32_t width, + uint32_t height, + size_t rowBytes); + + /* Unreference any pixelrefs or colortables + */ + void freePixels(); + void updatePixelsFromRef() const; + + static SkFixed ComputeMipLevel(SkFixed sx, SkFixed dy); + + /** 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); + bool hasMipMap() const; + void freeMipMap(); + + friend struct SkBitmapProcState; +}; + +class SkAutoLockPixels : public SkNoncopyable { +public: + SkAutoLockPixels(const SkBitmap& bm, bool doLock = true) : fBitmap(bm) { + fDidLock = doLock; + if (doLock) { + bm.lockPixels(); + } + } + ~SkAutoLockPixels() { + if (fDidLock) { + fBitmap.unlockPixels(); + } + } + +private: + const SkBitmap& fBitmap; + bool fDidLock; +}; + +/** 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; } + + /** Locks the table and returns is colors (assuming ctable is not null) and + unlocks the previous table if one was present + */ + const SkPMColor* lockColors(SkColorTable* ctable) { + if (fCTable) { + fCTable->unlockColors(false); + } + fCTable = ctable; + fColors = ctable ? ctable->lockColors() : NULL; + return fColors; + } + + const SkPMColor* lockColors(const SkBitmap& bm) { + return this->lockColors(bm.getColorTable()); + } + +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/core/SkBlitRow.h b/core/SkBlitRow.h new file mode 100644 index 0000000..5011342 --- /dev/null +++ b/core/SkBlitRow.h @@ -0,0 +1,104 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlitRow_DEFINED +#define SkBlitRow_DEFINED + +#include "SkBitmap.h" +#include "SkColor.h" + +class SkBlitRow { +public: + enum Flags16 { + //! If set, the alpha parameter will be != 255 + kGlobalAlpha_Flag = 0x01, + //! If set, the src colors may have alpha != 255 + kSrcPixelAlpha_Flag = 0x02, + //! If set, the resulting 16bit colors should be dithered + kDither_Flag = 0x04 + }; + + /** Function pointer that reads a scanline of src SkPMColors, and writes + a corresponding scanline of 16bit colors (specific format based on the + config passed to the Factory. + + The x,y params are useful just for dithering + + @param alpha A global alpha to be applied to all of the src colors + @param x The x coordinate of the beginning of the scanline + @param y THe y coordinate of the scanline + */ + typedef void (*Proc)(uint16_t* dst, + const SkPMColor* src, + int count, U8CPU alpha, int x, int y); + + static Proc Factory(unsigned flags, SkBitmap::Config); + + ///////////// D32 version + + enum Flags32 { + kGlobalAlpha_Flag32 = 1 << 0, + kSrcPixelAlpha_Flag32 = 1 << 1 + }; + + /** Function pointer that blends 32bit colors onto a 32bit destination. + @param dst array of dst 32bit colors + @param src array of src 32bit colors (w/ or w/o alpha) + @param count number of colors to blend + @param alpha global alpha to be applied to all src colors + */ + typedef void (*Proc32)(uint32_t* dst, + const SkPMColor* src, + int count, U8CPU alpha); + + static Proc32 Factory32(unsigned flags32); + + /** Function pointer that blends a single color with a row of 32-bit colors + onto a 32-bit destination + */ + typedef void (*ColorProc)(SkPMColor* dst, const SkPMColor* src, int count, + SkPMColor color); + + /** Blend a single color onto a row of S32 pixels, writing the result + into a row of D32 pixels. src and dst may be the same memory, but + if they are not, they may not overlap. + */ + static void Color32(SkPMColor dst[], const SkPMColor src[], + int count, SkPMColor color); + + //! Public entry-point to return a blit function ptr + static ColorProc ColorProcFactory(); + + /** Function pointer that blends a single color onto a 32-bit rectangle. */ + typedef void (*ColorRectProc)(SkPMColor* dst, int width, int height, + size_t rowBytes, SkPMColor color); + + /** Blend a single color into a rectangle of D32 pixels. */ + static void ColorRect32(SkPMColor* dst, int width, int height, + size_t rowBytes, SkPMColor color); + + //! Public entry-point to return a blit function ptr + static ColorRectProc ColorRectProcFactory(); + + /** These static functions are called by the Factory and Factory32 + functions, and should return either NULL, or a + platform-specific function-ptr to be used in place of the + system default. + */ + + static Proc32 PlatformProcs32(unsigned flags); + static Proc PlatformProcs565(unsigned flags); + static ColorProc PlatformColorProc(); + +private: + enum { + kFlags16_Mask = 7, + kFlags32_Mask = 3 + }; +}; + +#endif diff --git a/core/SkBounder.h b/core/SkBounder.h new file mode 100644 index 0000000..7368d09 --- /dev/null +++ b/core/SkBounder.h @@ -0,0 +1,93 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBounder_DEFINED +#define SkBounder_DEFINED + +#include "SkTypes.h" +#include "SkRefCnt.h" +#include "SkPoint.h" + +struct SkGlyph; +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: + SK_DECLARE_INST_COUNT(SkBounder) + + SkBounder(); + + /* Call to perform a clip test before calling onIRect. + Returns the result from onIRect. + */ + bool doIRect(const SkIRect&); + bool doIRectGlyph(const SkIRect& , int x, int y, const SkGlyph&); + +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&) { + return false; + } + + /** Passed to onIRectGlyph with the information about the current glyph. + LSB and RSB are fixed-point (16.16) coordinates of the start and end + of the glyph's advance + */ + struct GlyphRec { + SkIPoint fLSB; //!< fixed-point left-side-bearing of the glyph + SkIPoint fRSB; //!< fixed-point right-side-bearing of the glyph + uint16_t fGlyphID; + uint16_t fFlags; //!< currently set to 0 + }; + + /** Optionally, override in your subclass to receive the glyph ID when + text drawing supplies the device bounds of the object. + */ + virtual bool onIRectGlyph(const SkIRect& r, const GlyphRec&) { + return onIRect(r); + } + + /** 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; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkCanvas.h b/core/SkCanvas.h new file mode 100644 index 0000000..b4853f7 --- /dev/null +++ b/core/SkCanvas.h @@ -0,0 +1,1179 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkCanvas_DEFINED +#define SkCanvas_DEFINED + +#include "SkTypes.h" +#include "SkBitmap.h" +#include "SkDeque.h" +#include "SkClipStack.h" +#include "SkPaint.h" +#include "SkRefCnt.h" +#include "SkPath.h" +#include "SkRegion.h" +#include "SkScalarCompare.h" +#include "SkXfermode.h" + +class SkBounder; +class SkDevice; +class SkDraw; +class SkDrawFilter; +class SkMetaData; +class SkPicture; +class SkRRect; +class SkSurface_Base; + +/** \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 SK_API SkCanvas : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkCanvas) + + SkCanvas(); + + /** Construct a canvas with the specified device to draw into. + + @param device Specifies a device for the canvas to draw into. + */ + explicit SkCanvas(SkDevice* device); + + /** Deprecated - 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); + virtual ~SkCanvas(); + + SkMetaData& getMetaData(); + + /////////////////////////////////////////////////////////////////////////// + + /** + * Trigger the immediate execution of all pending draw operations. + */ + void flush(); + + /** + * Return the width/height of the underlying device. The current drawable + * area may be small (due to clipping or saveLayer). For a canvas with + * no device, 0,0 will be returned. + */ + SkISize getDeviceSize() const; + + /** 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; + + /** + * saveLayer() can create another device (which is later drawn onto + * the previous device). getTopDevice() returns the top-most device current + * installed. Note that this can change on other calls like save/restore, + * so do not access this device after subsequent canvas calls. + * The reference count of the device is not changed. + * + * @param updateMatrixClip If this is true, then before the device is + * returned, we ensure that its has been notified about the current + * matrix and clip. Note: this happens automatically when the device + * is drawn to, but is optional here, as there is a small perf hit + * sometimes. + */ + SkDevice* getTopDevice(bool updateMatrixClip = false) const; + + /** + * Shortcut for getDevice()->createCompatibleDevice(...). + * If getDevice() == NULL, this method does nothing, and returns NULL. + */ + SkDevice* createCompatibleDevice(SkBitmap::Config config, + int width, int height, + bool isOpaque); + + /////////////////////////////////////////////////////////////////////////// + + /** + * This enum can be used with read/writePixels to perform a pixel ops to or + * from an 8888 config other than Skia's native config (SkPMColor). There + * are three byte orders supported: native, BGRA, and RGBA. Each has a + * premultiplied and unpremultiplied variant. + * + * Components of a 8888 pixel can be packed/unpacked from a 32bit word using + * either byte offsets or shift values. Byte offsets are endian-invariant + * while shifts are not. BGRA and RGBA configs are defined by byte + * orderings. The native config is defined by shift values (SK_A32_SHIFT, + * ..., SK_B32_SHIFT). + */ + enum Config8888 { + /** + * Skia's native order specified by: + * SK_A32_SHIFT, SK_R32_SHIFT, SK_G32_SHIFT, and SK_B32_SHIFT + * + * kNative_Premul_Config8888 is equivalent to SkPMColor + * kNative_Unpremul_Config8888 has the same component order as SkPMColor + * but is not premultiplied. + */ + kNative_Premul_Config8888, + kNative_Unpremul_Config8888, + /** + * low byte to high byte: B, G, R, A. + */ + kBGRA_Premul_Config8888, + kBGRA_Unpremul_Config8888, + /** + * low byte to high byte: R, G, B, A. + */ + kRGBA_Premul_Config8888, + kRGBA_Unpremul_Config8888 + }; + + /** + * On success (returns true), copy the canvas pixels into the bitmap. + * On failure, the bitmap parameter is left unchanged and false is + * returned. + * + * The canvas' pixels are converted to the bitmap's config. The only + * supported config is kARGB_8888_Config, though this is likely to be + * relaxed in the future. The meaning of config kARGB_8888_Config is + * modified by the enum param config8888. The default value interprets + * kARGB_8888_Config as SkPMColor + * + * If the bitmap has pixels already allocated, the canvas pixels will be + * written there. If not, bitmap->allocPixels() will be called + * automatically. If the bitmap is backed by a texture readPixels will + * fail. + * + * The actual pixels written is the intersection of the canvas' bounds, and + * the rectangle formed by the bitmap's width,height and the specified x,y. + * If bitmap pixels extend outside of that intersection, they will not be + * modified. + * + * Other failure conditions: + * * If the canvas is backed by a non-raster device (e.g. PDF) then + * readPixels will fail. + * * If bitmap is texture-backed then readPixels will fail. (This may be + * relaxed in the future.) + * + * Example that reads the entire canvas into a bitmap using the native + * SkPMColor: + * SkISize size = canvas->getDeviceSize(); + * bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth, + * size.fHeight); + * if (canvas->readPixels(bitmap, 0, 0)) { + * // use the pixels + * } + */ + bool readPixels(SkBitmap* bitmap, + int x, int y, + Config8888 config8888 = kNative_Premul_Config8888); + + /** + * DEPRECATED: This will be removed as soon as webkit is no longer relying + * on it. The bitmap is resized to the intersection of srcRect and the + * canvas bounds. New pixels are always allocated on success. Bitmap is + * unmodified on failure. + */ + bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap); + + /** + * Similar to draw sprite, this method will copy the pixels in bitmap onto + * the canvas, with the top/left corner specified by (x, y). The canvas' + * pixel values are completely replaced: there is no blending. + * + * Currently if bitmap is backed by a texture this is a no-op. This may be + * relaxed in the future. + * + * If the bitmap has config kARGB_8888_Config then the config8888 param + * will determines how the pixel valuess are intepreted. If the bitmap is + * not kARGB_8888_Config then this parameter is ignored. + * + * Note: If you are recording drawing commands on this canvas to + * SkPicture, writePixels() is ignored! + */ + void writePixels(const SkBitmap& bitmap, + int x, int y, + Config8888 config8888 = kNative_Premul_Config8888); + + /////////////////////////////////////////////////////////////////////////// + + 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, clip, and drawFilter, and pushes a + copy onto a private stack. Subsequent calls to translate, scale, + rotate, skew, concat or clipRect, clipPath, and setDrawFilter all + operate on this copy. + When the balancing call to restore() is made, the previous matrix, clip, + and drawFilter are 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). + @param bounds (may be null) This rect, if non-null, is used as a hint to + limit the size of the offscreen, and thus drawing may be + clipped to it, though that clipping is not guaranteed to + happen. If exact clipping is desired, use clipRect(). + @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). + @param bounds (may be null) This rect, if non-null, is used as a hint to + limit the size of the offscreen, and thus drawing may be + clipped to it, though that clipping is not guaranteed to + happen. If exact clipping is desired, use clipRect(). + @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/drawFilter 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); + + /** Returns true if drawing is currently going to a layer (from saveLayer) + * rather than to the root device. + */ + virtual bool isDrawingToLayer() const; + + /** 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 combine with the current clip + * @param op The region op to apply to the current clip + * @param doAntiAlias true if the clip should be antialiased + * @return true if the canvas' clip is non-empty + */ + virtual bool clipRect(const SkRect& rect, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false); + + /** + * Modify the current clip with the specified SkRRect. + * @param rrect The rrect to combine with the current clip + * @param op The region op to apply to the current clip + * @param doAntiAlias true if the clip should be antialiased + * @return true if the canvas' clip is non-empty + */ + virtual bool clipRRect(const SkRRect& rrect, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false); + + /** + * Modify the current clip with the specified path. + * @param path The path to combine with the current clip + * @param op The region op to apply to the current clip + * @param doAntiAlias true if the clip should be antialiased + * @return true if the canvas' new clip is non-empty + */ + virtual bool clipPath(const SkPath& path, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false); + + /** EXPERIMENTAL -- only used for testing + Set to false to force clips to be hard, even if doAntiAlias=true is + passed to clipRect or clipPath. + */ + void setAllowSoftClip(bool allow) { + fAllowSoftClip = allow; + } + + /** EXPERIMENTAL -- only used for testing + Set to simplify clip stack using path ops. + */ + void setAllowSimplifyClip(bool allow) { + fAllowSimplifyClip = allow; + } + + /** 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); + } + + /** 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 + @return true if the rect (transformed by the canvas' matrix) does not + intersect with the canvas' clip + */ + bool quickReject(const SkRect& rect) 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 + @return true if the path (transformed by the canvas' matrix) does not + intersect with the canvas' clip + */ + bool quickReject(const SkPath& path) 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) const { + SkASSERT(SkScalarToCompareType(top) <= SkScalarToCompareType(bottom)); + const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); + // In the case where the clip is empty and we are provided with a + // negative top and positive bottom parameter then this test will return + // false even though it will be clipped. We have chosen to exclude that + // check as it is rare and would result double the comparisons. + return SkScalarToCompareType(top) >= clipR.fBottom + || SkScalarToCompareType(bottom) <= clipR.fTop; + } + + /** 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) const; + + /** Return the bounds of the current clip, in device coordinates; returns + true if non-empty. Maybe faster than getting the clip explicitly and + then taking its bounds. + */ + bool getClipDeviceBounds(SkIRect* bounds) const; + + + /** Fill the entire canvas' bitmap (restricted to the current clip) with the + specified ARGB color, using the specified 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, + SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); + + /** Fill the entire canvas' bitmap (restricted to the current clip) with the + specified color and mode. + @param color the color to draw with + @param mode the mode to apply the color in (defaults to SrcOver) + */ + void drawColor(SkColor color, + SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); + + /** + * This erases the entire drawing surface to the specified color, + * irrespective of the clip. It does not blend with the previous pixels, + * but always overwrites them. + * + * It is roughly equivalent to the following: + * canvas.save(); + * canvas.clipRect(hugeRect, kReplace_Op); + * paint.setColor(color); + * paint.setXfermodeMode(kSrc_Mode); + * canvas.drawPaint(paint); + * canvas.restore(); + * though it is almost always much more efficient. + */ + virtual void clear(SkColor); + + /** + * 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 + */ + virtual void drawOval(const SkRect& oval, const SkPaint&); + + /** + * Draw the specified RRect using the specified paint The rrect will be filled or stroked + * based on the Style in the paint. + * + * @param rrect The round-rect to draw + * @param paint The paint used to draw the round-rect + */ + virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint); + + /** 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 drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, + const SkPaint* paint); + + void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, + const SkPaint* paint) { + this->drawBitmapRectToRect(bitmap, NULL, dst, paint); + } + + void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* isrc, + const SkRect& dst, const SkPaint* paint = NULL) { + SkRect realSrcStorage; + SkRect* realSrcPtr = NULL; + if (isrc) { + realSrcStorage.set(*isrc); + realSrcPtr = &realSrcStorage; + } + this->drawBitmapRectToRect(bitmap, realSrcPtr, dst, paint); + } + + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint = NULL); + + /** + * Draw the bitmap stretched differentially to fit into dst. + * center is a rect within the bitmap, and logically divides the bitmap + * into 9 sections (3x3). For example, if the middle pixel of a [5x5] + * bitmap is the "center", then the center-rect should be [2, 2, 3, 3]. + * + * If the dst is >= the bitmap size, then... + * - The 4 corners are not stretched at all. + * - The sides are stretched in only one axis. + * - The center is stretched in both axes. + * Else, for each axis where dst < bitmap, + * - The corners shrink proportionally + * - The sides (along the shrink axis) and center are not drawn + */ + virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, 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); + +#ifdef SK_BUILD_FOR_ANDROID + /** Draw the text on path, 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) + @param path The path to draw on + @param matrix The canvas matrix + */ + void drawPosTextOnPath(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint, + const SkPath& path, const SkMatrix* matrix); +#endif + + /** 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. + @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 (not uv 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 + kModulate_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); + + /** Send a blob of data to the canvas. + For canvases that draw, this call is effectively a no-op, as the data + is not parsed, but just ignored. However, this call exists for + subclasses like SkPicture's recording canvas, that can store the data + and then play it back later (via another call to drawData). + */ + virtual void drawData(const void* data, size_t length) { + // do nothing. Subclasses may do something with the data + } + + /** Add comments. beginCommentGroup/endCommentGroup open/close a new group. + Each comment added via addComment is notionally attached to its + enclosing group. Top-level comments simply belong to no group. + */ + virtual void beginCommentGroup(const char* description) { + // do nothing. Subclasses may do something + } + virtual void addComment(const char* kywd, const char* value) { + // do nothing. Subclasses may do something + } + virtual void endCommentGroup() { + // do nothing. Subclasses may do something + } + + + ////////////////////////////////////////////////////////////////////////// + + /** 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 saved/restored, just like the matrix and clip. + @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 saved/restored, just like the + matrix and clip. + @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; + + enum ClipType { + kEmpty_ClipType = 0, + kRect_ClipType, + kComplex_ClipType + }; + + /** Returns a description of the total clip; may be cheaper than + getting the clip and querying it directly. + */ + ClipType getClipType() 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). + * + * DEPRECATED -- call getClipDeviceBounds() instead. + */ + const SkRegion& getTotalClip() const; + + /** Return the clip stack. The clip stack stores all the individual + * clips organized by the save/restore frame in which they were + * added. + * @return the current clip stack ("list" of individual clip elements) + */ + const SkClipStack* getClipStack() const { + return &fClipStack; + } + + class ClipVisitor { + public: + virtual ~ClipVisitor(); + virtual void clipRect(const SkRect&, SkRegion::Op, bool antialias) = 0; + virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) = 0; + }; + + /** + * Replays the clip operations, back to front, that have been applied to + * the canvas, calling the appropriate method on the visitor for each + * clip. All clips have already been transformed into device space. + */ + void replayClips(ClipVisitor*) const; + + /////////////////////////////////////////////////////////////////////////// + + /** 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 SK_API 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[32]; + class SkDrawIter* fImpl; // this points at fStorage + SkPaint fDefaultPaint; + bool fDone; + }; + +protected: + // Returns the canvas to be used by DrawIter. Default implementation + // returns this. Subclasses that encapsulate an indirect canvas may + // need to overload this method. The impl must keep track of this, as it + // is not released or deleted by the caller. + virtual SkCanvas* canvasForDrawIter(); + + // Clip rectangle bounds. Called internally by saveLayer. + // returns false if the entire rectangle is entirely clipped out + bool clipRectBounds(const SkRect* bounds, SaveFlags flags, + SkIRect* intersection); + + // Called by child classes that override clipPath and clipRRect to only + // track fast conservative clip bounds, rather than exact clips. + bool updateClipConservativelyUsingBounds(const SkRect&, SkRegion::Op, + bool inverseFilled); + + // notify our surface (if we have one) that we are about to draw, so it + // can perform copy-on-write or invalidate any cached images + void predrawNotify(); + + /** DEPRECATED -- use constructor(device) + + Marked as 'protected' to avoid new clients using this before we can + completely remove it. + + 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. + */ + virtual SkDevice* setDevice(SkDevice* device); + +private: + class MCRec; + + SkClipStack fClipStack; + 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; + int fSaveLayerCount; // number of successful saveLayer calls + + SkMetaData* fMetaData; + + SkSurface_Base* fSurfaceBase; + SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } + void setSurfaceBase(SkSurface_Base* sb) { + fSurfaceBase = sb; + } + friend class SkSurface_Base; + friend class SkSurface_Gpu; + + bool fDeviceCMDirty; // cleared by updateDeviceCMCache() + void updateDeviceCMCache(); + + friend class SkDrawIter; // needs setupDrawForLayerDevice() + friend class AutoDrawLooper; + + SkDevice* createLayerDevice(SkBitmap::Config, int width, int height, + bool isOpaque); + + SkDevice* init(SkDevice*); + + // internal methods are not virtual, so they can safely be called by other + // canvas apis, without confusing subclasses (like SkPictureRecording) + void internalDrawBitmap(const SkBitmap&, const SkMatrix& m, const SkPaint* paint); + void internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint); + void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint); + void internalDrawPaint(const SkPaint& paint); + int internalSaveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags, bool justForImageFilter); + void internalDrawDevice(SkDevice*, int x, int y, const SkPaint*); + + // shared by save() and saveLayer() + int internalSave(SaveFlags flags); + void internalRestore(); + static void DrawRect(const SkDraw& draw, const SkPaint& paint, + const SkRect& r, SkScalar textSize); + static void DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, + const char text[], size_t byteLength, + SkScalar x, SkScalar y); + + /* 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; + bool fAllowSoftClip; + bool fAllowSimplifyClip; + + const SkRectCompareType& getLocalClipBoundsCompareType() const { + if (fLocalBoundsCompareTypeDirty) { + this->computeLocalClipBoundsCompareType(); + fLocalBoundsCompareTypeDirty = false; + } + return fLocalBoundsCompareType; + } + void computeLocalClipBoundsCompareType() const; + + + class AutoValidateClip : ::SkNoncopyable { + public: + explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) { + fCanvas->validateClip(); + } + ~AutoValidateClip() { fCanvas->validateClip(); } + + private: + const SkCanvas* fCanvas; + }; + +#ifdef SK_DEBUG + void validateClip() const; +#else + void validateClip() const {} +#endif + + typedef SkRefCnt INHERITED; +}; + +/** Stack helper class to automatically call restoreToCount() on the canvas + when this object goes out of scope. Use this to guarantee that the canvas + is restored to a known state. +*/ +class SkAutoCanvasRestore : SkNoncopyable { +public: + SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas) { + SkASSERT(canvas); + fSaveCount = canvas->getSaveCount(); + if (doSave) { + canvas->save(); + } + } + ~SkAutoCanvasRestore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + } + } + + /** + * Perform the restore now, instead of waiting for the destructor. Will + * only do this once. + */ + void restore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + fCanvas = NULL; + } + } + +private: + SkCanvas* fCanvas; + int fSaveCount; +}; + +/** Stack helper class to automatically open and close a comment block + */ +class SkAutoCommentBlock : SkNoncopyable { +public: + SkAutoCommentBlock(SkCanvas* canvas, const char* description) { + fCanvas = canvas; + if (NULL != fCanvas) { + fCanvas->beginCommentGroup(description); + } + } + + ~SkAutoCommentBlock() { + if (NULL != fCanvas) { + fCanvas->endCommentGroup(); + } + } + +private: + SkCanvas* fCanvas; +}; + +#endif diff --git a/core/SkChecksum.h b/core/SkChecksum.h new file mode 100644 index 0000000..bf3228f --- /dev/null +++ b/core/SkChecksum.h @@ -0,0 +1,135 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkChecksum_DEFINED +#define SkChecksum_DEFINED + +#include "SkTypes.h" + +/** + * Computes a 32bit checksum from a blob of 32bit aligned data. This is meant + * to be very very fast, as it is used internally by the font cache, in + * conjuction with the entire raw key. This algorithm does not generate + * unique values as well as others (e.g. MD5) but it performs much faster. + * Skia's use cases can survive non-unique values (since the entire key is + * always available). Clients should only be used in circumstances where speed + * over uniqueness is at a premium. + */ +class SkChecksum : SkNoncopyable { +private: + /* + * Our Rotate and Mash helpers are meant to automatically do the right + * thing depending if sizeof(uintptr_t) is 4 or 8. + */ + enum { + ROTR = 17, + ROTL = sizeof(uintptr_t) * 8 - ROTR, + HALFBITS = sizeof(uintptr_t) * 4 + }; + + static inline uintptr_t Mash(uintptr_t total, uintptr_t value) { + return ((total >> ROTR) | (total << ROTL)) ^ value; + } + +public: + + /** + * Calculate 32-bit Murmur hash (murmur3). + * This should take 2-3x longer than SkChecksum::Compute, but is a considerably better hash. + * See en.wikipedia.org/wiki/MurmurHash. + * + * @param data Memory address of the data block to be processed. Must be 32-bit aligned. + * @param size Size of the data block in bytes. Must be a multiple of 4. + * @param seed Initial hash seed. (optional) + * @return hash result + */ + static uint32_t Murmur3(const uint32_t* data, size_t bytes, uint32_t seed=0) { + SkASSERT(SkIsAlign4(bytes)); + const size_t words = bytes/4; + + uint32_t hash = seed; + for (size_t i = 0; i < words; i++) { + uint32_t k = data[i]; + k *= 0xcc9e2d51; + k = (k << 15) | (k >> 17); + k *= 0x1b873593; + + hash ^= k; + hash = (hash << 13) | (hash >> 19); + hash *= 5; + hash += 0xe6546b64; + } + hash ^= bytes; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + return hash; + } + + /** + * Compute a 32-bit checksum for a given data block + * + * WARNING: this algorithm is tuned for efficiency, not backward/forward + * compatibility. It may change at any time, so a checksum generated with + * one version of the Skia code may not match a checksum generated with + * a different version of the Skia code. + * + * @param data Memory address of the data block to be processed. Must be + * 32-bit aligned. + * @param size Size of the data block in bytes. Must be a multiple of 4. + * @return checksum result + */ + static uint32_t Compute(const uint32_t* data, size_t size) { + SkASSERT(SkIsAlign4(size)); + + /* + * We want to let the compiler use 32bit or 64bit addressing and math + * so we use uintptr_t as our magic type. This makes the code a little + * more obscure (we can't hard-code 32 or 64 anywhere, but have to use + * sizeof()). + */ + uintptr_t result = 0; + const uintptr_t* ptr = reinterpret_cast<const uintptr_t*>(data); + + /* + * count the number of quad element chunks. This takes into account + * if we're on a 32bit or 64bit arch, since we use sizeof(uintptr_t) + * to compute how much to shift-down the size. + */ + size_t n4 = size / (sizeof(uintptr_t) << 2); + for (size_t i = 0; i < n4; ++i) { + result = Mash(result, *ptr++); + result = Mash(result, *ptr++); + result = Mash(result, *ptr++); + result = Mash(result, *ptr++); + } + size &= ((sizeof(uintptr_t) << 2) - 1); + + data = reinterpret_cast<const uint32_t*>(ptr); + const uint32_t* stop = data + (size >> 2); + while (data < stop) { + result = Mash(result, *data++); + } + + /* + * smash us down to 32bits if we were 64. Note that when uintptr_t is + * 32bits, this code-path should go away, but I still got a warning + * when I wrote + * result ^= result >> 32; + * since >>32 is undefined for 32bit ints, hence the wacky HALFBITS + * define. + */ + if (8 == sizeof(result)) { + result ^= result >> HALFBITS; + } + return static_cast<uint32_t>(result); + } +}; + +#endif diff --git a/core/SkChunkAlloc.h b/core/SkChunkAlloc.h new file mode 100644 index 0000000..e13e2b9 --- /dev/null +++ b/core/SkChunkAlloc.h @@ -0,0 +1,68 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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(); + + enum AllocFailType { + kReturnNil_AllocFailType, + kThrow_AllocFailType + }; + + void* alloc(size_t bytes, AllocFailType); + void* allocThrow(size_t bytes) { + return this->alloc(bytes, kThrow_AllocFailType); + } + + /** Call this to unalloc the most-recently allocated ptr by alloc(). On + success, the number of bytes freed is returned, or 0 if the block could + not be unallocated. This is a hint to the underlying allocator that + the previous allocation may be reused, but the implementation is free + to ignore this call (and return 0). + */ + size_t unalloc(void* ptr); + + size_t totalCapacity() const { return fTotalCapacity; } + size_t totalUsed() const { return fTotalUsed; } + int blockCount() const { return fBlockCount; } + + /** + * Returns true if the specified address is within one of the chunks, and + * has at least 1-byte following the address (i.e. if addr points to the + * end of a chunk, then contains() will return false). + */ + bool contains(const void* addr) const; + +private: + struct Block; + + Block* fBlock; + size_t fMinSize; + size_t fChunkSize; + size_t fTotalCapacity; + size_t fTotalUsed; // will be <= fTotalCapacity + int fBlockCount; + + Block* newBlock(size_t bytes, AllocFailType ftype); +}; + +#endif diff --git a/core/SkClipStack.h b/core/SkClipStack.h new file mode 100644 index 0000000..145552d --- /dev/null +++ b/core/SkClipStack.h @@ -0,0 +1,471 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkClipStack_DEFINED +#define SkClipStack_DEFINED + +#include "SkDeque.h" +#include "SkPath.h" +#include "SkRect.h" +#include "SkRegion.h" +#include "SkTDArray.h" + + +// Because a single save/restore state can have multiple clips, this class +// stores the stack depth (fSaveCount) and clips (fDeque) separately. +// Each clip in fDeque stores the stack state to which it belongs +// (i.e., the fSaveCount in force when it was added). Restores are thus +// implemented by removing clips from fDeque that have an fSaveCount larger +// then the freshly decremented count. +class SK_API SkClipStack { +public: + enum BoundsType { + // The bounding box contains all the pixels that can be written to + kNormal_BoundsType, + // The bounding box contains all the pixels that cannot be written to. + // The real bound extends out to infinity and all the pixels outside + // of the bound can be written to. Note that some of the pixels inside + // the bound may also be writeable but all pixels that cannot be + // written to are guaranteed to be inside. + kInsideOut_BoundsType + }; + + class Element { + public: + enum Type { + //!< This element makes the clip empty (regardless of previous elements). + kEmpty_Type, + //!< This element combines a rect with the current clip using a set operation + kRect_Type, + //!< This element combines a path with the current clip using a set operation + kPath_Type, + }; + + Element() { + this->initCommon(0, SkRegion::kReplace_Op, false); + this->setEmpty(); + } + + Element(const SkRect& rect, SkRegion::Op op, bool doAA) { + this->initRect(0, rect, op, doAA); + } + + Element(const SkPath& path, SkRegion::Op op, bool doAA) { + this->initPath(0, path, op, doAA); + } + + bool operator== (const Element& element) const { + if (this == &element) { + return true; + } + if (fOp != element.fOp || + fType != element.fType || + fDoAA != element.fDoAA || + fSaveCount != element.fSaveCount) { + return false; + } + switch (fType) { + case kPath_Type: + return fPath == element.fPath; + case kRect_Type: + return fRect == element.fRect; + case kEmpty_Type: + return true; + default: + SkDEBUGFAIL("Unexpected type."); + return false; + } + } + bool operator!= (const Element& element) const { return !(*this == element); } + + //!< Call to get the type of the clip element. + Type getType() const { return fType; } + + //!< Call if getType() is kPath to get the path. + const SkPath& getPath() const { return fPath; } + + //!< Call if getType() is kRect to get the rect. + const SkRect& getRect() const { return fRect; } + + //!< Call if getType() is not kEmpty to get the set operation used to combine this element. + SkRegion::Op getOp() const { return fOp; } + + /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased + when it is rasterized. */ + bool isAA() const { return fDoAA; } + + //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty. + void invertShapeFillType(); + + //!< Sets the set operation represented by the element. + void setOp(SkRegion::Op op) { fOp = op; } + + /** The GenID can be used by clip stack clients to cache representations of the clip. The + ID corresponds to the set of clip elements up to and including this element within the + stack not to the element itself. That is the same clip path in different stacks will + have a different ID since the elements produce different clip result in the context of + their stacks. */ + int32_t getGenID() const { return fGenID; } + + /** + * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape + * is inverse filled is not considered.) + */ + const SkRect& getBounds() const { + static const SkRect kEmpty = { 0, 0, 0, 0 }; + switch (fType) { + case kRect_Type: + return fRect; + case kPath_Type: + return fPath.getBounds(); + case kEmpty_Type: + return kEmpty; + default: + SkDEBUGFAIL("Unexpected type."); + return kEmpty; + } + } + + /** + * Conservatively checks whether the clip shape contains the rect param. (Whether the shape + * is inverse filled is not considered.) + */ + bool contains(const SkRect& rect) const { + switch (fType) { + case kRect_Type: + return fRect.contains(rect); + case kPath_Type: + return fPath.conservativelyContainsRect(rect); + case kEmpty_Type: + return false; + default: + SkDEBUGFAIL("Unexpected type."); + return false; + } + } + + /** + * Is the clip shape inverse filled. + */ + bool isInverseFilled() const { + return kPath_Type == fType && fPath.isInverseFillType(); + } + + private: + friend class SkClipStack; + + SkPath fPath; + SkRect fRect; + int fSaveCount; // save count of stack when this element was added. + SkRegion::Op fOp; + Type fType; + bool fDoAA; + + /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's + bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the + conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be + drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which + occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding + box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside + the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the + infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we + can capture the cancelling out of the extensions to infinity when two inverse filled + clips are Booleaned together. */ + SkClipStack::BoundsType fFiniteBoundType; + SkRect fFiniteBound; + + // When element is applied to the previous elements in the stack is the result known to be + // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle. + bool fIsIntersectionOfRects; + + int fGenID; + + Element(int saveCount) { + this->initCommon(saveCount, SkRegion::kReplace_Op, false); + this->setEmpty(); + } + + Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { + this->initRect(saveCount, rect, op, doAA); + } + + Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { + this->initPath(saveCount, path, op, doAA); + } + + void initCommon(int saveCount, SkRegion::Op op, bool doAA) { + fSaveCount = saveCount; + fOp = op; + fDoAA = doAA; + // A default of inside-out and empty bounds means the bounds are effectively void as it + // indicates that nothing is known to be outside the clip. + fFiniteBoundType = kInsideOut_BoundsType; + fFiniteBound.setEmpty(); + fIsIntersectionOfRects = false; + fGenID = kInvalidGenID; + } + + void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { + fRect = rect; + fType = kRect_Type; + this->initCommon(saveCount, op, doAA); + } + + void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { + fPath = path; + fType = kPath_Type; + this->initCommon(saveCount, op, doAA); + } + + void setEmpty() { + fType = kEmpty_Type; + fFiniteBound.setEmpty(); + fFiniteBoundType = kNormal_BoundsType; + fIsIntersectionOfRects = false; + fRect.setEmpty(); + fPath.reset(); + fGenID = kEmptyGenID; + } + + // All Element methods below are only used within SkClipStack.cpp + inline void checkEmpty() const; + inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const; + /* This method checks to see if two rect clips can be safely merged into one. The issue here + is that to be strictly correct all the edges of the resulting rect must have the same + anti-aliasing. */ + bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; + /** Determines possible finite bounds for the Element given the previous element of the + stack */ + void updateBoundAndGenID(const Element* prior); + // The different combination of fill & inverse fill when combining bounding boxes + enum FillCombo { + kPrev_Cur_FillCombo, + kPrev_InvCur_FillCombo, + kInvPrev_Cur_FillCombo, + kInvPrev_InvCur_FillCombo + }; + // per-set operation functions used by updateBoundAndGenID(). + inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite); + inline void combineBoundsXOR(int combination, const SkRect& prevFinite); + inline void combineBoundsUnion(int combination, const SkRect& prevFinite); + inline void combineBoundsIntersection(int combination, const SkRect& prevFinite); + inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite); + }; + + SkClipStack(); + SkClipStack(const SkClipStack& b); + explicit SkClipStack(const SkRect& r); + explicit SkClipStack(const SkIRect& r); + ~SkClipStack(); + + SkClipStack& operator=(const SkClipStack& b); + bool operator==(const SkClipStack& b) const; + bool operator!=(const SkClipStack& b) const { return !(*this == b); } + + void reset(); + + int getSaveCount() const { return fSaveCount; } + void save(); + void restore(); + + /** + * getBounds places the current finite bound in its first parameter. In its + * second, it indicates which kind of bound is being returned. If + * 'canvFiniteBound' is a normal bounding box then it encloses all writeable + * pixels. If 'canvFiniteBound' is an inside out bounding box then it + * encloses all the un-writeable pixels and the true/normal bound is the + * infinite plane. isIntersectionOfRects is an optional parameter + * that is true if 'canvFiniteBound' resulted from an intersection of rects. + */ + void getBounds(SkRect* canvFiniteBound, + BoundsType* boundType, + bool* isIntersectionOfRects = NULL) const; + + /** + * Takes an input rect in device space and conservatively clips it to the + * clip-stack. If false is returned then the rect does not intersect the + * clip and is unmodified. + */ + bool intersectRectWithClip(SkRect* devRect) const; + + /** + * Returns true if the input rect in device space is entirely contained + * by the clip. A return value of false does not guarantee that the rect + * is not contained by the clip. + */ + bool quickContains(const SkRect& devRect) const; + + void clipDevRect(const SkIRect& ir, SkRegion::Op op) { + SkRect r; + r.set(ir); + this->clipDevRect(r, op, false); + } + void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); + void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); + // An optimized version of clipDevRect(emptyRect, kIntersect, ...) + void clipEmpty(); + + /** + * isWideOpen returns true if the clip state corresponds to the infinite + * plane (i.e., draws are not limited at all) + */ + bool isWideOpen() const; + + /** + * Add a callback function that will be called whenever a clip state + * is no longer viable. This will occur whenever restore + * is called or when a clipDevRect or clipDevPath call updates the + * clip within an existing save/restore state. Each clip state is + * represented by a unique generation ID. + */ + typedef void (*PFPurgeClipCB)(int genID, void* data); + void addPurgeClipCallback(PFPurgeClipCB callback, void* data) const; + + /** + * Remove a callback added earlier via addPurgeClipCallback + */ + void removePurgeClipCallback(PFPurgeClipCB callback, void* data) const; + + /** + * The generation ID has three reserved values to indicate special + * (potentially ignorable) cases + */ + static const int32_t kInvalidGenID = 0; + static const int32_t kEmptyGenID = 1; // no pixels writeable + static const int32_t kWideOpenGenID = 2; // all pixels writeable + + int32_t getTopmostGenID() const; + +public: + class Iter { + public: + enum IterStart { + kBottom_IterStart = SkDeque::Iter::kFront_IterStart, + kTop_IterStart = SkDeque::Iter::kBack_IterStart + }; + + /** + * Creates an uninitialized iterator. Must be reset() + */ + Iter(); + + Iter(const SkClipStack& stack, IterStart startLoc); + + /** + * Return the clip element for this iterator. If next()/prev() returns NULL, then the + * iterator is done. + */ + const Element* next(); + const Element* prev(); + + /** + * Moves the iterator to the topmost element with the specified RegionOp and returns that + * element. If no clip element with that op is found, the first element is returned. + */ + const Element* skipToTopmost(SkRegion::Op op); + + /** + * Restarts the iterator on a clip stack. + */ + void reset(const SkClipStack& stack, IterStart startLoc); + + private: + const SkClipStack* fStack; + SkDeque::Iter fIter; + }; + + /** + * The B2TIter iterates from the bottom of the stack to the top. + * It inherits privately from Iter to prevent access to reverse iteration. + */ + class B2TIter : private Iter { + public: + B2TIter() {} + + /** + * Wrap Iter's 2 parameter ctor to force initialization to the + * beginning of the deque/bottom of the stack + */ + B2TIter(const SkClipStack& stack) + : INHERITED(stack, kBottom_IterStart) { + } + + using Iter::next; + + /** + * Wrap Iter::reset to force initialization to the + * beginning of the deque/bottom of the stack + */ + void reset(const SkClipStack& stack) { + this->INHERITED::reset(stack, kBottom_IterStart); + } + + private: + + typedef Iter INHERITED; + }; + + /** + * GetConservativeBounds returns a conservative bound of the current clip. + * Since this could be the infinite plane (if inverse fills were involved) the + * maxWidth and maxHeight parameters can be used to limit the returned bound + * to the expected drawing area. Similarly, the offsetX and offsetY parameters + * allow the caller to offset the returned bound to account for translated + * drawing areas (i.e., those resulting from a saveLayer). For finite bounds, + * the translation (+offsetX, +offsetY) is applied before the clamp to the + * maximum rectangle: [0,maxWidth) x [0,maxHeight). + * isIntersectionOfRects is an optional parameter that is true when + * 'devBounds' is the result of an intersection of rects. In this case + * 'devBounds' is the exact answer/clip. + */ + void getConservativeBounds(int offsetX, + int offsetY, + int maxWidth, + int maxHeight, + SkRect* devBounds, + bool* isIntersectionOfRects = NULL) const; + +private: + friend class Iter; + + SkDeque fDeque; + int fSaveCount; + + // Generation ID for the clip stack. This is incremented for each + // clipDevRect and clipDevPath call. 0 is reserved to indicate an + // invalid ID. + static int32_t gGenID; + + struct ClipCallbackData { + PFPurgeClipCB fCallback; + void* fData; + + friend bool operator==(const ClipCallbackData& a, + const ClipCallbackData& b) { + return a.fCallback == b.fCallback && a.fData == b.fData; + } + }; + + mutable SkTDArray<ClipCallbackData> fCallbackData; + + /** + * Restore the stack back to the specified save count. + */ + void restoreTo(int saveCount); + + /** + * Invoke all the purge callbacks passing in element's generation ID. + */ + void purgeClip(Element* element); + + /** + * Return the next unique generation ID. + */ + static int32_t GetNextGenID(); +}; + +#endif diff --git a/core/SkColor.h b/core/SkColor.h new file mode 100644 index 0000000..7faeca7 --- /dev/null +++ b/core/SkColor.h @@ -0,0 +1,169 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 SkColorSetARGBInline(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); +} + +#define SkColorSetARGBMacro(a, r, g, b) \ + static_cast<SkColor>( \ + (static_cast<U8CPU>(a) << 24) | \ + (static_cast<U8CPU>(r) << 16) | \ + (static_cast<U8CPU>(g) << 8) | \ + (static_cast<U8CPU>(b) << 0)) + +/** gcc will generate static initializers for code of this form: + * static const SkColor kMyColor = SkColorSetARGB(0xFF, 0x01, 0x02, 0x03) + * if SkColorSetARGB() is a static inline, but not if it's a macro. + */ +#if defined(NDEBUG) +#define SkColorSetARGB(a, r, g, b) SkColorSetARGBMacro(a, r, g, b) +#else +#define SkColorSetARGB(a, r, g, b) SkColorSetARGBInline(a, r, g, b) +#endif + +/** 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_AlphaTRANSPARENT 0x00 //!< transparent SkAlpha value +#define SK_AlphaOPAQUE 0xFF //!< opaque SkAlpha value + +#define SK_ColorTRANSPARENT 0x00000000 //!< transparent SkColor value + +#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. +*/ +SK_API 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 +*/ +SK_API 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 +*/ +SK_API 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. +*/ +SK_API 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/core/SkColorFilter.h b/core/SkColorFilter.h new file mode 100644 index 0000000..6359563 --- /dev/null +++ b/core/SkColorFilter.h @@ -0,0 +1,134 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkColorFilter_DEFINED +#define SkColorFilter_DEFINED + +#include "SkColor.h" +#include "SkFlattenable.h" +#include "SkXfermode.h" + +class SkBitmap; +class GrEffectRef; +class GrContext; + +class SK_API SkColorFilter : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkColorFilter) + + /** + * If the filter can be represented by a source color plus Mode, this + * returns true, and sets (if not NULL) the color and mode appropriately. + * If not, this returns false and ignores the parameters. + */ + virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) const; + + /** + * If the filter can be represented by a 5x4 matrix, this + * returns true, and sets the matrix appropriately. + * If not, this returns false and ignores the parameter. + */ + virtual bool asColorMatrix(SkScalar matrix[20]) const; + + /** + * If the filter can be represented by per-component table, return true, + * and if table is not null, copy the bitmap containing the table into it. + * + * The table bitmap will be in SkBitmap::kA8_Config. Each row corresponding + * to each component in ARGB order. e.g. row[0] == alpha, row[1] == red, + * etc. To transform a color, you (logically) perform the following: + * + * a' = *table.getAddr8(a, 0); + * r' = *table.getAddr8(r, 1); + * g' = *table.getAddr8(g, 2); + * b' = *table.getAddr8(b, 3); + * + * The original component value is the horizontal index for a given row, + * and the stored value at that index is the new value for that component. + */ + virtual bool asComponentTable(SkBitmap* table) const; + + /** 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[]) const = 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[]) const; + + 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() const { return 0; } + + /** + * Apply this colorfilter to the specified SkColor. This routine handles + * converting to SkPMColor, calling the filter, and then converting back + * to SkColor. This method is not virtual, but will call filterSpan() + * which is virtual. + */ + SkColor filterColor(SkColor) const; + + /** Create a colorfilter that uses the specified color and mode. + If the Mode is DST, this function will return NULL (since that + mode will have no effect on the result). + @param c The source color used with the specified mode + @param mode The xfermode mode that is applied to each color in + the colorfilter's filterSpan[16,32] methods + @return colorfilter object that applies the src color and mode, + or NULL if the mode will have no effect. + */ + static SkColorFilter* CreateModeFilter(SkColor c, SkXfermode::Mode mode); + + /** 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); + + /** A subclass may implement this factory function to work with the GPU backend. If the return + is non-NULL then the caller owns a ref on the returned object. + */ + virtual GrEffectRef* asNewEffect(GrContext*) const; + + SkDEVCODE(virtual void toString(SkString* str) const = 0;) + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +protected: + SkColorFilter() {} + SkColorFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {} + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkColorPriv.h b/core/SkColorPriv.h new file mode 100644 index 0000000..fe4377f --- /dev/null +++ b/core/SkColorPriv.h @@ -0,0 +1,867 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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" + +///@{ +/** See ITU-R Recommendation BT.709 at http://www.itu.int/rec/R-REC-BT.709/ .*/ +#define SK_ITU_BT709_LUM_COEFF_R (0.2126f) +#define SK_ITU_BT709_LUM_COEFF_G (0.7152f) +#define SK_ITU_BT709_LUM_COEFF_B (0.0722f) +///@} + +///@{ +/** A float value which specifies this channel's contribution to luminance. */ +#define SK_LUM_COEFF_R SK_ITU_BT709_LUM_COEFF_R +#define SK_LUM_COEFF_G SK_ITU_BT709_LUM_COEFF_G +#define SK_LUM_COEFF_B SK_ITU_BT709_LUM_COEFF_B +///@} + +/** Computes the luminance from the given r, g, and b in accordance with + SK_LUM_COEFF_X. For correct results, r, g, and b should be in linear space. +*/ +static inline U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b) { + //The following is + //r * SK_LUM_COEFF_R + g * SK_LUM_COEFF_G + b * SK_LUM_COEFF_B + //with SK_LUM_COEFF_X in 1.8 fixed point (rounding adjusted to sum to 256). + return (r * 54 + g * 183 + b * 19) >> 8; +} + +/** 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); + // this one assues that blending on top of an opaque dst keeps it that way + // even though it is less accurate than a+(a>>7) for non-opaque dsts + return alpha + 1; +} + +/** 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) +static inline int SkAlphaBlend(int src, int dst, int scale256) { + SkASSERT((unsigned)scale256 <= 256); + return dst + SkAlphaMul(src - dst, scale256); +} + +/** + * Returns (src * alpha + dst * (255 - alpha)) / 255 + * + * This is more accurate than SkAlphaBlend, but slightly slower + */ +static inline int SkAlphaBlend255(S16CPU src, S16CPU dst, U8CPU alpha) { + SkASSERT((int16_t)src == src); + SkASSERT((int16_t)dst == dst); + SkASSERT((uint8_t)alpha == alpha); + + int prod = SkMulS16(src - dst, alpha) + 128; + prod = (prod + (prod >> 8)) >> 8; + return dst + prod; +} + +#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 inline 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 + +#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 + static 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 + +/** + * Pack the components into a SkPMColor, checking (in the debug version) that + * the components are 0..255, and are already premultiplied (i.e. alpha >= color) + */ +static 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); +} + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + * srcWeight is [0..256], unlike SkFourByteInterp which takes [0..255] + */ +static inline SkPMColor SkFourByteInterp256(SkPMColor src, SkPMColor dst, + unsigned scale) { + unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale); + unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale); + unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale); + unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale); + + return SkPackARGB32(a, r, g, b); +} + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + */ +static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, + U8CPU srcWeight) { + unsigned scale = SkAlpha255To256(srcWeight); + return SkFourByteInterp256(src, dst, scale); +} + +/** + * 32b optimized version; currently appears to be 10% faster even on 64b + * architectures than an equivalent 64b version and 30% faster than + * SkFourByteInterp(). Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 256) returns src + * ** Does not match the results of SkFourByteInterp256() because we use + * a more accurate scale computation! + * TODO: migrate Skia function to using an accurate 255->266 alpha + * conversion. + */ +static inline SkPMColor SkFastFourByteInterp256(SkPMColor src, + SkPMColor dst, + unsigned scale) { + SkASSERT(scale <= 256); + + // Reorders ARGB to AG-RB in order to reduce the number of operations. + const uint32_t mask = 0xFF00FF; + uint32_t src_rb = src & mask; + uint32_t src_ag = (src >> 8) & mask; + uint32_t dst_rb = dst & mask; + uint32_t dst_ag = (dst >> 8) & mask; + + uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb; + uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag; + + return (ret_ag & ~mask) | ((ret_rb & ~mask) >> 8); +} + +static inline SkPMColor SkFastFourByteInterp(SkPMColor src, + SkPMColor dst, + U8CPU srcWeight) { + SkASSERT(srcWeight <= 255); + // scale = srcWeight + (srcWeight >> 7) is more accurate than + // scale = srcWeight + 1, but 7% slower + return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7)); +} + +/** + * Same as SkPackARGB32, but this version guarantees to not check that the + * values are premultiplied in the debug version. + */ +static inline SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) | + (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT); +} + +static inline +SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkA32Assert(a); + SkR32Assert(r); + SkG32Assert(g); + SkB32Assert(b); + + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + return SkPackARGB32(a, r, g, b); +} + +SK_API extern const uint32_t gMask_00FF00FF; + +static inline uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) { + uint32_t mask = gMask_00FF00FF; + + uint32_t rb = ((c & mask) * scale) >> 8; + uint32_t ag = ((c >> 8) & mask) * scale; + return (rb & mask) | (ag & ~mask); +} + +static inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) { + return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); +} + +static 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 + static inline unsigned SkR32ToR16(unsigned r) { + SkR32Assert(r); + return SkR32ToR16_MACRO(r); + } + static inline unsigned SkG32ToG16(unsigned g) { + SkG32Assert(g); + return SkG32ToG16_MACRO(g); + } + static 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) + +static 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; +} + +static 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) + +static 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); +} + +static 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 + +static inline unsigned SkR16ToR32(unsigned r) { + return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); +} + +static inline unsigned SkG16ToG32(unsigned g) { + return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); +} + +static 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)) + +static 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); +} + +// similar to SkPixel16ToPixel32, but returns SkColor instead of SkPMColor +static inline SkColor SkPixel16ToColor(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 SkColorSetRGB(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 inline 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; + +static 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. +*/ +static 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) { + // to ensure that we stay a legal premultiplied color, we take the max() + // of the truncated and dithered alpha values. If we didn't, cases like + // SkDitherARGB32To4444(0x31, 0x2E, ...) would generate SkPackARGB4444(2, 3, ...) + // which is not legal premultiplied, since a < color + unsigned dithered_a = ((a << 1) - ((a >> 4 << 4) | (a >> 4))) >> 4; + a = SkMax32(a >> 4, dithered_a); + // these we just dither in place + 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 inline 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 inline 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 inline 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); + +/////////////////////////////////////////////////////////////////////////////// + +static inline int SkUpscale31To32(int value) { + SkASSERT((unsigned)value <= 31); + return value + (value >> 4); +} + +static inline int SkBlend32(int src, int dst, int scale) { + SkASSERT((unsigned)src <= 0xFF); + SkASSERT((unsigned)dst <= 0xFF); + SkASSERT((unsigned)scale <= 32); + return dst + ((src - dst) * scale >> 5); +} + +static inline SkPMColor SkBlendLCD16(int srcA, int srcR, int srcG, int srcB, + SkPMColor dst, uint16_t mask) { + if (mask == 0) { + return dst; + } + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); + + // Now upscale them to 0..32, so we can use blend32 + maskR = SkUpscale31To32(maskR); + maskG = SkUpscale31To32(maskG); + maskB = SkUpscale31To32(maskB); + + // srcA has been upscaled to 256 before passed into this function + maskR = maskR * srcA >> 8; + maskG = maskG * srcA >> 8; + maskB = maskB * srcA >> 8; + + int dstR = SkGetPackedR32(dst); + int dstG = SkGetPackedG32(dst); + int dstB = SkGetPackedB32(dst); + + // LCD blitting is only supported if the dst is known/required + // to be opaque + return SkPackARGB32(0xFF, + SkBlend32(srcR, dstR, maskR), + SkBlend32(srcG, dstG, maskG), + SkBlend32(srcB, dstB, maskB)); +} + +static inline SkPMColor SkBlendLCD16Opaque(int srcR, int srcG, int srcB, + SkPMColor dst, uint16_t mask, + SkPMColor opaqueDst) { + if (mask == 0) { + return dst; + } + + if (0xFFFF == mask) { + return opaqueDst; + } + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); + + // Now upscale them to 0..32, so we can use blend32 + maskR = SkUpscale31To32(maskR); + maskG = SkUpscale31To32(maskG); + maskB = SkUpscale31To32(maskB); + + int dstR = SkGetPackedR32(dst); + int dstG = SkGetPackedG32(dst); + int dstB = SkGetPackedB32(dst); + + // LCD blitting is only supported if the dst is known/required + // to be opaque + return SkPackARGB32(0xFF, + SkBlend32(srcR, dstR, maskR), + SkBlend32(srcG, dstG, maskG), + SkBlend32(srcB, dstB, maskB)); +} + +static inline void SkBlitLCD16Row(SkPMColor dst[], const uint16_t mask[], + SkColor src, int width, SkPMColor) { + int srcA = SkColorGetA(src); + int srcR = SkColorGetR(src); + int srcG = SkColorGetG(src); + int srcB = SkColorGetB(src); + + srcA = SkAlpha255To256(srcA); + + for (int i = 0; i < width; i++) { + dst[i] = SkBlendLCD16(srcA, srcR, srcG, srcB, dst[i], mask[i]); + } +} + +static inline void SkBlitLCD16OpaqueRow(SkPMColor dst[], const uint16_t mask[], + SkColor src, int width, + SkPMColor opaqueDst) { + int srcR = SkColorGetR(src); + int srcG = SkColorGetG(src); + int srcB = SkColorGetB(src); + + for (int i = 0; i < width; i++) { + dst[i] = SkBlendLCD16Opaque(srcR, srcG, srcB, dst[i], mask[i], + opaqueDst); + } +} + +#endif diff --git a/core/SkColorShader.h b/core/SkColorShader.h new file mode 100644 index 0000000..c379068 --- /dev/null +++ b/core/SkColorShader.h @@ -0,0 +1,69 @@ + +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 SK_API SkColorShader : public SkShader { +public: + /** Create a ColorShader that will inherit its color from the Paint + at draw time. + */ + SkColorShader(); + + /** 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); + + virtual ~SkColorShader(); + + virtual uint32_t getFlags() SK_OVERRIDE; + virtual uint8_t getSpan16Alpha() const SK_OVERRIDE; + virtual bool isOpaque() const SK_OVERRIDE; + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE; + + // we return false for this, use asAGradient + virtual BitmapType asABitmap(SkBitmap* outTexture, + SkMatrix* outMatrix, + TileMode xy[2]) const SK_OVERRIDE; + + virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorShader) + +protected: + SkColorShader(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + + SkColor fColor; // ignored if fInheritColor is true + SkPMColor fPMColor; // cached after setContext() + uint32_t fFlags; // cached after setContext() + uint16_t fColor16; // cached after setContext() + SkBool8 fInheritColor; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/core/SkColorTable.h b/core/SkColorTable.h new file mode 100644 index 0000000..f8d1ccf --- /dev/null +++ b/core/SkColorTable.h @@ -0,0 +1,112 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkColorTable_DEFINED +#define SkColorTable_DEFINED + +#include "SkColor.h" +#include "SkFlattenable.h" + +/** \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 SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkColorTable) + + /** Makes a deep copy of colors. + */ + SkColorTable(const SkColorTable& src); + /** Preallocates the colortable to have 'count' colors, which + * are initially set to 0. + */ + explicit SkColorTable(int count); + 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); + + bool isOpaque() const { return (fFlags & kColorsAreOpaque_Flag) != 0; } + void setIsOpaque(bool isOpaque); + + /** 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(sk_atomic_inc(&fColorLockCount);) + 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); + } + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorTable) + +protected: + explicit SkColorTable(SkFlattenableReadBuffer&); + void flatten(SkFlattenableWriteBuffer&) const; + +private: + SkPMColor* fColors; + uint16_t* f16BitCache; + uint16_t fCount; + uint8_t fFlags; + SkDEBUGCODE(int fColorLockCount;) + SkDEBUGCODE(int f16BitCacheLockCount;) + + void inval16BitCache(); + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkComposeShader.h b/core/SkComposeShader.h new file mode 100644 index 0000000..524161b --- /dev/null +++ b/core/SkComposeShader.h @@ -0,0 +1,58 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 SK_API 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(); + + virtual bool setContext(const SkBitmap&, const SkPaint&, + const SkMatrix&) SK_OVERRIDE; + virtual void endContext() SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeShader) + +protected: + SkComposeShader(SkFlattenableReadBuffer& ); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + + SkShader* fShaderA; + SkShader* fShaderB; + SkXfermode* fMode; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/core/SkData.h b/core/SkData.h new file mode 100644 index 0000000..6f883c8 --- /dev/null +++ b/core/SkData.h @@ -0,0 +1,151 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkData_DEFINED +#define SkData_DEFINED + +#include "SkFlattenable.h" + +struct SkFILE; + +/** + * SkData holds an immutable data buffer. Not only is the data immutable, + * but the actual ptr that is returned (by data() or bytes()) is guaranteed + * to always be the same for the life of this instance. + */ +class SK_API SkData : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkData) + + /** + * Returns the number of bytes stored. + */ + size_t size() const { return fSize; } + + bool isEmpty() const { return 0 == fSize; } + + /** + * Returns the ptr to the data. + */ + const void* data() const { return fPtr; } + + /** + * Like data(), returns a read-only ptr into the data, but in this case + * it is cast to uint8_t*, to make it easy to add an offset to it. + */ + const uint8_t* bytes() const { + return reinterpret_cast<const uint8_t*>(fPtr); + } + + /** + * Helper to copy a range of the data into a caller-provided buffer. + * Returns the actual number of bytes copied, after clamping offset and + * length to the size of the data. If buffer is NULL, it is ignored, and + * only the computed number of bytes is returned. + */ + size_t copyRange(size_t offset, size_t length, void* buffer) const; + + /** + * Returns true if these two objects have the same length and contents, + * effectively returning 0 == memcmp(...) + */ + bool equals(const SkData* other) const; + + /** + * Function that, if provided, will be called when the SkData goes out + * of scope, allowing for custom allocation/freeing of the data. + */ + typedef void (*ReleaseProc)(const void* ptr, size_t length, void* context); + + /** + * Create a new dataref by copying the specified data + */ + static SkData* NewWithCopy(const void* data, size_t length); + + /** + * Create a new dataref by copying the specified c-string + * (a null-terminated array of bytes). The returned SkData will have size() + * equal to strlen(cstr) + 1. If cstr is NULL, it will be treated the same + * as "". + */ + static SkData* NewWithCString(const char cstr[]); + + /** + * Create a new dataref, taking the data ptr as is, and using the + * releaseproc to free it. The proc may be NULL. + */ + static SkData* NewWithProc(const void* data, size_t length, + ReleaseProc proc, void* context); + + /** + * Create a new dataref from a pointer allocated by malloc. The Data object + * takes ownership of that allocation, and will handling calling sk_free. + */ + static SkData* NewFromMalloc(const void* data, size_t length); + + /** + * Create a new dataref the file with the specified path. + * If the file cannot be opened, this returns NULL. + */ + static SkData* NewFromFileName(const char path[]); + + /** + * Create a new dataref from a SkFILE. + * This does not take ownership of the SkFILE, nor close it. + * The caller is free to close the SkFILE at its convenience. + * The SkFILE must be open for reading only. + * Returns NULL on failure. + */ + static SkData* NewFromFILE(SkFILE* f); + + /** + * Create a new dataref from a file descriptor. + * This does not take ownership of the file descriptor, nor close it. + * The caller is free to close the file descriptor at its convenience. + * The file descriptor must be open for reading only. + * Returns NULL on failure. + */ + static SkData* NewFromFD(int fd); + + /** + * Create a new dataref using a subset of the data in the specified + * src dataref. + */ + static SkData* NewSubset(const SkData* src, size_t offset, size_t length); + + /** + * Returns a new empty dataref (or a reference to a shared empty dataref). + * New or shared, the caller must see that unref() is eventually called. + */ + static SkData* NewEmpty(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkData) + +protected: + SkData(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + ReleaseProc fReleaseProc; + void* fReleaseProcContext; + + const void* fPtr; + size_t fSize; + + SkData(const void* ptr, size_t size, ReleaseProc, void* context); + virtual ~SkData(); + + typedef SkFlattenable INHERITED; +}; + +/** Typedef of SkAutoTUnref<SkData> for automatically unref-ing a SkData. */ +typedef SkAutoTUnref<SkData> SkAutoDataUnref; + +#endif diff --git a/core/SkDataSet.h b/core/SkDataSet.h new file mode 100644 index 0000000..2e5d96e --- /dev/null +++ b/core/SkDataSet.h @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDataSet_DEFINED +#define SkDataSet_DEFINED + +#include "SkData.h" +#include "SkFlattenable.h" + +class SkStream; +class SkWStream; + +class SkDataSet : public SkFlattenable { +public: + /** + * Returns a new empty dataset. Note: since SkDataSet is immutable, this + * "new" set may be the same one that was returned before, but each + * returned object must have its reference-count balanced regardless. + * + * SkDataSet* empty = SkDataSet::NewEmpty(); + * ... + * empty->unref(); + */ + static SkDataSet* NewEmpty(); + + struct Pair { + const char* fKey; + SkData* fValue; + }; + + SkDataSet(const char key[], SkData* value); + SkDataSet(const Pair[], int count); + virtual ~SkDataSet(); + + bool isEmpty() const { return 0 == fCount; } + int count() const { return fCount; } + SkData* find(const char name[]) const; + + class Iter { + public: + Iter(const SkDataSet& ds) { + fPair = ds.fPairs; + fStop = ds.fPairs + ds.fCount; + } + + const char* key() const { + SkASSERT(!this->done()); + return fPair->fKey; + } + + SkData* value() const { + SkASSERT(!this->done()); + return fPair->fValue; + } + + bool done() const { return fPair >= fStop; } + void next() { + SkASSERT(!this->done()); + fPair += 1; + } + + private: + const SkDataSet::Pair* fPair; + const SkDataSet::Pair* fStop; + }; + + explicit SkDataSet(SkStream*); + void writeToStream(SkWStream*) const; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataSet) + +protected: + SkDataSet(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + int32_t fCount; + uint32_t fKeySize; + Pair* fPairs; + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkDataTable.h b/core/SkDataTable.h new file mode 100644 index 0000000..cb74c3c --- /dev/null +++ b/core/SkDataTable.h @@ -0,0 +1,184 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDataTable_DEFINED +#define SkDataTable_DEFINED + +#include "SkChunkAlloc.h" +#include "SkData.h" +#include "SkFlattenable.h" +#include "SkString.h" +#include "SkTDArray.h" + +/** + * Like SkData, SkDataTable holds an immutable data buffer. The data buffer is + * organized into a table of entries, each with a length, so the entries are + * not required to all be the same size. + */ +class SK_API SkDataTable : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkDataTable) + + /** + * Returns true if the table is empty (i.e. has no entries). + */ + bool isEmpty() const { return 0 == fCount; } + + /** + * Return the number of entries in the table. 0 for an empty table + */ + int count() const { return fCount; } + + /** + * Return the size of the index'th entry in the table. The caller must + * ensure that index is valid for this table. + */ + size_t atSize(int index) const; + + /** + * Return a pointer to the data of the index'th entry in the table. + * The caller must ensure that index is valid for this table. + * + * @param size If non-null, this returns the byte size of this entry. This + * will be the same value that atSize(index) would return. + */ + const void* at(int index, size_t* size = NULL) const; + + template <typename T> + const T* atT(int index, size_t* size = NULL) const { + return reinterpret_cast<const T*>(this->at(index, size)); + } + + /** + * Returns the index'th entry as a c-string, and assumes that the trailing + * null byte had been copied into the table as well. + */ + const char* atStr(int index) const { + size_t size; + const char* str = this->atT<const char>(index, &size); + SkASSERT(strlen(str) + 1 == size); + return str; + } + + typedef void (*FreeProc)(void* context); + + static SkDataTable* NewEmpty(); + + /** + * Return a new DataTable that contains a copy of the data stored in each + * "array". + * + * @param ptrs array of points to each element to be copied into the table. + * @param sizes array of byte-lengths for each entry in the corresponding + * ptrs[] array. + * @param count the number of array elements in ptrs[] and sizes[] to copy. + */ + static SkDataTable* NewCopyArrays(const void * const * ptrs, + const size_t sizes[], int count); + + /** + * Return a new table that contains a copy of the data in array. + * + * @param array contiguous array of data for all elements to be copied. + * @param elemSize byte-length for a given element. + * @param count the number of entries to be copied out of array. The number + * of bytes that will be copied is count * elemSize. + */ + static SkDataTable* NewCopyArray(const void* array, size_t elemSize, + int count); + + static SkDataTable* NewArrayProc(const void* array, size_t elemSize, + int count, FreeProc proc, void* context); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataTable) + +protected: + SkDataTable(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + struct Dir { + const void* fPtr; + uintptr_t fSize; + }; + + int fCount; + size_t fElemSize; + union { + const Dir* fDir; + const char* fElems; + } fU; + + FreeProc fFreeProc; + void* fFreeProcContext; + + SkDataTable(); + SkDataTable(const void* array, size_t elemSize, int count, + FreeProc, void* context); + SkDataTable(const Dir*, int count, FreeProc, void* context); + virtual ~SkDataTable(); + + friend class SkDataTableBuilder; // access to Dir + + typedef SkFlattenable INHERITED; +}; + +/** + * Helper class that allows for incrementally building up the data needed to + * create a SkDataTable. + */ +class SK_API SkDataTableBuilder : SkNoncopyable { +public: + SkDataTableBuilder(size_t minChunkSize); + ~SkDataTableBuilder(); + + int count() const { return fDir.count(); } + size_t minChunkSize() const { return fMinChunkSize; } + + /** + * Forget any previously appended entries, setting count() back to 0. + */ + void reset(size_t minChunkSize); + void reset() { + this->reset(fMinChunkSize); + } + + /** + * Copy size-bytes from data, and append it to the growing SkDataTable. + */ + void append(const void* data, size_t size); + + /** + * Helper version of append() passes strlen() + 1 for the size, + * so the trailing-zero will be copied as well. + */ + void appendStr(const char str[]) { + this->append(str, strlen(str) + 1); + } + + /** + * Helper version of append() passes string.size() + 1 for the size, + * so the trailing-zero will be copied as well. + */ + void appendString(const SkString& string) { + this->append(string.c_str(), string.size() + 1); + } + + /** + * Return an SkDataTable from the accumulated entries that were added by + * calls to append(). This call also clears any accumluated entries from + * this builder, so its count() will be 0 after this call. + */ + SkDataTable* detachDataTable(); + +private: + SkTDArray<SkDataTable::Dir> fDir; + SkChunkAlloc* fHeap; + size_t fMinChunkSize; +}; + +#endif diff --git a/core/SkDeque.h b/core/SkDeque.h new file mode 100644 index 0000000..eef335d --- /dev/null +++ b/core/SkDeque.h @@ -0,0 +1,138 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDeque_DEFINED +#define SkDeque_DEFINED + +#include "SkTypes.h" + +/* + * The deque class works by blindly creating memory space of a specified element + * size. It manages the memory as a doubly linked list of blocks each of which + * can contain multiple elements. Pushes and pops add/remove blocks from the + * beginning/end of the list as necessary while each block tracks the used + * portion of its memory. + * One behavior to be aware of is that the pops do not immediately remove an + * empty block from the beginning/end of the list (Presumably so push/pop pairs + * on the block boundaries don't cause thrashing). This can result in the first/ + * last element not residing in the first/last block. + */ +class SK_API SkDeque : SkNoncopyable { +public: + /** + * elemSize specifies the size of each individual element in the deque + * allocCount specifies how many elements are to be allocated as a block + */ + explicit SkDeque(size_t elemSize, int allocCount = 1); + SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCount = 1); + ~SkDeque(); + + bool empty() const { return 0 == fCount; } + int count() const { return fCount; } + size_t elemSize() const { return fElemSize; } + + const void* front() const { return fFront; } + const void* back() const { return fBack; } + + void* front() { + return (void*)((const SkDeque*)this)->front(); + } + + void* back() { + return (void*)((const SkDeque*)this)->back(); + } + + /** + * push_front and push_back return a pointer to the memory space + * for the new element + */ + void* push_front(); + void* push_back(); + + void pop_front(); + void pop_back(); + +private: + struct Block; + +public: + class Iter { + public: + enum IterStart { + kFront_IterStart, + kBack_IterStart + }; + + /** + * Creates an uninitialized iterator. Must be reset() + */ + Iter(); + + Iter(const SkDeque& d, IterStart startLoc); + void* next(); + void* prev(); + + void reset(const SkDeque& d, IterStart startLoc); + + private: + SkDeque::Block* fCurBlock; + char* fPos; + size_t fElemSize; + }; + + // Inherit privately from Iter to prevent access to reverse iteration + class F2BIter : private Iter { + public: + F2BIter() {} + + /** + * Wrap Iter's 2 parameter ctor to force initialization to the + * beginning of the deque + */ + F2BIter(const SkDeque& d) : INHERITED(d, kFront_IterStart) {} + + using Iter::next; + + /** + * Wrap Iter::reset to force initialization to the beginning of the + * deque + */ + void reset(const SkDeque& d) { + this->INHERITED::reset(d, kFront_IterStart); + } + + private: + typedef Iter INHERITED; + }; + +private: + // allow unit test to call numBlocksAllocated + friend class DequeUnitTestHelper; + + void* fFront; + void* fBack; + + Block* fFrontBlock; + Block* fBackBlock; + size_t fElemSize; + void* fInitialStorage; + int fCount; // number of elements in the deque + int fAllocCount; // number of elements to allocate per block + + Block* allocateBlock(int allocCount); + void freeBlock(Block* block); + + /** + * This returns the number of chunk blocks allocated by the deque. It + * can be used to gauge the effectiveness of the selected allocCount. + */ + int numBlocksAllocated() const; +}; + +#endif diff --git a/core/SkDevice.h b/core/SkDevice.h new file mode 100644 index 0000000..f39e5dd --- /dev/null +++ b/core/SkDevice.h @@ -0,0 +1,468 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDevice_DEFINED +#define SkDevice_DEFINED + +#include "SkRefCnt.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkDeviceProperties.h" + +class SkClipStack; +class SkDraw; +struct SkIRect; +class SkMatrix; +class SkMetaData; +class SkRegion; + +class GrRenderTarget; + +class SK_API SkDevice : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkDevice) + + /** + * Construct a new device with the specified bitmap as its backend. It is + * valid for the bitmap to have no pixels associated with it. In that case, + * any drawing to this device will have no effect. + */ + SkDevice(const SkBitmap& bitmap); + + /** + * Construct a new device with the specified bitmap as its backend. It is + * valid for the bitmap to have no pixels associated with it. In that case, + * any drawing to this device will have no effect. + */ + SkDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties); + + /** + * Create a new raster device and have the pixels be automatically + * allocated. The rowBytes of the device will be computed automatically + * based on the config and the width. + * + * @param config The desired config for the pixels. If the request cannot + * be met, the closest matching support config will be used. + * @param width width (in pixels) of the device + * @param height height (in pixels) of the device + * @param isOpaque Set to true if it is known that all of the pixels will + * be drawn to opaquely. Used as an accelerator when drawing + * these pixels to another device. + */ + SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque = false); + + /** + * Create a new raster device and have the pixels be automatically + * allocated. The rowBytes of the device will be computed automatically + * based on the config and the width. + * + * @param config The desired config for the pixels. If the request cannot + * be met, the closest matching support config will be used. + * @param width width (in pixels) of the device + * @param height height (in pixels) of the device + * @param isOpaque Set to true if it is known that all of the pixels will + * be drawn to opaquely. Used as an accelerator when drawing + * these pixels to another device. + * @param deviceProperties Properties which affect compositing. + */ + SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque, + const SkDeviceProperties& deviceProperties); + + virtual ~SkDevice(); + + /** + * Creates a device that is of the same type as this device (e.g. SW-raster, + * GPU, or PDF). The backing store for this device is created automatically + * (e.g. offscreen pixels or FBO or whatever is appropriate). + * + * @param width width of the device to create + * @param height height of the device to create + * @param isOpaque performance hint, set to true if you know that you will + * draw into this device such that all of the pixels will + * be opaque. + */ + SkDevice* createCompatibleDevice(SkBitmap::Config config, + int width, int height, + bool isOpaque); + + SkMetaData& getMetaData(); + + enum Capabilities { + kGL_Capability = 0x1, //!< mask indicating GL support + kVector_Capability = 0x2, //!< mask indicating a vector representation + kAll_Capabilities = 0x3 + }; + virtual uint32_t getDeviceCapabilities() { return 0; } + + /** Return the width of the device (in pixels). + */ + virtual int width() const { return fBitmap.width(); } + /** Return the height of the device (in pixels). + */ + virtual int height() const { return fBitmap.height(); } + + /** Return the image properties of the device. */ + virtual const SkDeviceProperties& getDeviceProperties() const { + //Currently, all the properties are leaky. + return fLeakyProperties; + } + + /** + * Return the bounds of the device in the coordinate space of the root + * canvas. The root device will have its top-left at 0,0, but other devices + * such as those associated with saveLayer may have a non-zero origin. + */ + void getGlobalBounds(SkIRect* bounds) const; + + /** Returns true if the device's bitmap's config treats every pixels as + implicitly opaque. + */ + bool isOpaque() const { return fBitmap.isOpaque(); } + + /** Return the bitmap config of the device's pixels + */ + SkBitmap::Config config() const { return fBitmap.getConfig(); } + + /** 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); + + /** + * DEPRECATED: This will be made protected once WebKit stops using it. + * Instead use Canvas' writePixels method. + * + * Similar to draw sprite, this method will copy the pixels in bitmap onto + * the device, with the top/left corner specified by (x, y). The pixel + * values in the device are completely replaced: there is no blending. + * + * Currently if bitmap is backed by a texture this is a no-op. This may be + * relaxed in the future. + * + * If the bitmap has config kARGB_8888_Config then the config8888 param + * will determines how the pixel valuess are intepreted. If the bitmap is + * not kARGB_8888_Config then this parameter is ignored. + */ + virtual void writePixels(const SkBitmap& bitmap, int x, int y, + SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888); + + /** + * Return the device's associated gpu render target, or NULL. + */ + virtual GrRenderTarget* accessRenderTarget() { return NULL; } + + + /** + * Return the device's origin: its offset in device coordinates from + * the default origin in its canvas' matrix/clip + */ + const SkIPoint& getOrigin() const { return fOrigin; } + + /** + * onAttachToCanvas is invoked whenever a device is installed in a canvas + * (i.e., setDevice, saveLayer (for the new device created by the save), + * and SkCanvas' SkDevice & SkBitmap -taking ctors). It allows the + * devices to prepare for drawing (e.g., locking their pixels, etc.) + */ + virtual void onAttachToCanvas(SkCanvas*) { + SkASSERT(!fAttachedToCanvas); + this->lockPixels(); +#ifdef SK_DEBUG + fAttachedToCanvas = true; +#endif + }; + + /** + * onDetachFromCanvas notifies a device that it will no longer be drawn to. + * It gives the device a chance to clean up (e.g., unlock its pixels). It + * is invoked from setDevice (for the displaced device), restore and + * possibly from SkCanvas' dtor. + */ + virtual void onDetachFromCanvas() { + SkASSERT(fAttachedToCanvas); + this->unlockPixels(); +#ifdef SK_DEBUG + fAttachedToCanvas = false; +#endif + }; + +protected: + enum Usage { + kGeneral_Usage, + kSaveLayer_Usage // <! internal use only + }; + + struct TextFlags { + uint32_t fFlags; // SkPaint::getFlags() + SkPaint::Hinting fHinting; + }; + + /** + * Device may filter the text flags for drawing text here. If it wants to + * make a change to the specified values, it should write them into the + * textflags parameter (output) and return true. If the paint is fine as + * is, then ignore the textflags parameter and return false. + * + * The baseclass SkDevice filters based on its depth and blitters. + */ + virtual bool filterTextFlags(const SkPaint& paint, TextFlags*); + + /** + * + * DEPRECATED: This will be removed in a future change. Device subclasses + * should use the matrix and clip from the SkDraw passed to draw functions. + * + * 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. + * + * The clipstack is another view of the clip. It records the actual + * geometry that went into building the region. It is present for devices + * that want to parse it, but is not required: the region is a complete + * picture of the current clip. (i.e. if you regionize all of the geometry + * in the clipstack, you will arrive at an equivalent region to the one + * passed in). + */ + virtual void setMatrixClip(const SkMatrix&, const SkRegion&, + const SkClipStack&); + + /** Clears the entire device to the specified color (including alpha). + * Ignores the clip. + */ + virtual void clear(SkColor color); + + /** + * Deprecated name for clear. + */ + void eraseColor(SkColor eraseColor) { this->clear(eraseColor); } + + /** 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 drawOval(const SkDraw&, const SkRect& oval, + const SkPaint& paint); + virtual void drawRRect(const SkDraw&, const SkRRect& rr, + const SkPaint& paint); + + /** + * If pathIsMutable, then the implementation is allowed to cast path to a + * non-const pointer and modify it in place (as an optimization). Canvas + * may do this to implement helpers such as drawOval, by placing a temp + * path on the stack to hold the representation of the oval. + * + * If prePathMatrix is not null, it should logically be applied before any + * stroking or other effects. If there are no effects on the paint that + * affect the geometry/rasterization, then the pre matrix can just be + * pre-concated with the current matrix. + */ + virtual void drawPath(const SkDraw&, const SkPath& path, + const SkPaint& paint, + const SkMatrix* prePathMatrix = NULL, + bool pathIsMutable = false); + 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); + + /** + * The default impl. will create a bitmap-shader from the bitmap, + * and call drawRect with it. + */ + virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, + const SkRect* srcOrNull, const SkRect& dst, + const SkPaint& paint); + + /** + * Does not handle text decoration. + * Decorations (underline and stike-thru) will be handled by SkCanvas. + */ + 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); +#ifdef SK_BUILD_FOR_ANDROID + virtual void drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, + const SkPoint pos[], const SkPaint& paint, + const SkPath& path, const SkMatrix* matrix); +#endif + 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); + /** The SkDevice passed will be an SkDevice which was returned by a call to + onCreateCompatibleDevice on this device with kSaveLayer_Usage. + */ + virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&); + + /** + * On success (returns true), copy the device pixels into the bitmap. + * On failure, the bitmap parameter is left unchanged and false is + * returned. + * + * The device's pixels are converted to the bitmap's config. The only + * supported config is kARGB_8888_Config, though this is likely to be + * relaxed in the future. The meaning of config kARGB_8888_Config is + * modified by the enum param config8888. The default value interprets + * kARGB_8888_Config as SkPMColor + * + * If the bitmap has pixels already allocated, the device pixels will be + * written there. If not, bitmap->allocPixels() will be called + * automatically. If the bitmap is backed by a texture readPixels will + * fail. + * + * The actual pixels written is the intersection of the device's bounds, + * and the rectangle formed by the bitmap's width,height and the specified + * x,y. If bitmap pixels extend outside of that intersection, they will not + * be modified. + * + * Other failure conditions: + * * If the device is not a raster device (e.g. PDF) then readPixels will + * fail. + * * If bitmap is texture-backed then readPixels will fail. (This may be + * relaxed in the future.) + */ + bool readPixels(SkBitmap* bitmap, + int x, int y, + SkCanvas::Config8888 config8888); + + /////////////////////////////////////////////////////////////////////////// + + /** 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. + @param bitmap The device's bitmap + @return Echo the bitmap parameter, or an alternate (shadow) bitmap + maintained by the subclass. + */ + virtual const SkBitmap& onAccessBitmap(SkBitmap*); + + SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); } + // just for subclasses, to assign a custom pixelref + SkPixelRef* setPixelRef(SkPixelRef* pr, size_t offset) { + fBitmap.setPixelRef(pr, offset); + return pr; + } + + /** + * Implements readPixels API. The caller will ensure that: + * 1. bitmap has pixel config kARGB_8888_Config. + * 2. bitmap has pixels. + * 3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is + * contained in the device bounds. + */ + virtual bool onReadPixels(const SkBitmap& bitmap, + int x, int y, + SkCanvas::Config8888 config8888); + + /** 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(); + + /** + * Returns true if the device allows processing of this imagefilter. If + * false is returned, then the filter is ignored. This may happen for + * some subclasses that do not support pixel manipulations after drawing + * has occurred (e.g. printing). The default implementation returns true. + */ + virtual bool allowImageFilter(SkImageFilter*); + + /** + * Override and return true for filters that the device can handle + * intrinsically. Doing so means that SkCanvas will pass-through this + * filter to drawSprite and drawDevice (and potentially filterImage). + * Returning false means the SkCanvas will have apply the filter itself, + * and just pass the resulting image to the device. + */ + virtual bool canHandleImageFilter(SkImageFilter*); + + /** + * Related (but not required) to canHandleImageFilter, this method returns + * true if the device could apply the filter to the src bitmap and return + * the result (and updates offset as needed). + * If the device does not recognize or support this filter, + * it just returns false and leaves result and offset unchanged. + */ + virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&, + SkBitmap* result, SkIPoint* offset); + + // This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if + // either is identical to kNative_Premul_Config8888. Otherwise, -1. + static const SkCanvas::Config8888 kPMColorAlias; + +private: + friend class SkCanvas; + friend struct DeviceCM; //for setMatrixClip + friend class SkDraw; + friend class SkDrawIter; + friend class SkDeviceFilteredPaint; + friend class SkDeviceImageFilterProxy; + + friend class SkSurface_Raster; + // used to change the backend's pixels (and possibly config/rowbytes) + // but cannot change the width/height, so there should be no change to + // any clip information. + void replaceBitmapBackendForRasterSurface(const SkBitmap&); + + // just called by SkCanvas when built as a layer + void setOrigin(int x, int y) { fOrigin.set(x, y); } + // just called by SkCanvas for saveLayer + SkDevice* createCompatibleDeviceForSaveLayer(SkBitmap::Config config, + int width, int height, + bool isOpaque); + + /** + * Subclasses should override this to implement createCompatibleDevice. + */ + virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config, + int width, int height, + bool isOpaque, + Usage usage); + + /** Causes any deferred drawing to the device to be completed. + */ + virtual void flush() {} + + SkBitmap fBitmap; + SkIPoint fOrigin; + SkMetaData* fMetaData; + /** + * Leaky properties are those which the device should be applying but it isn't. + * These properties will be applied by the draw, when and as it can. + * If the device does handle a property, that property should be set to the identity value + * for that property, effectively making it non-leaky. + */ + SkDeviceProperties fLeakyProperties; + +#ifdef SK_DEBUG + bool fAttachedToCanvas; +#endif + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkDeviceProperties.h b/core/SkDeviceProperties.h new file mode 100644 index 0000000..fd573f4 --- /dev/null +++ b/core/SkDeviceProperties.h @@ -0,0 +1,112 @@ +#ifndef SkDeviceProperties_DEFINED +#define SkDeviceProperties_DEFINED + +#ifndef SK_GAMMA_EXPONENT + #define SK_GAMMA_EXPONENT (2.2f) +#endif + +#ifdef SK_GAMMA_SRGB + #undef SK_GAMMA_EXPONENT + #define SK_GAMMA_EXPONENT (0.0f) +#endif + +//TODO: get everyone to stop using SkFontLCDConfig::SetSubpixel* and remove this import. +#include "SkFontLCDConfig.h" + +struct SkDeviceProperties { + struct Geometry { + /** The orientation of the pixel specifies the interpretation of the + * layout. If the orientation is horizontal, the layout is interpreted as + * left to right. It the orientation is vertical, the layout is + * interpreted top to bottom (rotated 90deg cw from horizontal). + */ + enum Orientation { + kUnknown_Orientation = 0x0, + kKnown_Orientation = 0x2, + + kHorizontal_Orientation = 0x2, //!< this is the default + kVertical_Orientation = 0x3, + + kOrientationMask = 0x3, + }; + + /** The layout of the pixel specifies its subpixel geometry. + * + * kUnknown_Layout means that the subpixel elements are not spatially + * separated in any known or usable fashion. + */ + enum Layout { + kUnknown_Layout = 0x0, + kKnown_Layout = 0x8, + + kRGB_Layout = 0x8, //!< this is the default + kBGR_Layout = 0xC, + + kLayoutMask = 0xC, + }; + + Orientation getOrientation() { + return static_cast<Orientation>(fGeometry & kOrientationMask); + } + Layout getLayout() { + return static_cast<Layout>(fGeometry & kLayoutMask); + } + + bool isOrientationKnown() { + return SkToBool(fGeometry & kKnown_Orientation); + } + bool isLayoutKnown() { + return SkToBool(fGeometry & kKnown_Layout); + } + + private: + //TODO: get everyone to stop using SkFontLCDConfig::SetSubpixel* and replace these calls with constants. + static Orientation fromOldOrientation(SkFontLCDConfig::LCDOrientation orientation) { + switch (orientation) { + case SkFontLCDConfig::kHorizontal_LCDOrientation: return kHorizontal_Orientation; + case SkFontLCDConfig::kVertical_LCDOrientation: return kVertical_Orientation; + default: return kUnknown_Orientation; + } + } + static Layout fromOldLayout(SkFontLCDConfig::LCDOrder order) { + switch (order) { + case SkFontLCDConfig::kRGB_LCDOrder: return kRGB_Layout; + case SkFontLCDConfig::kBGR_LCDOrder: return kBGR_Layout; + default: return kUnknown_Layout; + } + } + public: + static Geometry MakeDefault() { + Orientation orientation = fromOldOrientation(SkFontLCDConfig::GetSubpixelOrientation()); //kHorizontal_Orientation + Layout layout = fromOldLayout(SkFontLCDConfig::GetSubpixelOrder()); //kRGB_Layout + Geometry ret = { SkToU8(orientation | layout) }; + return ret; + } + + static Geometry Make(Orientation orientation, Layout layout) { + Geometry ret = { SkToU8(orientation | layout) }; + return ret; + } + + uint8_t fGeometry; + }; + + static SkDeviceProperties MakeDefault() { + SkDeviceProperties ret = { Geometry::MakeDefault(), SK_GAMMA_EXPONENT }; + return ret; + } + + static SkDeviceProperties Make(Geometry geometry, SkScalar gamma) { + SkDeviceProperties ret = { geometry, gamma }; + return ret; + } + + /** Each pixel of an image will have some number of channels. + * Can the layout of those channels be exploited? */ + Geometry fGeometry; + + /** Represents the color space of the image. This is a woefully inadequate beginning. */ + SkScalar fGamma; +}; + +#endif diff --git a/core/SkDither.h b/core/SkDither.h new file mode 100644 index 0000000..d82b416 --- /dev/null +++ b/core/SkDither.h @@ -0,0 +1,198 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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/core/SkDocument.h b/core/SkDocument.h new file mode 100644 index 0000000..bbed64a --- /dev/null +++ b/core/SkDocument.h @@ -0,0 +1,98 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDocument_DEFINED +#define SkDocument_DEFINED + +#include "SkRect.h" +#include "SkRefCnt.h" + +class SkCanvas; +class SkWStream; + +/** + * High-level API for creating a document-based canvas. To use.. + * + * 1. Create a document, specifying a stream to store the output. + * 2. For each "page" of content: + * a. canvas = doc->beginPage(...) + * b. draw_my_content(canvas); + * c. doc->endPage(); + * 3. Close the document with doc->close(). + */ +class SkDocument : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkDocument) + + /** + * Create a PDF-backed document, writing the results into a file. + * If there is an error trying to create the doc, returns NULL. + */ + static SkDocument* CreatePDF(const char filename[]); + + /** + * Create a PDF-backed document, writing the results into a stream. + * If there is an error trying to create the doc, returns NULL. + * + * The document may write to the stream at anytime during its lifetime, + * until either close() is called or the document is deleted. Once close() + * has been called, and all of the data has been written to the stream, + * if there is a Done proc provided, it will be called with the stream. + * The proc can delete the stream, or whatever it needs to do. + */ + static SkDocument* CreatePDF(SkWStream*, void (*Done)(SkWStream*) = NULL); + + /** + * Begin a new page for the document, returning the canvas that will draw + * into the page. The document owns this canvas, and it will go out of + * scope when endPage() or close() is called, or the document is deleted. + */ + SkCanvas* beginPage(SkScalar width, SkScalar height, + const SkRect* content = NULL); + + /** + * Call endPage() when the content for the current page has been drawn + * (into the canvas returned by beginPage()). After this call the canvas + * returned by beginPage() will be out-of-scope. + */ + void endPage(); + + /** + * Call close() when all pages have been drawn. This will close the file + * or stream holding the document's contents. After close() the document + * can no longer add new pages. Deleting the document will automatically + * call close() if need be. + */ + void close(); + +protected: + SkDocument(SkWStream*, void (*)(SkWStream*)); + // note: subclasses must call close() in their destructor, as the base class + // cannot do this for them. + virtual ~SkDocument(); + + virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height, + const SkRect& content) = 0; + virtual void onEndPage() = 0; + virtual void onClose(SkWStream*) = 0; + + enum State { + kBetweenPages_State, + kInPage_State, + kClosed_State + }; + State getState() const { return fState; } + +private: + SkWStream* fStream; + void (*fDoneProc)(SkWStream*); + State fState; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkDraw.h b/core/SkDraw.h new file mode 100644 index 0000000..8642f0a --- /dev/null +++ b/core/SkDraw.h @@ -0,0 +1,141 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDraw_DEFINED +#define SkDraw_DEFINED + +#include "SkCanvas.h" +#include "SkMask.h" +#include "SkPaint.h" + +class SkBitmap; +class SkBounder; +class SkClipStack; +class SkDevice; +class SkMatrix; +class SkPath; +class SkRegion; +class SkRasterClip; +struct SkDrawProcs; +struct SkRect; + +class SkDraw { +public: + SkDraw(); + SkDraw(const SkDraw& src); + + void drawPaint(const SkPaint&) const; + void drawPoints(SkCanvas::PointMode, size_t count, const SkPoint[], + const SkPaint&, bool forceUseDevice = false) 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. + * + * If prePathMatrix is not null, it should logically be applied before any + * stroking or other effects. If there are no effects on the paint that + * affect the geometry/rasterization, then the pre matrix can just be + * pre-concated with the current matrix. + */ + 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; +#ifdef SK_BUILD_FOR_ANDROID + void drawPosTextOnPath(const char text[], size_t byteLength, + const SkPoint pos[], const SkPaint& paint, + const SkPath& path, const SkMatrix* matrix) const; +#endif + 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, + const SkMaskFilter*, const SkMatrix* filterMatrix, + SkMask* mask, SkMask::CreateMode mode, + SkPaint::Style style); + + enum RectType { + kHair_RectType, + kFill_RectType, + kStroke_RectType, + kPath_RectType + }; + + /** + * Based on the paint's style, strokeWidth, and the matrix, classify how + * to draw the rect. If no special-case is available, returns + * kPath_RectType. + * + * Iff RectType == kStroke_RectType, then strokeSize is set to the device + * width and height of the stroke. + */ + static RectType ComputeRectType(const SkPaint&, const SkMatrix&, + SkPoint* strokeSize); + +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; + + void drawPosText_asPaths(const char text[], size_t byteLength, + const SkScalar pos[], SkScalar constY, + int scalarsPerPosition, const SkPaint&) const; + + /** + * Return the current clip bounds, in local coordinates, with slop to account + * for antialiasing or hairlines (i.e. device-bounds outset by 1, and then + * run through the inverse of the matrix). + * + * If the matrix cannot be inverted, or the current clip is empty, return + * false and ignore bounds parameter. + */ + bool SK_WARN_UNUSED_RESULT + computeConservativeLocalClipBounds(SkRect* bounds) const; + + static bool ShouldDrawTextAsPaths(const SkPaint&, const SkMatrix&); + +public: + const SkBitmap* fBitmap; // required + const SkMatrix* fMatrix; // required + const SkRegion* fClip; // DEPRECATED + const SkRasterClip* fRC; // required + + const SkClipStack* fClipStack; // optional + SkDevice* fDevice; // optional + SkBounder* fBounder; // optional + SkDrawProcs* fProcs; // optional + +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif +}; + +#endif diff --git a/core/SkDrawFilter.h b/core/SkDrawFilter.h new file mode 100644 index 0000000..52cbba9 --- /dev/null +++ b/core/SkDrawFilter.h @@ -0,0 +1,55 @@ + +/* + * Copyright 2011 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDrawFilter_DEFINED +#define SkDrawFilter_DEFINED + +#include "SkRefCnt.h" + +class SkCanvas; +class SkPaint; + +/** + * Right before something is being draw, filter() is called with the + * paint. The filter may modify the paint as it wishes, which will then be + * used for the actual drawing. Note: this modification only lasts for the + * current draw, as a temporary copy of the paint is used. + */ +class SK_API SkDrawFilter : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkDrawFilter) + + enum Type { + kPaint_Type, + kPoint_Type, + kLine_Type, + kBitmap_Type, + kRect_Type, + kRRect_Type, + kOval_Type, + kPath_Type, + kText_Type, + }; + + enum { + kTypeCount = kText_Type + 1 + }; + + /** + * Called with the paint that will be used to draw the specified type. + * The implementation may modify the paint as they wish. If filter() + * returns false, the draw will be skipped. + */ + virtual bool filter(SkPaint*, Type) = 0; + +private: + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkDrawLooper.h b/core/SkDrawLooper.h new file mode 100644 index 0000000..2faf28b --- /dev/null +++ b/core/SkDrawLooper.h @@ -0,0 +1,76 @@ + +/* + * Copyright 2011 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDrawLooper_DEFINED +#define SkDrawLooper_DEFINED + +#include "SkFlattenable.h" + +class SkCanvas; +class SkPaint; +struct SkRect; +class SkString; + +/** \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 SK_API SkDrawLooper : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkDrawLooper) + + /** + * Called right before something is being drawn. This will be followed by + * calls to next() until next() returns false. + */ + virtual void init(SkCanvas*) = 0; + + /** + * 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. + * + * On each call, the paint will be in its original state, but the canvas + * will be as it was following the previous call to next() or init(). + * + * The implementation must ensure that, when next() finally returns false, + * that the canvas has been restored to the state it was initially, before + * init() was first called. + */ + virtual bool next(SkCanvas*, SkPaint* paint) = 0; + + /** + * The fast bounds functions are used to enable the paint to be culled early + * in the drawing pipeline. If a subclass can support this feature it must + * return true for the canComputeFastBounds() function. If that function + * returns false then computeFastBounds behavior is undefined otherwise it + * is expected to have the following behavior. Given the parent paint and + * the parent's bounding rect the subclass must fill in and return the + * storage rect, where the storage rect is with the union of the src rect + * and the looper's bounding rect. + */ + virtual bool canComputeFastBounds(const SkPaint& paint); + virtual void computeFastBounds(const SkPaint& paint, + const SkRect& src, SkRect* dst); + + SkDEVCODE(virtual void toString(SkString* str) const = 0;) + +protected: + SkDrawLooper() {} + SkDrawLooper(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkEmptyShader.h b/core/SkEmptyShader.h new file mode 100644 index 0000000..08c131d --- /dev/null +++ b/core/SkEmptyShader.h @@ -0,0 +1,43 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkEmptyShader_DEFINED +#define SkEmptyShader_DEFINED + +#include "SkShader.h" + +/** + * \class SkEmptyShader + * A Shader that always draws nothing. Its setContext always returns false, + * so it never expects that its shadeSpan() methods will get called. + */ +class SK_API SkEmptyShader : public SkShader { +public: + SkEmptyShader() {} + + virtual uint32_t getFlags() SK_OVERRIDE; + virtual uint8_t getSpan16Alpha() const SK_OVERRIDE; + virtual bool setContext(const SkBitmap&, const SkPaint&, + const SkMatrix&) SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader) + +protected: + SkEmptyShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + typedef SkShader INHERITED; +}; + +#endif diff --git a/core/SkEndian.h b/core/SkEndian.h new file mode 100644 index 0000000..6eba297 --- /dev/null +++ b/core/SkEndian.h @@ -0,0 +1,195 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 +*/ +static inline uint16_t SkEndianSwap16(U16CPU value) { + SkASSERT(value == (uint16_t)value); + return static_cast<uint16_t>((value >> 8) | (value << 8)); +} +template<uint16_t N> struct SkTEndianSwap16 { + static const uint16_t value = static_cast<uint16_t>((N >> 8) | ((N & 0xFF) << 8)); +}; + +/** Vector version of SkEndianSwap16(), which swaps the + low two bytes of each value in the array. +*/ +static 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 +*/ +static inline uint32_t SkEndianSwap32(uint32_t value) { + return ((value & 0xFF) << 24) | + ((value & 0xFF00) << 8) | + ((value & 0xFF0000) >> 8) | + (value >> 24); +} +template<uint32_t N> struct SkTEndianSwap32 { + static const uint32_t value = ((N & 0xFF) << 24) | + ((N & 0xFF00) << 8) | + ((N & 0xFF0000) >> 8) | + (N >> 24); +}; + +/** Vector version of SkEndianSwap32(), which swaps the + bytes of each value in the array. +*/ +static inline void SkEndianSwap32s(uint32_t array[], int count) { + SkASSERT(count == 0 || array != NULL); + + while (--count >= 0) { + *array = SkEndianSwap32(*array); + array += 1; + } +} + +/** Reverse all 8 bytes in a 64bit value. + e.g. 0x1122334455667788 -> 0x8877665544332211 +*/ +static inline uint64_t SkEndianSwap64(uint64_t value) { + return (((value & 0x00000000000000FFULL) << (8*7)) | + ((value & 0x000000000000FF00ULL) << (8*5)) | + ((value & 0x0000000000FF0000ULL) << (8*3)) | + ((value & 0x00000000FF000000ULL) << (8*1)) | + ((value & 0x000000FF00000000ULL) >> (8*1)) | + ((value & 0x0000FF0000000000ULL) >> (8*3)) | + ((value & 0x00FF000000000000ULL) >> (8*5)) | + ((value) >> (8*7))); +} +template<uint64_t N> struct SkTEndianSwap64 { + static const uint64_t value = (((N & 0x00000000000000FFULL) << (8*7)) | + ((N & 0x000000000000FF00ULL) << (8*5)) | + ((N & 0x0000000000FF0000ULL) << (8*3)) | + ((N & 0x00000000FF000000ULL) << (8*1)) | + ((N & 0x000000FF00000000ULL) >> (8*1)) | + ((N & 0x0000FF0000000000ULL) >> (8*3)) | + ((N & 0x00FF000000000000ULL) >> (8*5)) | + ((N) >> (8*7))); +}; + +/** Vector version of SkEndianSwap64(), which swaps the + bytes of each value in the array. +*/ +static inline void SkEndianSwap64s(uint64_t array[], int count) { + SkASSERT(count == 0 || array != NULL); + + while (--count >= 0) { + *array = SkEndianSwap64(*array); + array += 1; + } +} + +#ifdef SK_CPU_LENDIAN + #define SkEndian_SwapBE16(n) SkEndianSwap16(n) + #define SkEndian_SwapBE32(n) SkEndianSwap32(n) + #define SkEndian_SwapBE64(n) SkEndianSwap64(n) + #define SkEndian_SwapLE16(n) (n) + #define SkEndian_SwapLE32(n) (n) + #define SkEndian_SwapLE64(n) (n) + + #define SkTEndian_SwapBE16(n) SkTEndianSwap16<n>::value + #define SkTEndian_SwapBE32(n) SkTEndianSwap32<n>::value + #define SkTEndian_SwapBE64(n) SkTEndianSwap64<n>::value + #define SkTEndian_SwapLE16(n) (n) + #define SkTEndian_SwapLE32(n) (n) + #define SkTEndian_SwapLE64(n) (n) +#else // SK_CPU_BENDIAN + #define SkEndian_SwapBE16(n) (n) + #define SkEndian_SwapBE32(n) (n) + #define SkEndian_SwapBE64(n) (n) + #define SkEndian_SwapLE16(n) SkEndianSwap16(n) + #define SkEndian_SwapLE32(n) SkEndianSwap32(n) + #define SkEndian_SwapLE64(n) SkEndianSwap64(n) + + #define SkTEndian_SwapBE16(n) (n) + #define SkTEndian_SwapBE32(n) (n) + #define SkTEndian_SwapBE64(n) (n) + #define SkTEndian_SwapLE16(n) SkTEndianSwap16<n>::value + #define SkTEndian_SwapLE32(n) SkTEndianSwap32<n>::value + #define SkTEndian_SwapLE64(n) SkTEndianSwap64<n>::value +#endif + +// When a bytestream is embedded in a 32-bit word, how far we need to +// shift the word to extract each byte from the low 8 bits by anding with 0xff. +#ifdef SK_CPU_LENDIAN + #define SkEndian_Byte0Shift 0 + #define SkEndian_Byte1Shift 8 + #define SkEndian_Byte2Shift 16 + #define SkEndian_Byte3Shift 24 +#else // SK_CPU_BENDIAN + #define SkEndian_Byte0Shift 24 + #define SkEndian_Byte1Shift 16 + #define SkEndian_Byte2Shift 8 + #define SkEndian_Byte3Shift 0 +#endif + + +#if defined(SK_UINT8_BITFIELD_LENDIAN) && defined(SK_UINT8_BITFIELD_BENDIAN) + #error "can't have both bitfield LENDIAN and BENDIAN defined" +#endif + +#if !defined(SK_UINT8_BITFIELD_LENDIAN) && !defined(SK_UINT8_BITFIELD_BENDIAN) + #ifdef SK_CPU_LENDIAN + #define SK_UINT8_BITFIELD_LENDIAN + #else + #define SK_UINT8_BITFIELD_BENDIAN + #endif +#endif + +#ifdef SK_UINT8_BITFIELD_LENDIAN + #define SK_UINT8_BITFIELD(f0, f1, f2, f3, f4, f5, f6, f7) \ + SK_OT_BYTE f0 : 1; \ + SK_OT_BYTE f1 : 1; \ + SK_OT_BYTE f2 : 1; \ + SK_OT_BYTE f3 : 1; \ + SK_OT_BYTE f4 : 1; \ + SK_OT_BYTE f5 : 1; \ + SK_OT_BYTE f6 : 1; \ + SK_OT_BYTE f7 : 1; +#else + #define SK_UINT8_BITFIELD(f0, f1, f2, f3, f4, f5, f6, f7) \ + SK_OT_BYTE f7 : 1; \ + SK_OT_BYTE f6 : 1; \ + SK_OT_BYTE f5 : 1; \ + SK_OT_BYTE f4 : 1; \ + SK_OT_BYTE f3 : 1; \ + SK_OT_BYTE f2 : 1; \ + SK_OT_BYTE f1 : 1; \ + SK_OT_BYTE f0 : 1; +#endif + +#endif diff --git a/core/SkError.h b/core/SkError.h new file mode 100644 index 0000000..c5af460 --- /dev/null +++ b/core/SkError.h @@ -0,0 +1,86 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkError_DEFINED +#define SkError_DEFINED + + +/** \file SkError.h +*/ + +enum SkError { + /** All is well + */ + kNoError_SkError=0, + + /** User argument passed to Skia function was invalid: NULL when that’s + * not allowed, out of numeric range, bad enum, or violating some + * other general precondition. + */ + kInvalidArgument_SkError, + + /** User tried to perform some operation in a state when the operation + * was not legal, or the operands make no sense (e.g., asking for + * pixels from an SkPictureCanvas). Other examples might be + * inset()’ing a rectangle to make it degenerate (negative width/height). + */ + kInvalidOperation_SkError, + + /** Probably not needed right now, but in the future we could have opaque + * handles for SkPictures floating around, and it would be a good idea + * to anticipate this kind of issue. + */ + kInvalidHandle_SkError, + + /** This is probably not possible because paint surely has defaults for + * everything, but perhaps a paint can get into a bad state somehow. + */ + kInvalidPaint_SkError, + + /** Skia was unable to allocate memory to perform some task. + */ + kOutOfMemory_SkError, + + /** Skia failed while trying to consume some external resource. + */ + kParseError_SkError +}; + +/** Return the current per-thread error code. Error codes are "sticky"; they + * are not not reset by subsequent successful operations. + */ +SkError SkGetLastError(); + +/** Clear the current per-thread error code back to kNoError_SkError. + */ +void SkClearLastError(); + +/** Type for callback functions to be invoked whenever an error is registered. + * Callback functions take the error code being set, as well as a context + * argument that is provided when the callback is registered. + */ +typedef void (*SkErrorCallbackFunction)(SkError, void *); + +/** Set the current per-thread error callback. + * + * @param cb The callback function to be invoked. Passing NULL + * for cb will revert to the default error callback which + * does nothing on release builds, but on debug builds will + * print an informative error message to the screen. + * @param context An arbitrary pointer that will be passed to + * the provided callback function. + */ +void SkSetErrorCallback(SkErrorCallbackFunction cb, void *context); + +/** Get a human-readable description of the last (per-thread) error that + * occurred. The returned error message will include not only a human + * readable version of the error code, but also information about the + * conditions that led to the error itself. + */ +const char *SkGetLastErrorString(); + +#endif /* SkError_DEFINED */ diff --git a/core/SkFixed.h b/core/SkFixed.h new file mode 100644 index 0000000..acfbe9a --- /dev/null +++ b/core/SkFixed.h @@ -0,0 +1,291 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 (-SK_FixedMax) +#define SK_FixedNaN ((int) 0x80000000) +#define SK_FixedPI (0x3243F) +#define SK_FixedSqrt2 (92682) +#define SK_FixedTanPIOver8 (0x6A0A) +#define SK_FixedRoot2Over2 (0xB505) + +#define SkFixedToFloat(x) ((x) * 1.5258789e-5f) +#if 1 + #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1)) +#else + // pins over/under flows to max/min int32 (slower than just a cast) + static inline SkFixed SkFloatToFixed(float x) { + int64_t n = x * SK_Fixed1; + return (SkFixed)n; + } +#endif + +#ifdef SK_DEBUG + static inline SkFixed SkFloatToFixed_Check(float x) { + int64_t n64 = (int64_t)(x * SK_Fixed1); + SkFixed n32 = (SkFixed)n64; + SkASSERT(n64 == n32); + return n32; + } +#else + #define SkFloatToFixed_Check(x) SkFloatToFixed(x) +#endif + +#define SkFixedToDouble(x) ((x) * 1.5258789e-5) +#define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) + +/** 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) + +#define SkFractToFloat(x) ((float)(x) * 0.00000000093132257f) +#define SkFloatToFract(x) ((SkFract)((x) * SK_Fract1)) + +/** 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) + +#define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) +#define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) +#define SkFixedFloorToInt(x) ((x) >> 16) + +#define SkFixedRoundToFixed(x) (((x) + SK_FixedHalf) & 0xFFFF0000) +#define SkFixedCeilToFixed(x) (((x) + SK_Fixed1 - 1) & 0xFFFF0000) +#define SkFixedFloorToFixed(x) ((x) & 0xFFFF0000) + +// DEPRECATED +#define SkFixedFloor(x) SkFixedFloorToInt(x) +#define SkFixedCeil(x) SkFixedCeilToInt(x) +#define SkFixedRound(x) SkFixedRoundToInt(x) + +#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; + SkFixed result = ah * a + al * ah + (al * al >> 16); + if (result >= 0) + return result; + else // Overflow. + return SK_FixedMax; +} + +#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 (SkFract)((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(SK_CPU_ARM) + /* This guy does not handle NaN or other obscurities, but is faster than + than (int)(x*65536) + */ + 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" + "it cs \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 + +/////////////////////////////////////////////////////////////////////////////// + +typedef int64_t SkFixed48; + +#define SkIntToFixed48(x) ((SkFixed48)(x) << 48) +#define SkFixed48ToInt(x) ((int)((x) >> 48)) +#define SkFixedToFixed48(x) ((SkFixed48)(x) << 32) +#define SkFixed48ToFixed(x) ((SkFixed)((x) >> 32)) +#define SkFloatToFixed48(x) ((SkFixed48)((x) * (65536.0f * 65536.0f * 65536.0f))) + +#ifdef SK_SCALAR_IS_FLOAT + #define SkScalarToFixed48(x) SkFloatToFixed48(x) +#else + #define SkScalarToFixed48(x) SkFixedToFixed48(x) +#endif + +#endif diff --git a/core/SkFlate.h b/core/SkFlate.h new file mode 100644 index 0000000..e4c1417 --- /dev/null +++ b/core/SkFlate.h @@ -0,0 +1,52 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkFlate_DEFINED +#define SkFlate_DEFINED + +#include "SkTypes.h" + +class SkData; +class SkWStream; +class SkStream; + +/** \class SkFlate + A class to provide access to the flate compression algorithm. +*/ +class SkFlate { +public: + /** Indicates if the flate algorithm is available. + */ + static bool HaveFlate(); + + /** + * Use the flate compression algorithm to compress the data in src, + * putting the result into dst. Returns false if an error occurs. + */ + static bool Deflate(SkStream* src, SkWStream* dst); + + /** + * Use the flate compression algorithm to compress the data in src, + * putting the result into dst. Returns false if an error occurs. + */ + static bool Deflate(const void* src, size_t len, SkWStream* dst); + + /** + * Use the flate compression algorithm to compress the data, + * putting the result into dst. Returns false if an error occurs. + */ + static bool Deflate(const SkData*, SkWStream* dst); + + /** Use the flate compression algorithm to decompress the data in src, + putting the result into dst. Returns false if an error occurs. + */ + static bool Inflate(SkStream* src, SkWStream* dst); +}; + +#endif diff --git a/core/SkFlattenable.h b/core/SkFlattenable.h new file mode 100644 index 0000000..0b21abc --- /dev/null +++ b/core/SkFlattenable.h @@ -0,0 +1,86 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkFlattenable_DEFINED +#define SkFlattenable_DEFINED + +#include "SkRefCnt.h" + +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; + +#define SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(flattenable) \ + SkFlattenable::Registrar(#flattenable, flattenable::CreateProc); + +#define SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() static void InitializeFlattenables(); + +#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(flattenable) \ + void flattenable::InitializeFlattenables() { + +#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END \ + } + +#define SK_DECLARE_UNFLATTENABLE_OBJECT() \ + virtual Factory getFactory() SK_OVERRIDE { return NULL; }; \ + +#define SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(flattenable) \ + virtual Factory getFactory() SK_OVERRIDE { return CreateProc; } \ + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { \ + return SkNEW_ARGS(flattenable, (buffer)); \ + } + +/** \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 SK_API SkFlattenable : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkFlattenable) + + 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; + + 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&) {} + /** 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&) const; + +private: + static void InitializeFlattenables(); + + friend class SkGraphics; + friend class SkFlattenableWriteBuffer; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkFlattenableBuffers.h b/core/SkFlattenableBuffers.h new file mode 100644 index 0000000..03c03f3 --- /dev/null +++ b/core/SkFlattenableBuffers.h @@ -0,0 +1,175 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFlattenableBuffers_DEFINED +#define SkFlattenableBuffers_DEFINED + +#include "SkColor.h" +#include "SkPaint.h" +#include "SkPoint.h" + +class SkBitmap; +class SkFlattenable; +struct SkIRect; +class SkMatrix; +class SkOrderedReadBuffer; +class SkOrderedWriteBuffer; +class SkPath; +class SkPixelRef; +struct SkRect; +class SkRefCnt; +class SkRegion; +class SkStream; +class SkString; +class SkTypeface; +class SkWStream; + +class SkFlattenableReadBuffer { +public: + SkFlattenableReadBuffer(); + virtual ~SkFlattenableReadBuffer(); + + bool isOrderedBinaryBuffer() { return NULL != getOrderedBinaryBuffer(); } + virtual SkOrderedReadBuffer* getOrderedBinaryBuffer() { return NULL; } + + enum Flags { + kCrossProcess_Flag = 1 << 0, + kScalarIsFloat_Flag = 1 << 1, + kPtrIs64Bit_Flag = 1 << 2, + }; + + void setFlags(uint32_t flags) { fFlags = flags; } + uint32_t getFlags() const { return fFlags; } + + bool isCrossProcess() const { return SkToBool(fFlags & kCrossProcess_Flag); } + bool isScalarFloat() const { return SkToBool(fFlags & kScalarIsFloat_Flag); } + bool isPtr64Bit() const { return SkToBool(fFlags & kPtrIs64Bit_Flag); } + + // primitives + virtual bool readBool() = 0; + virtual SkColor readColor() = 0; + virtual SkFixed readFixed() = 0; + virtual int32_t readInt() = 0; + virtual SkScalar readScalar() = 0; + virtual uint32_t readUInt() = 0; + virtual int32_t read32() = 0; + + // strings -- the caller is responsible for freeing the string contents + virtual void readString(SkString* string) = 0; + virtual void* readEncodedString(size_t* length, SkPaint::TextEncoding encoding) = 0; + + // common data structures + virtual SkFlattenable* readFlattenable() = 0; + virtual void readPoint(SkPoint* point) = 0; + virtual void readMatrix(SkMatrix* matrix) = 0; + virtual void readIRect(SkIRect* rect) = 0; + virtual void readRect(SkRect* rect) = 0; + virtual void readRegion(SkRegion* region) = 0; + virtual void readPath(SkPath* path) = 0; + + // binary data and arrays + virtual uint32_t readByteArray(void* value) = 0; + virtual uint32_t readColorArray(SkColor* colors) = 0; + virtual uint32_t readIntArray(int32_t* values) = 0; + virtual uint32_t readPointArray(SkPoint* points) = 0; + virtual uint32_t readScalarArray(SkScalar* values) = 0; + + /** This helper peeks into the buffer and reports back the length of the next array in + * the buffer but does not change the state of the buffer. + */ + virtual uint32_t getArrayCount() = 0; + + // helper functions + virtual void* readFunctionPtr(); + virtual void readPaint(SkPaint* paint); + + virtual void readBitmap(SkBitmap* bitmap) = 0; + virtual SkTypeface* readTypeface() = 0; + + // helper function for classes with const SkPoint members + SkPoint readPoint() { + SkPoint point; + this->readPoint(&point); + return point; + } + + template <typename T> T* readFlattenableT() { + return static_cast<T*>(this->readFlattenable()); + } + +private: + uint32_t fFlags; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkFlattenableWriteBuffer { +public: + SkFlattenableWriteBuffer(); + virtual ~SkFlattenableWriteBuffer(); + + virtual bool isOrderedBinaryBuffer() { return false; } + virtual SkOrderedWriteBuffer* getOrderedBinaryBuffer() { sk_throw(); return NULL; } + + // primitives + virtual void writeByteArray(const void* data, size_t size) = 0; + virtual void writeBool(bool value) = 0; + virtual void writeFixed(SkFixed value) = 0; + virtual void writeScalar(SkScalar value) = 0; + virtual void writeScalarArray(const SkScalar* value, uint32_t count) = 0; + virtual void writeInt(int32_t value) = 0; + virtual void writeIntArray(const int32_t* value, uint32_t count) = 0; + virtual void writeUInt(uint32_t value) = 0; + virtual void write32(int32_t value) = 0; // printf in hex + virtual void writeString(const char* value) = 0; + virtual void writeEncodedString(const void* value, size_t byteLength, + SkPaint::TextEncoding encoding) = 0; + + // common data structures + virtual void writeFlattenable(SkFlattenable* flattenable) = 0; + virtual void writeColor(const SkColor& color) = 0; + virtual void writeColorArray(const SkColor* color, uint32_t count) = 0; + virtual void writePoint(const SkPoint& point) = 0; + virtual void writePointArray(const SkPoint* points, uint32_t count) = 0; + virtual void writeMatrix(const SkMatrix& matrix) = 0; + virtual void writeIRect(const SkIRect& rect) = 0; + virtual void writeRect(const SkRect& rect) = 0; + virtual void writeRegion(const SkRegion& region) = 0; + virtual void writePath(const SkPath& path) = 0; + virtual size_t writeStream(SkStream* stream, size_t length) = 0; + + // helper functions + virtual void writeFunctionPtr(void* ptr); + virtual void writePaint(const SkPaint& paint); + + virtual void writeBitmap(const SkBitmap& bitmap) = 0; + virtual void writeTypeface(SkTypeface* typeface) = 0; + + virtual bool writeToStream(SkWStream*) = 0; + + enum Flags { + kCrossProcess_Flag = 0x01, + }; + + uint32_t getFlags() const { return fFlags; } + void setFlags(uint32_t flags) { fFlags = flags; } + + bool isCrossProcess() const { + return SkToBool(fFlags & kCrossProcess_Flag); + } + + bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; } + +protected: + // A helper function so that each subclass does not have to be a friend of SkFlattenable + void flattenObject(SkFlattenable* obj, SkFlattenableWriteBuffer& buffer); + + uint32_t fFlags; +}; + +#endif diff --git a/core/SkFlattenableSerialization.h b/core/SkFlattenableSerialization.h new file mode 100644 index 0000000..2ed244c --- /dev/null +++ b/core/SkFlattenableSerialization.h @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFlattenableSerialization_DEFINED +#define SkFlattenableSerialization_DEFINED + +#include "SkTypes.h" + +class SkData; +class SkFlattenable; + +SK_API SkData* SkSerializeFlattenable(SkFlattenable*); +SK_API SkFlattenable* SkDeserializeFlattenable(const void* data, size_t size); + +#endif diff --git a/core/SkFloatBits.h b/core/SkFloatBits.h new file mode 100644 index 0000000..a1196ca --- /dev/null +++ b/core/SkFloatBits.h @@ -0,0 +1,138 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 + */ +SK_API 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 + */ +SK_API 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 + */ +SK_API int32_t SkFloatBits_toIntCeil(int32_t floatBits); + + +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)); +} + +// 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/core/SkFloatingPoint.h b/core/SkFloatingPoint.h new file mode 100644 index 0000000..44a3eef --- /dev/null +++ b/core/SkFloatingPoint.h @@ -0,0 +1,99 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkFloatingPoint_DEFINED +#define SkFloatingPoint_DEFINED + +#include "SkTypes.h" + +#include <math.h> +#include <float.h> +#include "SkFloatBits.h" + +// C++98 cmath std::pow seems to be the earliest portable way to get float pow. +// However, on Linux including cmath undefines isfinite. +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14608 +static inline float sk_float_pow(float base, float exp) { + return powf(base, exp); +} + +static inline float sk_float_copysign(float x, float y) { + int32_t xbits = SkFloat2Bits(x); + int32_t ybits = SkFloat2Bits(y); + return SkBits2Float((xbits & 0x7FFFFFFF) | (ybits & 0x80000000)); +} + +#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) static_cast<float>(acos(x)) + #define sk_float_asin(x) static_cast<float>(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) +#endif + +#ifdef SK_BUILD_FOR_WIN + #define sk_float_isfinite(x) _finite(x) + #define sk_float_isnan(x) _isnan(x) + static inline int sk_float_isinf(float x) { + int32_t bits = SkFloat2Bits(x); + return (bits << 1) == (0xFF << 24); + } +#else + #define sk_float_isfinite(x) isfinite(x) + #define sk_float_isnan(x) isnan(x) + #define sk_float_isinf(x) isinf(x) +#endif + +#define sk_double_isnan(a) sk_float_isnan(a) + +#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 + +extern const uint32_t gIEEENotANumber; +extern const uint32_t gIEEEInfinity; +extern const uint32_t gIEEENegativeInfinity; + +#define SK_FloatNaN (*SkTCast<const float*>(&gIEEENotANumber)) +#define SK_FloatInfinity (*SkTCast<const float*>(&gIEEEInfinity)) +#define SK_FloatNegativeInfinity (*SkTCast<const float*>(&gIEEENegativeInfinity)) +#endif diff --git a/core/SkFontHost.h b/core/SkFontHost.h new file mode 100644 index 0000000..e847b76 --- /dev/null +++ b/core/SkFontHost.h @@ -0,0 +1,133 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkFontHost_DEFINED +#define SkFontHost_DEFINED + +#include "SkTypeface.h" + +//#define SK_FONTHOST_USES_FONTMGR + +class SkDescriptor; +class SkScalerContext; +struct SkScalerContextRec; +class SkStream; +class SkWStream; + +/** \class SkFontHost + + This class is ported to each environment. It is responsible for bridging + the gap between the (sort of) abstract class SkTypeface and the + platform-specific implementation that provides access to font files. + + One basic task is for each create (subclass of) SkTypeface, the FontHost is + responsible for assigning a uniqueID. The ID should be unique for the + underlying font file/data, not unique per typeface instance. Thus it is + possible/common to request a typeface for the same font more than once + (e.g. asking for the same font by name several times). The FontHost may + return seperate typeface instances in that case, or it may choose to use a + cache and return the same instance (but calling typeface->ref(), since the + caller is always responsible for calling unref() on each instance that is + returned). Either way, the fontID for those instance(s) will be the same. + In addition, the fontID should never be set to 0. That value is used as a + sentinel to indicate no-font-id. + + The major aspects are: + 1) Given either a name/style, return a subclass of SkTypeface that + references the closest matching font available on the host system. + 2) Given the data for a font (either in a stream or a file name), return + a typeface that allows access to that data. + 3) Each typeface instance carries a 32bit ID for its corresponding font. + SkFontHost turns that ID into a stream to access the font's data. + 4) Given a font ID, return a subclass of SkScalerContext, which connects a + font scaler (e.g. freetype or other) to the font's data. + 5) Utilites to manage the font cache (budgeting) and gamma correction +*/ +class SK_API SkFontHost { +public: + /** LCDs either have their color elements arranged horizontally or + vertically. When rendering subpixel glyphs we need to know which way + round they are. + + Note, if you change this after startup, you'll need to flush the glyph + cache because it'll have the wrong type of masks cached. + + @deprecated use SkPixelGeometry instead. + */ + enum LCDOrientation { + kHorizontal_LCDOrientation = 0, //!< this is the default + kVertical_LCDOrientation = 1 + }; + + /** @deprecated set on Device creation. */ + static void SetSubpixelOrientation(LCDOrientation orientation); + /** @deprecated get from Device. */ + static LCDOrientation GetSubpixelOrientation(); + + /** LCD color elements can vary in order. For subpixel text we need to know + the order which the LCDs uses so that the color fringes are in the + correct place. + + Note, if you change this after startup, you'll need to flush the glyph + cache because it'll have the wrong type of masks cached. + + kNONE_LCDOrder means that the subpixel elements are not spatially + separated in any usable fashion. + + @deprecated use SkPixelGeometry instead. + */ + enum LCDOrder { + kRGB_LCDOrder = 0, //!< this is the default + kBGR_LCDOrder = 1, + kNONE_LCDOrder = 2 + }; + + /** @deprecated set on Device creation. */ + static void SetSubpixelOrder(LCDOrder order); + /** @deprecated get from Device. */ + static LCDOrder GetSubpixelOrder(); + +private: + /** Return a new, 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 familyName. + 2) If familyName is null, use data (UTF-16 to cover). + 3) If all are null, return the default font that best matches style + */ + static SkTypeface* CreateTypeface(const SkTypeface* familyFace, + const char familyName[], + SkTypeface::Style style); + + /** Return a new typeface given the data buffer. If the data does not + represent a valid font, returns null. + + If a typeface instance is returned, the caller is responsible for + calling unref() on the typeface when they are finished with it. + + The returned typeface may or may not have called ref() on the stream + parameter. If the typeface has not called ref(), then it may have made + a copy of the releveant data. In either case, the caller is still + responsible for its refcnt ownership of the stream. + */ + static SkTypeface* CreateTypefaceFromStream(SkStream*); + + /** Return a new typeface from the specified file path. If the file does not + represent a valid font, this returns null. If a typeface is returned, + the caller is responsible for calling unref() when it is no longer used. + */ + static SkTypeface* CreateTypefaceFromFile(const char path[]); + + /////////////////////////////////////////////////////////////////////////// + + friend class SkScalerContext; + friend class SkTypeface; +}; + +#endif diff --git a/core/SkFontLCDConfig.h b/core/SkFontLCDConfig.h new file mode 100644 index 0000000..03ee09f --- /dev/null +++ b/core/SkFontLCDConfig.h @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontLCDConfig_DEFINED +#define SkFontLCDConfig_DEFINED + +#include "SkTypes.h" + +class SkFontLCDConfig { +public: + /** LCDs either have their color elements arranged horizontally or + vertically. When rendering subpixel glyphs we need to know which way + round they are. + + Note, if you change this after startup, you'll need to flush the glyph + cache because it'll have the wrong type of masks cached. + + @deprecated use SkPixelGeometry instead. + */ + enum LCDOrientation { + kHorizontal_LCDOrientation = 0, //!< this is the default + kVertical_LCDOrientation = 1 + }; + + /** @deprecated set on Device creation. */ + static void SetSubpixelOrientation(LCDOrientation orientation); + /** @deprecated get from Device. */ + static LCDOrientation GetSubpixelOrientation(); + + /** LCD color elements can vary in order. For subpixel text we need to know + the order which the LCDs uses so that the color fringes are in the + correct place. + + Note, if you change this after startup, you'll need to flush the glyph + cache because it'll have the wrong type of masks cached. + + kNONE_LCDOrder means that the subpixel elements are not spatially + separated in any usable fashion. + + @deprecated use SkPixelGeometry instead. + */ + enum LCDOrder { + kRGB_LCDOrder = 0, //!< this is the default + kBGR_LCDOrder = 1, + kNONE_LCDOrder = 2 + }; + + /** @deprecated set on Device creation. */ + static void SetSubpixelOrder(LCDOrder order); + /** @deprecated get from Device. */ + static LCDOrder GetSubpixelOrder(); +}; + +#endif diff --git a/core/SkGeometry.h b/core/SkGeometry.h new file mode 100644 index 0000000..d7836db --- /dev/null +++ b/core/SkGeometry.h @@ -0,0 +1,307 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkGeometry_DEFINED +#define SkGeometry_DEFINED + +#include "SkMatrix.h" + +/** An XRay is a half-line that runs from the specific point/origin to + +infinity in the X direction. e.g. XRay(3,5) is the half-line + (3,5)....(infinity, 5) + */ +typedef SkPoint SkXRay; + +/** Given a line segment from pts[0] to pts[1], and an xray, return true if + they intersect. Optional outgoing "ambiguous" argument indicates + whether the answer is ambiguous because the query occurred exactly at + one of the endpoints' y coordinates, indicating that another query y + coordinate is preferred for robustness. +*/ +bool SkXRayCrossesLine(const SkXRay& pt, const SkPoint pts[2], + bool* ambiguous = NULL); + +/** Given a quadratic equation Ax^2 + Bx + C = 0, return 0, 1, 2 roots for the + equation. +*/ +int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]); + +/////////////////////////////////////////////////////////////////////////////// + +/** Set pt to the point on the src quadratic specified by t. t must be + 0 <= t <= 1.0 +*/ +void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, + SkVector* tangent = NULL); +void SkEvalQuadAtHalf(const SkPoint src[3], SkPoint* pt, + SkVector* tangent = NULL); + +/** Given a src quadratic bezier, chop it at the specified t value, + where 0 < t < 1, and return the two new quadratics in dst: + dst[0..2] and dst[2..4] +*/ +void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t); + +/** Given a src quadratic bezier, chop it at the specified t == 1/2, + The new quads are returned in dst[0..2] and dst[2..4] +*/ +void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]); + +/** Given the 3 coefficients for a quadratic bezier (either X or Y values), look + for extrema, and return the number of t-values that are found that represent + these extrema. If the quadratic has no extrema betwee (0..1) exclusive, the + function returns 0. + Returned count tValues[] + 0 ignored + 1 0 < tValues[0] < 1 +*/ +int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1]); + +/** Given 3 points on a quadratic bezier, chop it into 1, 2 beziers such that + the resulting beziers are monotonic in Y. This is called by the scan converter. + Depending on what is returned, dst[] is treated as follows + 0 dst[0..2] is the original quad + 1 dst[0..2] and dst[2..4] are the two new quads +*/ +int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]); +int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5]); + +/** Given 3 points on a quadratic bezier, if the point of maximum + curvature exists on the segment, returns the t value for this + point along the curve. Otherwise it will return a value of 0. +*/ +float SkFindQuadMaxCurvature(const SkPoint src[3]); + +/** Given 3 points on a quadratic bezier, divide it into 2 quadratics + if the point of maximum curvature exists on the quad segment. + Depending on what is returned, dst[] is treated as follows + 1 dst[0..2] is the original quad + 2 dst[0..2] and dst[2..4] are the two new quads + If dst == null, it is ignored and only the count is returned. +*/ +int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5]); + +/** Given 3 points on a quadratic bezier, use degree elevation to + convert it into the cubic fitting the same curve. The new cubic + curve is returned in dst[0..3]. +*/ +SK_API void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]); + +/////////////////////////////////////////////////////////////////////////////// + +/** Convert from parametric from (pts) to polynomial coefficients + coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3] +*/ +void SkGetCubicCoeff(const SkPoint pts[4], SkScalar cx[4], SkScalar cy[4]); + +/** Set pt to the point on the src cubic specified by t. t must be + 0 <= t <= 1.0 +*/ +void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* locOrNull, + SkVector* tangentOrNull, SkVector* curvatureOrNull); + +/** Given a src cubic bezier, chop it at the specified t value, + where 0 < t < 1, and return the two new cubics in dst: + dst[0..3] and dst[3..6] +*/ +void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t); +/** Given a src cubic bezier, chop it at the specified t values, + where 0 < t < 1, and return the new cubics in dst: + dst[0..3],dst[3..6],...,dst[3*t_count..3*(t_count+1)] +*/ +void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar t[], + int t_count); + +/** Given a src cubic bezier, chop it at the specified t == 1/2, + The new cubics are returned in dst[0..3] and dst[3..6] +*/ +void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7]); + +/** Given the 4 coefficients for a cubic bezier (either X or Y values), look + for extrema, and return the number of t-values that are found that represent + these extrema. If the cubic has no extrema betwee (0..1) exclusive, the + function returns 0. + Returned count tValues[] + 0 ignored + 1 0 < tValues[0] < 1 + 2 0 < tValues[0] < tValues[1] < 1 +*/ +int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, + SkScalar tValues[2]); + +/** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that + the resulting beziers are monotonic in Y. This is called by the scan converter. + Depending on what is returned, dst[] is treated as follows + 0 dst[0..3] is the original cubic + 1 dst[0..3] and dst[3..6] are the two new cubics + 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics + If dst == null, it is ignored and only the count is returned. +*/ +int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]); +int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]); + +/** Given a cubic bezier, return 0, 1, or 2 t-values that represent the + inflection points. +*/ +int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[2]); + +/** Return 1 for no chop, 2 for having chopped the cubic at a single + inflection point, 3 for having chopped at 2 inflection points. + dst will hold the resulting 1, 2, or 3 cubics. +*/ +int SkChopCubicAtInflections(const SkPoint src[4], SkPoint dst[10]); + +int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3]); +int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], + SkScalar tValues[3] = NULL); + +/** Given a monotonic cubic bezier, determine whether an xray intersects the + cubic. + By definition the cubic is open at the starting point; in other + words, if pt.fY is equivalent to cubic[0].fY, and pt.fX is to the + left of the curve, the line is not considered to cross the curve, + but if it is equal to cubic[3].fY then it is considered to + cross. + Optional outgoing "ambiguous" argument indicates whether the answer is + ambiguous because the query occurred exactly at one of the endpoints' y + coordinates, indicating that another query y coordinate is preferred + for robustness. + */ +bool SkXRayCrossesMonotonicCubic(const SkXRay& pt, const SkPoint cubic[4], + bool* ambiguous = NULL); + +/** Given an arbitrary cubic bezier, return the number of times an xray crosses + the cubic. Valid return values are [0..3] + By definition the cubic is open at the starting point; in other + words, if pt.fY is equivalent to cubic[0].fY, and pt.fX is to the + left of the curve, the line is not considered to cross the curve, + but if it is equal to cubic[3].fY then it is considered to + cross. + Optional outgoing "ambiguous" argument indicates whether the answer is + ambiguous because the query occurred exactly at one of the endpoints' y + coordinates or at a tangent point, indicating that another query y + coordinate is preferred for robustness. + */ +int SkNumXRayCrossingsForCubic(const SkXRay& pt, const SkPoint cubic[4], + bool* ambiguous = NULL); + +/////////////////////////////////////////////////////////////////////////////// + +enum SkRotationDirection { + kCW_SkRotationDirection, + kCCW_SkRotationDirection +}; + +/** Maximum number of points needed in the quadPoints[] parameter for + SkBuildQuadArc() +*/ +#define kSkBuildQuadArcStorage 17 + +/** Given 2 unit vectors and a rotation direction, fill out the specified + array of points with quadratic segments. Return is the number of points + written to, which will be { 0, 3, 5, 7, ... kSkBuildQuadArcStorage } + + matrix, if not null, is appled to the points before they are returned. +*/ +int SkBuildQuadArc(const SkVector& unitStart, const SkVector& unitStop, + SkRotationDirection, const SkMatrix*, SkPoint quadPoints[]); + +// experimental +struct SkConic { + SkPoint fPts[3]; + SkScalar fW; + + void set(const SkPoint pts[3], SkScalar w) { + memcpy(fPts, pts, 3 * sizeof(SkPoint)); + fW = w; + } + + /** + * Given a t-value [0...1] return its position and/or tangent. + * If pos is not null, return its position at the t-value. + * If tangent is not null, return its tangent at the t-value. NOTE the + * tangent value's length is arbitrary, and only its direction should + * be used. + */ + void evalAt(SkScalar t, SkPoint* pos, SkVector* tangent = NULL) const; + void chopAt(SkScalar t, SkConic dst[2]) const; + void chop(SkConic dst[2]) const; + + void computeAsQuadError(SkVector* err) const; + bool asQuadTol(SkScalar tol) const; + + /** + * return the power-of-2 number of quads needed to approximate this conic + * with a sequence of quads. Will be >= 0. + */ + int computeQuadPOW2(SkScalar tol) const; + + /** + * Chop this conic into N quads, stored continguously in pts[], where + * N = 1 << pow2. The amount of storage needed is (1 + 2 * N) + */ + int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const; + + bool findXExtrema(SkScalar* t) const; + bool findYExtrema(SkScalar* t) const; + bool chopAtXExtrema(SkConic dst[2]) const; + bool chopAtYExtrema(SkConic dst[2]) const; + + void computeTightBounds(SkRect* bounds) const; + void computeFastBounds(SkRect* bounds) const; +}; + +#include "SkTemplates.h" + +/** + * Help class to allocate storage for approximating a conic with N quads. + */ +class SkAutoConicToQuads { +public: + SkAutoConicToQuads() : fQuadCount(0) {} + + /** + * Given a conic and a tolerance, return the array of points for the + * approximating quad(s). Call countQuads() to know the number of quads + * represented in these points. + * + * The quads are allocated to share end-points. e.g. if there are 4 quads, + * there will be 9 points allocated as follows + * quad[0] == pts[0..2] + * quad[1] == pts[2..4] + * quad[2] == pts[4..6] + * quad[3] == pts[6..8] + */ + const SkPoint* computeQuads(const SkConic& conic, SkScalar tol) { + int pow2 = conic.computeQuadPOW2(tol); + fQuadCount = 1 << pow2; + SkPoint* pts = fStorage.reset(1 + 2 * fQuadCount); + conic.chopIntoQuadsPOW2(pts, pow2); + return pts; + } + + const SkPoint* computeQuads(const SkPoint pts[3], SkScalar weight, + SkScalar tol) { + SkConic conic; + conic.set(pts, weight); + return computeQuads(conic, tol); + } + + int countQuads() const { return fQuadCount; } + +private: + enum { + kQuadCount = 8, // should handle most conics + kPointCount = 1 + 2 * kQuadCount, + }; + SkAutoSTMalloc<kPointCount, SkPoint> fStorage; + int fQuadCount; // #quads for current usage +}; + +#endif diff --git a/core/SkGraphics.h b/core/SkGraphics.h new file mode 100644 index 0000000..c876042 --- /dev/null +++ b/core/SkGraphics.h @@ -0,0 +1,115 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkGraphics_DEFINED +#define SkGraphics_DEFINED + +#include "SkTypes.h" + +class SK_API SkGraphics { +public: + /** + * Call this at process initialization time if your environment does not + * permit static global initializers that execute code. Note that + * Init() is not thread-safe. + */ + static void Init(); + + /** + * Call this to release any memory held privately, such as the font cache. + */ + static void Term(); + + /** + * Return the version numbers for the library. If the parameter is not + * null, it is set to the version number. + */ + static void GetVersion(int32_t* major, int32_t* minor, int32_t* patch); + + /** + * Return the max number of bytes that should be used by the font cache. + * If the cache needs to allocate more, it will purge previous entries. + * This max can be changed by calling SetFontCacheLimit(). + */ + static size_t GetFontCacheLimit(); + + /** + * Specify the max number of bytes that should be used by the font cache. + * If the cache needs to allocate more, it will purge previous entries. + * + * This function returns the previous setting, as if GetFontCacheLimit() + * had be called before the new limit was set. + */ + static size_t SetFontCacheLimit(size_t bytes); + + /** + * Return the number of bytes currently used by the font cache. + */ + static size_t GetFontCacheUsed(); + + /** + * For debugging purposes, this will attempt to purge the font cache. It + * does not change the limit, but will cause subsequent font measures and + * draws to be recreated, since they will no longer be in the cache. + */ + static void PurgeFontCache(); + + static size_t GetImageCacheBytesUsed(); + static size_t GetImageCacheByteLimit(); + static size_t SetImageCacheByteLimit(size_t newLimit); + + /** + * Applications with command line options may pass optional state, such + * as cache sizes, here, for instance: + * font-cache-limit=12345678 + * + * The flags format is name=value[;name=value...] with no spaces. + * This format is subject to change. + */ + static void SetFlags(const char* flags); + + /** + * Return the max number of bytes that should be used by the thread-local + * font cache. + * If the cache needs to allocate more, it will purge previous entries. + * This max can be changed by calling SetFontCacheLimit(). + * + * If this thread has never called SetTLSFontCacheLimit, or has called it + * with 0, then this thread is using the shared font cache. In that case, + * this function will always return 0, and the caller may want to call + * GetFontCacheLimit. + */ + static size_t GetTLSFontCacheLimit(); + + /** + * Specify the max number of bytes that should be used by the thread-local + * font cache. If this value is 0, then this thread will use the shared + * global font cache. + */ + static void SetTLSFontCacheLimit(size_t bytes); + +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(); +}; + +class SkAutoGraphics { +public: + SkAutoGraphics() { + SkGraphics::Init(); + } + ~SkAutoGraphics() { + SkGraphics::Term(); + } +}; + +#endif diff --git a/core/SkImage.h b/core/SkImage.h new file mode 100644 index 0000000..871d461 --- /dev/null +++ b/core/SkImage.h @@ -0,0 +1,131 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImage_DEFINED +#define SkImage_DEFINED + +#include "SkImageEncoder.h" +#include "SkRefCnt.h" +#include "SkScalar.h" + +class SkData; +class SkCanvas; +class SkPaint; +class SkShader; +class GrContext; +class GrTexture; + +// need for TileMode +#include "SkShader.h" + +/** + * SkImage is an abstraction for drawing a rectagle of pixels, though the + * particular type of image could be actually storing its data on the GPU, or + * as drawing commands (picture or PDF or otherwise), ready to be played back + * into another canvas. + * + * The content of SkImage is always immutable, though the actual storage may + * change, if for example that image can be re-created via encoded data or + * other means. + */ +class SK_API SkImage : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkImage) + + enum ColorType { + kAlpha_8_ColorType, + kRGB_565_ColorType, + kRGBA_8888_ColorType, + kBGRA_8888_ColorType, + kPMColor_ColorType, + + kLastEnum_ColorType = kPMColor_ColorType + }; + + enum AlphaType { + kIgnore_AlphaType, + kOpaque_AlphaType, + kPremul_AlphaType, + kUnpremul_AlphaType, + + kLastEnum_AlphaType = kUnpremul_AlphaType + }; + + struct Info { + int fWidth; + int fHeight; + ColorType fColorType; + AlphaType fAlphaType; + }; + + static SkImage* NewRasterCopy(const Info&, const void* pixels, size_t rowBytes); + static SkImage* NewRasterData(const Info&, SkData* pixels, size_t rowBytes); + static SkImage* NewEncodedData(SkData*); + + /** + * GrTexture is a more logical parameter for this factory, but its + * interactions with scratch cache still has issues, so for now we take + * SkBitmap instead. This will be changed in the future. skbug.com/1449 + */ + static SkImage* NewTexture(const SkBitmap&); + + int width() const { return fWidth; } + int height() const { return fHeight; } + uint32_t uniqueID() const { return fUniqueID; } + + /** + * Return the GrTexture that stores the image pixels. Calling getTexture + * does not affect the reference count of the GrTexture object. + * Will return NULL if the image does not use a texture. + */ + GrTexture* getTexture(); + + SkShader* newShaderClamp() const; + SkShader* newShader(SkShader::TileMode, SkShader::TileMode) const; + + void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); + + /** + * Draw the image, cropped to the src rect, to the dst rect of a canvas. + * If src is larger than the bounds of the image, the rest of the image is + * filled with transparent black pixels. + * + * See SkCanvas::drawBitmapRectToRect for similar behavior. + */ + void draw(SkCanvas*, const SkRect* src, const SkRect& dst, const SkPaint*); + + /** + * Encode the image's pixels and return the result as a new SkData, which + * the caller must manage (i.e. call unref() when they are done). + * + * If the image type cannot be encoded, or the requested encoder type is + * not supported, this will return NULL. + */ + SkData* encode(SkImageEncoder::Type t = SkImageEncoder::kPNG_Type, + int quality = 80) const; + +protected: + SkImage(int width, int height) : + fWidth(width), + fHeight(height), + fUniqueID(NextUniqueID()) { + + SkASSERT(width >= 0); + SkASSERT(height >= 0); + } + +private: + const int fWidth; + const int fHeight; + const uint32_t fUniqueID; + + static uint32_t NextUniqueID(); + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkImageDecoder.h b/core/SkImageDecoder.h new file mode 100644 index 0000000..7bdaaa8 --- /dev/null +++ b/core/SkImageDecoder.h @@ -0,0 +1,560 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkImageDecoder_DEFINED +#define SkImageDecoder_DEFINED + +#include "SkBitmap.h" +#include "SkBitmapFactory.h" +#include "SkImage.h" +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkStream; + +/** \class SkImageDecoder + + Base class for decoding compressed images into a SkBitmap +*/ +class SkImageDecoder : public SkNoncopyable { +public: + virtual ~SkImageDecoder(); + + enum Format { + kUnknown_Format, + kBMP_Format, + kGIF_Format, + kICO_Format, + kJPEG_Format, + kPNG_Format, + kWBMP_Format, + kWEBP_Format, + + kLastKnownFormat = kWEBP_Format, + }; + + /** Return the format of image this decoder can decode. If this decoder can decode multiple + formats, kUnknown_Format will be returned. + */ + virtual Format getFormat() const; + + /** Return the format of the SkStream or kUnknown_Format if it cannot be determined. Rewinds the + stream before returning. + */ + static Format GetStreamFormat(SkStream*); + + /** Return a readable string of the Format provided. + */ + static const char* GetFormatName(Format); + + /** Return a readable string of the value returned by getFormat(). + */ + const char* getFormatName() const; + + /** Returns true if the decoder should try to dither the resulting image. + The default setting is true. + */ + bool getDitherImage() const { return fDitherImage; } + + /** Set to true if the the decoder should try to dither the resulting image. + The default setting is true. + */ + void setDitherImage(bool dither) { fDitherImage = dither; } + + /** Returns true if the decoder should try to decode the + resulting image to a higher quality even at the expense of + the decoding speed. + */ + bool getPreferQualityOverSpeed() const { return fPreferQualityOverSpeed; } + + /** Set to true if the the decoder should try to decode the + resulting image to a higher quality even at the expense of + the decoding speed. + */ + void setPreferQualityOverSpeed(bool qualityOverSpeed) { + fPreferQualityOverSpeed = qualityOverSpeed; + } + + /** Set to true to require the decoder to return a bitmap with unpremultiplied + colors. The default is false, meaning the resulting bitmap will have its + colors premultiplied. + NOTE: Passing true to this function may result in a bitmap which cannot + be properly used by Skia. + */ + void setRequireUnpremultipliedColors(bool request) { + fRequireUnpremultipliedColors = request; + } + + /** Returns true if the decoder will only return bitmaps with unpremultiplied + colors. + */ + bool getRequireUnpremultipliedColors() const { return fRequireUnpremultipliedColors; } + + /** \class Peeker + + Base class for optional callbacks to retrieve meta/chunk data out of + an image as it is being decoded. + */ + class Peeker : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Peeker) + + /** Return true to continue decoding, or false to indicate an error, which + will cause the decoder to not return the image. + */ + virtual bool peek(const char tag[], const void* data, size_t length) = 0; + private: + typedef SkRefCnt INHERITED; + }; + + Peeker* getPeeker() const { return fPeeker; } + Peeker* setPeeker(Peeker*); + + /** \class Chooser + + Base class for optional callbacks to choose an image from a format that + contains multiple images. + */ + class Chooser : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Chooser) + + virtual void begin(int count) {} + virtual void inspect(int index, SkBitmap::Config config, int width, int height) {} + /** Return the index of the subimage you want, or -1 to choose none of them. + */ + virtual int choose() = 0; + + private: + typedef SkRefCnt INHERITED; + }; + + Chooser* getChooser() const { return fChooser; } + Chooser* setChooser(Chooser*); + + /** + @Deprecated. Use the struct version instead. + + This optional table describes the caller's preferred config based on + information about the src data. For this table, the src attributes are + described in terms of depth (index (8), 16, 32/24) and if there is + per-pixel alpha. These inputs combine to create an index into the + pref[] table, which contains the caller's preferred config for that + input, or kNo_Config if there is no preference. + + To specify no preference, call setPrefConfigTable(NULL), which is + the default. + + Note, it is still at the discretion of the codec as to what output + config is actually returned, as it may not be able to support the + caller's preference. + + Here is how the index into the table is computed from the src: + depth [8, 16, 32/24] -> 0, 2, 4 + alpha [no, yes] -> 0, 1 + The two index values are OR'd together. + src: 8-index, no-alpha -> 0 + src: 8-index, yes-alpha -> 1 + src: 16bit, no-alpha -> 2 // e.g. 565 + src: 16bit, yes-alpha -> 3 // e.g. 1555 + src: 32/24, no-alpha -> 4 + src: 32/24, yes-alpha -> 5 + */ + void setPrefConfigTable(const SkBitmap::Config pref[6]); + + /** + * Optional table describing the caller's preferred config based on + * information about the src data. Each field should be set to the + * preferred config for a src described in the name of the field. The + * src attributes are described in terms of depth (8-index, + * 8bit-grayscale, or 8-bits/component) and whether there is per-pixel + * alpha (does not apply to grayscale). If the caller has no preference + * for a particular src type, its slot should be set to kNo_Config. + * + * NOTE ABOUT PREFERRED CONFIGS: + * If a config is preferred, either using a pref table or as a parameter + * to some flavor of decode, it is still at the discretion of the codec + * as to what output config is actually returned, as it may not be able + * to support the caller's preference. + * + * If a bitmap is decoded into SkBitmap::A8_Config, the resulting bitmap + * will either be a conversion of the grayscale in the case of a + * grayscale source or the alpha channel in the case of a source with + * an alpha channel. + */ + struct PrefConfigTable { + SkBitmap::Config fPrefFor_8Index_NoAlpha_src; + SkBitmap::Config fPrefFor_8Index_YesAlpha_src; + SkBitmap::Config fPrefFor_8Gray_src; + SkBitmap::Config fPrefFor_8bpc_NoAlpha_src; + SkBitmap::Config fPrefFor_8bpc_YesAlpha_src; + }; + + /** + * Set an optional table for specifying the caller's preferred config + * based on information about the src data. + * + * The default is no preference, which will assume the config set by + * decode is preferred. + */ + void setPrefConfigTable(const PrefConfigTable&); + + /** + * Do not use a PrefConfigTable to determine the output config. This + * is the default, so there is no need to call unless a PrefConfigTable + * was previously set. + */ + void resetPrefConfigTable() { fUsePrefTable = false; } + + SkBitmap::Allocator* getAllocator() const { return fAllocator; } + SkBitmap::Allocator* setAllocator(SkBitmap::Allocator*); + + // sample-size, if set to > 1, tells the decoder to return a smaller than + // original bitmap, sampling 1 pixel for every size pixels. e.g. if sample + // size is set to 3, then the returned bitmap will be 1/3 as wide and high, + // and will contain 1/9 as many pixels as the original. + // Note: this is a hint, and the codec may choose to ignore this, or only + // approximate the sample size. + int getSampleSize() const { return fSampleSize; } + void setSampleSize(int size); + + /** Reset the sampleSize to its default of 1 + */ + void resetSampleSize() { this->setSampleSize(1); } + + /** Decoding is synchronous, but for long decodes, a different thread can + call this method safely. This sets a state that the decoders will + periodically check, and if they see it changed to cancel, they will + cancel. This will result in decode() returning false. However, there is + no guarantee that the decoder will see the state change in time, so + it is possible that cancelDecode() will be called, but will be ignored + and decode() will return true (assuming no other problems were + encountered). + + This state is automatically reset at the beginning of decode(). + */ + void cancelDecode() { + // now the subclass must query shouldCancelDecode() to be informed + // of the request + fShouldCancelDecode = true; + } + + /** Passed to the decode method. If kDecodeBounds_Mode is passed, then + only the bitmap's width/height/config need be set. If kDecodePixels_Mode + is passed, then the bitmap must have pixels or a pixelRef. + */ + enum Mode { + kDecodeBounds_Mode, //!< only return width/height/config in bitmap + kDecodePixels_Mode //!< return entire bitmap (including pixels) + }; + + /** Given a stream, decode it into the specified bitmap. + If the decoder can decompress the image, it calls bitmap.setConfig(), + and then if the Mode is kDecodePixels_Mode, call allocPixelRef(), + which will allocated a pixelRef. To access the pixel memory, the codec + needs to call lockPixels/unlockPixels on the + bitmap. It can then set the pixels with the decompressed image. + * If the image cannot be decompressed, return false. After the + * decoding, the function converts the decoded config in bitmap + * to pref if possible. Whether a conversion is feasible is + * tested by Bitmap::canCopyTo(pref). + + If an SkBitmap::Allocator is installed via setAllocator, it will be + used to allocate the pixel memory. A clever allocator can be used + to allocate the memory from a cache, volatile memory, or even from + an existing bitmap's memory. + + If a Peeker is installed via setPeeker, it may be used to peek into + meta data during the decode. + + If a Chooser is installed via setChooser, it may be used to select + which image to return from a format that contains multiple images. + */ + bool decode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref, Mode); + bool decode(SkStream* stream, SkBitmap* bitmap, Mode mode) { + return this->decode(stream, bitmap, SkBitmap::kNo_Config, mode); + } + + /** + * Given a stream, build an index for doing tile-based decode. + * The built index will be saved in the decoder, and the image size will + * be returned in width and height. + * + * Return true for success or false on failure. + */ + bool buildTileIndex(SkStream*, int *width, int *height); + + /** + * Decode a rectangle subset in the image. + * The method can only be called after buildTileIndex(). + * + * Return true for success. + * Return false if the index is never built or failing in decoding. + */ + bool decodeSubset(SkBitmap* bm, const SkIRect& subset, SkBitmap::Config pref); + + /** + * @Deprecated + * Use decodeSubset instead. + */ + bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect, SkBitmap::Config pref) { + return this->decodeSubset(bitmap, rect, pref); + } + + /** Given a stream, this will try to find an appropriate decoder object. + If none is found, the method returns NULL. + */ + static SkImageDecoder* Factory(SkStream*); + + /** Decode the image stored in the specified file, and store the result + in bitmap. Return true for success or false on failure. + + @param prefConfig If the PrefConfigTable is not set, prefer this config. + See NOTE ABOUT PREFERRED CONFIGS. + + @param format On success, if format is non-null, it is set to the format + of the decoded file. On failure it is ignored. + */ + static bool DecodeFile(const char file[], SkBitmap* bitmap, + SkBitmap::Config prefConfig, Mode, + Format* format = NULL); + static bool DecodeFile(const char file[], SkBitmap* bitmap) { + return DecodeFile(file, bitmap, SkBitmap::kNo_Config, + kDecodePixels_Mode, NULL); + } + /** Decode the image stored in the specified memory buffer, and store the + result in bitmap. Return true for success or false on failure. + + @param prefConfig If the PrefConfigTable is not set, prefer this config. + See NOTE ABOUT PREFERRED CONFIGS. + + @param format On success, if format is non-null, it is set to the format + of the decoded buffer. On failure it is ignored. + */ + static bool DecodeMemory(const void* buffer, size_t size, SkBitmap* bitmap, + SkBitmap::Config prefConfig, Mode, + Format* format = NULL); + static bool DecodeMemory(const void* buffer, size_t size, SkBitmap* bitmap){ + return DecodeMemory(buffer, size, bitmap, SkBitmap::kNo_Config, + kDecodePixels_Mode, NULL); + } + + /** + * Decode memory. + * @param info Output parameter. Returns info about the encoded image. + * @param target Contains the address of pixel memory to decode into + * (which must be large enough to hold the width in info) and + * the row bytes to use. If NULL, returns info and does not + * decode pixels. + * @return bool Whether the function succeeded. + * + * Sample usage: + * <code> + * // Determine the image's info: width/height/config + * SkImage::Info info; + * bool success = DecodeMemoryToTarget(src, size, &info, NULL); + * if (!success) return; + * // Allocate space for the result: + * SkBitmapFactory::Target target; + * target.fAddr = malloc/other allocation + * target.fRowBytes = ... + * // Now decode the actual pixels into target. &info is optional, + * // and could be NULL + * success = DecodeMemoryToTarget(src, size, &info, &target); + * </code> + */ + static bool DecodeMemoryToTarget(const void* buffer, size_t size, SkImage::Info* info, + const SkBitmapFactory::Target* target); + + /** Decode the image stored in the specified SkStream, and store the result + in bitmap. Return true for success or false on failure. + + @param prefConfig If the PrefConfigTable is not set, prefer this config. + See NOTE ABOUT PREFERRED CONFIGS. + + @param format On success, if format is non-null, it is set to the format + of the decoded stream. On failure it is ignored. + */ + static bool DecodeStream(SkStream* stream, SkBitmap* bitmap, + SkBitmap::Config prefConfig, Mode, + Format* format = NULL); + static bool DecodeStream(SkStream* stream, SkBitmap* bitmap) { + return DecodeStream(stream, bitmap, SkBitmap::kNo_Config, + kDecodePixels_Mode, NULL); + } + + /** Return the default config for the running device. + Currently this used as a suggestion to image decoders that need to guess + what config they should decode into. + Default is kNo_Config, but this can be changed with SetDeviceConfig() + */ + static SkBitmap::Config GetDeviceConfig(); + /** Set the default config for the running device. + Currently this used as a suggestion to image decoders that need to guess + what config they should decode into. + Default is kNo_Config. + This can be queried with GetDeviceConfig() + */ + static void SetDeviceConfig(SkBitmap::Config); + +protected: + // must be overridden in subclasses. This guy is called by decode(...) + virtual bool onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0; + + // If the decoder wants to support tiled based decoding, + // this method must be overridden. This guy is called by buildTileIndex(...) + virtual bool onBuildTileIndex(SkStream*, int *width, int *height) { + return false; + } + + // If the decoder wants to support tiled based decoding, + // this method must be overridden. This guy is called by decodeRegion(...) + virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) { + return false; + } + + /* + * Crop a rectangle from the src Bitmap to the dest Bitmap. src and dst are + * both sampled by sampleSize from an original Bitmap. + * + * @param dst the destination bitmap. + * @param src the source bitmap that is sampled by sampleSize from the + * original bitmap. + * @param sampleSize the sample size that src is sampled from the original bitmap. + * @param (dstX, dstY) the upper-left point of the dest bitmap in terms of + * the coordinate in the original bitmap. + * @param (width, height) the width and height of the unsampled dst. + * @param (srcX, srcY) the upper-left point of the src bitmap in terms of + * the coordinate in the original bitmap. + * @return bool Whether or not it succeeded. + */ + bool cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize, + int dstX, int dstY, int width, int height, + int srcX, int srcY); + + /** + * Copy all fields on this decoder to the other decoder. Used by subclasses + * to decode a subimage using a different decoder, but with the same settings. + */ + void copyFieldsToOther(SkImageDecoder* other); + + /** + * Return the default preference being used by the current or latest call to + * decode. + */ + SkBitmap::Config getDefaultPref() { return fDefaultPref; } + + /** Can be queried from within onDecode, to see if the user (possibly in + a different thread) has requested the decode to cancel. If this returns + true, your onDecode() should stop and return false. + Each subclass needs to decide how often it can query this, to balance + responsiveness with performance. + + Calling this outside of onDecode() may return undefined values. + */ + +public: + bool shouldCancelDecode() const { return fShouldCancelDecode; } + +protected: + SkImageDecoder(); + + // helper function for decoders to handle the (common) case where there is only + // once choice available in the image file. + bool chooseFromOneChoice(SkBitmap::Config config, int width, int height) const; + + /* Helper for subclasses. Call this to allocate the pixel memory given the bitmap's + width/height/rowbytes/config. Returns true on success. This method handles checking + for an optional Allocator. + */ + bool allocPixelRef(SkBitmap*, SkColorTable*) const; + + /** + * The raw data of the src image. + */ + enum SrcDepth { + // Color-indexed. + kIndex_SrcDepth, + // Grayscale in 8 bits. + k8BitGray_SrcDepth, + // 8 bits per component. Used for 24 bit if there is no alpha. + k32Bit_SrcDepth, + }; + /** The subclass, inside onDecode(), calls this to determine the config of + the returned bitmap. SrcDepth and hasAlpha reflect the raw data of the + src image. This routine returns the caller's preference given + srcDepth and hasAlpha, or kNo_Config if there is no preference. + + Note: this also takes into account GetDeviceConfig(), so the subclass + need not call that. + */ + SkBitmap::Config getPrefConfig(SrcDepth, bool hasAlpha) const; + +private: + Peeker* fPeeker; + Chooser* fChooser; + SkBitmap::Allocator* fAllocator; + int fSampleSize; + SkBitmap::Config fDefaultPref; // use if fUsePrefTable is false + PrefConfigTable fPrefTable; // use if fUsePrefTable is true + bool fDitherImage; + bool fUsePrefTable; + mutable bool fShouldCancelDecode; + bool fPreferQualityOverSpeed; + bool fRequireUnpremultipliedColors; +}; + +/** Calling newDecoder with a stream returns a new matching imagedecoder + instance, or NULL if none can be found. The caller must manage its ownership + of the stream as usual, calling unref() when it is done, as the returned + decoder may have called ref() (and if so, the decoder is responsible for + balancing its ownership when it is destroyed). + */ +class SkImageDecoderFactory : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkImageDecoderFactory) + + virtual SkImageDecoder* newDecoder(SkStream*) = 0; + +private: + typedef SkRefCnt INHERITED; +}; + +class SkDefaultImageDecoderFactory : SkImageDecoderFactory { +public: + // calls SkImageDecoder::Factory(stream) + virtual SkImageDecoder* newDecoder(SkStream* stream) { + return SkImageDecoder::Factory(stream); + } +}; + +// This macro declares a global (i.e., non-class owned) creation entry point +// for each decoder (e.g., CreateJPEGImageDecoder) +#define DECLARE_DECODER_CREATOR(codec) \ + SkImageDecoder *Create ## codec (); + +// This macro defines the global creation entry point for each decoder. Each +// decoder implementation that registers with the decoder factory must call it. +#define DEFINE_DECODER_CREATOR(codec) \ + SkImageDecoder *Create ## codec () { \ + return SkNEW( Sk ## codec ); \ + } + +// All the decoders known by Skia. Note that, depending on the compiler settings, +// not all of these will be available +DECLARE_DECODER_CREATOR(BMPImageDecoder); +DECLARE_DECODER_CREATOR(GIFImageDecoder); +DECLARE_DECODER_CREATOR(ICOImageDecoder); +DECLARE_DECODER_CREATOR(JPEGImageDecoder); +DECLARE_DECODER_CREATOR(PNGImageDecoder); +DECLARE_DECODER_CREATOR(WBMPImageDecoder); +DECLARE_DECODER_CREATOR(WEBPImageDecoder); + +#endif diff --git a/core/SkImageEncoder.h b/core/SkImageEncoder.h new file mode 100644 index 0000000..b990aff --- /dev/null +++ b/core/SkImageEncoder.h @@ -0,0 +1,100 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkImageEncoder_DEFINED +#define SkImageEncoder_DEFINED + +#include "SkTypes.h" + +class SkBitmap; +class SkData; +class SkWStream; + +class SkImageEncoder { +public: + enum Type { + kUnknown_Type, + kBMP_Type, + kGIF_Type, + kICO_Type, + kJPEG_Type, + kPNG_Type, + kWBMP_Type, + kWEBP_Type, + }; + static SkImageEncoder* Create(Type); + + virtual ~SkImageEncoder(); + + /* Quality ranges from 0..100 */ + enum { + kDefaultQuality = 80 + }; + + /** + * Encode bitmap 'bm', returning the results in an SkData, at quality level + * 'quality' (which can be in range 0-100). If the bitmap cannot be + * encoded, return null. On success, the caller is responsible for + * calling unref() on the data when they are finished. + */ + SkData* encodeData(const SkBitmap&, int quality); + + /** + * Encode bitmap 'bm' in the desired format, writing results to + * file 'file', at quality level 'quality' (which can be in range + * 0-100). Returns false on failure. + */ + bool encodeFile(const char file[], const SkBitmap& bm, int quality); + + /** + * Encode bitmap 'bm' in the desired format, writing results to + * stream 'stream', at quality level 'quality' (which can be in + * range 0-100). Returns false on failure. + */ + bool encodeStream(SkWStream* stream, const SkBitmap& bm, int quality); + + static SkData* EncodeData(const SkBitmap&, Type, int quality); + static bool EncodeFile(const char file[], const SkBitmap&, Type, + int quality); + static bool EncodeStream(SkWStream*, const SkBitmap&, Type, + int quality); + +protected: + /** + * Encode bitmap 'bm' in the desired format, writing results to + * stream 'stream', at quality level 'quality' (which can be in + * range 0-100). + * + * This must be overridden by each SkImageEncoder implementation. + */ + virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) = 0; +}; + +// This macro declares a global (i.e., non-class owned) creation entry point +// for each encoder (e.g., CreateJPEGImageEncoder) +#define DECLARE_ENCODER_CREATOR(codec) \ + SkImageEncoder *Create ## codec (); + +// This macro defines the global creation entry point for each encoder. Each +// encoder implementation that registers with the encoder factory must call it. +#define DEFINE_ENCODER_CREATOR(codec) \ + SkImageEncoder *Create ## codec () { \ + return SkNEW( Sk ## codec ); \ + } + +// All the encoders known by Skia. Note that, depending on the compiler settings, +// not all of these will be available +/** An ARGBImageEncoder will always write out + * bitmap.width() * bitmap.height() * 4 + * bytes. + */ +DECLARE_ENCODER_CREATOR(ARGBImageEncoder); +DECLARE_ENCODER_CREATOR(JPEGImageEncoder); +DECLARE_ENCODER_CREATOR(PNGImageEncoder); +DECLARE_ENCODER_CREATOR(WEBPImageEncoder); + +#endif diff --git a/core/SkImageFilter.h b/core/SkImageFilter.h new file mode 100644 index 0000000..01b3e0b --- /dev/null +++ b/core/SkImageFilter.h @@ -0,0 +1,173 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageFilter_DEFINED +#define SkImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkRect.h" + +class SkBitmap; +class SkColorFilter; +class SkDevice; +class SkMatrix; +struct SkIPoint; +class SkShader; +class GrEffectRef; +class GrTexture; + +/** + * Base class for image filters. If one is installed in the paint, then + * all drawing occurs as usual, but it is as if the drawing happened into an + * offscreen (before the xfermode is applied). This offscreen bitmap will + * then be handed to the imagefilter, who in turn creates a new bitmap which + * is what will finally be drawn to the device (using the original xfermode). + */ +class SK_API SkImageFilter : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkImageFilter) + + class Proxy { + public: + virtual ~Proxy() {}; + + virtual SkDevice* createDevice(int width, int height) = 0; + // returns true if the proxy can handle this filter natively + virtual bool canHandleImageFilter(SkImageFilter*) = 0; + // returns true if the proxy handled the filter itself. if this returns + // false then the filter's code will be called. + virtual bool filterImage(SkImageFilter*, const SkBitmap& src, + const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) = 0; + }; + + /** + * Request a new (result) image to be created from the src image. + * If the src has no pixels (isNull()) then the request just wants to + * receive the config and width/height of the result. + * + * The matrix is the current matrix on the canvas. + * + * Offset is the amount to translate the resulting image relative to the + * src when it is drawn. + * + * If the result image cannot be created, return false, in which case both + * the result and offset parameters will be ignored by the caller. + */ + bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset); + + /** + * Given the src bounds of an image, this returns the bounds of the result + * image after the filter has been applied. + */ + bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst); + + /** + * Returns true if the filter can be expressed a single-pass + * GrEffect, used to process this filter on the GPU, or false if + * not. + * + * If effect is non-NULL, a new GrEffect instance is stored + * in it. The caller assumes ownership of the stage, and it is up to the + * caller to unref it. + * + * The effect can assume its vertexCoords space maps 1-to-1 with texels + * in the texture. "offset" is the delta between the source and + * destination rect's origins, when cropped processing is being performed. + */ + virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const; + + /** + * Returns true if the filter can be processed on the GPU. This is most + * often used for multi-pass effects, where intermediate results must be + * rendered to textures. For single-pass effects, use asNewEffect(). + * The default implementation returns asNewEffect(NULL, NULL). + */ + virtual bool canFilterImageGPU() const; + + /** + * Process this image filter on the GPU. This is most often used for + * multi-pass effects, where intermediate results must be rendered to + * textures. For single-pass effects, use asNewEffect(). src is the + * source image for processing, as a texture-backed bitmap. result is + * the destination bitmap, which should contain a texture-backed pixelref + * on success. offset is the amount to translate the resulting image + * relative to the src when it is drawn. The default implementation does + * single-pass processing using asNewEffect(). + */ + virtual bool filterImageGPU(Proxy*, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset); + + /** + * Returns whether this image filter is a color filter and puts the color filter into the + * "filterPtr" parameter if it can. Does nothing otherwise. + * If this returns false, then the filterPtr is unchanged. + * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler + * (i.e. it may not be set to NULL). + */ + virtual bool asColorFilter(SkColorFilter** filterPtr) const; + + /** + * Returns the number of inputs this filter will accept (some inputs can + * be NULL). + */ + int countInputs() const { return fInputCount; } + + /** + * Returns the input filter at a given index, or NULL if no input is + * connected. The indices used are filter-specific. + */ + SkImageFilter* getInput(int i) const { + SkASSERT(i < fInputCount); + return fInputs[i]; + } + + /** + * Returns the crop rectangle of this filter. This is set at construction + * time, and determines which pixels from the input image will + * be processed. The size of this rectangle should be used as the size + * of the destination image. The origin of this rect should be used to + * offset access to the input images, and should also be added to the + * "offset" parameter in onFilterImage and filterImageGPU(). (The latter + * ensures that the resulting buffer is drawn in the correct location.) + */ + const SkIRect& cropRect() const { return fCropRect; } + +protected: + SkImageFilter(int inputCount, SkImageFilter** inputs, const SkIRect* cropRect = NULL); + + // Convenience constructor for 1-input filters. + explicit SkImageFilter(SkImageFilter* input, const SkIRect* cropRect = NULL); + + // Convenience constructor for 2-input filters. + SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const SkIRect* cropRect = NULL); + + virtual ~SkImageFilter(); + + explicit SkImageFilter(SkFlattenableReadBuffer& rb); + + virtual void flatten(SkFlattenableWriteBuffer& wb) const SK_OVERRIDE; + + // Default impl returns false + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset); + // Default impl copies src into dst and returns true + virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*); + + // Sets rect to the intersection of rect and the crop rect. If there + // is no overlap, returns false and leaves rect unchanged. + bool applyCropRect(SkIRect* rect) const; + +private: + typedef SkFlattenable INHERITED; + int fInputCount; + SkImageFilter** fInputs; + SkIRect fCropRect; +}; + +#endif diff --git a/core/SkImageFilterUtils.h b/core/SkImageFilterUtils.h new file mode 100644 index 0000000..b3921cd --- /dev/null +++ b/core/SkImageFilterUtils.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageFilterUtils_DEFINED +#define SkImageFilterUtils_DEFINED + +#if SK_SUPPORT_GPU + +#include "SkImageFilter.h" + +class SkBitmap; +class GrTexture; +class SkImageFilter; + +class SK_API SkImageFilterUtils { +public: + /** + * Wrap the given texture in a texture-backed SkBitmap. + */ + static bool WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result); + + /** + * Recursively evaluate the given filter on the GPU. If filter is NULL, + * this function returns src. If the filter has no GPU implementation, it + * will be processed in software and uploaded to the GPU. + */ + static bool GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, + const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, + SkIPoint* offset); +}; + +#endif + +#endif diff --git a/core/SkImageTypes.h b/core/SkImageTypes.h new file mode 100644 index 0000000..541c388 --- /dev/null +++ b/core/SkImageTypes.h @@ -0,0 +1,39 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageTypes_DEFINED +#define SkImageTypes_DEFINED + +#include "SkTypes.h" + +enum SkColorType { + kAlpha_8_SkColorType, + kRGB_565_SkColorType, +// kRGBA_8888_SkColorType, +// kBGRA_8888_SkColorType, + kPMColor_SkColorType, + + kLastEnum_SkColorType = kPMColor_SkColorType +}; + +enum SkAlphaType { +// kIgnore_SkAlphaType, + kOpaque_SkAlphaType, +// kUnpremul_SkAlphaType, + kPremul_SkAlphaType, + + kLastEnum_SkAlphaType = kPremul_SkAlphaType +}; + +struct SkImageInfo { + int fWidth; + int fHeight; + SkColorType fColorType; + SkAlphaType fAlphaType; +}; + +#endif diff --git a/core/SkInstCnt.h b/core/SkInstCnt.h new file mode 100644 index 0000000..cab8ebb --- /dev/null +++ b/core/SkInstCnt.h @@ -0,0 +1,133 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkInstCnt_DEFINED +#define SkInstCnt_DEFINED + +/* + * The instance counting system consists of three macros that create the + * instance counting machinery. A class is added to the system by adding: + * SK_DECLARE_INST_COUNT at the top of its declaration for derived classes + * SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class + * SK_DEFINE_INST_COUNT at the top of its .cpp file (for both kinds). + * At the end of an application a call to all the "root" objects' + * CheckInstanceCount methods should be made + */ +#include "SkTypes.h" + +#if SK_ENABLE_INST_COUNT +#include "SkTArray.h" +#include "SkThread_platform.h" + +extern bool gPrintInstCount; + +// The non-root classes just register themselves with their parent +#define SK_DECLARE_INST_COUNT(className) \ + SK_DECLARE_INST_COUNT_INTERNAL(className, \ + INHERITED::AddInstChild(CheckInstanceCount);,\ + /**/) + +#define SK_DECLARE_INST_COUNT_TEMPLATE(className) \ + SK_DECLARE_INST_COUNT_INTERNAL(className, \ + INHERITED::AddInstChild(CheckInstanceCount);, \ + typename) + +// The root classes registers a function to print out the memory stats when +// the app ends +#define SK_DECLARE_INST_COUNT_ROOT(className) \ + SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);, /**/) + +#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep, templateType) \ + class SkInstanceCountHelper { \ + public: \ + typedef int (*PFCheckInstCnt)(int level, bool cleanUp); \ + SkInstanceCountHelper() { \ + if (!gInited) { \ + initStep \ + gChildren = new SkTArray<PFCheckInstCnt>; \ + gInited = true; \ + } \ + sk_atomic_inc(&gInstanceCount); \ + } \ + \ + SkInstanceCountHelper(const SkInstanceCountHelper&) { \ + sk_atomic_inc(&gInstanceCount); \ + } \ + \ + ~SkInstanceCountHelper() { \ + sk_atomic_dec(&gInstanceCount); \ + } \ + \ + static int32_t gInstanceCount; \ + static bool gInited; \ + static SkTArray<PFCheckInstCnt>* gChildren; \ + } fInstanceCountHelper; \ + \ + static int32_t GetInstanceCount() { \ + return SkInstanceCountHelper::gInstanceCount; \ + } \ + \ + static void exitPrint() { \ + CheckInstanceCount(0, true); \ + } \ + \ + static int CheckInstanceCount(int level = 0, bool cleanUp = false) { \ + if (gPrintInstCount && 0 != SkInstanceCountHelper::gInstanceCount) {\ + SkDebugf("%*c Leaked %s: %d\n", \ + 4*level, ' ', #className, \ + SkInstanceCountHelper::gInstanceCount); \ + } \ + if (NULL == SkInstanceCountHelper::gChildren) { \ + return SkInstanceCountHelper::gInstanceCount; \ + } \ + int childCount = SkInstanceCountHelper::gChildren->count(); \ + int count = SkInstanceCountHelper::gInstanceCount; \ + for (int i = 0; i < childCount; ++i) { \ + count -= (*(*SkInstanceCountHelper::gChildren)[i])(level+1, cleanUp); \ + } \ + SkASSERT(count >= 0); \ + if (gPrintInstCount && childCount > 0 && count > 0) { \ + SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count); \ + } \ + if (cleanUp) { \ + delete SkInstanceCountHelper::gChildren; \ + SkInstanceCountHelper::gChildren = NULL; \ + } \ + return SkInstanceCountHelper::gInstanceCount; \ + } \ + \ + static void AddInstChild(templateType SkInstanceCountHelper::PFCheckInstCnt \ + childCheckInstCnt) { \ + if (CheckInstanceCount != childCheckInstCnt && \ + NULL != SkInstanceCountHelper::gChildren) { \ + SkInstanceCountHelper::gChildren->push_back(childCheckInstCnt); \ + } \ + } + +#define SK_DEFINE_INST_COUNT(className) \ + int32_t className::SkInstanceCountHelper::gInstanceCount = 0; \ + bool className::SkInstanceCountHelper::gInited = false; \ + SkTArray<className::SkInstanceCountHelper::PFCheckInstCnt>* \ + className::SkInstanceCountHelper::gChildren = NULL; + +#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) \ + templateInfo int32_t className::SkInstanceCountHelper::gInstanceCount = 0;\ + templateInfo bool className::SkInstanceCountHelper::gInited = false; \ + templateInfo \ + SkTArray<typename className::SkInstanceCountHelper::PFCheckInstCnt>*\ + className::SkInstanceCountHelper::gChildren = NULL; + +#else +#define SK_DECLARE_INST_COUNT(className) +#define SK_DECLARE_INST_COUNT_TEMPLATE(className) +#define SK_DECLARE_INST_COUNT_ROOT(className) +#define SK_DEFINE_INST_COUNT(className) +#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) +#endif + +#endif // SkInstCnt_DEFINED diff --git a/core/SkLineClipper.h b/core/SkLineClipper.h new file mode 100644 index 0000000..8026890 --- /dev/null +++ b/core/SkLineClipper.h @@ -0,0 +1,47 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkLineClipper_DEFINED +#define SkLineClipper_DEFINED + +#include "SkRect.h" +#include "SkPoint.h" + +class SkLineClipper { +public: + enum { + kMaxPoints = 4, + kMaxClippedLineSegments = kMaxPoints - 1 + }; + + /* Clip the line pts[0]...pts[1] against clip, ignoring segments that + lie completely above or below the clip. For portions to the left or + right, turn those into vertical line segments that are aligned to the + edge of the clip. + + Return the number of line segments that result, and store the end-points + of those segments sequentially in lines as follows: + 1st segment: lines[0]..lines[1] + 2nd segment: lines[1]..lines[2] + 3rd segment: lines[2]..lines[3] + */ + static int ClipLine(const SkPoint pts[2], const SkRect& clip, + SkPoint lines[kMaxPoints]); + + /* Intersect the line segment against the rect. If there is a non-empty + resulting segment, return true and set dst[] to that segment. If not, + return false and ignore dst[]. + + ClipLine is specialized for scan-conversion, as it adds vertical + segments on the sides to show where the line extended beyond the + left or right sides. IntersectLine does not. + */ + static bool IntersectLine(const SkPoint src[2], const SkRect& clip, + SkPoint dst[2]); +}; + +#endif diff --git a/core/SkMallocPixelRef.h b/core/SkMallocPixelRef.h new file mode 100644 index 0000000..2241a51 --- /dev/null +++ b/core/SkMallocPixelRef.h @@ -0,0 +1,51 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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. If addr is NULL, sk_malloc_throw() + is called to allocate it. + */ + SkMallocPixelRef(void* addr, size_t size, SkColorTable* ctable, bool ownPixels = true); + virtual ~SkMallocPixelRef(); + + //! Return the allocation size for the pixels + size_t getSize() const { return fSize; } + void* getAddr() const { return fStorage; } + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMallocPixelRef) + +protected: + // overrides from SkPixelRef + virtual void* onLockPixels(SkColorTable**); + virtual void onUnlockPixels(); + + SkMallocPixelRef(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + void* fStorage; + size_t fSize; + SkColorTable* fCTable; + bool fOwnPixels; + + typedef SkPixelRef INHERITED; +}; + + +#endif diff --git a/core/SkMask.h b/core/SkMask.h new file mode 100644 index 0000000..7155184 --- /dev/null +++ b/core/SkMask.h @@ -0,0 +1,161 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 + kARGB32_Format, //!< SkPMColor + kLCD16_Format, //!< 565 alpha for r/g/b + kLCD32_Format //!< 888 alpha for r/g/b + }; + + enum { + kCountMaskFormats = kLCD32_Format + 1 + }; + + uint8_t* fImage; + SkIRect fBounds; + uint32_t fRowBytes; + Format fFormat; + + /** Returns true if the mask is empty: i.e. it has an empty bounds. + */ + bool isEmpty() const { return fBounds.isEmpty(); } + + /** Return the byte size of the mask, assuming only 1 plane. + Does not account for k3D_Format. For that, use computeTotalImageSize(). + If there is an overflow of 32bits, then returns 0. + */ + size_t computeImageSize() const; + + /** Return the byte size of the mask, taking into account + any extra planes (e.g. k3D_Format). + If there is an overflow of 32bits, then returns 0. + */ + 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(kBW_Format == fFormat); + 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* getAddr8(int x, int y) const { + SkASSERT(kA8_Format == fFormat); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes; + } + + /** + * Return the address of the specified 16bit mask. In the debug build, + * this asserts that the mask's format is kLCD16_Format, and that (x,y) + * are contained in the mask's fBounds. + */ + uint16_t* getAddrLCD16(int x, int y) const { + SkASSERT(kLCD16_Format == fFormat); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + uint16_t* row = (uint16_t*)(fImage + (y - fBounds.fTop) * fRowBytes); + return row + (x - fBounds.fLeft); + } + + /** + * Return the address of the specified 32bit mask. In the debug build, + * this asserts that the mask's format is kLCD32_Format, and that (x,y) + * are contained in the mask's fBounds. + */ + uint32_t* getAddrLCD32(int x, int y) const { + SkASSERT(kLCD32_Format == fFormat); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes); + return row + (x - fBounds.fLeft); + } + + /** + * Return the address of the specified 32bit mask. In the debug build, + * this asserts that the mask's format is 32bits, and that (x,y) + * are contained in the mask's fBounds. + */ + uint32_t* getAddr32(int x, int y) const { + SkASSERT(kLCD32_Format == fFormat || kARGB32_Format == fFormat); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes); + return row + (x - fBounds.fLeft); + } + + /** + * Returns the address of the specified pixel, computing the pixel-size + * at runtime based on the mask format. This will be slightly slower than + * using one of the routines where the format is implied by the name + * e.g. getAddr8 or getAddrLCD32. + * + * x,y must be contained by the mask's bounds (this is asserted in the + * debug build, but not checked in the release build.) + * + * This should not be called with kBW_Format, as it will give unspecified + * results (and assert in the debug build). + */ + void* getAddr(int x, int y) const; + + 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 + }; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * \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 SkAutoMaskFreeImage { +public: + SkAutoMaskFreeImage(uint8_t* maskImage) { + fImage = maskImage; + } + + ~SkAutoMaskFreeImage() { + SkMask::FreeImage(fImage); + } + +private: + uint8_t* fImage; +}; + +#endif diff --git a/core/SkMaskFilter.h b/core/SkMaskFilter.h new file mode 100644 index 0000000..fda1289 --- /dev/null +++ b/core/SkMaskFilter.h @@ -0,0 +1,179 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMaskFilter_DEFINED +#define SkMaskFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkMask.h" +#include "SkPaint.h" + +class SkBitmap; +class SkBlitter; +class SkBounder; +class SkMatrix; +class SkPath; +class SkRasterClip; + +/** \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 SK_API SkMaskFilter : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkMaskFilter) + + SkMaskFilter() {} + + /** Returns the format of the resulting mask that this subclass will return + when its filterMask() method is called. + */ + virtual SkMask::Format getFormat() const = 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) const; + +#if SK_SUPPORT_GPU + /** + * Returns true if the filter can be expressed a single-pass + * GrEffect, used to process this filter on the GPU, or false if + * not. + * + * If effect is non-NULL, a new GrEffect instance is stored + * in it. The caller assumes ownership of the stage, and it is up to the + * caller to unref it. + */ + virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const; + + /** + * Returns true if the filter can be processed on the GPU. This is most + * often used for multi-pass effects, where intermediate results must be + * rendered to textures. For single-pass effects, use asNewEffect(). + * + * 'maskRect' returns the device space portion of the mask the the filter + * needs. The mask passed into 'filterMaskGPU' should have the same extent + * as 'maskRect' but be translated to the upper-left corner of the mask + * (i.e., (maskRect.fLeft, maskRect.fTop) appears at (0, 0) in the mask). + */ + virtual bool canFilterMaskGPU(const SkRect& devBounds, + const SkIRect& clipBounds, + const SkMatrix& ctm, + SkRect* maskRect) const; + + /** + * Perform this mask filter on the GPU. This is most often used for + * multi-pass effects, where intermediate results must be rendered to + * textures. For single-pass effects, use asNewEffect(). 'src' is the + * source image for processing, as a texture-backed bitmap. 'result' is + * the destination bitmap, which should contain a texture-backed pixelref + * on success. 'maskRect' should be the rect returned from canFilterMaskGPU. + */ + bool filterMaskGPU(GrContext* context, + const SkBitmap& src, + const SkRect& maskRect, + SkBitmap* result) const; + + /** + * This flavor of 'filterMaskGPU' provides a more direct means of accessing + * the filtering capabilities. Setting 'canOverwriteSrc' can allow some + * filters to skip the allocation of an additional texture. + */ + virtual bool filterMaskGPU(GrTexture* src, + const SkRect& maskRect, + GrTexture** result, + bool canOverwriteSrc) const; +#endif + + /** + * The fast bounds function is used to enable the paint to be culled early + * in the drawing pipeline. This function accepts the current bounds of the + * paint as its src param and the filter adjust those bounds using its + * current mask and returns the result using the dest param. Callers are + * allowed to provide the same struct for both src and dest so each + * implementation must accomodate that behavior. + * + * The default impl calls filterMask with the src mask having no image, + * but subclasses may override this if they can compute the rect faster. + */ + virtual void computeFastBounds(const SkRect& src, SkRect* dest) const; + + SkDEVCODE(virtual void toString(SkString* str) const = 0;) + +protected: + // empty for now, but lets get our subclass to remember to init us for the future + SkMaskFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + + enum FilterReturn { + kFalse_FilterReturn, + kTrue_FilterReturn, + kUnimplemented_FilterReturn + }; + + struct NinePatch { + SkMask fMask; // fBounds must have [0,0] in its top-left + SkIRect fOuterRect; // width/height must be >= fMask.fBounds' + SkIPoint fCenter; // identifies center row/col for stretching + }; + + /** + * Override if your subclass can filter a rect, and return the answer as + * a ninepatch mask to be stretched over the returned outerRect. On success + * return kTrue_FilterReturn. On failure (e.g. out of memory) return + * kFalse_FilterReturn. If the normal filterMask() entry-point should be + * called (the default) return kUnimplemented_FilterReturn. + * + * By convention, the caller will take the center rol/col from the returned + * mask as the slice it can replicate horizontally and vertically as we + * stretch the mask to fit inside outerRect. It is an error for outerRect + * to be smaller than the mask's bounds. This would imply that the width + * and height of the mask should be odd. This is not required, just that + * the caller will call mask.fBounds.centerX() and centerY() to find the + * strips that will be replicated. + */ + virtual FilterReturn filterRectsToNine(const SkRect[], int count, + const SkMatrix&, + const SkIRect& clipBounds, + NinePatch*) const; + +private: + friend class SkDraw; + + /** 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 SkRasterClip&, SkBounder*, SkBlitter* blitter, + SkPaint::Style style) const; + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkMath.h b/core/SkMath.h new file mode 100644 index 0000000..078c8fc --- /dev/null +++ b/core/SkMath.h @@ -0,0 +1,176 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMath_DEFINED +#define SkMath_DEFINED + +#include "SkTypes.h" + +/** + * 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) + +/////////////////////////////////////////////////////////////////////////////// + +//! Returns the number of leading zero bits (0...32) +int SkCLZ_portable(uint32_t); + +#ifndef SkCLZ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + #include <intrin.h> + + static inline int SkCLZ(uint32_t mask) { + if (mask) { + DWORD index; + _BitScanReverse(&index, mask); + return index ^ 0x1F; + } else { + return 32; + } + } + #elif defined(SK_CPU_ARM) || defined(__GNUC__) || defined(__clang__) + static inline int SkCLZ(uint32_t mask) { + // __builtin_clz(0) is undefined, so we have to detect that case. + return mask ? __builtin_clz(mask) : 32; + } + #else + #define SkCLZ(x) SkCLZ_portable(x) + #endif +#endif + +/** + * 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. + * @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); + if (value < 0) { + value = 0; + } + if (value > max) { + value = max; + } + return value; +} + +/** + * 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); +} + +/** + * Returns true if value is a power of 2. Does not explicitly check for + * value <= 0. + */ +static inline bool SkIsPow2(int value) { + return (value & (value - 1)) == 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 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. + */ +#ifdef SK_ARM_HAS_EDSP + 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/((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(U16CPU a, U16CPU 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; +} + +/** + * Return a*b/255, rounding any fractional bits. + * Only valid if a and b are unsigned and <= 32767. + */ +static inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) { + SkASSERT(a <= 32767); + SkASSERT(b <= 32767); + unsigned prod = SkMulS16(a, b) + 128; + return (prod + (prod >> 8)) >> 8; +} + +#endif diff --git a/core/SkMatrix.h b/core/SkMatrix.h new file mode 100644 index 0000000..f148e39 --- /dev/null +++ b/core/SkMatrix.h @@ -0,0 +1,674 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMatrix_DEFINED +#define SkMatrix_DEFINED + +#include "SkRect.h" + +class SkString; + +#ifdef SK_SCALAR_IS_FLOAT + typedef SkScalar SkPersp; + #define SkScalarToPersp(x) (x) + #define SkPerspToScalar(x) (x) +#else + typedef SkFract SkPersp; + #define SkScalarToPersp(x) SkFixedToFract(x) + #define SkPerspToScalar(x) SkFractToFixed(x) +#endif + +/** \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 SK_API 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 bitfield describing the transformations the matrix may + perform. The bitfield is computed conservatively, so it may include + false positives. For example, when kPerspective_Mask is true, all + other bits may be set to true even in the case of a pure perspective + transform. + */ + 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; + } + // alias for rectStaysRect() + bool preservesAxisAlignment() const { return this->rectStaysRect(); } + + /** + * Returns true if the matrix contains perspective elements. + */ + bool hasPerspective() const { + return SkToBool(this->getPerspectiveTypeMaskOnly() & + kPerspective_Mask); + } + + /** Returns true if the matrix contains only translation, rotation or uniform scale + Returns false if other transformation types are included or is degenerate + */ + bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; + + /** Returns true if the matrix contains only translation, rotation or scale + (non-uniform scale is allowed). + Returns false if other transformation types are included or is degenerate + */ + bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; + + enum { + kMScaleX, + kMSkewX, + kMTransX, + kMSkewY, + kMScaleY, + kMTransY, + kMPersp0, + kMPersp1, + kMPersp2 + }; + + /** Affine arrays are in column major order + because that's how PDF and XPS like it. + */ + enum { + kAScaleX, + kASkewY, + kASkewX, + kAScaleY, + kATransX, + kATransY + }; + + 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]; } + SkPersp getPerspX() const { return fMat[kMPersp0]; } + SkPersp getPerspY() const { return fMat[kMPersp1]; } + + SkScalar& operator[](int index) { + SkASSERT((unsigned)index < 9); + this->setTypeMask(kUnknown_Mask); + return fMat[index]; + } + + 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(SkPersp v) { this->set(kMPersp0, v); } + void setPerspY(SkPersp v) { this->set(kMPersp1, v); } + + void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkPersp persp0, SkPersp persp1, SkPersp persp2) { + fMat[kMScaleX] = scaleX; + fMat[kMSkewX] = skewX; + fMat[kMTransX] = transX; + fMat[kMSkewY] = skewY; + fMat[kMScaleY] = scaleY; + fMat[kMTransY] = transY; + fMat[kMPersp0] = persp0; + fMat[kMPersp1] = persp1; + fMat[kMPersp2] = persp2; + this->setTypeMask(kUnknown_Mask); + } + + /** Set the matrix to identity + */ + void reset(); + // alias for reset() + void setIdentity() { this->reset(); } + + /** Set the matrix to translate by (dx, dy). + */ + void setTranslate(SkScalar dx, SkScalar dy); + void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); } + + /** Set the matrix to scale by sx and sy, with a pivot point at (px, py). + The pivot point is the coordinate that should remain unchanged by the + specified transformation. + */ + 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 scale by 1/divx and 1/divy. Returns false and doesn't + touch the matrix if either divx or divy is zero. + */ + bool setIDiv(int divx, int divy); + /** 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 SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const { + // Allow the trivial case to be inlined. + if (this->isIdentity()) { + if (NULL != inverse) { + inverse->reset(); + } + return true; + } + return this->invertNonIdentity(inverse); + } + + /** Fills the passed array with affine identity values + in column major order. + @param affine The array to fill with affine identity values. + Must not be NULL. + */ + static void SetAffineIdentity(SkScalar affine[6]); + + /** Fills the passed array with the affine values in column major order. + If the matrix is a perspective transform, returns false + and does not change the passed array. + @param affine The array to fill with affine values. Ignored if NULL. + */ + bool asAffine(SkScalar affine[6]) 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); + } + + /** Like mapPoints but with custom byte stride between the points. Stride + * should be a multiple of sizeof(SkScalar). + */ + void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const { + SkASSERT(stride >= sizeof(SkPoint)); + SkASSERT(0 == stride % sizeof(SkScalar)); + for (int i = 0; i < count; ++i) { + this->mapPoints(pts, pts, 1); + pts = (SkPoint*)((intptr_t)pts + stride); + } + } + + /** Like mapPoints but with custom byte stride between the points. + */ + void mapPointsWithStride(SkPoint dst[], SkPoint src[], + size_t stride, int count) const { + SkASSERT(stride >= sizeof(SkPoint)); + SkASSERT(0 == stride % sizeof(SkScalar)); + for (int i = 0; i < count; ++i) { + this->mapPoints(dst, src, 1); + src = (SkPoint*)((intptr_t)src + stride); + dst = (SkPoint*)((intptr_t)dst + stride); + } + } + + 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; + + /** Efficient comparison of two matrices. It distinguishes between zero and + * negative zero. It will return false when the sign of zero values is the + * only difference between the two matrices. It considers NaN values to be + * equal to themselves. So a matrix full of NaNs is "cheap equal" to + * another matrix full of NaNs iff the NaN values are bitwise identical + * while according to strict the strict == test a matrix with a NaN value + * is equal to nothing, including itself. + */ + bool cheapEqualTo(const SkMatrix& m) const { + return 0 == memcmp(fMat, m.fMat, sizeof(fMat)); + } + +#ifdef SK_SCALAR_IS_FIXED + friend bool operator==(const SkMatrix& a, const SkMatrix& b) { + return a.cheapEqualTo(b); + } +#else + friend bool operator==(const SkMatrix& a, const SkMatrix& b); +#endif + friend bool operator!=(const SkMatrix& a, const SkMatrix& b) { + return !(a == b); + } + + enum { + // writeTo/readFromMemory will never return a value larger than this + kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t) + }; + // return the number of bytes written, whether or not buffer is null + uint32_t writeToMemory(void* buffer) const; + // return the number of bytes read + uint32_t readFromMemory(const void* buffer); + + SkDEVCODE(void dump() const;) + SkDEVCODE(void toString(SkString*) const;) + + /** + * Calculates the maximum stretching factor of the matrix. If the matrix has + * perspective -1 is returned. + * + * @return maximum strecthing factor + */ + SkScalar getMaxStretch() const; + + /** + * Return a reference to a const identity matrix + */ + static const SkMatrix& I(); + + /** + * Return a reference to a const matrix that is "invalid", one that could + * never be used. + */ + static const SkMatrix& InvalidMatrix(); + + /** + * Testing routine; the matrix's type cache should never need to be + * manually invalidated during normal use. + */ + void dirtyMatrixTypeCache() { + this->setTypeMask(kUnknown_Mask); + } + +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 will be set on identity matrices + */ + kRectStaysRect_Mask = 0x10, + + /** Set if the perspective bit is valid even though the rest of + the matrix is Unknown. + */ + kOnlyPerspectiveValid_Mask = 0x40, + + kUnknown_Mask = 0x80, + + kORableMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask, + + kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask + }; + + SkScalar fMat[9]; + mutable uint32_t fTypeMask; + + uint8_t computeTypeMask() const; + uint8_t computePerspectiveTypeMask() const; + + void setTypeMask(int mask) { + // allow kUnknown or a valid mask + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || + ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) + == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); + fTypeMask = SkToU8(mask); + } + + void orTypeMask(int mask) { + SkASSERT((mask & kORableMasks) == mask); + fTypeMask = SkToU8(fTypeMask | mask); + } + + void clearTypeMask(int mask) { + // only allow a valid mask + SkASSERT((mask & kAllMasks) == mask); + fTypeMask &= ~mask; + } + + TypeMask getPerspectiveTypeMaskOnly() const { + if ((fTypeMask & kUnknown_Mask) && + !(fTypeMask & kOnlyPerspectiveValid_Mask)) { + fTypeMask = this->computePerspectiveTypeMask(); + } + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if we already know that the matrix is identity; + false otherwise. + */ + bool isTriviallyIdentity() const { + if (fTypeMask & kUnknown_Mask) { + return false; + } + return ((fTypeMask & 0xF) == 0); + } + + bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const; + + 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/core/SkMetaData.h b/core/SkMetaData.h new file mode 100644 index 0000000..5db437c --- /dev/null +++ b/core/SkMetaData.h @@ -0,0 +1,175 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMetaData_DEFINED +#define SkMetaData_DEFINED + +#include "SkScalar.h" + +class SkRefCnt; + +class SK_API SkMetaData { +public: + /** + * Used to manage the life-cycle of a ptr in the metadata. This is option + * in setPtr, and is only invoked when either copying one metadata to + * another, or when the metadata is destroyed. + * + * setPtr(name, ptr, proc) { + * fPtr = proc(ptr, true); + * } + * + * copy: A = B { + * A.fPtr = B.fProc(B.fPtr, true); + * } + * + * ~SkMetaData { + * fProc(fPtr, false); + * } + */ + typedef void* (*PtrProc)(void* ptr, bool doRef); + + /** + * Implements PtrProc for SkRefCnt pointers + */ + static void* RefCntProc(void* ptr, bool doRef); + + SkMetaData(); + SkMetaData(const SkMetaData& src); + ~SkMetaData(); + + SkMetaData& operator=(const SkMetaData& src); + + void reset(); + + bool findS32(const char name[], int32_t* value = NULL) const; + bool findScalar(const char name[], SkScalar* value = NULL) const; + const SkScalar* findScalars(const char name[], int* count, + SkScalar values[] = NULL) const; + const char* findString(const char name[]) const; + bool findPtr(const char name[], void** value = NULL, PtrProc* = NULL) const; + bool findBool(const char name[], bool* value = NULL) const; + const void* findData(const char name[], size_t* byteCount = NULL) const; + + bool hasS32(const char name[], int32_t value) const { + int32_t v; + return this->findS32(name, &v) && v == value; + } + bool hasScalar(const char name[], SkScalar value) const { + SkScalar v; + return this->findScalar(name, &v) && v == value; + } + bool hasString(const char name[], const char value[]) const { + const char* v = this->findString(name); + return (v == NULL && value == NULL) || + (v != NULL && value != NULL && !strcmp(v, value)); + } + bool hasPtr(const char name[], void* value) const { + void* v; + return this->findPtr(name, &v) && v == value; + } + bool hasBool(const char name[], bool value) const { + bool v; + return this->findBool(name, &v) && v == value; + } + bool hasData(const char name[], const void* data, size_t byteCount) const { + size_t len; + const void* ptr = this->findData(name, &len); + return NULL != ptr && len == byteCount && !memcmp(ptr, data, len); + } + + void setS32(const char name[], int32_t value); + void setScalar(const char name[], SkScalar value); + SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL); + void setString(const char name[], const char value[]); + void setPtr(const char name[], void* value, PtrProc proc = NULL); + void setBool(const char name[], bool value); + // the data is copied from the input pointer. + void setData(const char name[], const void* data, size_t byteCount); + + bool removeS32(const char name[]); + bool removeScalar(const char name[]); + bool removeString(const char name[]); + bool removePtr(const char name[]); + bool removeBool(const char name[]); + bool removeData(const char name[]); + + // helpers for SkRefCnt + bool findRefCnt(const char name[], SkRefCnt** ptr = NULL) { + return this->findPtr(name, reinterpret_cast<void**>(ptr)); + } + bool hasRefCnt(const char name[], SkRefCnt* ptr) { + return this->hasPtr(name, ptr); + } + void setRefCnt(const char name[], SkRefCnt* ptr) { + this->setPtr(name, ptr, RefCntProc); + } + bool removeRefCnt(const char name[]) { + return this->removePtr(name); + } + + enum Type { + kS32_Type, + kScalar_Type, + kString_Type, + kPtr_Type, + kBool_Type, + kData_Type, + + kTypeCount + }; + + struct Rec; + class Iter; + friend class Iter; + + class Iter { + public: + Iter() : fRec(NULL) {} + Iter(const SkMetaData&); + + /** Reset the iterator, so that calling next() will return the first + data element. This is done implicitly in the constructor. + */ + void reset(const SkMetaData&); + + /** Each time next is called, it returns the name of the next data element, + or null when there are no more elements. If non-null is returned, then the + element's type is returned (if not null), and the number of data values + is returned in count (if not null). + */ + const char* next(Type*, int* count); + + private: + Rec* fRec; + }; + +public: + struct Rec { + Rec* fNext; + uint16_t fDataCount; // number of elements + uint8_t fDataLen; // sizeof a single element + uint8_t fType; + + const void* data() const { return (this + 1); } + void* data() { return (this + 1); } + const char* name() const { return (const char*)this->data() + fDataLen * fDataCount; } + char* name() { return (char*)this->data() + fDataLen * fDataCount; } + + static Rec* Alloc(size_t); + static void Free(Rec*); + }; + Rec* fRec; + + const Rec* find(const char name[], Type) const; + void* set(const char name[], const void* data, size_t len, Type, int count); + bool remove(const char name[], Type); +}; + +#endif diff --git a/core/SkOSFile.h b/core/SkOSFile.h new file mode 100644 index 0000000..b75fe6c --- /dev/null +++ b/core/SkOSFile.h @@ -0,0 +1,159 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +// TODO: add unittests for all these operations + +#ifndef SkOSFile_DEFINED +#define SkOSFile_DEFINED + +#include "SkString.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS) + #include <dirent.h> +#endif + +#include <stddef.h> // ptrdiff_t + +struct SkFILE; + +enum SkFILE_Flags { + kRead_SkFILE_Flag = 0x01, + kWrite_SkFILE_Flag = 0x02 +}; + +#ifdef _WIN32 +const static char SkPATH_SEPARATOR = '\\'; +#else +const static char SkPATH_SEPARATOR = '/'; +#endif + +SkFILE* sk_fopen(const char path[], SkFILE_Flags); +void sk_fclose(SkFILE*); + +size_t sk_fgetsize(SkFILE*); +/** Return true if the file could seek back to the beginning +*/ +bool sk_frewind(SkFILE*); + +size_t sk_fread(void* buffer, size_t byteCount, SkFILE*); +size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE*); + +char* sk_fgets(char* str, int size, SkFILE* f); + +void sk_fflush(SkFILE*); + +bool sk_fseek(SkFILE*, size_t); +bool sk_fmove(SkFILE*, long); +size_t sk_ftell(SkFILE*); + +/** Maps a file into memory. Returns the address and length on success, NULL otherwise. + * The mapping is read only. + * When finished with the mapping, free the returned pointer with sk_fmunmap. + */ +void* sk_fmmap(SkFILE* f, size_t* length); + +/** Maps a file descriptor into memory. Returns the address and length on success, NULL otherwise. + * The mapping is read only. + * When finished with the mapping, free the returned pointer with sk_fmunmap. + */ +void* sk_fdmmap(int fd, size_t* length); + +/** Unmaps a file previously mapped by sk_fmmap or sk_fdmmap. + * The length parameter must be the same as returned from sk_fmmap. + */ +void sk_fmunmap(const void* addr, size_t length); + +/** Returns true if the two point at the exact same filesystem object. */ +bool sk_fidentical(SkFILE* a, SkFILE* b); + +/** Returns the underlying file descriptor for the given file. + * The return value will be < 0 on failure. + */ +int sk_fileno(SkFILE* f); + +// Returns true if something (file, directory, ???) exists at this path. +bool sk_exists(const char *path); + +// Returns true if a directory exists at this path. +bool sk_isdir(const char *path); + +// Have we reached the end of the file? +int sk_feof(SkFILE *); + + +// Create a new directory at this path; returns true if successful. +// If the directory already existed, this will return true. +// Description of the error, if any, will be written to stderr. +bool sk_mkdir(const char* path); + +class SkOSFile { +public: + class Iter { + public: + Iter(); + Iter(const char path[], const char suffix[] = NULL); + ~Iter(); + + void reset(const char path[], const char suffix[] = NULL); + /** If getDir is true, only returns directories. + Results are undefined if true and false calls are + interleaved on a single iterator. + */ + bool next(SkString* name, bool getDir = false); + + private: +#ifdef SK_BUILD_FOR_WIN + HANDLE fHandle; + uint16_t* fPath16; +#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS) + DIR* fDIR; + SkString fPath, fSuffix; +#endif + }; +}; + +class SkUTF16_Str { +public: + SkUTF16_Str(const char src[]); + ~SkUTF16_Str() + { + sk_free(fStr); + } + const uint16_t* get() const { return fStr; } + +private: + uint16_t* fStr; +}; + +/** + * Functions for modifying SkStrings which represent paths on the filesystem. + */ +class SkOSPath { +public: + /** + * Assembles rootPath and relativePath into a single path, like this: + * rootPath/relativePath. + * It is okay to call with a NULL rootPath and/or relativePath. A path + * separator will still be inserted. + * + * Uses SkPATH_SEPARATOR, to work on all platforms. + */ + static SkString SkPathJoin(const char *rootPath, const char *relativePath); + + /** + * Return the name of the file, ignoring the directory structure. + * Behaves like python's os.path.basename. If the fullPath is + * /dir/subdir/, an empty string is returned. + * @param fullPath Full path to the file. + * @return SkString The basename of the file - anything beyond the + * final slash, or the full name if there is no slash. + */ + static SkString SkBasename(const char* fullPath); +}; +#endif diff --git a/core/SkPackBits.h b/core/SkPackBits.h new file mode 100644 index 0000000..f0614a0 --- /dev/null +++ b/core/SkPackBits.h @@ -0,0 +1,79 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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/core/SkPaint.h b/core/SkPaint.h new file mode 100644 index 0000000..fa0c61e --- /dev/null +++ b/core/SkPaint.h @@ -0,0 +1,1105 @@ + + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPaint_DEFINED +#define SkPaint_DEFINED + +#include "SkColor.h" +#include "SkDrawLooper.h" +#include "SkMatrix.h" +#include "SkXfermode.h" +#ifdef SK_BUILD_FOR_ANDROID +#include "SkPaintOptionsAndroid.h" +#endif + +class SkAnnotation; +class SkAutoGlyphCache; +class SkColorFilter; +class SkDescriptor; +struct SkDeviceProperties; +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; +struct SkGlyph; +struct SkRect; +class SkGlyphCache; +class SkImageFilter; +class SkMaskFilter; +class SkPath; +class SkPathEffect; +struct SkPoint; +class SkRasterizer; +class SkShader; +class SkTypeface; + +typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**, + SkFixed x, SkFixed y); + +typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**); + +#define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag + +/** \class SkPaint + + The SkPaint class holds the style and color information about how to draw + geometries, text and bitmaps. +*/ + +class SK_API SkPaint { + enum { + // DEPRECATED -- use setFilterLevel instead + kFilterBitmap_Flag = 0x02, // temporary flag + // DEPRECATED -- use setFilterLevel instead + kHighQualityFilterBitmap_Flag = 0x4000, // temporary flag + // DEPRECATED -- use setFilterLevel instead + kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag + }; +public: + SkPaint(); + SkPaint(const SkPaint& paint); + ~SkPaint(); + + SkPaint& operator=(const SkPaint&); + + SK_API friend bool operator==(const SkPaint& a, const SkPaint& b); + friend bool 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 level of hinting to be performed. These names are taken + from the Gnome/Cairo names for the same. They are translated into + Freetype concepts the same as in cairo-ft-font.c: + kNo_Hinting -> FT_LOAD_NO_HINTING + kSlight_Hinting -> FT_LOAD_TARGET_LIGHT + kNormal_Hinting -> <default, no option> + kFull_Hinting -> <same as kNormalHinting, unless we are rendering + subpixel glyphs, in which case TARGET_LCD or + TARGET_LCD_V is used> + */ + enum Hinting { + kNo_Hinting = 0, + kSlight_Hinting = 1, + kNormal_Hinting = 2, //!< this is the default + kFull_Hinting = 3 + }; + + Hinting getHinting() const { + return static_cast<Hinting>(fHinting); + } + + void setHinting(Hinting hintingLevel); + + /** Specifies the bit values that are stored in the paint's flags. + */ + enum Flags { + kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing + 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 positioning + kDevKernText_Flag = 0x100, //!< mask to enable device kerning text + kLCDRenderText_Flag = 0x200, //!< mask to enable subpixel glyph renderering + kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes + kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter + kVerticalText_Flag = 0x1000, + kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it + // when adding extra flags, note that the fFlags member is specified + // with a bit-width and you'll have to expand it. + + kAllFlags = 0xFFFF + }; + + /** 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. + * @param subpixelText true to set the subpixelText bit in the paint's + * flags, false to clear it. + */ + void setSubpixelText(bool subpixelText); + + bool isLCDRenderText() const { + return SkToBool(this->getFlags() & kLCDRenderText_Flag); + } + + /** + * Helper for setFlags(), setting or clearing the kLCDRenderText_Flag. + * Note: antialiasing must also be on for lcd rendering + * @param lcdText true to set the LCDRenderText bit in the paint's flags, + * false to clear it. + */ + void setLCDRenderText(bool lcdText); + + bool isEmbeddedBitmapText() const { + return SkToBool(this->getFlags() & kEmbeddedBitmapText_Flag); + } + + /** Helper for setFlags(), setting or clearing the kEmbeddedBitmapText_Flag bit + @param useEmbeddedBitmapText true to set the kEmbeddedBitmapText bit in the paint's flags, + false to clear it. + */ + void setEmbeddedBitmapText(bool useEmbeddedBitmapText); + + bool isAutohinted() const { + return SkToBool(this->getFlags() & kAutoHinting_Flag); + } + + /** Helper for setFlags(), setting or clearing the kAutoHinting_Flag bit + @param useAutohinter true to set the kEmbeddedBitmapText bit in the + paint's flags, + false to clear it. + */ + void setAutohinted(bool useAutohinter); + + bool isVerticalText() const { + return SkToBool(this->getFlags() & kVerticalText_Flag); + } + + /** + * Helper for setting or clearing the kVerticalText_Flag bit in + * setFlags(...). + * + * If this bit is set, then advances are treated as Y values rather than + * X values, and drawText will places its glyphs vertically rather than + * horizontally. + */ + void setVerticalText(bool); + + /** 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); + + enum FilterLevel { + kNone_FilterLevel, + kLow_FilterLevel, + kMedium_FilterLevel, + kHigh_FilterLevel + }; + + /** + * Return the filter level. This affects the quality (and performance) of + * drawing scaled images. + */ + FilterLevel getFilterLevel() const; + + /** + * Set the filter level. This affects the quality (and performance) of + * drawing scaled images. + */ + void setFilterLevel(FilterLevel); + + /** + * DEPRECATED: use setFilterLevel instead. + * If the predicate is true, set the filterLevel to Low, else set it to + * None. + */ + void setFilterBitmap(bool doFilter) { + this->setFilterLevel(doFilter ? kLow_FilterLevel : kNone_FilterLevel); + } + + /** + * DEPRECATED: call getFilterLevel() instead. + * Returns true if getFilterLevel() returns anything other than None. + */ + bool isFilterBitmap() const { + return kNone_FilterLevel != this->getFilterLevel(); + } + + /** Styles apply to rect, oval, path, and text. + Bitmaps are always drawn in "fill", and lines are always drawn in + "stroke". + + Note: strokeandfill implicitly draws the result with + SkPath::kWinding_FillType, so if the original path is even-odd, the + results may not appear the same as if it was drawn twice, filled and + then stroked. + */ + enum Style { + kFill_Style, //!< fill the geometry + kStroke_Style, //!< stroke the geometry + kStrokeAndFill_Style, //!< fill and stroke the geometry + }; + enum { + kStyleCount = kStrokeAndFill_Style + 1 + }; + + /** 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) + * @param cullRect If not null, the dst path may be culled to this rect. + * @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 SkRect* cullRect = NULL) 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. + * Shaders specify the source color(s) for what is being drawn. If a paint + * has no shader, then the paint's color is used. If the paint has a + * shader, then the shader's color(s) are use instead, but they are + * modulated by the paint's alpha. This makes it easy to create a shader + * once (e.g. bitmap tiling or gradient) and then change its transparency + * w/o having to modify the original shader... only the paint's alpha needs + * to be modified. + * <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); + + /** Create an xfermode based on the specified Mode, and assign it into the + paint, returning the mode that was set. If the Mode is SrcOver, then + the paint's xfermode is set to null. + */ + SkXfermode* setXfermodeMode(SkXfermode::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); + + SkImageFilter* getImageFilter() const { return fImageFilter; } + SkImageFilter* setImageFilter(SkImageFilter*); + + SkAnnotation* getAnnotation() const { return fAnnotation; } + SkAnnotation* setAnnotation(SkAnnotation*); + + /** + * Returns true if there is an annotation installed on this paint, and + * the annotation specifics no-drawing. + */ + bool isNoDrawAnnotation() const { + return SkToBool(fPrivFlags & kNoDrawAnnotation_PrivFlag); + } + + /** + * Return the paint's SkDrawLooper (if any). Does not affect the looper's + * reference count. + */ + SkDrawLooper* getLooper() const { return fLooper; } + + /** + * Set or clear the looper object. + * <p /> + * Pass NULL to clear any previous looper. + * As a convenience, the parameter passed is also returned. + * If a previous looper exists in the paint, its reference count is + * decremented. If looper is not NULL, its reference count is + * incremented. + * @param looper May be NULL. The new looper to be installed in the paint. + * @return looper + */ + SkDrawLooper* setLooper(SkDrawLooper* looper); + + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; + enum { + kAlignCount = 3 + }; + + /** 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); + +#ifdef SK_SUPPORT_HINTING_SCALE_FACTOR + /** Return the paint's scale factor used for correctly rendering + glyphs in high DPI mode without text subpixel positioning. + @return the scale factor used for rendering glyphs in high DPI mode. + */ + SkScalar getHintingScaleFactor() const { return fHintingScaleFactor; } + + /** Set the paint's scale factor used for correctly rendering + glyphs in high DPI mode without text subpixel positioning. + @param the scale factor used for rendering glyphs in high DPI mode. + */ + void setHintingScaleFactor(SkScalar hintingScaleFactor); +#endif + + /** 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 + kUTF32_TextEncoding, //!< the text parameters are UTF32 + 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) + SkScalar fAvgCharWidth; //!< the average charactor width (>= 0) + SkScalar fMaxCharWidth; //!< the max charactor width (>= 0) + SkScalar fXMin; //!< The minimum bounding box x value for all glyphs + SkScalar fXMax; //!< The maximum bounding box x value for all glyphs + SkScalar fXHeight; //!< the height of an 'x' in px, or 0 if no 'x' in face + }; + + /** 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 true if all of the specified text has a corresponding non-zero + glyph ID. If any of the code-points in the text are not supported in + the typeface (i.e. the glyph ID would be zero), then return false. + + If the text encoding for the paint is kGlyph_TextEncoding, then this + returns true if all of the specified glyph IDs are non-zero. + */ + bool containsText(const void* text, size_t byteLength) const; + + /** Convert the glyph array into Unichars. Unconvertable glyphs are mapped + to zero. Note: this does not look at the text-encoding setting in the + paint, only at the typeface. + */ + void glyphsToUnichars(const uint16_t glyphs[], int count, + SkUnichar text[]) 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. This will return the vertical measure + * if isVerticalText() is true, in which case the returned value should + * be treated has a height instead of a width. + * + * @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. This will return the vertical measure + * if isVerticalText() is true, in which case the returned value should + * be treated has a height instead of a width. + * + * @param text Address of the text + * @param length Number of bytes of text to measure + * @return The advance 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 number of bytes of text that were measured. If + * isVerticalText() is true, then the vertical advances are used for + * the measurement. + * + * @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 advances for the text. These will be vertical advances if + * isVerticalText() returns true. + * + * @param text the text + * @param byteLength number of bytes to of text + * @param widths If not null, returns the array of advances for + * 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; + + void getPosTextPath(const void* text, size_t length, + const SkPoint pos[], SkPath* path) const; + +#ifdef SK_BUILD_FOR_ANDROID + const SkGlyph& getUnicharMetrics(SkUnichar, const SkMatrix*); + const SkGlyph& getGlyphMetrics(uint16_t, const SkMatrix*); + const void* findImage(const SkGlyph&, const SkMatrix*); + + uint32_t getGenerationID() const; + void setGenerationID(uint32_t generationID); + + /** Returns the base glyph count for the strike associated with this paint + */ + unsigned getBaseGlyphCount(SkUnichar text) const; + + const SkPaintOptionsAndroid& getPaintOptionsAndroid() const { + return fPaintOptionsAndroid; + } + void setPaintOptionsAndroid(const SkPaintOptionsAndroid& options); +#endif + + // returns true if the paint's settings (e.g. xfermode + alpha) resolve to + // mean that we need not draw at all (e.g. SrcOver + 0-alpha) + bool nothingToDraw() const; + + /////////////////////////////////////////////////////////////////////////// + // would prefer to make these private... + + /** 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 { + if (this->getLooper()) { + return this->getLooper()->canComputeFastBounds(*this); + } + return !this->getRasterizer(); + } + + /** 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 { + SkPaint::Style style = this->getStyle(); + // ultra fast-case: filling with no effects that affect geometry + if (kFill_Style == style) { + uintptr_t effects = reinterpret_cast<uintptr_t>(this->getLooper()); + effects |= reinterpret_cast<uintptr_t>(this->getMaskFilter()); + effects |= reinterpret_cast<uintptr_t>(this->getPathEffect()); + if (!effects) { + return orig; + } + } + + return this->doComputeFastBounds(orig, storage, style); + } + + const SkRect& computeFastStrokeBounds(const SkRect& orig, + SkRect* storage) const { + return this->doComputeFastBounds(orig, storage, kStroke_Style); + } + + // Take the style explicitly, so the caller can force us to be stroked + // without having to make a copy of the paint just to change that field. + const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage, + Style) const; + + /** + * Return a matrix that applies the paint's text values: size, scale, skew + */ + static SkMatrix* SetTextMatrix(SkMatrix* matrix, SkScalar size, + SkScalar scaleX, SkScalar skewX) { + matrix->setScale(size * scaleX, size); + if (skewX) { + matrix->postSkew(skewX, 0); + } + return matrix; + } + + SkMatrix* setTextMatrix(SkMatrix* matrix) const { + return SetTextMatrix(matrix, fTextSize, fTextScaleX, fTextSkewX); + } + + SkDEVCODE(void toString(SkString*) const;) + +private: + SkTypeface* fTypeface; + SkScalar fTextSize; + SkScalar fTextScaleX; + SkScalar fTextSkewX; +#ifdef SK_SUPPORT_HINTING_SCALE_FACTOR + SkScalar fHintingScaleFactor; +#endif + + SkPathEffect* fPathEffect; + SkShader* fShader; + SkXfermode* fXfermode; + SkMaskFilter* fMaskFilter; + SkColorFilter* fColorFilter; + SkRasterizer* fRasterizer; + SkDrawLooper* fLooper; + SkImageFilter* fImageFilter; + SkAnnotation* fAnnotation; + + SkColor fColor; + SkScalar fWidth; + SkScalar fMiterLimit; + // all of these bitfields should add up to 32 + unsigned fFlags : 16; + unsigned fTextAlign : 2; + unsigned fCapType : 2; + unsigned fJoinType : 2; + unsigned fStyle : 2; + unsigned fTextEncoding : 2; // 3 values + unsigned fHinting : 2; + unsigned fPrivFlags : 4; // these are not flattened/unflattened + + enum PrivFlags { + kNoDrawAnnotation_PrivFlag = 1 << 0, + }; + + 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 SkDeviceProperties* deviceProperties, const SkMatrix*) const; + + void descriptorProc(const SkDeviceProperties* deviceProperties, const SkMatrix* deviceMatrix, + void (*proc)(SkTypeface*, const SkDescriptor*, void*), + void* context, bool ignoreGamma = false) const; + + static void Term(); + + enum { + /* This is the size we use when we ask for a glyph's path. We then + * post-transform it as we draw to match the request. + * This is done to try to re-use cache entries for the path. + * + * This value is somewhat arbitrary. In theory, it could be 1, since + * we store paths as floats. However, we get the path from the font + * scaler, and it may represent its paths as fixed-point (or 26.6), + * so we shouldn't ask for something too big (might overflow 16.16) + * or too small (underflow 26.6). + * + * This value could track kMaxSizeForGlyphCache, assuming the above + * constraints, but since we ask for unhinted paths, the two values + * need not match per-se. + */ + kCanonicalTextSizeForPaths = 64, + + /* + * Above this size (taking into account CTM and textSize), we never use + * the cache for bits or metrics (we might overflow), so we just ask + * for a caononical size and post-transform that. + */ + kMaxSizeForGlyphCache = 256, + }; + + static bool TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM); + + bool tooBigToUseCache() const; + bool tooBigToUseCache(const SkMatrix& ctm) const; + + // Set flags/hinting/textSize up to use for drawing text as paths. + // Returns scale factor to restore the original textSize, since will will + // have change it to kCanonicalTextSizeForPaths. + SkScalar setupForAsPaths(); + + static SkScalar MaxCacheSize2() { + static const SkScalar kMaxSize = SkIntToScalar(kMaxSizeForGlyphCache); + static const SkScalar kMag2Max = kMaxSize * kMaxSize; + return kMag2Max; + } + + friend class SkAutoGlyphCache; + friend class SkCanvas; + friend class SkDraw; + friend class SkGraphics; // So Term() can be called. + friend class SkPDFDevice; + friend class SkTextToPathIter; + friend class SkCanonicalizePaint; + +#ifdef SK_BUILD_FOR_ANDROID + SkPaintOptionsAndroid fPaintOptionsAndroid; + + // In order for the == operator to work properly this must be the last field + // in the struct so that we can do a memcmp to this field's offset. + uint32_t fGenerationID; +#endif +}; + +#endif diff --git a/core/SkPaintOptionsAndroid.h b/core/SkPaintOptionsAndroid.h new file mode 100644 index 0000000..78e4386 --- /dev/null +++ b/core/SkPaintOptionsAndroid.h @@ -0,0 +1,129 @@ + +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPaintOptionsAndroid_DEFINED +#define SkPaintOptionsAndroid_DEFINED + +#include "SkTypes.h" +#include "SkString.h" + +#ifdef SK_BUILD_FOR_ANDROID + +class SkFlattenableReadBuffer; +class SkFlattenableWriteBuffer; + +/** \class SkLanguage + + The SkLanguage class represents a human written language, and is used by + text draw operations to determine which glyph to draw when drawing + characters with variants (ie Han-derived characters). +*/ +class SkLanguage { +public: + SkLanguage() { } + SkLanguage(const SkString& tag) : fTag(tag) { } + SkLanguage(const char* tag) : fTag(tag) { } + SkLanguage(const char* tag, size_t len) : fTag(tag, len) { } + SkLanguage(const SkLanguage& b) : fTag(b.fTag) { } + + /** Gets a BCP 47 language identifier for this SkLanguage. + @return a BCP 47 language identifier representing this language + */ + const SkString& getTag() const { return fTag; } + + /** Performs BCP 47 fallback to return an SkLanguage one step more general. + @return an SkLanguage one step more general + */ + SkLanguage getParent() const; + + bool operator==(const SkLanguage& b) const { + return fTag == b.fTag; + } + bool operator!=(const SkLanguage& b) const { + return fTag != b.fTag; + } + SkLanguage& operator=(const SkLanguage& b) { + fTag = b.fTag; + return *this; + } + +private: + //! BCP 47 language identifier + SkString fTag; +}; + +class SkPaintOptionsAndroid { +public: + SkPaintOptionsAndroid() { + fFontVariant = kDefault_Variant; + fUseFontFallbacks = false; + } + + SkPaintOptionsAndroid& operator=(const SkPaintOptionsAndroid& b) { + fLanguage = b.fLanguage; + fFontVariant = b.fFontVariant; + fUseFontFallbacks = b.fUseFontFallbacks; + return *this; + } + + bool operator!=(const SkPaintOptionsAndroid& b) const { + return fLanguage != b.fLanguage || + fFontVariant != b.fFontVariant || + fUseFontFallbacks != b.fUseFontFallbacks; + } + + void flatten(SkFlattenableWriteBuffer&) const; + void unflatten(SkFlattenableReadBuffer&); + + /** Return the paint's language value used for drawing text. + @return the paint's language value used for drawing text. + */ + const SkLanguage& getLanguage() const { return fLanguage; } + + /** Set the paint's language value used for drawing text. + @param language set the paint's language value for drawing text. + */ + void setLanguage(const SkLanguage& language) { fLanguage = language; } + void setLanguage(const char* languageTag) { fLanguage = SkLanguage(languageTag); } + + + enum FontVariant { + kDefault_Variant = 0x01, // Currently setting yourself to Default gives you Compact Variant + kCompact_Variant = 0x02, + kElegant_Variant = 0x04, + kLast_Variant = kElegant_Variant, + }; + + /** Return the font variant + @return the font variant used by this paint object + */ + FontVariant getFontVariant() const { return fFontVariant; } + + /** Set the font variant + @param fontVariant set the paint's font variant for choosing fonts + */ + void setFontVariant(FontVariant fontVariant) { + SkASSERT((unsigned)fontVariant <= kLast_Variant); + fFontVariant = fontVariant; + } + + bool isUsingFontFallbacks() const { return fUseFontFallbacks; } + + void setUseFontFallbacks(bool useFontFallbacks) { + fUseFontFallbacks = useFontFallbacks; + } + +private: + SkLanguage fLanguage; + FontVariant fFontVariant; + bool fUseFontFallbacks; +}; + +#endif // #ifdef SK_BUILD_FOR_ANDROID +#endif // #ifndef SkPaintOptionsAndroid_DEFINED diff --git a/core/SkPath.h b/core/SkPath.h new file mode 100644 index 0000000..be15a63 --- /dev/null +++ b/core/SkPath.h @@ -0,0 +1,1008 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPath_DEFINED +#define SkPath_DEFINED + +#include "SkInstCnt.h" +#include "SkMatrix.h" +#include "SkTDArray.h" +#include "SkRefCnt.h" + +#ifdef SK_BUILD_FOR_ANDROID +#define GEN_ID_INC fGenerationID++ +#define GEN_ID_PTR_INC(ptr) (ptr)->fGenerationID++ +#else +#define GEN_ID_INC +#define GEN_ID_PTR_INC(ptr) +#endif + +class SkReader32; +class SkWriter32; +class SkAutoPathBoundsUpdate; +class SkString; +class SkPathRef; +class SkRRect; + +/** \class SkPath + + The SkPath class encapsulates compound (multiple contour) geometric paths + consisting of straight line segments, quadratic curves, and cubic curves. +*/ +class SK_API SkPath { +public: + SK_DECLARE_INST_COUNT_ROOT(SkPath); + + SkPath(); + SkPath(const SkPath&); // Copies fGenerationID on Android. + ~SkPath(); + + SkPath& operator=(const SkPath&); // Increments fGenerationID on Android. + friend SK_API bool operator==(const SkPath&, const SkPath&); + friend bool operator!=(const SkPath& a, const SkPath& b) { + return !(a == b); + } + + 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); + GEN_ID_INC; + } + + /** Returns true if the filltype is one of the Inverse variants */ + bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); } + + /** + * Toggle between inverse and normal filltypes. This reverse the return + * value of isInverseFillType() + */ + void toggleInverseFillType() { + fFillType ^= 2; + GEN_ID_INC; + } + + enum Convexity { + kUnknown_Convexity, + kConvex_Convexity, + kConcave_Convexity + }; + + /** + * Return the path's convexity, as stored in the path. If it is currently unknown, + * then this function will attempt to compute the convexity (and cache the result). + */ + Convexity getConvexity() const { + if (kUnknown_Convexity != fConvexity) { + return static_cast<Convexity>(fConvexity); + } else { + return this->internalGetConvexity(); + } + } + + /** + * Return the currently cached value for convexity, even if that is set to + * kUnknown_Convexity. Note: getConvexity() will automatically call + * ComputeConvexity and cache its return value if the current setting is + * kUnknown. + */ + Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; } + + /** + * Store a convexity setting in the path. There is no automatic check to + * see if this value actually agrees with the return value that would be + * computed by getConvexity(). + * + * Note: even if this is set to a "known" value, if the path is later + * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be + * reset to kUnknown_Convexity. + */ + void setConvexity(Convexity); + + /** + * DEPRECATED: use getConvexity() + * Returns true if the path is flagged as being convex. This is not a + * confirmed by any analysis, it is just the value set earlier. + */ + bool isConvex() const { + return kConvex_Convexity == this->getConvexity(); + } + + /** + * DEPRECATED: use setConvexity() + * Set the isConvex flag to true or false. Convex paths may draw faster if + * this flag is set, though setting this to true on a path that is in fact + * not convex can give undefined results when drawn. Paths default to + * isConvex == false + */ + void setIsConvex(bool isConvex) { + this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); + } + + /** Returns true if the path is an oval. + * + * @param rect returns the bounding rect of this oval. It's a circle + * if the height and width are the same. + * + * @return true if this path is an oval. + * Tracking whether a path is an oval is considered an + * optimization for performance and so some paths that are in + * fact ovals can report false. + */ + bool isOval(SkRect* rect) const; + + /** Clear any lines and curves from the path, making it empty. This frees up + internal storage associated with those segments. + */ + 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. + */ + 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 all of the points in this path are finite, meaning there + * are no infinities and no NaNs. + */ + bool isFinite() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return SkToBool(fIsFinite); + } + + /** Test a line for zero length + + @return true if the line is of zero length; otherwise false. + */ + static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) { + return p1.equalsWithinTolerance(p2); + } + + /** Test a quad for zero length + + @return true if the quad is of zero length; otherwise false. + */ + static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3) { + return p1.equalsWithinTolerance(p2) && + p2.equalsWithinTolerance(p3); + } + + /** Test a cubic curve for zero length + + @return true if the cubic is of zero length; otherwise false. + */ + static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3, const SkPoint& p4) { + return p1.equalsWithinTolerance(p2) && + p2.equalsWithinTolerance(p3) && + p3.equalsWithinTolerance(p4); + } + + /** + * Returns true if the path specifies a single line (i.e. it contains just + * a moveTo and a lineTo). If so, and line[] is not null, it sets the 2 + * points in line[] to the end-points of the line. If the path is not a + * line, returns false and ignores line[]. + */ + bool isLine(SkPoint line[2]) 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; + + /** Return the number of points in the path + */ + int countPoints() const; + + /** Return the point at the specified index. If the index is out of range + (i.e. is not 0 <= index < countPoints()) then the returned coordinates + will be (0,0) + */ + SkPoint getPoint(int index) 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; + + /** Return the number of verbs in the path + */ + int countVerbs() const; + + /** Returns the number of verbs in the path. Up to max verbs are copied. The + verbs are copied as one byte per verb. + + @param verbs If not null, receives up to max verbs + @param max The maximum number of verbs to copy into verbs + @return the actual number of verbs in the path + */ + int getVerbs(uint8_t verbs[], int max) const; + + //! Swap contents of this and other. Guaranteed not to throw + void swap(SkPath& other); + + /** Returns the bounds of the path's points. If the path contains 0 or 1 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. + Note: this bounds may be larger than the actual shape, since curves + do not extend as far as their control points. + */ + const SkRect& getBounds() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return fBounds; + } + + /** Calling this will, if the internal cache of the bounds is out of date, + update it so that subsequent calls to getBounds will be instantaneous. + This also means that any copies or simple transformations of the path + will inherit the cached bounds. + */ + void updateBoundsCache() const { + // for now, just calling getBounds() is sufficient + this->getBounds(); + } + + /** + * Does a conservative test to see whether a rectangle is inside a path. Currently it only + * will ever return true for single convex contour paths. The empty-status of the rect is not + * considered (e.g. a rect that is a point can be inside a path). Points or line segments where + * the rect edge touches the path border are not considered containment violations. + */ + bool conservativelyContainsRect(const SkRect& rect) 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); + + void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar w); + void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { + this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); + } + void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, + SkScalar w); + + /** 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 { + /** Direction either has not been or could not be computed */ + kUnknown_Direction, + /** clockwise direction for adding closed contours */ + kCW_Direction, + /** counter-clockwise direction for adding closed contours */ + kCCW_Direction, + }; + + /** + * Return the opposite of the specified direction. kUnknown is its own + * opposite. + */ + static Direction OppositeDirection(Direction dir) { + static const Direction gOppositeDir[] = { + kUnknown_Direction, kCCW_Direction, kCW_Direction + }; + return gOppositeDir[dir]; + } + + /** + * Returns whether or not a fill type is inverted + * + * kWinding_FillType -> false + * kEvenOdd_FillType -> false + * kInverseWinding_FillType -> true + * kInverseEvenOdd_FillType -> true + */ + static bool IsInverseFillType(FillType fill) { + SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); + return (fill & 2) != 0; + } + + /** + * Returns the equivalent non-inverted fill type to the given fill type + * + * kWinding_FillType -> kWinding_FillType + * kEvenOdd_FillType -> kEvenOdd_FillType + * kInverseWinding_FillType -> kWinding_FillType + * kInverseEvenOdd_FillType -> kEvenOdd_FillType + */ + static FillType ConvertToNonInverseFillType(FillType fill) { + SK_COMPILE_ASSERT(0 == kWinding_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(1 == kEvenOdd_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(2 == kInverseWinding_FillType, fill_type_mismatch); + SK_COMPILE_ASSERT(3 == kInverseEvenOdd_FillType, fill_type_mismatch); + return (FillType)(fill & 1); + } + + /** + * Tries to quickly compute the direction of the first non-degenerate + * contour. If it can be computed, return true and set dir to that + * direction. If it cannot be (quickly) determined, return false and ignore + * the dir parameter. If the direction was determined, it is cached to make + * subsequent calls return quickly. + */ + bool cheapComputeDirection(Direction* dir) const; + + /** + * Returns true if the path's direction can be computed via + * cheapComputDirection() and if that computed direction matches the + * specified direction. If dir is kUnknown, returns true if the direction + * cannot be computed. + */ + bool cheapIsDirection(Direction dir) const { + Direction computedDir = kUnknown_Direction; + (void)this->cheapComputeDirection(&computedDir); + return computedDir == dir; + } + + /** Returns true if the path specifies a rectangle. If so, and if isClosed is + not null, set isClosed to true if the path is closed. Also, if returning true + and direction is not null, return the rect direction. If the path does not + specify a rectangle, return false and ignore isClosed and direction. + + @param isClosed If not null, set to true if the path is closed + @param direction If not null, set to the rectangle's direction + @return true if the path specifies a rectangle + */ + bool isRect(bool* isClosed, Direction* direction) const; + + /** Returns true if the path specifies a pair of nested rectangles. If so, and if + rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner + rectangle. If so, and dirs is not null, set dirs[0] to the direction of + the outer rectangle and dirs[1] to the direction of the inner rectangle. If + the path does not specify a pair of nested rectangles, return + false and ignore rect and dirs. + + @param rect If not null, returns the path as a pair of nested rectangles + @param dirs If not null, returns the direction of the rects + @return true if the path describes a pair of nested rectangles + */ + bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const; + + /** + * 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. Cannot be + * kUnknown_Direction. + */ + 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. Cannot be + * kUnknown_Direction. + */ + 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. Cannot be + * kUnknown_Direction. + */ + 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. Cannot be + * kUnknown_Direction. + */ + 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 rectangle's contour. Cannot be + * kUnknown_Direction. + */ + 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 rectangle's contour. Cannot be + * kUnknown_Direction. + * Note: The radii here now go through the same constraint handling as the + * SkRRect radii (i.e., either radii at a corner being 0 implies a + * sqaure corner and oversized radii are proportionally scaled down). + */ + void addRoundRect(const SkRect& rect, const SkScalar radii[], + Direction dir = kCW_Direction); + + /** + * Add an SkRRect contour to the path + * @param rrect The rounded rect to add as a closed contour + * @param dir The winding direction for the new contour. Cannot be + * kUnknown_Direction. + */ + void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction); + + /** + * Add a new contour made of just lines. This is just a fast version of + * the following: + * this->moveTo(pts[0]); + * for (int i = 1; i < count; ++i) { + * this->lineTo(pts[i]); + * } + * if (close) { + * this->close(); + * } + */ + void addPoly(const SkPoint pts[], int count, bool close); + + /** 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); + + /** + * Same as addPath(), but reverses the src input + */ + void reverseAddPath(const SkPath& src); + + /** 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. If there are no points, this returns false, otherwise it + returns true. + + @param lastPt The last point on the path is returned here + */ + bool 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 SegmentMask { + kLine_SegmentMask = 1 << 0, + kQuad_SegmentMask = 1 << 1, + kConic_SegmentMask = 1 << 2, + kCubic_SegmentMask = 1 << 3, + }; + + /** + * Returns a mask, where each bit corresponding to a SegmentMask is + * set if the path contains 1 or more segments of that type. + * Returns 0 for an empty path (no segments). + */ + uint32_t getSegmentMasks() const { return fSegmentMask; } + + enum Verb { + kMove_Verb, //!< iter.next returns 1 point + kLine_Verb, //!< iter.next returns 2 points + kQuad_Verb, //!< iter.next returns 3 points + kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight() + kCubic_Verb, //!< iter.next returns 4 points + kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt) + kDone_Verb, //!< iter.next returns 0 points + }; + + /** Iterate through all of the segments (lines, quadratics, cubics) of + each contours in a path. + + The iterator cleans up the segments along the way, removing degenerate + segments and adding close verbs where necessary. When the forceClose + argument is provided, each contour (as defined by a new starting + move command) will be completed with a close verb regardless of the + contour's contents. + */ + class SK_API 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 + @param doConsumeDegerates If true, first scan for segments that are + deemed degenerate (too short) and skip those. + @return The verb for the current segment + */ + Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { + if (doConsumeDegerates) { + this->consumeDegenerateSegments(); + } + return this->doNext(pts); + } + + /** + * Return the weight for the current conic. Only valid if the current + * segment return by next() was a conic. + */ + SkScalar conicWeight() const { return *fConicWeights; } + + /** 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; + const SkScalar* fConicWeights; + SkPoint fMoveTo; + SkPoint fLastPt; + SkBool8 fForceClose; + SkBool8 fNeedClose; + SkBool8 fCloseLine; + SkBool8 fSegmentState; + + inline const SkPoint& cons_moveTo(); + Verb autoClose(SkPoint pts[2]); + void consumeDegenerateSegments(); + Verb doNext(SkPoint pts[4]); + }; + + /** Iterate through the verbs in the path, providing the associated points. + */ + class SK_API RawIter { + public: + RawIter(); + RawIter(const SkPath&); + + void setPath(const SkPath&); + + /** 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 + This must not be NULL. + @return The verb for the current segment + */ + Verb next(SkPoint pts[4]); + + SkScalar conicWeight() const { return *fConicWeights; } + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + SkPoint fMoveTo; + SkPoint fLastPt; + }; + + /** + * Returns true if the point { x, y } is contained by the path, taking into + * account the FillType. + */ + bool contains(SkScalar x, SkScalar y) const; + + void dump(bool forceClose, const char title[] = NULL) const; + void dump() const; + + /** + * 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 writeToMemory(void* buffer) const; + /** + * Initialized the region from the buffer, returning the number + * of bytes actually read. + */ + uint32_t readFromMemory(const void* buffer); + +#ifdef SK_BUILD_FOR_ANDROID + uint32_t getGenerationID() const; + const SkPath* getSourcePath() const; + void setSourcePath(const SkPath* path); +#endif + + SkDEBUGCODE(void validate() const;) + +private: + enum SerializationOffsets { + kDirection_SerializationShift = 26, // requires 2 bits + kIsFinite_SerializationShift = 25, // requires 1 bit + kIsOval_SerializationShift = 24, // requires 1 bit + kConvexity_SerializationShift = 16, // requires 2 bits + kFillType_SerializationShift = 8, // requires 2 bits + kSegmentMask_SerializationShift = 0 // requires 4 bits + }; + + SkAutoTUnref<SkPathRef> fPathRef; + + mutable SkRect fBounds; + int fLastMoveToIndex; + uint8_t fFillType; + uint8_t fSegmentMask; + mutable uint8_t fBoundsIsDirty; + mutable uint8_t fConvexity; + mutable uint8_t fDirection; + mutable SkBool8 fIsFinite; // only meaningful if bounds are valid + mutable SkBool8 fIsOval; +#ifdef SK_BUILD_FOR_ANDROID + uint32_t fGenerationID; + const SkPath* fSourcePath; +#endif + + /** Resets all fields other than fPathRef to their initial 'empty' values. + * Assumes the caller has already emptied fPathRef. + * On Android increments fGenerationID without reseting it. + */ + void resetFields(); + + /** Sets all fields other than fPathRef to the values in 'that'. + * Assumes the caller has already set fPathRef. + * Doesn't change fGenerationID or fSourcePath on Android. + */ + void copyFields(const SkPath& that); + + // called, if dirty, by getBounds() + void computeBounds() const; + + friend class Iter; + + 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&); + + // called before we add points for lineTo, quadTo, cubicTo, checking to see + // if we need to inject a leading moveTo first + // + // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) + // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) + // + inline void injectMoveToIfNeeded(); + + inline bool hasOnlyMoveTos() const; + + Convexity internalGetConvexity() const; + + bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, + bool* isClosed, Direction* direction) const; + + friend class SkAutoPathBoundsUpdate; + friend class SkAutoDisableOvalCheck; + friend class SkAutoDisableDirectionCheck; + friend class SkBench_AddPathTest; // perf test pathTo/reversePathTo +}; + +#endif diff --git a/core/SkPathEffect.h b/core/SkPathEffect.h new file mode 100644 index 0000000..3b4541d --- /dev/null +++ b/core/SkPathEffect.h @@ -0,0 +1,204 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPathEffect_DEFINED +#define SkPathEffect_DEFINED + +#include "SkFlattenable.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkStrokeRec.h" +#include "SkTDArray.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 SK_API SkPathEffect : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkPathEffect) + + SkPathEffect() {} + + /** + * Given a src path (input) and a stroke-rec (input and output), apply + * this effect to the src path, returning the new path in dst, and return + * true. If this effect cannot be applied, return false and ignore dst + * and stroke-rec. + * + * The stroke-rec specifies the initial request for stroking (if any). + * The effect can treat this as input only, or it can choose to change + * the rec as well. For example, the effect can decide to change the + * stroke's width or join, or the effect can change the rec from stroke + * to fill (or fill to stroke) in addition to returning a new (dst) path. + * + * If this method returns true, the caller will apply (as needed) the + * resulting stroke-rec to dst and then draw. + */ + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect* cullR) const = 0; + + /** + * Compute a conservative bounds for its effect, given the src bounds. + * The baseline implementation just assigns src to dst. + */ + virtual void computeFastBounds(SkRect* dst, const SkRect& src) const; + + /** \class PointData + + PointData aggregates all the information needed to draw the point + primitives returned by an 'asPoints' call. + */ + class PointData { + public: + PointData() + : fFlags(0) + , fPoints(NULL) + , fNumPoints(0) { + fSize.set(SK_Scalar1, SK_Scalar1); + // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets + // the kUseClip flag + }; + ~PointData() { + delete [] fPoints; + } + + // TODO: consider using passed-in flags to limit the work asPoints does. + // For example, a kNoPath flag could indicate don't bother generating + // stamped solutions. + + // Currently none of these flags are supported. + enum PointFlags { + kCircles_PointFlag = 0x01, // draw points as circles (instead of rects) + kUsePath_PointFlag = 0x02, // draw points as stamps of the returned path + kUseClip_PointFlag = 0x04, // apply 'fClipRect' before drawing the points + }; + + uint32_t fFlags; // flags that impact the drawing of the points + SkPoint* fPoints; // the center point of each generated point + int fNumPoints; // number of points in fPoints + SkVector fSize; // the size to draw the points + SkRect fClipRect; // clip required to draw the points (if kUseClip is set) + SkPath fPath; // 'stamp' to be used at each point (if kUsePath is set) + + SkPath fFirst; // If not empty, contains geometry for first point + SkPath fLast; // If not empty, contains geometry for last point + }; + + /** + * Does applying this path effect to 'src' yield a set of points? If so, + * optionally return the points in 'results'. + */ + virtual bool asPoints(PointData* results, const SkPath& src, + const SkStrokeRec&, const SkMatrix&, + const SkRect* cullR) const; + +protected: + SkPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + // illegal + SkPathEffect(const SkPathEffect&); + SkPathEffect& operator=(const SkPathEffect&); + + typedef SkFlattenable INHERITED; +}; + +/** \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&) const SK_OVERRIDE; + + // 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) {} + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposePathEffect) + +protected: + SkComposePathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + // 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) {} + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSumPathEffect) + +protected: + SkSumPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + // illegal + SkSumPathEffect(const SkSumPathEffect&); + SkSumPathEffect& operator=(const SkSumPathEffect&); + + typedef SkPairPathEffect INHERITED; +}; + +#endif diff --git a/core/SkPathMeasure.h b/core/SkPathMeasure.h new file mode 100644 index 0000000..bc46b4a --- /dev/null +++ b/core/SkPathMeasure.h @@ -0,0 +1,109 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPathMeasure_DEFINED +#define SkPathMeasure_DEFINED + +#include "SkPath.h" +#include "SkTDArray.h" + +class SK_API 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 SK_WARN_UNUSED_RESULT 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 SK_WARN_UNUSED_RESULT 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(); +#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; // index into the fPts array + unsigned fTValue : 15; + unsigned fType : 2; + + SkScalar getScalarT() const; + }; + SkTDArray<Segment> fSegments; + SkTDArray<SkPoint> fPts; // Points used to define the segments + + 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/core/SkPicture.h b/core/SkPicture.h new file mode 100644 index 0000000..0bac3f7 --- /dev/null +++ b/core/SkPicture.h @@ -0,0 +1,278 @@ + +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPicture_DEFINED +#define SkPicture_DEFINED + +#include "SkBitmap.h" +#include "SkImageDecoder.h" +#include "SkRefCnt.h" + +class SkBBoxHierarchy; +class SkCanvas; +class SkDrawPictureCallback; +class SkData; +class SkPicturePlayback; +class SkPictureRecord; +class SkStream; +class SkWStream; + +struct SkPictInfo; + +/** \class SkPicture + + The SkPicture class records the drawing commands made to a canvas, to + be played back at a later time. +*/ +class SK_API SkPicture : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkPicture) + + /** 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); + + /** + * Function signature defining a function that sets up an SkBitmap from encoded data. On + * success, the SkBitmap should have its Config, width, height, rowBytes and pixelref set. + * If the installed pixelref has decoded the data into pixels, then the src buffer need not be + * copied. If the pixelref defers the actual decode until its lockPixels() is called, then it + * must make a copy of the src buffer. + * @param src Encoded data. + * @param length Size of the encoded data, in bytes. + * @param dst SkBitmap to install the pixel ref on. + * @param bool Whether or not a pixel ref was successfully installed. + */ + typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst); + + /** + * Recreate a picture that was serialized into a stream. + * @param SkStream Serialized picture data. + * @param proc Function pointer for installing pixelrefs on SkBitmaps representing the + * encoded bitmap data from the stream. + * @return A new SkPicture representing the serialized data, or NULL if the stream is + * invalid. + */ + static SkPicture* CreateFromStream(SkStream*, + InstallPixelRefProc proc = &SkImageDecoder::DecodeMemory); + + virtual ~SkPicture(); + + /** + * Swap the contents of the two pictures. Guaranteed to succeed. + */ + void swap(SkPicture& other); + + /** + * Creates a thread-safe clone of the picture that is ready for playback. + */ + SkPicture* clone() const; + + /** + * Creates multiple thread-safe clones of this picture that are ready for + * playback. The resulting clones are stored in the provided array of + * SkPictures. + */ + void clone(SkPicture* pictures, int count) const; + + enum RecordingFlags { + /* This flag specifies that when clipPath() is called, the path will + be faithfully recorded, but the recording canvas' current clip will + only see the path's bounds. This speeds up the recording process + without compromising the fidelity of the playback. The only side- + effect for recording is that calling getTotalClip() or related + clip-query calls will reflect the path's bounds, not the actual + path. + */ + kUsePathBoundsForClip_RecordingFlag = 0x01, + /* This flag causes the picture to compute bounding boxes and build + up a spatial hierarchy (currently an R-Tree), plus a tree of Canvas' + usually stack-based clip/etc state. This requires an increase in + recording time (often ~2x; likely more for very complex pictures), + but allows us to perform much faster culling at playback time, and + completely avoid some unnecessary clips and other operations. This + is ideal for tiled rendering, or any other situation where you're + drawing a fraction of a large scene into a smaller viewport. + + In most cases the record cost is offset by the playback improvement + after a frame or two of tiled rendering (and complex pictures that + induce the worst record times will generally get the largest + speedups at playback time). + + Note: Currently this is not serializable, the bounding data will be + discarded if you serialize into a stream and then deserialize. + */ + kOptimizeForClippedPlayback_RecordingFlag = 0x02, + /* + This flag disables all the picture recording optimizations (i.e., + those in SkPictureRecord). It is mainly intended for testing the + existing optimizations (i.e., to actually have the pattern + appear in an .skp we have to disable the optimization). This + option doesn't affect the optimizations controlled by + 'kOptimizeForClippedPlayback_RecordingFlag'. + */ + kDisableRecordOptimizations_RecordingFlag = 0x04 + }; + + /** Returns the canvas that records the drawing commands. + @param width the base width for the picture, as if the recording + canvas' bitmap had this width. + @param height the base width for the picture, as if the recording + canvas' bitmap had this height. + @param recordFlags optional flags that control recording. + @return the picture canvas. + */ + SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0); + + /** 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 canvas the canvas receiving the drawing commands. + */ + void draw(SkCanvas* canvas, SkDrawPictureCallback* = NULL); + + /** 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; } + + /** + * Function to encode an SkBitmap to an SkData. A function with this + * signature can be passed to serialize() and SkOrderedWriteBuffer. + * Returning NULL will tell the SkOrderedWriteBuffer to use + * SkBitmap::flatten() to store the bitmap. + * @param pixelRefOffset Output parameter, telling the deserializer what + * offset in the bm's pixelRef corresponds to the encoded data. + * @return SkData If non-NULL, holds encoded data representing the passed + * in bitmap. The caller is responsible for calling unref(). + */ + typedef SkData* (*EncodeBitmap)(size_t* pixelRefOffset, const SkBitmap& bm); + + /** + * Serialize to a stream. If non NULL, encoder will be used to encode + * any bitmaps in the picture. + * encoder will never be called with a NULL pixelRefOffset. + */ + void serialize(SkWStream*, EncodeBitmap encoder = NULL) const; + +#ifdef SK_BUILD_FOR_ANDROID + /** 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. + @deprecated preserving for legacy purposes + */ + void abortPlayback(); +#endif + +protected: + // V2 : adds SkPixelRef's generation ID. + // V3 : PictInfo tag at beginning, and EOF tag at the end + // V4 : move SkPictInfo to be the header + // V5 : don't read/write FunctionPtr on cross-process (we can detect that) + // V6 : added serialization of SkPath's bounds (and packed its flags tighter) + // V7 : changed drawBitmapRect(IRect) to drawBitmapRectToRect(Rect) + // V8 : Add an option for encoding bitmaps + // V9 : Allow the reader and writer of an SKP disagree on whether to support + // SK_SUPPORT_HINTING_SCALE_FACTOR + // V10: add drawRRect, drawOval, clipRRect + // V11: modify how readBitmap and writeBitmap store their info. + // V12: add conics to SkPath, use new SkPathRef flattening + static const uint32_t PICTURE_VERSION = 12; + + // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to + // install their own SkPicturePlayback-derived players,SkPictureRecord-derived + // recorders and set the picture size + SkPicturePlayback* fPlayback; + SkPictureRecord* fRecord; + int fWidth, fHeight; + + // Create a new SkPicture from an existing SkPicturePlayback. Ref count of + // playback is unchanged. + SkPicture(SkPicturePlayback*, int width, int height); + + // For testing. Derived classes may instantiate an alternate + // SkBBoxHierarchy implementation + virtual SkBBoxHierarchy* createBBoxHierarchy() const; + + // Return true if the SkStream represents a serialized picture, and fills out + // SkPictInfo. After this function returns, the SkStream is not rewound; it + // will be ready to be parsed to create an SkPicturePlayback. + // If false is returned, SkPictInfo is unmodified. + static bool StreamIsSKP(SkStream*, SkPictInfo*); +private: + friend class SkFlatPicture; + friend class SkPicturePlayback; + + typedef SkRefCnt INHERITED; +}; + +class SkAutoPictureRecord : SkNoncopyable { +public: + SkAutoPictureRecord(SkPicture* pict, int width, int height, + uint32_t recordingFlags = 0) { + fPicture = pict; + fCanvas = pict->beginRecording(width, height, recordingFlags); + } + ~SkAutoPictureRecord() { + fPicture->endRecording(); + } + + /** Return the canvas to draw into for recording into the picture. + */ + SkCanvas* getRecordingCanvas() const { return fCanvas; } + +private: + SkPicture* fPicture; + SkCanvas* fCanvas; +}; + +/** + * Subclasses of this can be passed to canvas.drawPicture. During the drawing + * of the picture, this callback will periodically be invoked. If its + * abortDrawing() returns true, then picture playback will be interrupted. + * + * The resulting drawing is undefined, as there is no guarantee how often the + * callback will be invoked. If the abort happens inside some level of nested + * calls to save(), restore will automatically be called to return the state + * to the same level it was before the drawPicture call was made. + */ +class SK_API SkDrawPictureCallback { +public: + SkDrawPictureCallback() {} + virtual ~SkDrawPictureCallback() {} + + virtual bool abortDrawing() = 0; +}; + +#endif diff --git a/core/SkPixelRef.h b/core/SkPixelRef.h new file mode 100644 index 0000000..0487e42 --- /dev/null +++ b/core/SkPixelRef.h @@ -0,0 +1,243 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPixelRef_DEFINED +#define SkPixelRef_DEFINED + +#include "SkBitmap.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkFlattenable.h" + +#ifdef SK_DEBUG + /** + * Defining SK_IGNORE_PIXELREF_SETPRELOCKED will force all pixelref + * subclasses to correctly handle lock/unlock pixels. For performance + * reasons, simple malloc-based subclasses call setPreLocked() to skip + * the overhead of implementing these calls. + * + * This build-flag disables that optimization, to add in debugging our + * call-sites, to ensure that they correctly balance their calls of + * lock and unlock. + */ +// #define SK_IGNORE_PIXELREF_SETPRELOCKED +#endif + +class SkColorTable; +class SkData; +struct SkIRect; +class SkMutex; + +class GrTexture; + +/** \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 SK_API SkPixelRef : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkPixelRef) + + explicit SkPixelRef(SkBaseMutex* 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; } + + /** + * Returns true if the lockcount > 0 + */ + bool isLocked() const { return fLockCount > 0; } + + SkDEBUGCODE(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(); + + /** + * Some bitmaps can return a copy of their pixels for lockPixels(), but + * that copy, if modified, will not be pushed back. These bitmaps should + * not be used as targets for a raster device/canvas (since all pixels + * modifications will be lost when unlockPixels() is called.) + */ + bool lockPixelsAreWritable() const; + + /** 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; } + + /** + * If the pixelRef has an encoded (i.e. compressed) representation, + * return a ref to its data. If the pixelRef + * is uncompressed or otherwise does not have this form, return NULL. + * + * If non-null is returned, the caller is responsible for calling unref() + * on the data when it is finished. + */ + SkData* refEncodedData() { + return this->onRefEncodedData(); + } + + /** Are we really wrapping a texture instead of a bitmap? + */ + virtual GrTexture* getTexture() { return NULL; } + + bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL); + + /** + * Makes a deep copy of this PixelRef, respecting the requested config. + * @param config Desired config. + * @param subset Subset of this PixelRef to copy. Must be fully contained within the bounds of + * of this PixelRef. + * @return A new SkPixelRef, or NULL if either there is an error (e.g. the destination could + * not be created with the given config), or this PixelRef does not support deep + * copies. + */ + virtual SkPixelRef* deepCopy(SkBitmap::Config config, const SkIRect* subset = NULL) { + return NULL; + } + +#ifdef SK_BUILD_FOR_ANDROID + /** + * Acquire a "global" ref on this object. + * The default implementation just calls ref(), but subclasses can override + * this method to implement additional behavior. + */ + virtual void globalRef(void* data=NULL); + + /** + * Release a "global" ref on this object. + * The default implementation just calls unref(), but subclasses can override + * this method to implement additional behavior. + */ + virtual void globalUnref(); +#endif + +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; + + /** Default impl returns true */ + virtual bool onLockPixelsAreWritable() const; + + /** + * For pixelrefs that don't have access to their raw pixels, they may be + * able to make a copy of them (e.g. if the pixels are on the GPU). + * + * The base class implementation returns false; + */ + virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subsetOrNull); + + // default impl returns NULL. + virtual SkData* onRefEncodedData(); + + /** Return the mutex associated with this pixelref. This value is assigned + in the constructor, and cannot change during the lifetime of the object. + */ + SkBaseMutex* mutex() const { return fMutex; } + + // serialization + SkPixelRef(SkFlattenableReadBuffer&, SkBaseMutex*); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + // only call from constructor. Flags this to always be locked, removing + // the need to grab the mutex and call onLockPixels/onUnlockPixels. + // Performance tweak to avoid those calls (esp. in multi-thread use case). + void setPreLocked(void* pixels, SkColorTable* ctable); + +private: + + SkBaseMutex* 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; + + // SkBitmap is only a friend so that when copying, it can modify the new SkPixelRef to have the + // same fGenerationID as the original. + friend class SkBitmap; + + SkString fURI; + + // can go from false to true, but never from true to false + bool fIsImmutable; + // only ever set in constructor, const after that + bool fPreLocked; + + void setMutex(SkBaseMutex* mutex); + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkPoint.h b/core/SkPoint.h new file mode 100644 index 0000000..5eca72f --- /dev/null +++ b/core/SkPoint.h @@ -0,0 +1,516 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#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; + + static SkIPoint Make(int32_t x, int32_t y) { + SkIPoint pt; + pt.set(x, y); + return pt; + } + + int32_t x() const { return fX; } + int32_t y() const { return fY; } + void setX(int32_t x) { fX = x; } + void setY(int32_t y) { fY = y; } + + /** + * Returns true iff fX and fY are both zero. + */ + bool isZero() const { return (fX | fY) == 0; } + + /** + * Set both fX and fY to zero. Same as set(0, 0) + */ + void setZero() { fX = fY = 0; } + + /** 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 SK_API SkPoint { + SkScalar fX, fY; + + static SkPoint Make(SkScalar x, SkScalar y) { + SkPoint pt; + pt.set(x, y); + return pt; + } + + SkScalar x() const { return fX; } + SkScalar y() const { return fY; } + + /** + * Returns true iff fX and fY are both zero. + */ + bool isZero() const { return (0 == fX) & (0 == 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); + } + + void setAbs(const SkPoint& pt) { + fX = SkScalarAbs(pt.fX); + fY = SkScalarAbs(pt.fY); + } + + // counter-clockwise fan + void setIRectFan(int l, int t, int r, int b) { + SkPoint* v = this; + v[0].set(SkIntToScalar(l), SkIntToScalar(t)); + v[1].set(SkIntToScalar(l), SkIntToScalar(b)); + v[2].set(SkIntToScalar(r), SkIntToScalar(b)); + v[3].set(SkIntToScalar(r), SkIntToScalar(t)); + } + void setIRectFan(int l, int t, int r, int b, size_t stride); + + // counter-clockwise fan + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { + SkPoint* v = this; + v[0].set(l, t); + v[1].set(l, b); + v[2].set(r, b); + v[3].set(r, t); + } + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride); + + static void Offset(SkPoint points[], int count, const SkPoint& offset) { + Offset(points, count, offset.fX, offset.fY); + } + + static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { + for (int i = 0; i < count; ++i) { + points[i].offset(dx, dy); + } + } + + void offset(SkScalar dx, SkScalar dy) { + fX += dx; + fY += dy; + } + + /** Return the euclidian distance from (0,0) to the point + */ + SkScalar length() const { return SkPoint::Length(fX, fY); } + SkScalar distanceToOrigin() const { return this->length(); } + + /** + * Return true if the computed length of the vector is >= the internal + * tolerance (used to avoid dividing by tiny values). + */ + static bool CanNormalize(SkScalar dx, SkScalar dy) +#ifdef SK_SCALAR_IS_FLOAT + // Simple enough (and performance critical sometimes) so we inline it. + { return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero); } +#else + ; +#endif + + bool canNormalize() const { + return CanNormalize(fX, fY); + } + + /** Set the point (vector) to be unit-length in the same direction as it + already points. If the point has a degenerate length (i.e. nearly 0) + then return false and do nothing; 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 value) { this->scale(value, 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 both X and Y are finite (not infinity or NaN) + */ + bool isFinite() const { +#ifdef SK_SCALAR_IS_FLOAT + SkScalar accum = 0; + accum *= fX; + accum *= fY; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || !(accum == accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return accum == accum; +#else + // use bit-or for speed, since we don't care about short-circuting the + // tests, and we expect the common case will be that we need to check all. + int isNaN = (SK_FixedNaN == fX) | (SK_FixedNaN == fX)); + return !isNaN; +#endif + } + + /** + * 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; + } + + /** Return true if this point and the given point are far enough apart + such that a vector between them would be non-degenerate. + + WARNING: Unlike the deprecated version of equalsWithinTolerance(), + this method does not use componentwise comparison. Instead, it + uses a comparison designed to match judgments elsewhere regarding + degeneracy ("points A and B are so close that the vector between them + is essentially zero"). + */ + bool equalsWithinTolerance(const SkPoint& p) const { + return !CanNormalize(fX - p.fX, fY - p.fY); + } + + /** DEPRECATED: Return true if this and the given point are componentwise + within tolerance "tol". + + WARNING: There is no guarantee that the result will reflect judgments + elsewhere regarding degeneracy ("points A and B are so close that the + vector between them is essentially zero"). + */ + bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const { + return SkScalarNearlyZero(fX - p.fX, tol) + && SkScalarNearlyZero(fY - p.fY, tol); + } + + /** 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); + + /** Normalize pt, returning its previous length. If the prev length is too + small (degenerate), return 0 and leave pt unchanged. This uses the same + tolerance as CanNormalize. + + Note that this method may be significantly more expensive than + the non-static normalize(), because it has to return the previous length + of the point. If you don't need the previous length, call the + non-static normalize() method instead. + */ + static SkScalar Normalize(SkPoint* pt); + + /** 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); + } + + SkScalar cross(const SkPoint& vec) const { + return CrossProduct(*this, vec); + } + + SkScalar dot(const SkPoint& vec) const { + return DotProduct(*this, vec); + } + + SkScalar lengthSqd() const { + return DotProduct(*this, *this); + } + + SkScalar distanceToSqd(const SkPoint& pt) const { + SkScalar dx = fX - pt.fX; + SkScalar dy = fY - pt.fY; + return SkScalarMul(dx, dx) + SkScalarMul(dy, dy); + } + + /** + * The side of a point relative to a line. If the line is from a to b then + * the values are consistent with the sign of (b-a) cross (pt-a) + */ + enum Side { + kLeft_Side = -1, + kOn_Side = 0, + kRight_Side = 1 + }; + + /** + * Returns the squared distance to the infinite line between two pts. Also + * optionally returns the side of the line that the pt falls on (looking + * along line from a to b) + */ + SkScalar distanceToLineBetweenSqd(const SkPoint& a, + const SkPoint& b, + Side* side = NULL) const; + + /** + * Returns the distance to the infinite line between two pts. Also + * optionally returns the side of the line that the pt falls on (looking + * along the line from a to b) + */ + SkScalar distanceToLineBetween(const SkPoint& a, + const SkPoint& b, + Side* side = NULL) const { + return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side)); + } + + /** + * Returns the squared distance to the line segment between pts a and b + */ + SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a, + const SkPoint& b) const; + + /** + * Returns the distance to the line segment between pts a and b. + */ + SkScalar distanceToLineSegmentBetween(const SkPoint& a, + const SkPoint& b) const { + return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b)); + } + + /** + * Make this vector be orthogonal to vec. Looking down vec the + * new vector will point in direction indicated by side (which + * must be kLeft_Side or kRight_Side). + */ + void setOrthog(const SkPoint& vec, Side side = kLeft_Side) { + // vec could be this + SkScalar tmp = vec.fX; + if (kRight_Side == side) { + fX = -vec.fY; + fY = tmp; + } else { + SkASSERT(kLeft_Side == side); + fX = vec.fY; + fY = -tmp; + } + } + + /** + * cast-safe way to treat the point as an array of (2) SkScalars. + */ + const SkScalar* asScalars() const { return &fX; } +}; + +typedef SkPoint SkVector; + +#endif diff --git a/core/SkPostConfig.h b/core/SkPostConfig.h new file mode 100644 index 0000000..4a819d3 --- /dev/null +++ b/core/SkPostConfig.h @@ -0,0 +1,393 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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) + #define SK_SCALAR_IS_FLOAT +#endif + +#if defined(SK_MSCALAR_IS_DOUBLE) && defined(SK_MSCALAR_IS_FLOAT) + #error "cannot define both SK_MSCALAR_IS_DOUBLE and SK_MSCALAR_IS_FLOAT" +#elif !defined(SK_MSCALAR_IS_DOUBLE) && !defined(SK_MSCALAR_IS_FLOAT) + // default is double, as that is faster given our impl uses doubles + // for intermediate calculations. + #define SK_MSCALAR_IS_DOUBLE +#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 + +#if !defined(SK_HAS_COMPILER_FEATURE) + #if defined(__has_feature) + #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x) + #else + #define SK_HAS_COMPILER_FEATURE(x) 0 + #endif +#endif + +#if !defined(SK_ATTRIBUTE) + #if defined(__clang__) || defined(__GNUC__) + #define SK_ATTRIBUTE(attr) __attribute__((attr)) + #else + #define SK_ATTRIBUTE(attr) + #endif +#endif + +#if !defined(SK_SUPPORT_GPU) + #define SK_SUPPORT_GPU 1 +#endif + +/** + * The clang static analyzer likes to know that when the program is not + * expected to continue (crash, assertion failure, etc). It will notice that + * some combination of parameters lead to a function call that does not return. + * It can then make appropriate assumptions about the parameters in code + * executed only if the non-returning function was *not* called. + */ +#if !defined(SkNO_RETURN_HINT) + #if SK_HAS_COMPILER_FEATURE(attribute_analyzer_noreturn) + static inline void SkNO_RETURN_HINT() __attribute__((analyzer_noreturn)); + static inline void SkNO_RETURN_HINT() {} + #else + #define SkNO_RETURN_HINT() do {} while (false) + #endif +#endif + +#if defined(SK_ZLIB_INCLUDE) && defined(SK_SYSTEM_ZLIB) + #error "cannot define both SK_ZLIB_INCLUDE and SK_SYSTEM_ZLIB" +#elif defined(SK_ZLIB_INCLUDE) || defined(SK_SYSTEM_ZLIB) + #define SK_HAS_ZLIB +#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 SkNEW_PLACEMENT(buf, type_name) (new (buf) type_name) + #define SkNEW_PLACEMENT_ARGS(buf, type_name, args) \ + (new (buf) type_name args) + #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() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false) +#else + #define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// SK_ENABLE_INST_COUNT defaults to 1 in DEBUG and 0 in RELEASE +#ifndef SK_ENABLE_INST_COUNT + #ifdef SK_DEBUG + // FIXME: fails if multiple threads run at once (see skbug.com/1219 ) + #define SK_ENABLE_INST_COUNT 0 + #else + #define SK_ENABLE_INST_COUNT 0 + #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 + #ifndef SK_USE_FLOATBITS + #define SK_USE_FLOATBITS + #endif +#endif + +#ifdef SK_BUILD_FOR_WIN + // we want lean_and_mean when we include windows.h + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define WIN32_IS_MEAN_WAS_LOCALLY_DEFINED + #endif + #ifndef NOMINMAX + #define NOMINMAX + #define NOMINMAX_WAS_LOCALLY_DEFINED + #endif + + #include <windows.h> + + #ifdef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED + #undef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED + #undef WIN32_LEAN_AND_MEAN + #endif + + #ifdef NOMINMAX_WAS_LOCALLY_DEFINED + #undef NOMINMAX_WAS_LOCALLY_DEFINED + #undef NOMINMAX + #endif + + #ifndef SK_DEBUGBREAK + #define SK_DEBUGBREAK(cond) do { if (!(cond)) { SkNO_RETURN_HINT(); __debugbreak(); }} while (false) + #endif + + #ifndef SK_A32_SHIFT + #define SK_A32_SHIFT 24 + #define SK_R32_SHIFT 16 + #define SK_G32_SHIFT 8 + #define SK_B32_SHIFT 0 + #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 + +/* + * We check to see if the SHIFT value has already been defined. + * 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 + +/** + * SK_PMCOLOR_BYTE_ORDER can be used to query the byte order of SkPMColor at compile time. The + * relationship between the byte order and shift values depends on machine endianness. If the shift + * order is R=0, G=8, B=16, A=24 then ((char*)&pmcolor)[0] will produce the R channel on a little + * endian machine and the A channel on a big endian machine. Thus, given those shifts values, + * SK_PMCOLOR_BYTE_ORDER(R,G,B,A) will be true on a little endian machine and + * SK_PMCOLOR_BYTE_ORDER(A,B,G,R) will be true on a big endian machine. + */ +#ifdef SK_CPU_BENDIAN + #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C3 ## 32_SHIFT == 0 && \ + SK_ ## C2 ## 32_SHIFT == 8 && \ + SK_ ## C1 ## 32_SHIFT == 16 && \ + SK_ ## C0 ## 32_SHIFT == 24) +#else + #define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C0 ## 32_SHIFT == 0 && \ + SK_ ## C1 ## 32_SHIFT == 8 && \ + SK_ ## C2 ## 32_SHIFT == 16 && \ + SK_ ## C3 ## 32_SHIFT == 24) +#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 + +////////////////////////////////////////////////////////////////////// + +#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC) + #ifndef SkLONGLONG + #ifdef SK_BUILD_FOR_WIN32 + #define SkLONGLONG __int64 + #else + #define SkLONGLONG long long + #endif + #endif +#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 + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_OVERRIDE + #if defined(_MSC_VER) + #define SK_OVERRIDE override + #elif defined(__clang__) + // Clang defaults to C++03 and warns about using override. Squelch that. Intentionally no + // push/pop here so all users of SK_OVERRIDE ignore the warning too. This is like passing + // -Wno-c++11-extensions, except that GCC won't die (because it won't see this pragma). + #pragma clang diagnostic ignored "-Wc++11-extensions" + + #if __has_feature(cxx_override_control) + // Some documentation suggests we should be using __attribute__((override)), + // but it doesn't work. + #define SK_OVERRIDE override + #elif defined(__has_extension) + #if __has_extension(cxx_override_control) + #define SK_OVERRIDE override + #endif + #endif + #endif + #ifndef SK_OVERRIDE + #define SK_OVERRIDE + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_UNUSED) + #define SK_UNUSED SK_ATTRIBUTE(unused) +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_PRINTF_LIKE +#if defined(__clang__) || defined(__GNUC__) +#define SK_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B)))) +#else +#define SK_PRINTF_LIKE(A, B) +#endif +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_SIZE_T_SPECIFIER +#if defined(_MSC_VER) +#define SK_SIZE_T_SPECIFIER "%Iu" +#else +#define SK_SIZE_T_SPECIFIER "%zu" +#endif +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS +#define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1 +#endif diff --git a/core/SkPreConfig.h b/core/SkPreConfig.h new file mode 100644 index 0000000..fbaa69e --- /dev/null +++ b/core/SkPreConfig.h @@ -0,0 +1,261 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPreConfig_DEFINED +#define SkPreConfig_DEFINED + +#ifdef WEBKIT_VERSION_MIN_REQUIRED + #include "config.h" +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW) && !defined(SK_BUILD_FOR_NACL) + + #ifdef __APPLE__ + #include "TargetConditionals.h" + #endif + + #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(ANDROID) + #define SK_BUILD_FOR_ANDROID + #elif defined(linux) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__sun) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__GLIBC__) || defined(__GNU__) + #define SK_BUILD_FOR_UNIX + #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define SK_BUILD_FOR_IOS + #else + #define SK_BUILD_FOR_MAC + #endif + +#endif + +/* Even if the user only defined the framework variant we still need to build + * the default (NDK-compliant) Android code. Therefore, when attempting to + * include/exclude something from the framework variant check first that we are + * building for Android then check the status of the framework define. + */ +#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && !defined(SK_BUILD_FOR_ANDROID) + #define SK_BUILD_FOR_ANDROID +#endif + + +// USE_CHROMIUM_SKIA is defined when building Skia for the Chromium +// browser. +#if defined(USE_CHROMIUM_SKIA) + #define SK_BUILD_FOR_CHROMIUM +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_DEBUG) && !defined(SK_RELEASE) + #ifdef NDEBUG + #define SK_RELEASE + #else + #define SK_DEBUG + #endif +#endif + +#ifdef SK_BUILD_FOR_WIN32 + #if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict + #endif + #if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT + #endif + #include "sk_stdint.h" +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict__ +#endif + +#if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_SCALAR_IS_FLOAT) && !defined(SK_SCALAR_IS_FIXED) + #define SK_SCALAR_IS_FLOAT +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN) + #if defined (__ppc__) || defined(__PPC__) || defined(__ppc64__) \ + || defined(__PPC64__) + #define SK_CPU_BENDIAN + #else + #define SK_CPU_LENDIAN + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_MMAP_SUPPORT + #ifdef SK_BUILD_FOR_WIN32 + // by default, if we're windows, we assume we don't have mmap + #define SK_MMAP_SUPPORT 0 + #else + #define SK_MMAP_SUPPORT 1 + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +/** + * SK_CPU_SSE_LEVEL + * + * If defined, SK_CPU_SSE_LEVEL should be set to the highest supported level. + * On non-intel CPU this should be undefined. + */ + +#define SK_CPU_SSE_LEVEL_SSE1 10 +#define SK_CPU_SSE_LEVEL_SSE2 20 +#define SK_CPU_SSE_LEVEL_SSE3 30 +#define SK_CPU_SSE_LEVEL_SSSE3 31 + +// Are we in GCC? +#ifndef SK_CPU_SSE_LEVEL + #if defined(__SSE2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif defined(__SSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3 + #elif defined(__SSSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3 + #endif +#endif + +// Are we in VisualStudio? +#ifndef SK_CPU_SSE_LEVEL + #if _M_IX86_FP == 1 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1 + #elif _M_IX86_FP >= 2 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #endif +#endif + +// 64bit intel guarantees at least SSE2 +#if defined(__x86_64__) || defined(_WIN64) + #if !defined(SK_CPU_SSE_LEVEL) || (SK_CPU_SSE_LEVEL < SK_CPU_SSE_LEVEL_SSE2) + #undef SK_CPU_SSE_LEVEL + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #endif +#endif + +////////////////////////////////////////////////////////////////////// +// ARM defines + +#if defined(__arm__) && (!defined(__APPLE__) || !TARGET_IPHONE_SIMULATOR) + #define SK_CPU_ARM + + #if defined(__GNUC__) + #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ + || defined(__ARM_ARCH_7EM__) || defined(_ARM_ARCH_7) + #define SK_ARM_ARCH 7 + #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH_6M__) || defined(_ARM_ARCH_6) + #define SK_ARM_ARCH 6 + #elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) || defined(_ARM_ARCH_5) + #define SK_ARM_ARCH 5 + #elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || defined(_ARM_ARCH_4) + #define SK_ARM_ARCH 4 + #else + #define SK_ARM_ARCH 3 + #endif + + #if defined(__thumb2__) && (SK_ARM_ARCH >= 6) \ + || !defined(__thumb__) && ((SK_ARM_ARCH > 5) || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)) + #define SK_ARM_HAS_EDSP + #endif + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SKIA_IMPLEMENTATION) + #define SKIA_IMPLEMENTATION 0 +#endif + +#if defined(SKIA_DLL) + #if defined(WIN32) + #if SKIA_IMPLEMENTATION + #define SK_API __declspec(dllexport) + #else + #define SK_API __declspec(dllimport) + #endif + #else + #define SK_API __attribute__((visibility("default"))) + #endif +#else + #define SK_API +#endif + +////////////////////////////////////////////////////////////////////// + +/** + * Use SK_PURE_FUNC as an attribute to indicate that a function's + * return value only depends on the value of its parameters. This + * can help the compiler optimize out successive calls. + * + * Usage: + * void function(int params) SK_PURE_FUNC; + */ +#if defined(__GNUC__) +# define SK_PURE_FUNC __attribute__((pure)) +#else +# define SK_PURE_FUNC /* nothing */ +#endif + +////////////////////////////////////////////////////////////////////// + +/** + * SK_HAS_ATTRIBUTE(<name>) should return true iff the compiler + * supports __attribute__((<name>)). Mostly important because + * Clang doesn't support all of GCC attributes. + */ +#if defined(__has_attribute) +# define SK_HAS_ATTRIBUTE(x) __has_attribute(x) +#elif defined(__GNUC__) +# define SK_HAS_ATTRIBUTE(x) 1 +#else +# define SK_HAS_ATTRIBUTE(x) 0 +#endif + +/** + * SK_ATTRIBUTE_OPTIMIZE_O1 can be used as a function attribute + * to specify individual optimization level of -O1, if the compiler + * supports it. + * + * NOTE: Clang/ARM (r161757) does not support the 'optimize' attribute. + */ +#if SK_HAS_ATTRIBUTE(optimize) +# define SK_ATTRIBUTE_OPTIMIZE_O1 __attribute__((optimize("O1"))) +#else +# define SK_ATTRIBUTE_OPTIMIZE_O1 /* nothing */ +#endif + +#endif diff --git a/core/SkRRect.h b/core/SkRRect.h new file mode 100644 index 0000000..bce896a --- /dev/null +++ b/core/SkRRect.h @@ -0,0 +1,295 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRRect_DEFINED +#define SkRRect_DEFINED + +#include "SkRect.h" +#include "SkPoint.h" + +class SkPath; + +// Path forward: +// core work +// add validate method (all radii positive, all radii sums < rect size, etc.) +// add contains(SkRect&) - for clip stack +// add contains(SkRRect&) - for clip stack +// add heart rect computation (max rect inside RR) +// add 9patch rect computation +// add growToInclude(SkPath&) +// analysis +// use growToInclude to fit skp round rects & generate stats (RRs vs. real paths) +// check on # of rectorus's the RRs could handle +// rendering work +// add entry points (clipRRect, drawRRect) - plumb down to SkDevice +// update SkPath.addRRect() to take an SkRRect - only use quads +// -- alternatively add addRRectToPath here +// add GM and bench +// clipping opt +// update SkClipStack to perform logic with RRs +// further out +// add RR rendering shader to Ganesh (akin to cicle drawing code) +// - only for simple RRs +// detect and triangulate RRectorii rather than falling back to SW in Ganesh +// + +/** \class SkRRect + + The SkRRect class represents a rounded rect with a potentially different + radii for each corner. It does not have a constructor so must be + initialized with one of the initialization functions (e.g., setEmpty, + setRectRadii, etc.) + + This class is intended to roughly match CSS' border-*-*-radius capabilities. + This means: + If either of a corner's radii are 0 the corner will be square. + Negative radii are not allowed (they are clamped to zero). + If the corner curves overlap they will be proportionally reduced to fit. +*/ +class SK_API SkRRect { +public: + /** + * Enum to capture the various possible subtypes of RR. Accessed + * by type(). The subtypes become progressively less restrictive. + */ + enum Type { + // !< Internal indicator that the sub type must be computed. + kUnknown_Type = -1, + + // !< The RR is empty + kEmpty_Type, + + //!< The RR is actually a (non-empty) rect (i.e., at least one radius + //!< at each corner is zero) + kRect_Type, + + //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal + //!< and >= width/2 and all the y radii are equal and >= height/2 + kOval_Type, + + //!< The RR is non-empty and all the x radii are equal & all y radii + //!< are equal but it is not an oval (i.e., there are lines between + //!< the curves) nor a rect (i.e., both radii are non-zero) + kSimple_Type, + + //!< A fully general (non-empty) RR. Some of the x and/or y radii are + //!< different from the others and there must be one corner where + //!< both radii are non-zero. + kComplex_Type, + }; + + /** + * Returns the RR's sub type. + */ + Type getType() const { + SkDEBUGCODE(this->validate();) + + if (kUnknown_Type == fType) { + this->computeType(); + } + SkASSERT(kUnknown_Type != fType); + return fType; + } + + Type type() const { return this->getType(); } + + inline bool isEmpty() const { return kEmpty_Type == this->getType(); } + inline bool isRect() const { return kRect_Type == this->getType(); } + inline bool isOval() const { return kOval_Type == this->getType(); } + inline bool isSimple() const { return kSimple_Type == this->getType(); } + inline bool isComplex() const { return kComplex_Type == this->getType(); } + + SkScalar width() const { return fRect.width(); } + SkScalar height() const { return fRect.height(); } + + /** + * Set this RR to the empty rectangle (0,0,0,0) with 0 x & y radii. + */ + void setEmpty() { + fRect.setEmpty(); + memset(fRadii, 0, sizeof(fRadii)); + fType = kEmpty_Type; + + SkDEBUGCODE(this->validate();) + } + + /** + * Set this RR to match the supplied rect. All radii will be 0. + */ + void setRect(const SkRect& rect) { + if (rect.isEmpty()) { + this->setEmpty(); + return; + } + + fRect = rect; + memset(fRadii, 0, sizeof(fRadii)); + fType = kRect_Type; + + SkDEBUGCODE(this->validate();) + } + + /** + * Set this RR to match the supplied oval. All x radii will equal half the + * width and all y radii will equal half the height. + */ + void setOval(const SkRect& oval) { + if (oval.isEmpty()) { + this->setEmpty(); + return; + } + + SkScalar xRad = SkScalarHalf(oval.width()); + SkScalar yRad = SkScalarHalf(oval.height()); + + fRect = oval; + for (int i = 0; i < 4; ++i) { + fRadii[i].set(xRad, yRad); + } + fType = kOval_Type; + + SkDEBUGCODE(this->validate();) + } + + /** + * Initialize the RR with the same radii for all four corners. + */ + void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); + + /** + * Initialize the RR with potentially different radii for all four corners. + */ + void setRectRadii(const SkRect& rect, const SkVector radii[4]); + + // The radii are stored in UL, UR, LR, LL order. + enum Corner { + kUpperLeft_Corner, + kUpperRight_Corner, + kLowerRight_Corner, + kLowerLeft_Corner + }; + + const SkRect& rect() const { return fRect; } + const SkVector& radii(Corner corner) const { return fRadii[corner]; } + const SkRect& getBounds() const { return fRect; } + + /** + * When a rrect is simple, all of its radii are equal. This returns one + * of those radii. This call requires the rrect to be non-complex. + */ + const SkVector& getSimpleRadii() const { + SkASSERT(!this->isComplex()); + return fRadii[0]; + } + + friend bool operator==(const SkRRect& a, const SkRRect& b) { + return a.fRect == b.fRect && + SkScalarsEqual(a.fRadii[0].asScalars(), + b.fRadii[0].asScalars(), 8); + } + + friend bool operator!=(const SkRRect& a, const SkRRect& b) { + return a.fRect != b.fRect || + !SkScalarsEqual(a.fRadii[0].asScalars(), + b.fRadii[0].asScalars(), 8); + } + + /** + * Returns true if (p.fX,p.fY) is inside the RR, and the RR + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the RR are themselves considered + * to be inside, while the right and bottom are not. All the points on the + * edges of the corners are considered to be inside. + */ + bool contains(const SkPoint& p) const { + return contains(p.fX, p.fY); + } + + /** + * Returns true if (x,y) is inside the RR, and the RR + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the RR are themselves considered + * to be inside, while the right and bottom are not. All the points on the + * edges of the corners are considered to be inside. + */ + bool contains(SkScalar x, SkScalar y) const; + + /** + * Call inset on the bounds, and adjust the radii to reflect what happens + * in stroking: If the corner is sharp (no curvature), leave it alone, + * otherwise we grow/shrink the radii by the amount of the inset. If a + * given radius becomes negative, it is pinned to 0. + * + * It is valid for dst == this. + */ + void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const; + + void inset(SkScalar dx, SkScalar dy) { + this->inset(dx, dy, this); + } + + /** + * Call outset on the bounds, and adjust the radii to reflect what happens + * in stroking: If the corner is sharp (no curvature), leave it alone, + * otherwise we grow/shrink the radii by the amount of the inset. If a + * given radius becomes negative, it is pinned to 0. + * + * It is valid for dst == this. + */ + void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const { + this->inset(-dx, -dy, dst); + } + void outset(SkScalar dx, SkScalar dy) { + this->inset(-dx, -dy, this); + } + + /** + * Returns true if 'rect' is wholy inside the RR, and both + * are not empty. + */ + bool contains(const SkRect& rect) const; + + SkDEBUGCODE(void validate() const;) + + enum { + kSizeInMemory = 12 * sizeof(SkScalar) + }; + + /** + * Write the rrect into the specified buffer. This is guaranteed to always + * write kSizeInMemory bytes, and that value is guaranteed to always be + * a multiple of 4. Return kSizeInMemory. + */ + uint32_t writeToMemory(void* buffer) const; + + /** + * Read the rrect from the specified buffer. This is guaranteed to always + * read kSizeInMemory bytes, and that value is guaranteed to always be + * a multiple of 4. Return kSizeInMemory. + */ + uint32_t readFromMemory(const void* buffer); + +private: + SkRect fRect; + // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] + SkVector fRadii[4]; + mutable Type fType; + // TODO: add padding so we can use memcpy for flattening and not copy + // uninitialized data + + void computeType() const; + bool checkCornerContainment(SkScalar x, SkScalar y) const; + + // to access fRadii directly + friend class SkPath; +}; + +#endif diff --git a/core/SkRasterizer.h b/core/SkRasterizer.h new file mode 100644 index 0000000..3e662ab --- /dev/null +++ b/core/SkRasterizer.h @@ -0,0 +1,44 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkRasterizer_DEFINED +#define SkRasterizer_DEFINED + +#include "SkFlattenable.h" +#include "SkMask.h" + +class SkMaskFilter; +class SkMatrix; +class SkPath; +struct SkIRect; + +class SK_API SkRasterizer : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkRasterizer) + + 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) const; + +protected: + SkRasterizer(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + + virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix, + const SkIRect* clipBounds, + SkMask* mask, SkMask::CreateMode mode) const; + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkReader32.h b/core/SkReader32.h new file mode 100644 index 0000000..7a8d22a --- /dev/null +++ b/core/SkReader32.h @@ -0,0 +1,158 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkReader32_DEFINED +#define SkReader32_DEFINED + +#include "SkMatrix.h" +#include "SkPath.h" +#include "SkRegion.h" +#include "SkRRect.h" +#include "SkScalar.h" + +class SkString; + +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 SkToU32(fStop - fBase); } + uint32_t offset() const { return SkToU32(fCurr - fBase); } + bool eof() const { return fCurr >= fStop; } + const void* base() const { return fBase; } + const void* peek() const { return fCurr; } + + uint32_t available() const { return SkToU32(fStop - fCurr); } + bool isAvailable(uint32_t size) const { return fCurr + size <= fStop; } + + 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; + } + + void* readPtr() { + void* ptr; + // we presume this "if" is resolved at compile-time + if (4 == sizeof(void*)) { + ptr = *(void**)fCurr; + } else { + memcpy(&ptr, fCurr, sizeof(void*)); + } + fCurr += sizeof(void*); + return ptr; + } + + SkScalar readScalar() { + SkASSERT(ptr_align_4(fCurr)); + SkScalar value = *(const SkScalar*)fCurr; + fCurr += sizeof(value); + SkASSERT(fCurr <= fStop); + return value; + } + + const void* skip(size_t size) { + SkASSERT(ptr_align_4(fCurr)); + const void* addr = fCurr; + fCurr += SkAlign4(size); + SkASSERT(fCurr <= fStop); + return addr; + } + + template <typename T> const T& skipT() { + SkASSERT(SkAlign4(sizeof(T)) == sizeof(T)); + return *(const T*)this->skip(sizeof(T)); + } + + void read(void* dst, size_t size) { + SkASSERT(0 == size || 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(); } + + void readPath(SkPath* path) { + size_t size = path->readFromMemory(this->peek()); + SkASSERT(SkAlign4(size) == size); + (void)this->skip(size); + } + + void readMatrix(SkMatrix* matrix) { + size_t size = matrix->readFromMemory(this->peek()); + SkASSERT(SkAlign4(size) == size); + (void)this->skip(size); + } + + SkRRect* readRRect(SkRRect* rrect) { + rrect->readFromMemory(this->skip(SkRRect::kSizeInMemory)); + return rrect; + } + + void readRegion(SkRegion* rgn) { + size_t size = rgn->readFromMemory(this->peek()); + SkASSERT(SkAlign4(size) == size); + (void)this->skip(size); + } + + /** + * Read the length of a string (written by SkWriter32::writeString) into + * len (if len is not NULL) and return the null-ternimated address of the + * string within the reader's buffer. + */ + const char* readString(size_t* len = NULL); + + /** + * Read the string (written by SkWriter32::writeString) and return it in + * copy (if copy is not null). Return the length of the string. + */ + size_t readIntoString(SkString* copy); + +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/core/SkRect.h b/core/SkRect.h new file mode 100644 index 0000000..9f3b59a --- /dev/null +++ b/core/SkRect.h @@ -0,0 +1,790 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkRect_DEFINED +#define SkRect_DEFINED + +#include "SkPoint.h" +#include "SkSize.h" + +/** \struct SkIRect + + SkIRect holds four 32 bit integer coordinates for a rectangle +*/ +struct SK_API SkIRect { + int32_t fLeft, fTop, fRight, fBottom; + + static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { + SkIRect r; + r.setEmpty(); + return r; + } + + static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() { + SkIRect r; + r.setLargest(); + return r; + } + + static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { + SkIRect r; + r.set(0, 0, w, h); + return r; + } + + static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { + SkIRect r; + r.set(0, 0, size.width(), size.height()); + return r; + } + + static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { + SkIRect rect; + rect.set(l, t, r, b); + return rect; + } + + static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { + SkIRect r; + r.set(x, y, x + w, y + h); + return r; + } + + int left() const { return fLeft; } + int top() const { return fTop; } + int right() const { return fRight; } + int bottom() const { return fBottom; } + + /** return the left edge of the rect */ + int x() const { return fLeft; } + /** return the top edge of the rect */ + int y() const { return fTop; } + /** + * Returns the rectangle's width. This does not check for a valid rect + * (i.e. left <= right) so the result may be negative. + */ + int width() const { return fRight - fLeft; } + + /** + * Returns the rectangle's height. This does not check for a valid rect + * (i.e. top <= bottom) so the result may be negative. + */ + int height() const { return fBottom - fTop; } + + /** + * Since the center of an integer rect may fall on a factional value, this + * method is defined to return (right + left) >> 1. + * + * This is a specific "truncation" of the average, which is different than + * (right + left) / 2 when the sum is negative. + */ + int centerX() const { return (fRight + fLeft) >> 1; } + + /** + * Since the center of an integer rect may fall on a factional value, this + * method is defined to return (bottom + top) >> 1 + * + * This is a specific "truncation" of the average, which is different than + * (bottom + top) / 2 when the sum is negative. + */ + int centerY() const { return (fBottom + fTop) >> 1; } + + /** + * Return true if the rectangle's width or height are <= 0 + */ + bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + + bool isLargest() const { return SK_MinS32 == fLeft && + SK_MinS32 == fTop && + SK_MaxS32 == fRight && + SK_MaxS32 == fBottom; } + + friend bool operator==(const SkIRect& a, const SkIRect& b) { + return !memcmp(&a, &b, sizeof(a)); + } + + friend bool operator!=(const SkIRect& a, const SkIRect& b) { + return !(a == b); + } + + bool is16Bit() const { + return SkIsS16(fLeft) && SkIsS16(fTop) && + SkIsS16(fRight) && SkIsS16(fBottom); + } + + /** 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; + } + // alias for set(l, t, r, b) + void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { + this->set(left, top, right, bottom); + } + + void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { + fLeft = x; + fTop = y; + fRight = x + width; + fBottom = y + height; + } + + /** + * Make the largest representable rectangle + */ + void setLargest() { + fLeft = fTop = SK_MinS32; + fRight = fBottom = SK_MaxS32; + } + + /** + * Make the largest representable rectangle, but inverted (e.g. fLeft will + * be max 32bit and right will be min 32bit). + */ + void setLargestInverted() { + fLeft = fTop = SK_MaxS32; + fRight = fBottom = SK_MinS32; + } + + /** 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; + } + + void offset(const SkIPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** + * Offset this rect such its new x() and y() will equal newX and newY. + */ + void offsetTo(int32_t newX, int32_t newY) { + fRight += newX - fLeft; + fBottom += newY - fTop; + fLeft = newX; + fTop = newY; + } + + /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, + making the rectangle narrower. If dx is negative, then the sides are moved outwards, + making the rectangle wider. The same holds true for dy and the top and bottom. + */ + void inset(int32_t dx, int32_t dy) { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + + /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are + moved outwards, making the rectangle wider. If dx is negative, then the + sides are moved inwards, making the rectangle narrower. The same holds + true for dy and the top and bottom. + */ + void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } + + bool quickReject(int l, int t, int r, int b) const { + return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; + } + + /** Returns true if (x,y) is inside the rectangle and the rectangle is not + empty. The left and top are considered to be inside, while the right + and bottom are not. Thus for the rectangle (0, 0, 5, 10), the + points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. + */ + 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; + } + + bool containsNoEmptyCheck(const SkIRect& r) const { + return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** If r intersects this rectangle, return true and set this rectangle to that + intersection, otherwise return false and do not change this rectangle. + If either rectangle is empty, do nothing and return false. + */ + 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; + } + + /** + * Returns true if a and b intersect. debug-asserts that neither are empty. + */ + static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) { + SkASSERT(!a.isEmpty()); + SkASSERT(!b.isEmpty()); + return 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(); + + static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() { + static const SkIRect gEmpty = { 0, 0, 0, 0 }; + return gEmpty; + } +}; + +/** \struct SkRect +*/ +struct SK_API SkRect { + SkScalar fLeft, fTop, fRight, fBottom; + + static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { + SkRect r; + r.setEmpty(); + return r; + } + + static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { + SkRect r; + r.set(0, 0, w, h); + return r; + } + + static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { + SkRect r; + r.set(0, 0, size.width(), size.height()); + return r; + } + + static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { + SkRect rect; + rect.set(l, t, r, b); + return rect; + } + + static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { + SkRect r; + r.set(x, y, x + w, y + h); + return r; + } + + // DEPRECATED: call Make(r) + static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) { + SkRect r; + r.set(SkIntToScalar(irect.fLeft), + SkIntToScalar(irect.fTop), + SkIntToScalar(irect.fRight), + SkIntToScalar(irect.fBottom)); + return r; + } + + static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { + SkRect r; + r.set(SkIntToScalar(irect.fLeft), + SkIntToScalar(irect.fTop), + SkIntToScalar(irect.fRight), + SkIntToScalar(irect.fBottom)); + return r; + } + + /** + * Return true if the rectangle's width or height are <= 0 + */ + bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + + /** + * Returns true iff all values in the rect are finite. If any are + * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this + * returns false. + */ + bool isFinite() const { +#ifdef SK_SCALAR_IS_FLOAT + float accum = 0; + accum *= fLeft; + accum *= fTop; + accum *= fRight; + accum *= fBottom; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || !(accum == accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return accum == accum; +#else + // use bit-or for speed, since we don't care about short-circuting the + // tests, and we expect the common case will be that we need to check all. + int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) | + (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom); + return !isNaN; +#endif + } + + SkScalar x() const { return fLeft; } + SkScalar y() const { return fTop; } + SkScalar left() const { return fLeft; } + SkScalar top() const { return fTop; } + SkScalar right() const { return fRight; } + SkScalar bottom() const { return 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 bool operator==(const SkRect& a, const SkRect& b) { + return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); + } + + friend bool operator!=(const SkRect& a, const SkRect& b) { + return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4); + } + + /** 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; + } + // alias for set(l, t, r, b) + void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { + this->set(left, top, right, bottom); + } + + /** Initialize the rect with the 4 specified integers. The routine handles + converting them to scalars (by calling SkIntToScalar) + */ + 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 left/top at 0,0, and have the specified width + * and height (automatically converted to SkScalar). + */ + void isetWH(int width, int height) { + fLeft = fTop = 0; + fRight = SkIntToScalar(width); + fBottom = SkIntToScalar(height); + } + + /** Set this rectangle to be the bounds of the array of points. + If the array is empty (count == 0), then set this rectangle + to the empty rectangle (0,0,0,0) + */ + void set(const SkPoint pts[], int count) { + // set() had been checking for non-finite values, so keep that behavior + // for now. Now that we have setBoundsCheck(), we may decide to make + // set() be simpler/faster, and not check for those. + (void)this->setBoundsCheck(pts, count); + } + + // alias for set(pts, count) + void setBounds(const SkPoint pts[], int count) { + (void)this->setBoundsCheck(pts, count); + } + + /** + * Compute the bounds of the array of points, and set this rect to that + * bounds and return true... unless a non-finite value is encountered, + * in which case this rect is set to empty and false is returned. + */ + bool setBoundsCheck(const SkPoint pts[], int count); + + void set(const SkPoint& p0, const SkPoint& p1) { + fLeft = SkMinScalar(p0.fX, p1.fX); + fRight = SkMaxScalar(p0.fX, p1.fX); + fTop = SkMinScalar(p0.fY, p1.fY); + fBottom = SkMaxScalar(p0.fY, p1.fY); + } + + void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { + fLeft = x; + fTop = y; + fRight = x + width; + fBottom = y + height; + } + + void setWH(SkScalar width, SkScalar height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + + /** + * Make the largest representable rectangle + */ + void setLargest() { + fLeft = fTop = SK_ScalarMin; + fRight = fBottom = SK_ScalarMax; + } + + /** + * Make the largest representable rectangle, but inverted (e.g. fLeft will + * be max and right will be min). + */ + void setLargestInverted() { + fLeft = fTop = SK_ScalarMax; + fRight = fBottom = SK_ScalarMin; + } + + /** 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; + } + + void offset(const SkPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** + * Offset this rect such its new x() and y() will equal newX and newY. + */ + void offsetTo(SkScalar newX, SkScalar newY) { + fRight += newX - fLeft; + fBottom += newY - fTop; + fLeft = newX; + fTop = newY; + } + + /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are + moved inwards, making the rectangle narrower. If dx is negative, then + the sides are moved outwards, making the rectangle wider. The same holds + true for dy and the top and bottom. + */ + void inset(SkScalar dx, SkScalar dy) { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + + /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are + moved outwards, making the rectangle wider. If dx is negative, then the + sides are moved inwards, making the rectangle narrower. The same holds + true for dy and the top and bottom. + */ + void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } + + /** If this rectangle intersects r, return true and set this rectangle to that + intersection, otherwise return false and do not change this rectangle. + If either rectangle is empty, do nothing and return false. + */ + 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; + } + + /** 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 SkRect& a, const SkRect& b); + + /** + * 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() && + 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); + } + // alias for join() + void growToInclude(const SkRect& r) { this->join(r); } + + /** + * Grow the rect to include the specified (x,y). After this call, the + * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. + * + * This is close, but not quite the same contract as contains(), since + * contains() treats the left and top different from the right and bottom. + * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note + * that contains(x,y) always returns false if the rect is empty. + */ + void growToInclude(SkScalar x, SkScalar y) { + fLeft = SkMinScalar(x, fLeft); + fRight = SkMaxScalar(x, fRight); + fTop = SkMinScalar(y, fTop); + fBottom = SkMaxScalar(y, fBottom); + } + + /** + * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the rectangle are themselves considered + * to be inside, while the right and bottom are not. Thus for the rectangle + * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. + */ + 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, and the rectangle + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the rectangle are themselves considered + * to be inside, while the right and bottom are not. Thus for the rectangle + * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. + */ + 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, and if both rectangles are + * not empty. + */ + bool contains(const SkRect& r) const { + return !r.isEmpty() && !this->isEmpty() && + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** + * Set the dst rectangle by rounding this rectangle's coordinates to their + * nearest integer values using SkScalarRound. + */ + void round(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); + } + + /** + * Set the dst rectangle by rounding "out" this rectangle, choosing the + * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. + */ + void roundOut(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); + } + + /** + * Expand this rectangle by rounding its coordinates "out", choosing the + * floor of top and left, and the ceil of right and bottom. If this rect + * is already on integer coordinates, then it will be unchanged. + */ + void roundOut() { + this->set(SkScalarFloorToScalar(fLeft), + SkScalarFloorToScalar(fTop), + SkScalarCeilToScalar(fRight), + SkScalarCeilToScalar(fBottom)); + } + + /** + * Set the dst rectangle by rounding "in" this rectangle, choosing the + * ceil of top and left, and the floor of right and bottom. This does *not* + * call sort(), so it is possible that the resulting rect is inverted... + * e.g. left >= right or top >= bottom. Call isEmpty() to detect that. + */ + void roundIn(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); + } + + + /** + * Swap top/bottom or left/right if there are flipped (i.e. if width() + * or height() would have returned a negative value.) This should be called + * if the edges are computed separately, and may have crossed over each + * other. When this returns, left <= right && top <= bottom + */ + void sort(); + + /** + * cast-safe way to treat the rect as an array of (4) SkScalars. + */ + const SkScalar* asScalars() const { return &fLeft; } +}; + +#endif diff --git a/core/SkRefCnt.h b/core/SkRefCnt.h new file mode 100644 index 0000000..87ff7db --- /dev/null +++ b/core/SkRefCnt.h @@ -0,0 +1,274 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkRefCnt_DEFINED +#define SkRefCnt_DEFINED + +#include "SkThread.h" +#include "SkInstCnt.h" +#include "SkTemplates.h" + +/** \class SkRefCnt + + SkRefCnt is the base class for objects that may be shared by multiple + objects. When an existing owner wants to share 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 SK_API SkRefCnt : SkNoncopyable { +public: + SK_DECLARE_INST_COUNT_ROOT(SkRefCnt) + + /** Default construct, initializing the reference count to 1. + */ + SkRefCnt() : fRefCnt(1) {} + + /** Destruct, asserting that the reference count is 1. + */ + virtual ~SkRefCnt() { +#ifdef SK_DEBUG + SkASSERT(fRefCnt == 1); + fRefCnt = 0; // illegal value, to catch us if we reuse after delete +#endif + } + + /** Return the reference count. Use only for debugging. */ + int32_t getRefCnt() const { return fRefCnt; } + + /** Returns true if the caller is the only owner. + * Ensures that all previous owner's actions are complete. + */ + bool unique() const { + bool const unique = (1 == fRefCnt); + if (unique) { + // Aquire barrier (L/SL), if not provided by load of fRefCnt. + // Prevents user's 'unique' code from happening before decrements. + //TODO: issue the barrier. + } + return unique; + } + + /** Increment the reference count. Must be balanced by a call to unref(). + */ + void ref() const { + SkASSERT(fRefCnt > 0); + sk_atomic_inc(&fRefCnt); // No barrier required. + } + + /** Decrement the reference count. If the reference count is 1 before the + decrement, then delete 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); + // Release barrier (SL/S), if not provided below. + if (sk_atomic_dec(&fRefCnt) == 1) { + // Aquire barrier (L/SL), if not provided above. + // Prevents code in dispose from happening before the decrement. + sk_membar_aquire__after_atomic_dec(); + internal_dispose(); + } + } + + void validate() const { + SkASSERT(fRefCnt > 0); + } + + /** + * Alias for unref(), for compatibility with WTF::RefPtr. + */ + void deref() { this->unref(); } + +protected: + /** + * Allow subclasses to call this if they've overridden internal_dispose + * so they can reset fRefCnt before the destructor is called. Should only + * be called right before calling through to inherited internal_dispose() + * or before calling the destructor. + */ + void internal_dispose_restore_refcnt_to_1() const { +#ifdef SK_DEBUG + SkASSERT(0 == fRefCnt); + fRefCnt = 1; +#endif + } + +private: + /** + * Called when the ref count goes to 0. + */ + virtual void internal_dispose() const { + this->internal_dispose_restore_refcnt_to_1(); + SkDELETE(this); + } + + // The following friends are those which override internal_dispose() + // and conditionally call SkRefCnt::internal_dispose(). + friend class GrTexture; + friend class SkWeakRefCnt; + + mutable int32_t fRefCnt; + + typedef SkNoncopyable INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** 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) + + +/** Call obj->ref() and return obj. The obj must not be NULL. + */ +template <typename T> static inline T* SkRef(T* obj) { + SkASSERT(obj); + obj->ref(); + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->ref() and return obj. + */ +template <typename T> static inline T* SkSafeRef(T* obj) { + if (obj) { + obj->ref(); + } + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->unref() + */ +template <typename T> static inline void SkSafeUnref(T* obj) { + if (obj) { + obj->unref(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Utility class that simply unref's its argument in the destructor. + */ +template <typename T> class SkAutoTUnref : SkNoncopyable { +public: + explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {} + ~SkAutoTUnref() { SkSafeUnref(fObj); } + + T* get() const { return fObj; } + + T* reset(T* obj) { + SkSafeUnref(fObj); + fObj = obj; + return obj; + } + + void swap(SkAutoTUnref* other) { + T* tmp = fObj; + fObj = other->fObj; + other->fObj = tmp; + } + + /** + * Return the hosted object (which may be null), transferring ownership. + * The reference count is not modified, and the internal ptr is set to NULL + * so unref() will not be called in our destructor. A subsequent call to + * detach() will do nothing and return null. + */ + T* detach() { + T* obj = fObj; + fObj = NULL; + return obj; + } + + /** + * BlockRef<B> is a type which inherits from B, cannot be created, + * cannot be deleted, and makes ref and unref private. + */ + template<typename B> class BlockRef : public B { + private: + BlockRef(); + ~BlockRef(); + void ref() const; + void unref() const; + }; + + /** If T is const, the type returned from operator-> will also be const. */ + typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType; + + /** + * SkAutoTUnref assumes ownership of the ref. As a result, it is an error + * for the user to ref or unref through SkAutoTUnref. Therefore + * SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of + * skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref(). + */ + BlockRefType *operator->() const { + return static_cast<BlockRefType*>(fObj); + } + operator T*() { return fObj; } + +private: + T* fObj; +}; + +class SkAutoUnref : public SkAutoTUnref<SkRefCnt> { +public: + SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {} +}; + +class SkAutoRef : SkNoncopyable { +public: + SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); } + ~SkAutoRef() { SkSafeUnref(fObj); } +private: + SkRefCnt* fObj; +}; + +/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to + a SkRefCnt (or subclass) object. + */ +template <typename T> class SkRefPtr { +public: + SkRefPtr() : fObj(NULL) {} + SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); } + SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); } + ~SkRefPtr() { SkSafeUnref(fObj); } + + SkRefPtr& operator=(const SkRefPtr& rp) { + SkRefCnt_SafeAssign(fObj, rp.fObj); + return *this; + } + SkRefPtr& operator=(T* obj) { + SkRefCnt_SafeAssign(fObj, obj); + return *this; + } + + T* get() const { return fObj; } + T& operator*() const { return *fObj; } + T* operator->() const { return fObj; } + + typedef T* SkRefPtr::*unspecified_bool_type; + operator unspecified_bool_type() const { + return fObj ? &SkRefPtr::fObj : NULL; + } + +private: + T* fObj; +}; + +#endif diff --git a/core/SkRegion.h b/core/SkRegion.h new file mode 100644 index 0000000..a088d54 --- /dev/null +++ b/core/SkRegion.h @@ -0,0 +1,446 @@ + +/* + * Copyright 2005 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 SK_API SkRegion { +public: + typedef int32_t RunType; + enum { + kRunTypeSentinel = 0x7FFFFFFF + }; + + SkRegion(); + SkRegion(const SkRegion&); + explicit SkRegion(const SkIRect&); + ~SkRegion(); + + SkRegion& operator=(const SkRegion&); + + /** + * Return true if the two regions are equal. i.e. The enclose exactly + * the same area. + */ + bool operator==(const SkRegion& other) const; + + /** + * Return true if the two regions are not equal. + */ + bool operator!=(const SkRegion& other) const { + return !(*this == other); + } + + /** + * 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 a value that grows approximately linearly with the number of + * intervals comprised in the region. Empty region will return 0, Rect + * will return 1, Complex will return a value > 1. + * + * Use this to compare two regions, where the larger count likely + * indicates a more complex region. + */ + int computeRegionComplexity() const; + + /** + * Returns true if the region is non-empty, and if so, appends the + * boundary(s) of the region to the specified path. + * If the region is empty, returns false, and path is left unmodified. + */ + 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 union of an array of rects. This is generally + * faster than calling region.op(rect, kUnion_Op) in a loop. If count is + * 0, then this region is set to the empty region. + * @return true if the resulting region is non-empty + */ + bool setRects(const SkIRect rects[], int count); + + /** + * 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); + +#ifdef SK_BUILD_FOR_ANDROID + /** Returns a new char* containing the list of rectangles in this region + */ + char* toString(); +#endif + + /** + * Returns the sequence of rectangles, sorted in Y and X, that make up + * this region. + */ + class SK_API 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() const { return fDone; } + void next(); + const SkIRect& rect() const { return fRect; } + // may return null + const SkRegion* rgn() const { return fRgn; } + + 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 SK_API 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 writeToMemory(void* buffer) const; + + /** + * Initialized the region from the buffer, returning the number + * of bytes actually read. + */ + uint32_t readFromMemory(const void* buffer); + + /** + * Returns a reference to a global empty region. Just a convenience for + * callers that need a const empty region. + */ + static const SkRegion& GetEmptyRegion(); + + 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 { + // T + // [B N L R S] + // S + kRectRegionRuns = 7 + }; + + friend class android::Region; // needed for marshalling efficiently + + struct RunHead; + + // allocate space for count runs + void allocateRuns(int count); + void allocateRuns(int count, int ySpanCount, int intervalCount); + void allocateRuns(const RunHead& src); + + SkIRect fBounds; + RunHead* fRunHead; + + void freeRuns(); + + /** + * Return the runs from this region, consing up fake runs if the region + * is empty or a rect. In those 2 cases, we use tmpStorage to hold the + * run data. + */ + const RunType* getRuns(RunType tmpStorage[], int* intervals) const; + + // This is called with runs[] that do not yet have their interval-count + // field set on each scanline. That is computed as part of this call + // (inside ComputeRunBounds). + bool setRuns(RunType runs[], int count); + + int count_runtype_values(int* itop, int* ibot) const; + + static void BuildRectRuns(const SkIRect& bounds, + RunType runs[kRectRegionRuns]); + + // If the runs define a simple rect, return true and set bounds to that + // rect. If not, return false and ignore bounds. + static bool RunsAreARect(const SkRegion::RunType runs[], int count, + SkIRect* bounds); + + /** + * If the last arg is null, just return if the result is non-empty, + * else store the result in the last arg. + */ + static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); + + friend struct RunHead; + friend class Iterator; + friend class Spanerator; + friend class SkRgnBuilder; + friend class SkFlatRegion; +}; + +#endif diff --git a/core/SkScalar.h b/core/SkScalar.h new file mode 100644 index 0000000..2dd7a62 --- /dev/null +++ b/core/SkScalar.h @@ -0,0 +1,341 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkScalar_DEFINED +#define SkScalar_DEFINED + +#include "SkFixed.h" +#include "SkFloatingPoint.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 + + /** 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; + + /** 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 SK_FloatInfinity + /** SK_ScalarNegativeInfinity is defined to be negative infinity as an SkScalar + */ + #define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity + /** SK_ScalarMax is defined to be the largest value representable as an SkScalar + */ + #define SK_ScalarMax (3.402823466e+38f) + /** SK_ScalarMin is defined to be the smallest value representable as an SkScalar + */ + #define SK_ScalarMin (-SK_ScalarMax) + /** SK_ScalarNaN is defined to be 'Not a Number' as an SkScalar + */ + #define SK_ScalarNaN SK_FloatNaN + /** SkScalarIsNaN(n) returns true if argument is not a number + */ + static inline bool SkScalarIsNaN(float x) { return x != x; } + + /** Returns true if x is not NaN and not infinite */ + static inline bool SkScalarIsFinite(float x) { + // We rely on the following behavior of infinities and nans + // 0 * finite --> 0 + // 0 * infinity --> NaN + // 0 * NaN --> NaN + float prod = x * 0; + // At this point, prod will either be NaN or 0 + // Therefore we can return (prod == prod) or (0 == prod). + return prod == prod; + } + + /** 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) + + #define SkScalarFloorToScalar(x) sk_float_floor(x) + #define SkScalarCeilToScalar(x) sk_float_ceil(x) + #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f) + + #define SkScalarFloorToInt(x) sk_float_floor2int(x) + #define SkScalarCeilToInt(x) sk_float_ceil2int(x) + #define SkScalarRoundToInt(x) sk_float_round2int(x) + #define SkScalarTruncToInt(x) static_cast<int>(x) + + /** Returns the absolute value of the specified SkScalar + */ + #define SkScalarAbs(x) sk_float_abs(x) + /** Return x with the sign of y + */ + #define SkScalarCopySign(x, y) sk_float_copysign(x, y) + /** 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 b to the e + */ + #define SkScalarPow(b, e) sk_float_pow(b, e) + /** 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; } + + static inline bool SkScalarIsInt(SkScalar x) { + return x == (float)(int)x; + } +#else + typedef SkFixed SkScalar; + + #define SK_Scalar1 SK_Fixed1 + #define SK_ScalarHalf SK_FixedHalf + #define SK_ScalarInfinity SK_FixedMax + #define SK_ScalarNegativeInfinity SK_FixedMin + #define SK_ScalarMax SK_FixedMax + #define SK_ScalarMin SK_FixedMin + #define SK_ScalarNaN SK_FixedNaN + #define SkScalarIsNaN(x) ((x) == SK_FixedNaN) + #define SkScalarIsFinite(x) ((x) != SK_FixedNaN) + + #define SkIntToScalar(n) SkIntToFixed(n) + #define SkFixedToScalar(x) (x) + #define SkScalarToFixed(x) (x) + #define SkScalarToFloat(n) SkFixedToFloat(n) + #define SkFloatToScalar(n) SkFloatToFixed(n) + + #define SkScalarToDouble(n) SkFixedToDouble(n) + #define SkDoubleToScalar(n) SkDoubleToFixed(n) + #define SkScalarFraction(x) SkFixedFraction(x) + + #define SkScalarFloorToScalar(x) SkFixedFloorToFixed(x) + #define SkScalarCeilToScalar(x) SkFixedCeilToFixed(x) + #define SkScalarRoundToScalar(x) SkFixedRoundToFixed(x) + + #define SkScalarFloorToInt(x) SkFixedFloorToInt(x) + #define SkScalarCeilToInt(x) SkFixedCeilToInt(x) + #define SkScalarRoundToInt(x) SkFixedRoundToInt(x) + #define SkScalarTruncToInt(x) (((x) < 0) ? SkScalarCeilToInt(x) : SkScalarFloorToInt(x)) + + #define SkScalarAbs(x) SkFixedAbs(x) + #define SkScalarCopySign(x, y) SkCopySign32(x, y) + #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) + + static inline bool SkScalarIsInt(SkFixed x) { + return 0 == (x & 0xffff); + } +#endif + +// DEPRECATED : use ToInt or ToScalar variant +#define SkScalarFloor(x) SkScalarFloorToInt(x) +#define SkScalarCeil(x) SkScalarCeilToInt(x) +#define SkScalarRound(x) SkScalarRoundToInt(x) + +/** + * Returns -1 || 0 || 1 depending on the sign of value: + * -1 if x < 0 + * 0 if x == 0 + * 1 if x > 0 + */ +static inline int SkScalarSignAsInt(SkScalar x) { + return x < 0 ? -1 : (x > 0); +} + +// Scalar result version of above +static inline SkScalar SkScalarSignAsScalar(SkScalar x) { + return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0); +} + +#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) + +static inline bool SkScalarNearlyZero(SkScalar x, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x) <= tolerance; +} + +static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x-y) <= 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] +*/ +static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) { + SkASSERT(t >= 0 && t <= SK_Scalar1); + return A + SkScalarMul(B - A, t); +} + +static inline SkScalar SkScalarLog2(SkScalar x) { + static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2)); + + return SkScalarMul(SkScalarLog(x), log2_conversion_factor); +} + +/** Interpolate along the function described by (keys[length], values[length]) + for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length] + clamp to the min or max value. This function was inspired by a desire + to change the multiplier for thickness in fakeBold; therefore it assumes + the number of pairs (length) will be small, and a linear search is used. + Repeated keys are allowed for discontinuous functions (so long as keys is + monotonically increasing), and if key is the value of a repeated scalar in + keys, the first one will be used. However, that may change if a binary + search is used. +*/ +SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[], + const SkScalar values[], int length); + +/* + * Helper to compare an array of scalars. + */ +static inline bool SkScalarsEqual(const SkScalar a[], const SkScalar b[], int n) { +#ifdef SK_SCALAR_IS_FLOAT + SkASSERT(n >= 0); + for (int i = 0; i < n; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; +#else + return 0 == memcmp(a, b, n * sizeof(SkScalar)); +#endif +} + +#endif diff --git a/core/SkScalarCompare.h b/core/SkScalarCompare.h new file mode 100644 index 0000000..5361294 --- /dev/null +++ b/core/SkScalarCompare.h @@ -0,0 +1,38 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkScalarCompare_DEFINED +#define SkScalarCompare_DEFINED + +#include "SkFloatBits.h" +#include "SkRect.h" + +/** Skia can spend a lot of time just comparing scalars (e.g. quickReject). + When scalar==fixed, this is very fast, and when scalar==hardware-float, this + is also reasonable, but if scalar==software-float, then each compare can be + a function call and take real time. To account for that, we have the flag + SK_SCALAR_SLOW_COMPARES. + + If this is defined, we have a special trick where we quickly convert floats + to a 2's compliment form, and then treat them as signed 32bit integers. In + this form we lose a few subtlties (e.g. NaNs always comparing false) but + we gain the speed of integer compares. + */ + +#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/core/SkShader.h b/core/SkShader.h new file mode 100644 index 0000000..e1cab96 --- /dev/null +++ b/core/SkShader.h @@ -0,0 +1,377 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkShader_DEFINED +#define SkShader_DEFINED + +#include "SkBitmap.h" +#include "SkFlattenable.h" +#include "SkMask.h" +#include "SkMatrix.h" +#include "SkPaint.h" + +class SkPath; +class GrContext; +class GrEffectRef; + +/** \class SkShader + * + * Shaders specify the source color(s) for what is being drawn. If a paint + * has no shader, then the paint's color is used. If the paint has a + * shader, then the shader's color(s) are use instead, but they are + * modulated by the paint's alpha. This makes it easy to create a shader + * once (e.g. bitmap tiling or gradient) and then change its transparency + * w/o having to modify the original shader... only the paint's alpha needs + * to be modified. + */ +class SK_API SkShader : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkShader) + + SkShader(); + virtual ~SkShader(); + + /** + * Returns true if the local matrix is not an identity matrix. + */ + bool hasLocalMatrix() const { return !fLocalMatrix.isIdentity(); } + + /** + * Returns the local matrix. + */ + const SkMatrix& getLocalMatrix() const { return fLocalMatrix; } + + /** + * Set the shader's local matrix. + * @param localM The shader's new local matrix. + */ + void setLocalMatrix(const SkMatrix& localM) { fLocalMatrix = localM; } + + /** + * Reset the shader's local matrix to identity. + */ + void resetLocalMatrix() { fLocalMatrix.reset(); } + + enum TileMode { + /** replicate the edge color if the shader draws outside of its + * original bounds + */ + kClamp_TileMode, + + /** repeat the shader's image horizontally and vertically */ + kRepeat_TileMode, + + /** repeat the shader's image horizontally and vertically, alternating + * mirror images so that adjacent images always seam + */ + kMirror_TileMode, + +#if 0 + /** only draw within the original domain, return 0 everywhere else */ + kDecal_TileMode, +#endif + + 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, + + /** set (after setContext) if the spans only vary in X (const in Y). + e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient + that varies from left-to-right. This flag specifies this for + shadeSpan(). + */ + kConstInY32_Flag = 0x08, + + /** same as kConstInY32_Flag, but is set if this is true for shadeSpan16 + which may not always be the case, since shadeSpan16 may be + predithered, which would mean it was not const in Y, even though + the 32bit shadeSpan() would be const. + */ + kConstInY16_Flag = 0x10 + }; + + /** + * 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; } + + /** + * Returns true if the shader is guaranteed to produce only opaque + * colors, subject to the SkPaint using the shader to apply an opaque + * alpha value. Subclasses should override this to allow some + * optimizations. isOpaque() can be called at any time, unlike getFlags, + * which only works properly when the context is set. + */ + virtual bool isOpaque() const { return false; } + + /** + * 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. If true is returned, then + * a balancing call to endContext() will be made before the next call to + * setContext. + * + * Subclasses should be sure to call their INHERITED::setContext() if they + * override this method. + */ + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix); + + /** + * Assuming setContext returned true, endContext() will be called when + * the draw using the shader has completed. It is an error for setContext + * to be called twice w/o an intervening call to endContext(). + * + * Subclasses should be sure to call their INHERITED::endContext() if they + * override this method. + */ + virtual void endContext(); + + SkDEBUGCODE(bool setContextHasBeenCalled() const { return SkToBool(fInSetContext); }) + + /** + * 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; + + typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count); + virtual ShadeProc asAShadeProc(void** ctx); + + /** + * 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; + } + + /** + Gives method bitmap should be read to implement a shader. + Also determines number and interpretation of "extra" parameters returned + by asABitmap + */ + enum BitmapType { + kNone_BitmapType, //<! Shader is not represented as a bitmap + kDefault_BitmapType,//<! Access bitmap using local coords transformed + // by matrix. No extras + kRadial_BitmapType, //<! Access bitmap by transforming local coordinates + // by the matrix and taking the distance of result + // from (0,0) as bitmap column. Bitmap is 1 pixel + // tall. No extras + kSweep_BitmapType, //<! Access bitmap by transforming local coordinates + // by the matrix and taking the angle of result + // to (0,0) as bitmap x coord, where angle = 0 is + // bitmap left edge of bitmap = 2pi is the + // right edge. Bitmap is 1 pixel tall. No extras + kTwoPointRadial_BitmapType, + //<! Matrix transforms to space where (0,0) is + // the center of the starting circle. The second + // circle will be centered (x, 0) where x may be + // 0. The post-matrix space is normalized such + // that 1 is the second radius - first radius. + // Three extra parameters are returned: + // 0: x-offset of second circle center + // to first. + // 1: radius of first circle in post-matrix + // space + // 2: the second radius minus the first radius + // in pre-transformed space. + kTwoPointConical_BitmapType, + //<! Matrix transforms to space where (0,0) is + // the center of the starting circle. The second + // circle will be centered (x, 0) where x may be + // 0. + // Three extra parameters are returned: + // 0: x-offset of second circle center + // to first. + // 1: radius of first circle + // 2: the second radius minus the first radius + kLinear_BitmapType, //<! Access bitmap using local coords transformed + // by matrix. No extras + + kLast_BitmapType = kLinear_BitmapType + }; + /** Optional methods for shaders that can pretend to be a bitmap/texture + to play along with opengl. Default just returns kNone_BitmapType and + ignores the out parameters. + + @param outTexture if non-NULL will be the bitmap representing the shader + after return. + @param outMatrix if non-NULL will be the matrix to apply to vertices + to access the bitmap after return. + @param xy if non-NULL will be the tile modes that should be + used to access the bitmap after return. + @param twoPointRadialParams Two extra return values needed for two point + radial bitmaps. The first is the x-offset of + the second point and the second is the radius + about the first point. + */ + virtual BitmapType asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, + TileMode xy[2]) const; + + /** + * If the shader subclass can be represented as a gradient, asAGradient + * returns the matching GradientType enum (or kNone_GradientType if it + * cannot). Also, if info is not null, asAGradient populates info with + * the relevant (see below) parameters for the gradient. fColorCount + * is both an input and output parameter. On input, it indicates how + * many entries in fColors and fColorOffsets can be used, if they are + * non-NULL. After asAGradient has run, fColorCount indicates how + * many color-offset pairs there are in the gradient. If there is + * insufficient space to store all of the color-offset pairs, fColors + * and fColorOffsets will not be altered. fColorOffsets specifies + * where on the range of 0 to 1 to transition to the given color. + * The meaning of fPoint and fRadius is dependant on the type of gradient. + * + * None: + * info is ignored. + * Color: + * fColorOffsets[0] is meaningless. + * Linear: + * fPoint[0] and fPoint[1] are the end-points of the gradient + * Radial: + * fPoint[0] and fRadius[0] are the center and radius + * Radial2: + * fPoint[0] and fRadius[0] are the center and radius of the 1st circle + * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle + * Sweep: + * fPoint[0] is the center of the sweep. + */ + + enum GradientType { + kNone_GradientType, + kColor_GradientType, + kLinear_GradientType, + kRadial_GradientType, + kRadial2_GradientType, + kSweep_GradientType, + kConical_GradientType, + kLast_GradientType = kConical_GradientType + }; + + struct GradientInfo { + int fColorCount; //!< In-out parameter, specifies passed size + // of fColors/fColorOffsets on input, and + // actual number of colors/offsets on + // output. + SkColor* fColors; //!< The colors in the gradient. + SkScalar* fColorOffsets; //!< The unit offset for color transitions. + SkPoint fPoint[2]; //!< Type specific, see above. + SkScalar fRadius[2]; //!< Type specific, see above. + TileMode fTileMode; //!< The tile mode used. + uint32_t fGradientFlags; //!< see SkGradientShader::Flags + }; + + virtual GradientType asAGradient(GradientInfo* info) const; + + /** + * If the shader subclass has a GrEffect implementation, this installs an effect on the stage. + * The GrContext may be used by the effect to create textures. The GPU device does not call + * setContext. Instead we pass the paint here in case the shader needs paint info. + */ + virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const; + + ////////////////////////////////////////////////////////////////////////// + // Factory methods for stock shaders + + /** Call this to create a new shader that will draw with the specified bitmap. + * + * If the bitmap cannot be used (e.g. has no pixels, or its dimensions + * exceed implementation limits (currently at 64K - 1)) then SkEmptyShader + * may be returned. + * + * @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); + + SkDEVCODE(virtual void toString(SkString* str) const;) + +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& ); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; +private: + SkMatrix fLocalMatrix; + SkMatrix fTotalInverse; + uint8_t fPaintAlpha; + uint8_t fDeviceConfig; + uint8_t fTotalInverseClass; + SkDEBUGCODE(SkBool8 fInSetContext;) + + static SkShader* CreateBitmapShader(const SkBitmap& src, + TileMode, TileMode, + void* storage, size_t storageSize); + friend class SkAutoBitmapShaderInstall; + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkSize.h b/core/SkSize.h new file mode 100644 index 0000000..01c6e35 --- /dev/null +++ b/core/SkSize.h @@ -0,0 +1,110 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSize_DEFINED +#define SkSize_DEFINED + +#include "SkScalar.h" + +template <typename T> struct SkTSize { + T fWidth; + T fHeight; + + static SkTSize Make(T w, T h) { + SkTSize s; + s.fWidth = w; + s.fHeight = h; + return s; + } + + void set(T w, T h) { + fWidth = w; + fHeight = h; + } + + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { + return 0 == fWidth && 0 == fHeight; + } + + /** Returns true if either widht or height are <= 0 */ + bool isEmpty() const { + return fWidth <= 0 || fHeight <= 0; + } + + /** Set the width and height to 0 */ + void setEmpty() { + fWidth = fHeight = 0; + } + + T width() const { return fWidth; } + T height() const { return fHeight; } + + /** If width or height is < 0, it is set to 0 */ + void clampNegToZero() { + if (fWidth < 0) { + fWidth = 0; + } + if (fHeight < 0) { + fHeight = 0; + } + } + + bool equals(T w, T h) const { + return fWidth == w && fHeight == h; + } +}; + +template <typename T> +static inline bool operator==(const SkTSize<T>& a, const SkTSize<T>& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +template <typename T> +static inline bool operator!=(const SkTSize<T>& a, const SkTSize<T>& b) { + return !(a == b); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef SkTSize<int32_t> SkISize; + +struct SkSize : public SkTSize<SkScalar> { + static SkSize Make(SkScalar w, SkScalar h) { + SkSize s; + s.fWidth = w; + s.fHeight = h; + return s; + } + + + SkSize& operator=(const SkISize& src) { + this->set(SkIntToScalar(src.fWidth), SkIntToScalar(src.fHeight)); + return *this; + } + + SkISize toRound() const { + SkISize s; + s.set(SkScalarRound(fWidth), SkScalarRound(fHeight)); + return s; + } + + SkISize toCeil() const { + SkISize s; + s.set(SkScalarCeil(fWidth), SkScalarCeil(fHeight)); + return s; + } + + SkISize toFloor() const { + SkISize s; + s.set(SkScalarFloor(fWidth), SkScalarFloor(fHeight)); + return s; + } +}; + +#endif diff --git a/core/SkStream.h b/core/SkStream.h new file mode 100644 index 0000000..d7a105d --- /dev/null +++ b/core/SkStream.h @@ -0,0 +1,467 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStream_DEFINED +#define SkStream_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" + +class SkData; + +class SkStream; +class SkStreamRewindable; +class SkStreamSeekable; +class SkStreamAsset; +class SkStreamMemory; + +/** + * SkStream -- abstraction for a source of bytes. Subclasses can be backed by + * memory, or a file, or something else. + * + * NOTE: + * + * Classic "streams" APIs are sort of async, in that on a request for N + * bytes, they may return fewer than N bytes on a given call, in which case + * the caller can "try again" to get more bytes, eventually (modulo an error) + * receiving their total N bytes. + * + * Skia streams behave differently. They are effectively synchronous, and will + * always return all N bytes of the request if possible. If they return fewer + * (the read() call returns the number of bytes read) then that means there is + * no more data (at EOF or hit an error). The caller should *not* call again + * in hopes of fulfilling more of the request. + */ +class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt +public: + /** + * Attempts to open the specified file, and return a stream to it (using + * mmap if available). On success, the caller must call unref() on the + * returned object. On failure, returns NULL. + */ + static SkStreamAsset* NewFromFile(const char path[]); + + SK_DECLARE_INST_COUNT(SkStream) + + /** Reads or skips size number of bytes. + * If buffer == NULL, skip size bytes, return how many were skipped. + * If buffer != NULL, copy size bytes into buffer, return how many were copied. + * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer + * @param size the number of bytes to skip or copy + * @return the number of bytes actually read. + */ + virtual size_t read(void* buffer, size_t size) = 0; + + /** Skip size number of bytes. + * @return the actual number bytes that could be skipped. + */ + size_t skip(size_t size) { + //return this->read(NULL, size); + //TODO: remove this old logic after updating existing implementations + return 0 == size ? 0 : this->read(NULL, size); + } + + /** Returns true when all the bytes in the stream have been read. + * This may return true early (when there are no more bytes to be read) + * or late (after the first unsuccessful read). + * + * In Progress: do not use until all implementations are updated. + * TODO: after this is implemented everywhere, make pure virtual. + */ + virtual bool isAtEnd() const { + SkASSERT(false); + return true; + } + + 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(); + + /** + * Reconstitute an SkData object that was written to the stream + * using SkWStream::writeData(). + */ + SkData* readData(); + +//SkStreamRewindable + /** Rewinds to the beginning of the stream. If this cannot be done, return false. */ + virtual bool rewind() { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned at the beginning of its data. + */ + virtual SkStreamRewindable* duplicate() const { return NULL; } + +//SkStreamSeekable + /** Returns true if this stream can report it's current position. */ + virtual bool hasPosition() const { return false; } + /** Returns the current position in the stream. If this cannot be done, returns 0. */ + virtual size_t getPosition() const { return 0; } + + /** Seeks to an absolute position in the stream. If this cannot be done, returns false. + * If an attempt is made to seek past the end of the stream, the position will be set + * to the end of the stream. + */ + virtual bool seek(size_t position) { return false; } + + /** Seeks to an relative offset in the stream. If this cannot be done, returns false. + * If an attempt is made to move to a position outside the stream, the position will be set + * to the closest point within the stream (beginning or end). + */ + virtual bool move(long offset) { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned the same as this stream. + */ + virtual SkStreamSeekable* fork() const { return NULL; } + +//SkStreamAsset + /** Returns true if this stream can report it's total length. */ + virtual bool hasLength() const { return false; } + /** Returns the total length of the stream. If this cannot be done, returns 0. */ + virtual size_t getLength() const { + //return 0; + //TODO: remove the following after everyone is updated. + return ((SkStream*)this)->read(NULL, 0); + } + +//SkStreamMemory + /** Returns the starting address for the data. If this cannot be done, returns NULL. */ + //TODO: replace with virtual const SkData* getData() + virtual const void* getMemoryBase() { return NULL; } + +private: + typedef SkRefCnt INHERITED; +}; + +/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ +class SK_API SkStreamRewindable : public SkStream { +public: + //TODO: remove the following after everyone is updated (ensures new behavior on new classes). + virtual bool isAtEnd() const SK_OVERRIDE = 0; + //TODO: remove the following after everyone is updated (ensures new behavior on new classes). + virtual size_t getLength() const SK_OVERRIDE { return 0; } + + virtual bool rewind() SK_OVERRIDE = 0; + virtual SkStreamRewindable* duplicate() const SK_OVERRIDE = 0; +}; + +/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ +class SK_API SkStreamSeekable : public SkStreamRewindable { +public: + virtual SkStreamSeekable* duplicate() const SK_OVERRIDE = 0; + + virtual bool hasPosition() const SK_OVERRIDE { return true; } + virtual size_t getPosition() const SK_OVERRIDE = 0; + virtual bool seek(size_t position) SK_OVERRIDE = 0; + virtual bool move(long offset) SK_OVERRIDE = 0; + virtual SkStreamSeekable* fork() const SK_OVERRIDE = 0; +}; + +/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ +class SK_API SkStreamAsset : public SkStreamSeekable { +public: + virtual SkStreamAsset* duplicate() const SK_OVERRIDE = 0; + virtual SkStreamAsset* fork() const SK_OVERRIDE = 0; + + virtual bool hasLength() const SK_OVERRIDE { return true; } + virtual size_t getLength() const SK_OVERRIDE = 0; +}; + +/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ +class SK_API SkStreamMemory : public SkStreamAsset { +public: + virtual SkStreamMemory* duplicate() const SK_OVERRIDE = 0; + virtual SkStreamMemory* fork() const SK_OVERRIDE = 0; + + virtual const void* getMemoryBase() SK_OVERRIDE = 0; +}; + +class SK_API SkWStream : SkNoncopyable { +public: + SK_DECLARE_INST_COUNT_ROOT(SkWStream) + + 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 writeBigDecAsText(int64_t, int minDigits = 0); + 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); + + /** + * Append an SkData object to the stream, such that it can be read + * out of the stream using SkStream::readData(). + * + * Note that the encoding method used to write the SkData object + * to the stream may change over time. This method DOES NOT + * just write the raw content of the SkData object to the stream. + */ + bool writeData(const SkData*); +}; + +//////////////////////////////////////////////////////////////////////////////////////// + +#include "SkString.h" + +struct SkFILE; + +/** A stream that wraps a C FILE* file stream. */ +class SK_API SkFILEStream : public SkStreamAsset { +public: + SK_DECLARE_INST_COUNT(SkFILEStream) + + /** Initialize the stream by calling sk_fopen on the specified path. + * This internal stream will be closed in the destructor. + */ + explicit SkFILEStream(const char path[] = NULL); + + enum Ownership { + kCallerPasses_Ownership, + kCallerRetains_Ownership + }; + /** Initialize the stream with an existing C file stream. + * While this stream exists, it assumes exclusive access to the C file stream. + * The C file stream will be closed in the destructor unless the caller specifies + * kCallerRetains_Ownership. + */ + explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership); + + 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 size_t read(void* buffer, size_t size) SK_OVERRIDE; + virtual bool isAtEnd() const SK_OVERRIDE; + + virtual bool rewind() SK_OVERRIDE; + virtual SkStreamAsset* duplicate() const SK_OVERRIDE; + + virtual size_t getPosition() const SK_OVERRIDE; + virtual bool seek(size_t position) SK_OVERRIDE; + virtual bool move(long offset) SK_OVERRIDE; + virtual SkStreamAsset* fork() const SK_OVERRIDE; + + virtual size_t getLength() const SK_OVERRIDE; + + virtual const void* getMemoryBase() SK_OVERRIDE; + +private: + SkFILE* fFILE; + SkString fName; + Ownership fOwnership; + // fData is lazilly initialized when needed. + mutable SkAutoTUnref<SkData> fData; + + typedef SkStreamAsset INHERITED; +}; + +class SK_API SkMemoryStream : public SkStreamMemory { +public: + SK_DECLARE_INST_COUNT(SkMemoryStream) + + 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); + + /** Use the specified data as the memory for this stream. + * The stream will call ref() on the data (assuming it is not NULL). + */ + SkMemoryStream(SkData*); + + 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); + /** Replace any memory buffer with the specified buffer. The caller + must have allocated data with sk_malloc or sk_realloc, since it + will be freed with sk_free. + */ + void setMemoryOwned(const void* data, size_t length); + + /** Return the stream's data in a SkData. + * The caller must call unref() when it is finished using the data. + */ + SkData* copyToData() const; + + /** + * Use the specified data as the memory for this stream. + * The stream will call ref() on the data (assuming it is not NULL). + * The function returns the data parameter as a convenience. + */ + SkData* setData(SkData*); + + void skipToAlign4(); + const void* getAtPos(); + size_t peek() const { return fOffset; } + + virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; + virtual bool isAtEnd() const SK_OVERRIDE; + + virtual bool rewind() SK_OVERRIDE; + virtual SkMemoryStream* duplicate() const SK_OVERRIDE; + + virtual size_t getPosition() const SK_OVERRIDE; + virtual bool seek(size_t position) SK_OVERRIDE; + virtual bool move(long offset) SK_OVERRIDE; + virtual SkMemoryStream* fork() const SK_OVERRIDE; + + virtual size_t getLength() const SK_OVERRIDE; + + virtual const void* getMemoryBase() SK_OVERRIDE; + +private: + SkData* fData; + size_t fOffset; + + typedef SkStreamMemory INHERITED; +}; + +///////////////////////////////////////////////////////////////////////////////////////////// + +class SK_API SkFILEWStream : public SkWStream { +public: + SK_DECLARE_INST_COUNT(SkFILEWStream) + + 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) SK_OVERRIDE; + virtual void flush() SK_OVERRIDE; + +private: + SkFILE* fFILE; + + typedef SkWStream INHERITED; +}; + +class SkMemoryWStream : public SkWStream { +public: + SK_DECLARE_INST_COUNT(SkMemoryWStream) + + SkMemoryWStream(void* buffer, size_t size); + virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; + size_t bytesWritten() const { return fBytesWritten; } + +private: + char* fBuffer; + size_t fMaxLength; + size_t fBytesWritten; + + typedef SkWStream INHERITED; +}; + +class SK_API SkDynamicMemoryWStream : public SkWStream { +public: + SK_DECLARE_INST_COUNT(SkDynamicMemoryWStream) + + SkDynamicMemoryWStream(); + virtual ~SkDynamicMemoryWStream(); + + virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; + // 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() const { return fBytesWritten; } + size_t bytesWritten() const { return fBytesWritten; } + + // copy what has been written to the stream into dst + void copyTo(void* dst) const; + + /** + * Return a copy of the data written so far. This call is responsible for + * calling unref() when they are finished with the data. + */ + SkData* copyToData() const; + + /** Reset, returning a reader stream with the current content. */ + SkStreamAsset* detachAsStream(); + + /** Reset the stream to its original, empty, state. */ + void reset(); + void padToAlign4(); +private: + struct Block; + Block* fHead; + Block* fTail; + size_t fBytesWritten; + mutable SkData* fCopy; // is invalidated if we write after it is created + + void invalidateCopy(); + + // For access to the Block type. + friend class SkBlockMemoryStream; + friend class SkBlockMemoryRefCnt; + + typedef SkWStream INHERITED; +}; + + +class SK_API SkDebugWStream : public SkWStream { +public: + SK_DECLARE_INST_COUNT(SkDebugWStream) + + // overrides + virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; + virtual void newline() SK_OVERRIDE; + +private: + typedef SkWStream INHERITED; +}; + +// for now +typedef SkFILEStream SkURLStream; + +#endif diff --git a/core/SkString.h b/core/SkString.h new file mode 100644 index 0000000..5d97533 --- /dev/null +++ b/core/SkString.h @@ -0,0 +1,265 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkString_DEFINED +#define SkString_DEFINED + +#include "SkScalar.h" + +#include <stdarg.h> + +/* Some helper functions for C strings +*/ + +static bool SkStrStartsWith(const char string[], const char prefixStr[]) { + SkASSERT(string); + SkASSERT(prefixStr); + return !strncmp(string, prefixStr, strlen(prefixStr)); +} +static bool SkStrStartsWith(const char string[], const char prefixChar) { + SkASSERT(string); + return (prefixChar == *string); +} + +bool SkStrEndsWith(const char string[], const char suffixStr[]); +bool SkStrEndsWith(const char string[], const char suffixChar); + +int SkStrStartsWithOneOf(const char string[], const char prefixes[]); + +static int SkStrFind(const char string[], const char substring[]) { + const char *first = strstr(string, substring); + if (NULL == first) return -1; + return SkToS32(first - &string[0]); +} + +static bool SkStrContains(const char string[], const char substring[]) { + SkASSERT(string); + SkASSERT(substring); + return (-1 != SkStrFind(string, substring)); +} +static bool SkStrContains(const char string[], const char subchar) { + SkASSERT(string); + char tmp[2]; + tmp[0] = subchar; + tmp[1] = '\0'; + return (-1 != SkStrFind(string, tmp)); +} + +static inline char *SkStrDup(const char string[]) { + char *ret = (char *) sk_malloc_throw(strlen(string)+1); + memcpy(ret,string,strlen(string)+1); + return ret; +} + + + +#define SkStrAppendU32_MaxSize 10 +char* SkStrAppendU32(char buffer[], uint32_t); +#define SkStrAppendU64_MaxSize 20 +char* SkStrAppendU64(char buffer[], uint64_t, int minDigits); + +#define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1) +char* SkStrAppendS32(char buffer[], int32_t); +#define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1) +char* SkStrAppendS64(char buffer[], int64_t, int minDigits); + +/** + * Floats have at most 8 significant digits, so we limit our %g to that. + * However, the total string could be 15 characters: -1.2345678e-005 + * + * In theory we should only expect up to 2 digits for the exponent, but on + * some platforms we have seen 3 (as in the example above). + */ +#define SkStrAppendScalar_MaxSize 15 + +/** + * Write the scaler in decimal format into buffer, and return a pointer to + * the next char after the last one written. Note: a terminating 0 is not + * written into buffer, which must be at least SkStrAppendScalar_MaxSize. + * Thus if the caller wants to add a 0 at the end, buffer must be at least + * SkStrAppendScalar_MaxSize + 1 bytes large. + */ +#ifdef SK_SCALAR_IS_FLOAT + #define SkStrAppendScalar SkStrAppendFloat +#else + #define SkStrAppendScalar SkStrAppendFixed +#endif + +char* SkStrAppendFloat(char buffer[], float); +char* SkStrAppendFixed(char buffer[], SkFixed); + +/** \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 SK_API SkString { +public: + SkString(); + explicit SkString(size_t len); + explicit SkString(const char text[]); + SkString(const char text[], size_t len); + SkString(const SkString&); + ~SkString(); + + bool isEmpty() const { return 0 == fRec->fLength; } + size_t size() const { return (size_t) fRec->fLength; } + const char* c_str() const { return fRec->data(); } + char operator[](size_t n) const { return this->c_str()[n]; } + + bool equals(const SkString&) const; + bool equals(const char text[]) const; + bool equals(const char text[], size_t len) const; + + bool startsWith(const char prefixStr[]) const { + return SkStrStartsWith(fRec->data(), prefixStr); + } + bool startsWith(const char prefixChar) const { + return SkStrStartsWith(fRec->data(), prefixChar); + } + bool endsWith(const char suffixStr[]) const { + return SkStrEndsWith(fRec->data(), suffixStr); + } + bool endsWith(const char suffixChar) const { + return SkStrEndsWith(fRec->data(), suffixChar); + } + bool contains(const char substring[]) const { + return SkStrContains(fRec->data(), substring); + } + bool contains(const char subchar) const { + return SkStrContains(fRec->data(), subchar); + } + int find(const char substring[]) const { + return SkStrFind(fRec->data(), substring); + } + + friend bool operator==(const SkString& a, const SkString& b) { + return a.equals(b); + } + friend bool operator!=(const SkString& a, const SkString& b) { + return !a.equals(b); + } + + // these methods edit the string + + SkString& operator=(const SkString&); + SkString& operator=(const char text[]); + + char* writable_str(); + char& operator[](size_t n) { return this->writable_str()[n]; } + + 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 insertS64(size_t offset, int64_t value, int minDigits = 0); + void insertU32(size_t offset, uint32_t value); + void insertU64(size_t offset, uint64_t value, int minDigits = 0); + 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 appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); } + void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); } + void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); } + 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 prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); } + 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[], ...) SK_PRINTF_LIKE(2, 3); + void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void appendf(const char format[], va_list); + void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + + void remove(size_t offset, size_t length); + + SkString& operator+=(const SkString& s) { this->append(s); return *this; } + SkString& operator+=(const char text[]) { this->append(text); return *this; } + SkString& operator+=(const char c) { this->append(&c, 1); return *this; } + + /** + * Swap contents between this and other. This function is guaranteed + * to never fail or throw. + */ + void swap(SkString& other); + +private: + struct Rec { + public: + uint32_t fLength; // logically size_t, but we want it to stay 32bits + int32_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[], size_t 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; +}; + +/// Creates a new string and writes into it using a printf()-style format. +SkString SkStringPrintf(const char* format, ...); + +// Specialized to take advantage of SkString's fast swap path. The unspecialized function is +// declared in SkTypes.h and called by SkTSort. +template <> inline void SkTSwap(SkString& a, SkString& b) { + a.swap(b); +} + +#endif diff --git a/core/SkStringUtils.h b/core/SkStringUtils.h new file mode 100644 index 0000000..aa5c809 --- /dev/null +++ b/core/SkStringUtils.h @@ -0,0 +1,23 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStringUtils_DEFINED +#define SkStringUtils_DEFINED + +class SkString; + +/** + * Add 'flagStr' to 'string' and set 'needSeparator' to true only if 'flag' is + * true. If 'needSeparator' is true append a '|' before 'flagStr'. This method + * is used to streamline the creation of ASCII flag strings within the toString + * methods. + */ +void SkAddFlagToString(SkString* string, bool flag, + const char* flagStr, bool* needSeparator); + + +#endif diff --git a/core/SkStrokeRec.h b/core/SkStrokeRec.h new file mode 100644 index 0000000..c5b47c2 --- /dev/null +++ b/core/SkStrokeRec.h @@ -0,0 +1,92 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStrokeRec_DEFINED +#define SkStrokeRec_DEFINED + +#include "SkPaint.h" + +class SkPath; + +class SkStrokeRec { +public: + enum InitStyle { + kHairline_InitStyle, + kFill_InitStyle + }; + SkStrokeRec(InitStyle style); + + SkStrokeRec(const SkStrokeRec&); + explicit SkStrokeRec(const SkPaint&); + + enum Style { + kHairline_Style, + kFill_Style, + kStroke_Style, + kStrokeAndFill_Style + }; + + Style getStyle() const; + SkScalar getWidth() const { return fWidth; } + SkScalar getMiter() const { return fMiterLimit; } + SkPaint::Cap getCap() const { return fCap; } + SkPaint::Join getJoin() const { return fJoin; } + + bool isHairlineStyle() const { + return kHairline_Style == this->getStyle(); + } + + bool isFillStyle() const { + return kFill_Style == this->getStyle(); + } + + void setFillStyle(); + void setHairlineStyle(); + /** + * Specify the strokewidth, and optionally if you want stroke + fill. + * Note, if width==0, then this request is taken to mean: + * strokeAndFill==true -> new style will be Fill + * strokeAndFill==false -> new style will be Hairline + */ + void setStrokeStyle(SkScalar width, bool strokeAndFill = false); + + void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) { + fCap = cap; + fJoin = join; + fMiterLimit = miterLimit; + } + + /** + * Returns true if this specifes any thick stroking, i.e. applyToPath() + * will return true. + */ + bool needToApply() const { + Style style = this->getStyle(); + return (kStroke_Style == style) || (kStrokeAndFill_Style == style); + } + + /** + * Apply these stroke parameters to the src path, returning the result + * in dst. + * + * If there was no change (i.e. style == hairline or fill) this returns + * false and dst is unchanged. Otherwise returns true and the result is + * stored in dst. + * + * src and dst may be the same path. + */ + bool applyToPath(SkPath* dst, const SkPath& src) const; + +private: + SkScalar fWidth; + SkScalar fMiterLimit; + SkPaint::Cap fCap; + SkPaint::Join fJoin; + bool fStrokeAndFill; +}; + +#endif diff --git a/core/SkSurface.h b/core/SkSurface.h new file mode 100644 index 0000000..a713277 --- /dev/null +++ b/core/SkSurface.h @@ -0,0 +1,158 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSurface_DEFINED +#define SkSurface_DEFINED + +#include "SkRefCnt.h" +#include "SkImage.h" + +class SkCanvas; +class SkPaint; +class GrContext; +class GrRenderTarget; + +/** + * SkSurface represents the backend/results of drawing to a canvas. For raster + * drawing, the surface will be pixels, but (for example) when drawing into + * a PDF or Picture canvas, the surface stores the recorded commands. + * + * To draw into a canvas, first create the appropriate type of Surface, and + * then request the canvas from the surface. + */ +class SK_API SkSurface : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkSurface) + + /** + * Create a new surface, using the specified pixels/rowbytes as its + * backend. + * + * If the requested surface cannot be created, or the request is not a + * supported configuration, NULL will be returned. + */ + static SkSurface* NewRasterDirect(const SkImage::Info&, void* pixels, size_t rowBytes); + + /** + * Return a new surface, with the memory for the pixels automatically + * allocated. + * + * If the requested surface cannot be created, or the request is not a + * supported configuration, NULL will be returned. + */ + static SkSurface* NewRaster(const SkImage::Info&); + + /** + * Return a new surface whose contents will be recorded into a picture. + * When this surface is drawn into another canvas, its contents will be + * "replayed" into that canvas. + */ + static SkSurface* NewPicture(int width, int height); + + /** + * Return a new surface using the specified render target. + */ + static SkSurface* NewRenderTargetDirect(GrContext*, GrRenderTarget*); + + /** + * Return a new surface whose contents will be drawn to an offscreen + * render target, allocated by the surface. + */ + static SkSurface* NewRenderTarget(GrContext*, const SkImage::Info&, int sampleCount = 0); + + int width() const { return fWidth; } + int height() const { return fHeight; } + + /** + * Returns a unique non-zero, unique value identifying the content of this + * surface. Each time the content is changed changed, either by drawing + * into this surface, or explicitly calling notifyContentChanged()) this + * method will return a new value. + * + * If this surface is empty (i.e. has a zero-dimention), this will return + * 0. + */ + uint32_t generationID(); + + /** + * Modes that can be passed to notifyContentWillChange + */ + enum ContentChangeMode { + /** + * Use this mode if it is known that the upcoming content changes will + * clear or overwrite prior contents, thus making them discardable. + */ + kDiscard_ContentChangeMode, + /** + * Use this mode if prior surface contents need to be preserved or + * if in doubt. + */ + kRetain_ContentChangeMode, + }; + + /** + * Call this if the contents are about to change. This will (lazily) force a new + * value to be returned from generationID() when it is called next. + */ + void notifyContentWillChange(ContentChangeMode mode); + + /** + * Return a canvas that will draw into this surface. This will always + * return the same canvas for a given surface, and is manged/owned by the + * surface. It should not be used when its parent surface has gone out of + * scope. + */ + SkCanvas* getCanvas(); + + /** + * Return a new surface that is "compatible" with this one, in that it will + * efficiently be able to be drawn into this surface. Typical calling + * pattern: + * + * SkSurface* A = SkSurface::New...(); + * SkCanvas* canvasA = surfaceA->newCanvas(); + * ... + * SkSurface* surfaceB = surfaceA->newSurface(...); + * SkCanvas* canvasB = surfaceB->newCanvas(); + * ... // draw using canvasB + * canvasA->drawSurface(surfaceB); // <--- this will always be optimal! + */ + SkSurface* newSurface(const SkImage::Info&); + + /** + * Returns an image of the current state of the surface pixels up to this + * point. Subsequent changes to the surface (by drawing into its canvas) + * will not be reflected in this image. + */ + SkImage* newImageSnapshot(); + + /** + * Thought the caller could get a snapshot image explicitly, and draw that, + * it seems that directly drawing a surface into another canvas might be + * a common pattern, and that we could possibly be more efficient, since + * we'd know that the "snapshot" need only live until we've handed it off + * to the canvas. + */ + void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); + +protected: + SkSurface(int width, int height); + + // called by subclass if their contents have changed + void dirtyGenerationID() { + fGenerationID = 0; + } + +private: + const int fWidth; + const int fHeight; + uint32_t fGenerationID; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkTArray.h b/core/SkTArray.h new file mode 100644 index 0000000..b5ecdc9 --- /dev/null +++ b/core/SkTArray.h @@ -0,0 +1,506 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTArray_DEFINED +#define SkTArray_DEFINED + +#include <new> +#include "SkTypes.h" +#include "SkTemplates.h" + +template <typename T, bool MEM_COPY = false> class SkTArray; + +namespace SkTArrayExt { + +template<typename T> +inline void copy(SkTArray<T, true>* self, const T* array) { + memcpy(self->fMemArray, array, self->fCount * sizeof(T)); +} +template<typename T> +inline void copyAndDelete(SkTArray<T, true>* self, char* newMemArray) { + memcpy(newMemArray, self->fMemArray, self->fCount * sizeof(T)); +} + +template<typename T> +inline void copy(SkTArray<T, false>* self, const T* array) { + for (int i = 0; i < self->fCount; ++i) { + SkNEW_PLACEMENT_ARGS(self->fItemArray + i, T, (array[i])); + } +} +template<typename T> +inline void copyAndDelete(SkTArray<T, false>* self, char* newMemArray) { + for (int i = 0; i < self->fCount; ++i) { + SkNEW_PLACEMENT_ARGS(newMemArray + sizeof(T) * i, T, (self->fItemArray[i])); + self->fItemArray[i].~T(); + } +} + +} + +template <typename T, bool MEM_COPY> void* operator new(size_t, SkTArray<T, MEM_COPY>*, int); + +/** When MEM_COPY is true T will be bit copied when moved. + When MEM_COPY is false, T will be copy constructed / destructed. + In all cases T's constructor will be called on allocation, + and its destructor will be called from this object's destructor. +*/ +template <typename T, bool MEM_COPY> class SkTArray { +public: + /** + * Creates an empty array with no initial storage + */ + SkTArray() { + fCount = 0; + fReserveCount = gMIN_ALLOC_COUNT; + fAllocCount = 0; + fMemArray = NULL; + fPreAllocMemArray = NULL; + } + + /** + * Creates an empty array that will preallocate space for reserveCount + * elements. + */ + explicit SkTArray(int reserveCount) { + this->init(NULL, 0, NULL, reserveCount); + } + + /** + * Copies one array to another. The new array will be heap allocated. + */ + explicit SkTArray(const SkTArray& array) { + this->init(array.fItemArray, array.fCount, NULL, 0); + } + + /** + * Creates a SkTArray by copying contents of a standard C array. The new + * array will be heap allocated. Be careful not to use this constructor + * when you really want the (void*, int) version. + */ + SkTArray(const T* array, int count) { + this->init(array, count, NULL, 0); + } + + /** + * assign copy of array to this + */ + SkTArray& operator =(const SkTArray& array) { + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + fCount = 0; + this->checkRealloc((int)array.count()); + fCount = array.count(); + SkTArrayExt::copy(this, static_cast<const T*>(array.fMemArray)); + return *this; + } + + virtual ~SkTArray() { + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + if (fMemArray != fPreAllocMemArray) { + sk_free(fMemArray); + } + } + + /** + * Resets to count() == 0 + */ + void reset() { this->pop_back_n(fCount); } + + /** + * Resets to count() = n newly constructed T objects. + */ + void reset(int n) { + SkASSERT(n >= 0); + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + // set fCount to 0 before calling checkRealloc so that no copy cons. are called. + fCount = 0; + this->checkRealloc(n); + fCount = n; + for (int i = 0; i < fCount; ++i) { + SkNEW_PLACEMENT(fItemArray + i, T); + } + } + + /** + * Resets to a copy of a C array. + */ + void reset(const T* array, int count) { + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + int delta = count - fCount; + this->checkRealloc(delta); + fCount = count; + for (int i = 0; i < count; ++i) { + SkTArrayExt::copy(this, array); + } + } + + /** + * Number of elements in the array. + */ + int count() const { return fCount; } + + /** + * Is the array empty. + */ + bool empty() const { return !fCount; } + + /** + * Adds 1 new default-constructed T value and returns in by reference. Note + * the reference only remains valid until the next call that adds or removes + * elements. + */ + T& push_back() { + T* newT = reinterpret_cast<T*>(this->push_back_raw(1)); + SkNEW_PLACEMENT(newT, T); + return *newT; + } + + /** + * Version of above that uses a copy constructor to initialize the new item + */ + T& push_back(const T& t) { + T* newT = reinterpret_cast<T*>(this->push_back_raw(1)); + SkNEW_PLACEMENT_ARGS(newT, T, (t)); + return *newT; + } + + /** + * Allocates n more default T values, and returns the address of the start + * of that new range. Note: this address is only valid until the next API + * call made on the array that might add or remove elements. + */ + T* push_back_n(int n) { + SkASSERT(n >= 0); + T* newTs = reinterpret_cast<T*>(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + SkNEW_PLACEMENT(newTs + i, T); + } + return newTs; + } + + /** + * Version of above that uses a copy constructor to initialize all n items + * to the same T. + */ + T* push_back_n(int n, const T& t) { + SkASSERT(n >= 0); + T* newTs = reinterpret_cast<T*>(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + SkNEW_PLACEMENT_ARGS(newTs[i], T, (t)); + } + return newTs; + } + + /** + * Version of above that uses a copy constructor to initialize the n items + * to separate T values. + */ + T* push_back_n(int n, const T t[]) { + SkASSERT(n >= 0); + this->checkRealloc(n); + for (int i = 0; i < n; ++i) { + SkNEW_PLACEMENT_ARGS(fItemArray + fCount + i, T, (t[i])); + } + fCount += n; + return fItemArray + fCount - n; + } + + /** + * Removes the last element. Not safe to call when count() == 0. + */ + void pop_back() { + SkASSERT(fCount > 0); + --fCount; + fItemArray[fCount].~T(); + this->checkRealloc(0); + } + + /** + * Removes the last n elements. Not safe to call when count() < n. + */ + void pop_back_n(int n) { + SkASSERT(n >= 0); + SkASSERT(fCount >= n); + fCount -= n; + for (int i = 0; i < n; ++i) { + fItemArray[fCount + i].~T(); + } + this->checkRealloc(0); + } + + /** + * Pushes or pops from the back to resize. Pushes will be default + * initialized. + */ + void resize_back(int newCount) { + SkASSERT(newCount >= 0); + + if (newCount > fCount) { + this->push_back_n(newCount - fCount); + } else if (newCount < fCount) { + this->pop_back_n(fCount - newCount); + } + } + + T* begin() { + return fItemArray; + } + const T* begin() const { + return fItemArray; + } + T* end() { + return fItemArray ? fItemArray + fCount : NULL; + } + const T* end() const { + return fItemArray ? fItemArray + fCount : NULL;; + } + + /** + * Get the i^th element. + */ + T& operator[] (int i) { + SkASSERT(i < fCount); + SkASSERT(i >= 0); + return fItemArray[i]; + } + + const T& operator[] (int i) const { + SkASSERT(i < fCount); + SkASSERT(i >= 0); + return fItemArray[i]; + } + + /** + * equivalent to operator[](0) + */ + T& front() { SkASSERT(fCount > 0); return fItemArray[0];} + + const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];} + + /** + * equivalent to operator[](count() - 1) + */ + T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];} + + const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1];} + + /** + * equivalent to operator[](count()-1-i) + */ + T& fromBack(int i) { + SkASSERT(i >= 0); + SkASSERT(i < fCount); + return fItemArray[fCount - i - 1]; + } + + const T& fromBack(int i) const { + SkASSERT(i >= 0); + SkASSERT(i < fCount); + return fItemArray[fCount - i - 1]; + } + + bool operator==(const SkTArray<T, MEM_COPY>& right) const { + int leftCount = this->count(); + if (leftCount != right.count()) { + return false; + } + for (int index = 0; index < leftCount; ++index) { + if (fItemArray[index] != right.fItemArray[index]) { + return false; + } + } + return true; + } + + bool operator!=(const SkTArray<T, MEM_COPY>& right) const { + return !(*this == right); + } + +protected: + /** + * Creates an empty array that will use the passed storage block until it + * is insufficiently large to hold the entire array. + */ + template <int N> + SkTArray(SkAlignedSTStorage<N,T>* storage) { + this->init(NULL, 0, storage->get(), N); + } + + /** + * Copy another array, using preallocated storage if preAllocCount >= + * array.count(). Otherwise storage will only be used when array shrinks + * to fit. + */ + template <int N> + SkTArray(const SkTArray& array, SkAlignedSTStorage<N,T>* storage) { + this->init(array.fItemArray, array.fCount, storage->get(), N); + } + + /** + * Copy a C array, using preallocated storage if preAllocCount >= + * count. Otherwise storage will only be used when array shrinks + * to fit. + */ + template <int N> + SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) { + this->init(array, count, storage->get(), N); + } + + void init(const T* array, int count, + void* preAllocStorage, int preAllocOrReserveCount) { + SkASSERT(count >= 0); + SkASSERT(preAllocOrReserveCount >= 0); + fCount = count; + fReserveCount = (preAllocOrReserveCount > 0) ? + preAllocOrReserveCount : + gMIN_ALLOC_COUNT; + fPreAllocMemArray = preAllocStorage; + if (fReserveCount >= fCount && + NULL != preAllocStorage) { + fAllocCount = fReserveCount; + fMemArray = preAllocStorage; + } else { + fAllocCount = SkMax32(fCount, fReserveCount); + fMemArray = sk_malloc_throw(fAllocCount * sizeof(T)); + } + + SkTArrayExt::copy(this, array); + } + +private: + + static const int gMIN_ALLOC_COUNT = 8; + + // Helper function that makes space for n objects, adjusts the count, but does not initialize + // the new objects. + void* push_back_raw(int n) { + this->checkRealloc(n); + void* ptr = fItemArray + fCount; + fCount += n; + return ptr; + } + + inline void checkRealloc(int delta) { + SkASSERT(fCount >= 0); + SkASSERT(fAllocCount >= 0); + + SkASSERT(-delta <= fCount); + + int newCount = fCount + delta; + int newAllocCount = fAllocCount; + + if (newCount > fAllocCount || newCount < (fAllocCount / 3)) { + // whether we're growing or shrinking, we leave at least 50% extra space for future + // growth (clamped to the reserve count). + newAllocCount = SkMax32(newCount + ((newCount + 1) >> 1), fReserveCount); + } + if (newAllocCount != fAllocCount) { + + fAllocCount = newAllocCount; + char* newMemArray; + + if (fAllocCount == fReserveCount && NULL != fPreAllocMemArray) { + newMemArray = (char*) fPreAllocMemArray; + } else { + newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T)); + } + + SkTArrayExt::copyAndDelete<T>(this, newMemArray); + + if (fMemArray != fPreAllocMemArray) { + sk_free(fMemArray); + } + fMemArray = newMemArray; + } + } + + friend void* operator new<T>(size_t, SkTArray*, int); + + template<typename X> friend void SkTArrayExt::copy(SkTArray<X, true>* that, const X*); + template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, true>* that, char*); + + template<typename X> friend void SkTArrayExt::copy(SkTArray<X, false>* that, const X*); + template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, false>* that, char*); + + int fReserveCount; + int fCount; + int fAllocCount; + void* fPreAllocMemArray; + union { + T* fItemArray; + void* fMemArray; + }; +}; + +// Use the below macro (SkNEW_APPEND_TO_TARRAY) rather than calling this directly +template <typename T, bool MEM_COPY> +void* operator new(size_t, SkTArray<T, MEM_COPY>* array, int atIndex) { + // Currently, we only support adding to the end of the array. When the array class itself + // supports random insertion then this should be updated. + // SkASSERT(atIndex >= 0 && atIndex <= array->count()); + SkASSERT(atIndex == array->count()); + return array->push_back_raw(1); +} + +// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete +// to match the op new silences warnings about missing op delete when a constructor throws an +// exception. +template <typename T, bool MEM_COPY> +void operator delete(void*, SkTArray<T, MEM_COPY>* array, int atIndex) { + SK_CRASH(); +} + +// Constructs a new object as the last element of an SkTArray. +#define SkNEW_APPEND_TO_TARRAY(array_ptr, type_name, args) \ + (new ((array_ptr), (array_ptr)->count()) type_name args) + + +/** + * Subclass of SkTArray that contains a preallocated memory block for the array. + */ +template <int N, typename T, bool MEM_COPY = false> +class SkSTArray : public SkTArray<T, MEM_COPY> { +private: + typedef SkTArray<T, MEM_COPY> INHERITED; + +public: + SkSTArray() : INHERITED(&fStorage) { + } + + SkSTArray(const SkSTArray& array) + : INHERITED(array, &fStorage) { + } + + explicit SkSTArray(const INHERITED& array) + : INHERITED(array, &fStorage) { + } + + SkSTArray(const T* array, int count) + : INHERITED(array, count, &fStorage) { + } + + SkSTArray& operator= (const SkSTArray& array) { + return *this = *(const INHERITED*)&array; + } + + SkSTArray& operator= (const INHERITED& array) { + INHERITED::operator=(array); + return *this; + } + +private: + SkAlignedSTStorage<N,T> fStorage; +}; + +#endif diff --git a/core/SkTDArray.h b/core/SkTDArray.h new file mode 100644 index 0000000..8b8bb01 --- /dev/null +++ b/core/SkTDArray.h @@ -0,0 +1,368 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTDArray_DEFINED +#define SkTDArray_DEFINED + +#include "SkTypes.h" + +template <typename T> class SK_API 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 bool 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))); + } + friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) { + return !(a == b); + } + + 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); + } + + /** Return a ptr to the array of data, to be freed with sk_free. This also + resets the SkTDArray to be empty. + */ + T* detach() { + T* array = fArray; + fArray = NULL; + fReserve = fCount = 0; + SkDEBUGCODE(fData = NULL;) + return array; + } + + bool isEmpty() const { return fCount == 0; } + + /** + * Return the number of elements in the array + */ + int count() const { return (int)fCount; } + + /** + * return the number of bytes in the array: count * sizeof(T) + */ + size_t bytes() const { return fCount * sizeof(T); } + + T* begin() { return fArray; } + const T* begin() const { return fArray; } + T* end() { return fArray ? fArray + fCount : NULL; } + const T* end() const { return fArray ? fArray + fCount : NULL; } + + T& operator[](int index) { + SkASSERT((unsigned)index < fCount); + return fArray[index]; + } + const T& operator[](int index) const { + SkASSERT((unsigned)index < fCount); + return fArray[index]; + } + + T& getAt(int index) { + return (*this)[index]; + } + const T& getAt(int index) const { + return (*this)[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) { + size_t 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); + size_t 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); + size_t 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; + } + + /** + * Returns true iff the array contains this element. + */ + bool contains(const T& elem) const { + return (this->find(elem) >= 0); + } + + /** + * Copies up to max elements into dst. The number of items copied is + * capped by count - index. The actual number copied is returned. + */ + int copyRange(T* dst, size_t index, int max) const { + SkASSERT(max >= 0); + SkASSERT(!max || dst); + if (index >= fCount) { + return 0; + } + int count = SkMin32(max, fCount - index); + memcpy(dst, fArray + index, sizeof(T) * count); + return count; + } + + void copy(T* dst) const { + this->copyRange(dst, 0, fCount); + } + + // 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) { + SkDELETE (*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(); + } + + void safeUnrefAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + SkSafeUnref(*iter); + iter += 1; + } + this->reset(); + } + + void visitAll(void visitor(T&)) { + T* stop = this->end(); + for (T* curr = this->begin(); curr < stop; curr++) { + if (*curr) { + visitor(*curr); + } + } + } + +#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/core/SkTDStack.h b/core/SkTDStack.h new file mode 100644 index 0000000..e286e4a --- /dev/null +++ b/core/SkTDStack.h @@ -0,0 +1,110 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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; } + int depth() const { return fTotalCount; } + bool empty() const { return fTotalCount == 0; } + + 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/core/SkTDict.h b/core/SkTDict.h new file mode 100644 index 0000000..49d07d4 --- /dev/null +++ b/core/SkTDict.h @@ -0,0 +1,161 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 + { + const Pair* end = fArray.end(); + for (const 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: + const Pair* fIter; + const 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/core/SkTInternalLList.h b/core/SkTInternalLList.h new file mode 100644 index 0000000..a6b6f15 --- /dev/null +++ b/core/SkTInternalLList.h @@ -0,0 +1,272 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTInternalLList_DEFINED +#define SkTInternalLList_DEFINED + +#include "SkTypes.h" + +/** + * Helper class to automatically initialize the doubly linked list created pointers. + */ +template <typename T> class SkPtrWrapper { + public: + SkPtrWrapper() : fPtr(NULL) {} + SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; } + operator T*() const { return fPtr; } + T* operator->() { return fPtr; } + private: + T* fPtr; +}; + + +/** + * This macro creates the member variables required by the SkTInternalLList class. It should be + * placed in the private section of any class that will be stored in a double linked list. + */ +#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ + friend class SkTInternalLList<ClassName>; \ + /* back pointer to the owning list - for debugging */ \ + SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \ + SkPtrWrapper<ClassName> fPrev; \ + SkPtrWrapper<ClassName> fNext + +/** + * This class implements a templated internal doubly linked list data structure. + */ +template <class T> class SkTInternalLList : public SkNoncopyable { +public: + SkTInternalLList() + : fHead(NULL) + , fTail(NULL) { + } + + void remove(T* entry) { + SkASSERT(NULL != fHead && NULL != fTail); + SkASSERT(this->isInList(entry)); + + T* prev = entry->fPrev; + T* next = entry->fNext; + + if (NULL != prev) { + prev->fNext = next; + } else { + fHead = next; + } + if (NULL != next) { + next->fPrev = prev; + } else { + fTail = prev; + } + + entry->fPrev = NULL; + entry->fNext = NULL; + +#ifdef SK_DEBUG + entry->fList = NULL; +#endif + } + + void addToHead(T* entry) { + SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); + SkASSERT(NULL == entry->fList); + + entry->fPrev = NULL; + entry->fNext = fHead; + if (NULL != fHead) { + fHead->fPrev = entry; + } + fHead = entry; + if (NULL == fTail) { + fTail = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + void addToTail(T* entry) { + SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); + SkASSERT(NULL == entry->fList); + + entry->fPrev = fTail; + entry->fNext = NULL; + if (NULL != fTail) { + fTail->fNext = entry; + } + fTail = entry; + if (NULL == fHead) { + fHead = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + /** + * Inserts a new list entry before an existing list entry. The new entry must not already be + * a member of this or any other list. If existingEntry is NULL then the new entry is added + * at the tail. + */ + void addBefore(T* newEntry, T* existingEntry) { + SkASSERT(NULL != newEntry); + + if (NULL == existingEntry) { + this->addToTail(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fNext = existingEntry; + T* prev = existingEntry->fPrev; + existingEntry->fPrev = newEntry; + newEntry->fPrev = prev; + if (NULL == prev) { + SkASSERT(fHead == existingEntry); + fHead = newEntry; + } else { + prev->fNext = newEntry; + } +#ifdef SK_DEBUG + newEntry->fList = this; +#endif + } + + /** + * Inserts a new list entry after an existing list entry. The new entry must not already be + * a member of this or any other list. If existingEntry is NULL then the new entry is added + * at the head. + */ + void addAfter(T* newEntry, T* existingEntry) { + SkASSERT(NULL != newEntry); + + if (NULL == existingEntry) { + this->addToHead(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fPrev = existingEntry; + T* next = existingEntry->fNext; + existingEntry->fNext = newEntry; + newEntry->fNext = next; + if (NULL == next) { + SkASSERT(fTail == existingEntry); + fTail = newEntry; + } else { + next->fPrev = newEntry; + } +#ifdef SK_DEBUG + newEntry->fList = this; +#endif + } + + bool isEmpty() const { + return NULL == fHead && NULL == fTail; + } + + T* head() { return fHead; } + T* tail() { return fTail; } + + class Iter { + public: + enum IterStart { + kHead_IterStart, + kTail_IterStart + }; + + Iter() : fCurr(NULL) {} + Iter(const Iter& iter) : fCurr(iter.fCurr) {} + Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } + + T* init(const SkTInternalLList& list, IterStart startLoc) { + if (kHead_IterStart == startLoc) { + fCurr = list.fHead; + } else { + SkASSERT(kTail_IterStart == startLoc); + fCurr = list.fTail; + } + + return fCurr; + } + + T* get() { return fCurr; } + + /** + * Return the next/previous element in the list or NULL if at the end. + */ + T* next() { + if (NULL == fCurr) { + return NULL; + } + + fCurr = fCurr->fNext; + return fCurr; + } + + T* prev() { + if (NULL == fCurr) { + return NULL; + } + + fCurr = fCurr->fPrev; + return fCurr; + } + + private: + T* fCurr; + }; + +#ifdef SK_DEBUG + void validate() const { + SkASSERT(!fHead == !fTail); + Iter iter; + for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != (item = iter.next()); ) { + SkASSERT(this->isInList(item)); + if (NULL == item->fPrev) { + SkASSERT(fHead == item); + } else { + SkASSERT(item->fPrev->fNext == item); + } + if (NULL == item->fNext) { + SkASSERT(fTail == item); + } else { + SkASSERT(item->fNext->fPrev == item); + } + } + } + + /** + * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' + * list. + */ + bool isInList(const T* entry) const { + return entry->fList == this; + } + + /** + * Debugging-only method that laboriously counts the list entries. + */ + int countEntries() const { + int count = 0; + for (T* entry = fHead; NULL != entry; entry = entry->fNext) { + ++count; + } + return count; + } +#endif // SK_DEBUG + +private: + T* fHead; + T* fTail; + + typedef SkNoncopyable INHERITED; +}; + +#endif diff --git a/core/SkTLazy.h b/core/SkTLazy.h new file mode 100644 index 0000000..2147b66 --- /dev/null +++ b/core/SkTLazy.h @@ -0,0 +1,182 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkTLazy_DEFINED +#define SkTLazy_DEFINED + +#include "SkTypes.h" +#include <new> + +template <typename T> class SkTLazy; +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy); + +/** + * Efficient way to defer allocating/initializing a class until it is needed + * (if ever). + */ +template <typename T> class SkTLazy { +public: + SkTLazy() : fPtr(NULL) {} + + explicit SkTLazy(const T* src) : fPtr(NULL) { + if (src) { + fPtr = new (fStorage) T(*src); + } + } + + SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) { + if (src.isValid()) { + fPtr = new (fStorage) T(*src->get()); + } else { + fPtr = NULL; + } + } + + ~SkTLazy() { + if (this->isValid()) { + fPtr->~T(); + } + } + + /** + * Return a pointer to a default-initialized instance of the class. If a + * previous instance had been initialized (either from init() or set()) it + * will first be destroyed, so that a freshly initialized instance is + * always returned. + */ + T* init() { + if (this->isValid()) { + fPtr->~T(); + } + fPtr = new (SkTCast<T*>(fStorage)) T; + return fPtr; + } + + /** + * Copy src into this, and return a pointer to a copy of it. Note this + * will always return the same pointer, so if it is called on a lazy that + * has already been initialized, then this will copy over the previous + * contents. + */ + T* set(const T& src) { + if (this->isValid()) { + *fPtr = src; + } else { + fPtr = new (SkTCast<T*>(fStorage)) T(src); + } + return fPtr; + } + + /** + * Returns true if a valid object has been initialized in the SkTLazy, + * false otherwise. + */ + bool isValid() const { return NULL != fPtr; } + + /** + * Returns the object. This version should only be called when the caller + * knows that the object has been initialized. + */ + T* get() const { SkASSERT(this->isValid()); return fPtr; } + + /** + * Like above but doesn't assert if object isn't initialized (in which case + * NULL is returned). + */ + T* getMaybeNull() const { return fPtr; } + +private: + friend void* operator new<T>(size_t, SkTLazy* lazy); + + T* fPtr; // NULL or fStorage + char fStorage[sizeof(T)]; +}; + +// Use the below macro (SkNEW_IN_TLAZY) rather than calling this directly +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy) { + SkASSERT(!lazy->isValid()); + lazy->fPtr = reinterpret_cast<T*>(lazy->fStorage); + return lazy->fPtr; +} + +// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete +// to match the op new silences warnings about missing op delete when a constructor throws an +// exception. +template <typename T> void operator delete(void*, SkTLazy<T>*) { SK_CRASH(); } + +// Use this to construct a T inside an SkTLazy using a non-default constructor. +#define SkNEW_IN_TLAZY(tlazy_ptr, type_name, args) (new (tlazy_ptr) type_name args) + +/** + * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized + * with a const pointer but provides a non-const pointer accessor. The first time the + * accessor is called (if ever) the object is cloned. + * + * In the following example at most one copy of constThing is made: + * + * SkTCopyOnFirstWrite<Thing> thing(&constThing); + * ... + * function_that_takes_a_const_thing_ptr(thing); // constThing is passed + * ... + * if (need_to_modify_thing()) { + * thing.writable()->modifyMe(); // makes a copy of constThing + * } + * ... + * x = thing->readSomething(); + * ... + * if (need_to_modify_thing_now()) { + * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe() + * } + * + * consume_a_thing(thing); // could be constThing or a modified copy. + */ +template <typename T> +class SkTCopyOnFirstWrite { +public: + SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {} + + // Constructor for delayed initialization. + SkTCopyOnFirstWrite() : fObj(NULL) {} + + // Should only be called once, and only if the default constructor was used. + void init(const T& initial) { + SkASSERT(NULL == fObj); + SkASSERT(!fLazy.isValid()); + fObj = &initial; + } + + /** + * Returns a writable T*. The first time this is called the initial object is cloned. + */ + T* writable() { + SkASSERT(NULL != fObj); + if (!fLazy.isValid()) { + fLazy.set(*fObj); + fObj = fLazy.get(); + } + return const_cast<T*>(fObj); + } + + /** + * Operators for treating this as though it were a const pointer. + */ + + const T *operator->() const { return fObj; } + + operator const T*() const { return fObj; } + + const T& operator *() const { return *fObj; } + +private: + const T* fObj; + SkTLazy<T> fLazy; +}; + +#endif diff --git a/core/SkTRegistry.h b/core/SkTRegistry.h new file mode 100644 index 0000000..34fcffd --- /dev/null +++ b/core/SkTRegistry.h @@ -0,0 +1,56 @@ + +/* + * Copyright 2009 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTRegistry_DEFINED +#define SkTRegistry_DEFINED + +#include "SkTypes.h" + +/** Template class that registers itself (in the constructor) into a linked-list + and provides a function-pointer. This can be used to auto-register a set of + services, e.g. a set of image codecs. + */ +template <typename T, typename P> class SkTRegistry : SkNoncopyable { +public: + typedef T (*Factory)(P); + + SkTRegistry(Factory fact) { +#ifdef SK_BUILD_FOR_ANDROID + // work-around for double-initialization bug + { + SkTRegistry* reg = gHead; + while (reg) { + if (reg == this) { + return; + } + reg = reg->fChain; + } + } +#endif + fFact = fact; + fChain = gHead; + gHead = this; + } + + static const SkTRegistry* Head() { return gHead; } + + const SkTRegistry* next() const { return fChain; } + Factory factory() const { return fFact; } + +private: + Factory fFact; + SkTRegistry* fChain; + + static SkTRegistry* gHead; +}; + +// The caller still needs to declare an instance of this somewhere +template <typename T, typename P> SkTRegistry<T, P>* SkTRegistry<T, P>::gHead; + +#endif diff --git a/core/SkTScopedPtr.h b/core/SkTScopedPtr.h new file mode 100644 index 0000000..580d72f --- /dev/null +++ b/core/SkTScopedPtr.h @@ -0,0 +1,76 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTScopedPtr_DEFINED +#define SkTScopedPtr_DEFINED + +#include "SkTypes.h" + +/** \class SkTScopedPtr + A SkTScopedPtr<T> is like a T*, except that the destructor of SkTScopedPtr<T> + automatically deletes the pointer it holds (if any). That is, SkTScopedPtr<T> + owns the T object that it points to. Like a T*, a SkTScopedPtr<T> may hold + either NULL or a pointer to a T object. Also like T*, SkTScopedPtr<T> is + thread-compatible, and once you dereference it, you get the threadsafety + guarantees of T. + + The size of a SkTScopedPtr is small: sizeof(SkTScopedPtr<T>) == sizeof(T*) +*/ +template <typename T> class SkTScopedPtr : SkNoncopyable { +public: + explicit SkTScopedPtr(T* o = NULL) : fObj(o) {} + ~SkTScopedPtr() { + enum { kTypeMustBeComplete = sizeof(T) }; + delete fObj; + } + + /** Delete the current object, if any. Then take ownership of the + passed object. + */ + void reset(T* o = NULL) { + if (o != fObj) { + enum { kTypeMustBeComplete = sizeof(T) }; + delete fObj; + fObj = o; + } + } + + /** Without deleting the current object, return it and forget about it. + Similar to calling get() and reset(), but the object is not deleted. + */ + T* release() { + T* retVal = fObj; + fObj = NULL; + return retVal; + } + + T& operator*() const { + SkASSERT(fObj != NULL); + return *fObj; + } + T* operator->() const { + SkASSERT(fObj != NULL); + return fObj; + } + T* get() const { return fObj; } + + bool operator==(T* o) const { return fObj == o; } + bool operator!=(T* o) const { return fObj != o; } + +private: + T* fObj; + + // Forbid comparison of SkTScopedPtr types. If T2 != T, it doesn't make + // sense, and if T2 == T, it still doesn't make sense because the same + // object can't be owned by two different scoped_ptrs. + template <class T2> bool operator==(SkTScopedPtr<T2> const& o2) const; + template <class T2> bool operator!=(SkTScopedPtr<T2> const& o2) const; +}; + +#endif diff --git a/core/SkTSearch.h b/core/SkTSearch.h new file mode 100644 index 0000000..a4e4994 --- /dev/null +++ b/core/SkTSearch.h @@ -0,0 +1,146 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTSearch_DEFINED +#define SkTSearch_DEFINED + +#include "SkTypes.h" + +/** + * All of the SkTSearch variants want to return the index (0...N-1) of the + * found element, or the bit-not of where to insert the element. + * + * At a simple level, if the return value is negative, it was not found. + * + * For clients that want to insert the new element if it was not found, use + * the following logic: + * + * int index = SkTSearch(...); + * if (index >= 0) { + * // found at index + * } else { + * index = ~index; // now we are positive + * // insert at index + * } + */ + + +// The most general form of SkTSearch takes an array of T and a key of type K. A functor, less, is +// used to perform comparisons. It has two function operators: +// bool operator() (const T& t, const K& k) +// bool operator() (const K& t, const T& k) +template <typename T, typename K, typename LESS> +int SkTSearch(const T base[], int count, const K& key, size_t elemSize, LESS& less) +{ + 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 (less(*elem, key)) + lo = mid + 1; + else + hi = mid; + } + + const T* elem = (const T*)((const char*)base + hi * elemSize); + if (less(*elem, key)) { + hi += 1; + hi = ~hi; + } else if (less(key, *elem)) { + hi = ~hi; + } + return hi; +} + +// Adapts a less-than function to a functor. +template <typename T, bool (LESS)(const T&, const T&)> struct SkTLessFunctionToFunctorAdaptor { + bool operator()(const T& a, const T& b) { return LESS(a, b); } +}; + +// Specialization for case when T==K and the caller wants to use a function rather than functor. +template <typename T, bool (LESS)(const T&, const T&)> +int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { + static SkTLessFunctionToFunctorAdaptor<T, LESS> functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +// Adapts operator < to a functor. +template <typename T> struct SkTLessFunctor { + bool operator()(const T& a, const T& b) { return a < b; } +}; + +// Specialization for T==K, compare using op <. +template <typename T> +int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { + static SkTLessFunctor<T> functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +// Similar to SkLessFunctionToFunctorAdaptor but makes the functor interface take T* rather than T. +template <typename T, bool (LESS)(const T&, const T&)> struct SkTLessFunctionToPtrFunctorAdaptor { + bool operator() (const T* t, const T* k) { return LESS(*t, *k); } +}; + +// Specialization for case where domain is an array of T* and the key value is a T*, and you want +// to compare the T objects, not the pointers. +template <typename T, bool (LESS)(const T&, const T&)> +int SkTSearch(T* base[], int count, T* target, size_t elemSize) { + static SkTLessFunctionToPtrFunctorAdaptor<T, LESS> functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +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]; +}; + +// Helper when calling qsort with a compare proc that has typed its arguments +#define SkCastForQSort(compare) reinterpret_cast<int (*)(const void*, const void*)>(compare) + +#endif diff --git a/core/SkTemplates.h b/core/SkTemplates.h new file mode 100644 index 0000000..e49cc47 --- /dev/null +++ b/core/SkTemplates.h @@ -0,0 +1,457 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTemplates_DEFINED +#define SkTemplates_DEFINED + +#include "SkTypes.h" +#include <new> + +/** \file SkTemplates.h + + This file contains light-weight template classes for type-safe and exception-safe + resource management. +*/ + +/** + * Marks a local variable as known to be unused (to avoid warnings). + * Note that this does *not* prevent the local variable from being optimized away. + */ +template<typename T> inline void sk_ignore_unused_variable(const T&) { } + +/** + * SkTIsConst<T>::value is true if the type T is const. + * The type T is constrained not to be an array or reference type. + */ +template <typename T> struct SkTIsConst { + static T* t; + static uint16_t test(const volatile void*); + static uint32_t test(volatile void *); + static const bool value = (sizeof(uint16_t) == sizeof(test(t))); +}; + +///@{ +/** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */ +template <typename T, bool CONST> struct SkTConstType { + typedef T type; +}; +template <typename T> struct SkTConstType<T, true> { + typedef const T type; +}; +///@} + +/** + * Returns a pointer to a D which comes immediately after S[count]. + */ +template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) { + return reinterpret_cast<D*>(ptr + count); +} + +/** + * Returns a pointer to a D which comes byteOffset bytes after S. + */ +template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) { + // The intermediate char* has the same const-ness as D as this produces better error messages. + // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. + return reinterpret_cast<D*>( + reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset + ); +} + +/** \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 = NULL) : fObj(obj) {} + ~SkAutoTDelete() { SkDELETE(fObj); } + + T* get() const { return fObj; } + T& operator*() const { SkASSERT(fObj); return *fObj; } + T* operator->() const { SkASSERT(fObj); return fObj; } + + void reset(T* obj) { + if (fObj != obj) { + SkDELETE(fObj); + fObj = obj; + } + } + + /** + * Delete the owned object, setting the internal pointer to NULL. + */ + void free() { + SkDELETE(fObj); + fObj = NULL; + } + + /** + * Transfer ownership of the object to the caller, setting the internal + * pointer to NULL. Note that this differs from get(), which also returns + * the pointer, but it does not transfer ownership. + */ + T* detach() { + T* obj = fObj; + fObj = NULL; + return obj; + } + +private: + T* fObj; +}; + +// Calls ~T() in the destructor. +template <typename T> class SkAutoTDestroy : SkNoncopyable { +public: + SkAutoTDestroy(T* obj = NULL) : fObj(obj) {} + ~SkAutoTDestroy() { + if (NULL != fObj) { + fObj->~T(); + } + } + + T* get() const { return fObj; } + T& operator*() const { SkASSERT(fObj); return *fObj; } + T* operator->() const { SkASSERT(fObj); return fObj; } + +private: + T* fObj; +}; + +template <typename T> class SkAutoTDeleteArray : SkNoncopyable { +public: + SkAutoTDeleteArray(T array[]) : fArray(array) {} + ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); } + + T* get() const { return fArray; } + void free() { SkDELETE_ARRAY(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: + SkAutoTArray() { + fArray = NULL; + SkDEBUGCODE(fCount = 0;) + } + /** Allocate count number of T elements + */ + explicit SkAutoTArray(int count) { + SkASSERT(count >= 0); + fArray = NULL; + if (count) { + fArray = SkNEW_ARRAY(T, count); + } + SkDEBUGCODE(fCount = count;) + } + + /** Reallocates given a new count. Reallocation occurs even if new count equals old count. + */ + void reset(int count) { + SkDELETE_ARRAY(fArray); + SkASSERT(count >= 0); + fArray = NULL; + if (count) { + fArray = SkNEW_ARRAY(T, count); + } + SkDEBUGCODE(fCount = count;) + } + + ~SkAutoTArray() { + SkDELETE_ARRAY(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 < (unsigned)fCount); + return fArray[index]; + } + +private: + T* fArray; + SkDEBUGCODE(int fCount;) +}; + +/** Wraps SkAutoTArray, with room for up to N elements preallocated + */ +template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { +public: + /** Initialize with no objects */ + SkAutoSTArray() { + fArray = NULL; + fCount = 0; + } + + /** Allocate count number of T elements + */ + SkAutoSTArray(size_t count) { + fArray = NULL; + fCount = 0; + this->reset(count); + } + + ~SkAutoSTArray() { + this->reset(0); + } + + /** Destroys previous objects in the array and default constructs count number of objects */ + void reset(size_t count) { + T* start = fArray; + T* iter = start + fCount; + while (iter > start) { + (--iter)->~T(); + } + + if (fCount != count) { + if (fCount > N) { + // 'fArray' was allocated last time so free it now + SkASSERT((T*) fStorage != fArray); + sk_free(fArray); + } + + if (count > N) { + fArray = (T*) sk_malloc_throw(count * sizeof(T)); + } else if (count > 0) { + fArray = (T*) fStorage; + } else { + fArray = NULL; + } + + fCount = count; + } + + iter = fArray; + T* stop = fArray + count; + while (iter < stop) { + SkNEW_PLACEMENT(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)]; +}; + +/** Manages an array of T elements, freeing the array in the destructor. + * Does NOT call any constructors/destructors on T (T must be POD). + */ +template <typename T> class SkAutoTMalloc : SkNoncopyable { +public: + /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ + explicit SkAutoTMalloc(T* ptr = NULL) { + fPtr = ptr; + } + + /** Allocates space for 'count' Ts. */ + explicit SkAutoTMalloc(size_t count) { + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + + ~SkAutoTMalloc() { + sk_free(fPtr); + } + + /** Resize the memory area pointed to by the current ptr preserving contents. */ + void realloc(size_t count) { + fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T))); + } + + /** Resize the memory area pointed to by the current ptr without preserving contents. */ + void reset(size_t count) { + sk_free(fPtr); + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + + T* get() const { return fPtr; } + + operator T*() { + return fPtr; + } + + operator const T*() const { + return fPtr; + } + + T& operator[](int index) { + return fPtr[index]; + } + + const T& operator[](int index) const { + return fPtr[index]; + } + + /** + * Transfer ownership of the ptr to the caller, setting the internal + * pointer to NULL. Note that this differs from get(), which also returns + * the pointer, but it does not transfer ownership. + */ + T* detach() { + T* ptr = fPtr; + fPtr = NULL; + return ptr; + } + +private: + T* fPtr; +}; + +template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable { +public: + SkAutoSTMalloc() { + fPtr = NULL; + } + + SkAutoSTMalloc(size_t count) { + if (count > N) { + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = NULL; + } + } + + ~SkAutoSTMalloc() { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + } + + // doesn't preserve contents + T* reset(size_t count) { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + if (count > N) { + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = NULL; + } + return fPtr; + } + + T* get() const { return fPtr; } + + operator T*() { + return fPtr; + } + + operator const T*() const { + return fPtr; + } + + T& operator[](int index) { + return fPtr[index]; + } + + const T& operator[](int index) const { + return fPtr[index]; + } + +private: + T* fPtr; + union { + uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; + T fTStorage[1]; // do NOT want to invoke T::T() + }; +}; + +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. + */ +template <size_t N> class SkAlignedSStorage : SkNoncopyable { +public: + void* get() { return fData; } +private: + union { + void* fPtr; + double fDouble; + char fData[N]; + }; +}; + +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. Otherwise, + * we have to do some arcane trickery to determine alignment of non-POD + * types. Lifetime of the memory is the lifetime of the object. + */ +template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { +public: + /** + * Returns void* because this object does not initialize the + * memory. Use placement new for types that require a cons. + */ + void* get() { return fStorage.get(); } +private: + SkAlignedSStorage<sizeof(T)*N> fStorage; +}; + +#endif diff --git a/core/SkThread.h b/core/SkThread.h new file mode 100644 index 0000000..4a2499a --- /dev/null +++ b/core/SkThread.h @@ -0,0 +1,68 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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_add(int32_t*, int32_t); +int32_t sk_atomic_dec(int32_t*); +int32_t sk_atomic_conditional_inc(int32_t*); + +class SkMutex { +public: + SkMutex(); + ~SkMutex(); + + void acquire(); + void release(); +}; + +****************/ + +class SkAutoMutexAcquire : SkNoncopyable { +public: + explicit SkAutoMutexAcquire(SkBaseMutex& mutex) : fMutex(&mutex) { + SkASSERT(fMutex != NULL); + mutex.acquire(); + } + + SkAutoMutexAcquire(SkBaseMutex* mutex) : fMutex(mutex) { + if (mutex) { + 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: + SkBaseMutex* fMutex; +}; + +#endif diff --git a/core/SkThread_platform.h b/core/SkThread_platform.h new file mode 100644 index 0000000..7df778c --- /dev/null +++ b/core/SkThread_platform.h @@ -0,0 +1,194 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkThread_platform_DEFINED +#define SkThread_platform_DEFINED + +#if defined(SK_BUILD_FOR_ANDROID) + +#if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) + +#include <stdint.h> + +/* Just use the GCC atomic intrinsics. They're supported by the NDK toolchain, + * have reasonable performance, and provide full memory barriers + */ +static inline __attribute__((always_inline)) int32_t sk_atomic_inc(int32_t *addr) { + return __sync_fetch_and_add(addr, 1); +} + +static inline __attribute__((always_inline)) int32_t sk_atomic_add(int32_t *addr, int32_t inc) { + return __sync_fetch_and_add(addr, inc); +} + +static inline __attribute__((always_inline)) int32_t sk_atomic_dec(int32_t *addr) { + return __sync_fetch_and_add(addr, -1); +} +static inline __attribute__((always_inline)) void sk_membar_aquire__after_atomic_dec() { } + +static inline __attribute__((always_inline)) int32_t sk_atomic_conditional_inc(int32_t* addr) { + int32_t value = *addr; + + while (true) { + if (value == 0) { + return 0; + } + + int32_t before = __sync_val_compare_and_swap(addr, value, value + 1); + + if (before == value) { + return value; + } else { + value = before; + } + } +} +static inline __attribute__((always_inline)) void sk_membar_aquire__after_atomic_conditional_inc() { } + +#else // SK_BUILD_FOR_ANDROID_FRAMEWORK + +/* The platform atomics operations are slightly more efficient than the + * GCC built-ins, so use them. + */ +#include <utils/Atomic.h> + +#define sk_atomic_inc(addr) android_atomic_inc(addr) +#define sk_atomic_add(addr, inc) android_atomic_add(inc, addr) +#define sk_atomic_dec(addr) android_atomic_dec(addr) + +static inline __attribute__((always_inline)) void sk_membar_aquire__after_atomic_dec() { + //HACK: Android is actually using full memory barriers. + // Should this change, uncomment below. + //int dummy; + //android_atomic_aquire_store(0, &dummy); +} +static inline __attribute__((always_inline)) int32_t sk_atomic_conditional_inc(int32_t* addr) { + while (true) { + int32_t value = *addr; + if (value == 0) { + return 0; + } + if (0 == android_atomic_release_cas(value, value + 1, addr)) { + return value; + } + } +} +static inline __attribute__((always_inline)) void sk_membar_aquire__after_atomic_conditional_inc() { + //HACK: Android is actually using full memory barriers. + // Should this change, uncomment below. + //int dummy; + //android_atomic_aquire_store(0, &dummy); +} + +#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK + +#else // !SK_BUILD_FOR_ANDROID + +/** Implemented by the porting layer, this function adds one to the int + specified by the address (in a thread-safe manner), and returns the + previous value. + No additional memory barrier is required. + This must act as a compiler barrier. +*/ +SK_API int32_t sk_atomic_inc(int32_t* addr); + +/** Implemented by the porting layer, this function adds inc to the int + specified by the address (in a thread-safe manner), and returns the + previous value. + No additional memory barrier is required. + This must act as a compiler barrier. + */ +SK_API int32_t sk_atomic_add(int32_t* addr, int32_t inc); + +/** Implemented by the porting layer, this function subtracts one from the int + specified by the address (in a thread-safe manner), and returns the + previous value. + Expected to act as a release (SL/S) memory barrier and a compiler barrier. +*/ +SK_API int32_t sk_atomic_dec(int32_t* addr); +/** If sk_atomic_dec does not act as an aquire (L/SL) barrier, this is expected + to act as an aquire (L/SL) memory barrier and as a compiler barrier. +*/ +SK_API void sk_membar_aquire__after_atomic_dec(); + +/** Implemented by the porting layer, this function adds one to the int + specified by the address iff the int specified by the address is not zero + (in a thread-safe manner), and returns the previous value. + No additional memory barrier is required. + This must act as a compiler barrier. +*/ +SK_API int32_t sk_atomic_conditional_inc(int32_t*); +/** If sk_atomic_conditional_inc does not act as an aquire (L/SL) barrier, this + is expected to act as an aquire (L/SL) memory barrier and as a compiler + barrier. +*/ +SK_API void sk_membar_aquire__after_atomic_conditional_inc(); + +#endif // !SK_BUILD_FOR_ANDROID + +#ifdef SK_USE_POSIX_THREADS + +#include <pthread.h> + +// A SkBaseMutex is a POD structure that can be directly initialized +// at declaration time with SK_DECLARE_STATIC/GLOBAL_MUTEX. This avoids the +// generation of a static initializer in the final machine code (and +// a corresponding static finalizer). +// +struct SkBaseMutex { + void acquire() { pthread_mutex_lock(&fMutex); } + void release() { pthread_mutex_unlock(&fMutex); } + pthread_mutex_t fMutex; +}; + +// Using POD-style initialization prevents the generation of a static initializer +// and keeps the acquire() implementation small and fast. +#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name = { PTHREAD_MUTEX_INITIALIZER } + +// Special case used when the static mutex must be available globally. +#define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name = { PTHREAD_MUTEX_INITIALIZER } + +// A normal mutex that requires to be initialized through normal C++ construction, +// i.e. when it's a member of another class, or allocated on the heap. +class SK_API SkMutex : public SkBaseMutex, SkNoncopyable { +public: + SkMutex(); + ~SkMutex(); +}; + +#else // !SK_USE_POSIX_THREADS + +// In the generic case, SkBaseMutex and SkMutex are the same thing, and we +// can't easily get rid of static initializers. +// +class SK_API SkMutex : SkNoncopyable { +public: + SkMutex(); + ~SkMutex(); + + void acquire(); + void release(); + +private: + bool fIsGlobal; + enum { + kStorageIntCount = 64 + }; + uint32_t fStorage[kStorageIntCount]; +}; + +typedef SkMutex SkBaseMutex; + +#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name +#define SK_DECLARE_GLOBAL_MUTEX(name) SkBaseMutex name + +#endif // !SK_USE_POSIX_THREADS + + +#endif diff --git a/core/SkTileGridPicture.h b/core/SkTileGridPicture.h new file mode 100644 index 0000000..af7f0e2 --- /dev/null +++ b/core/SkTileGridPicture.h @@ -0,0 +1,56 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTileGridPicture_DEFINED +#define SkTileGridPicture_DEFINED + +#include "SkPicture.h" +#include "SkPoint.h" +#include "SkSize.h" + +/** + * Subclass of SkPicture that override the behavior of the + * kOptimizeForClippedPlayback_RecordingFlag by creating an SkTileGrid + * structure rather than an R-Tree. The tile grid has lower recording + * and playback costs, but is less effective at eliminating extraneous + * primitives for arbitrary query rectangles. It is most effective for + * tiled playback when the tile structure is known at record time. + */ +class SK_API SkTileGridPicture : public SkPicture { +public: + struct TileGridInfo { + /** Tile placement interval */ + SkISize fTileInterval; + + /** Pixel coverage overlap between adjacent tiles */ + SkISize fMargin; + + /** Offset added to device-space bounding box positions to convert + * them to tile-grid space. This can be used to adjust the "phase" + * of the tile grid to match probable query rectangles that will be + * used to search into the tile grid. As long as the offset is smaller + * or equal to the margin, there is no need to extend the domain of + * the tile grid to prevent data loss. + */ + SkIPoint fOffset; + }; + /** + * Constructor + * @param width recording canvas width in device pixels + * @param height recording canvas height in device pixels + * @param info description of the tiling layout + */ + SkTileGridPicture(int width, int height, const TileGridInfo& info); + + virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE; + +private: + int fXTileCount, fYTileCount; + TileGridInfo fInfo; +}; + +#endif diff --git a/core/SkTime.h b/core/SkTime.h new file mode 100644 index 0000000..7f3c270 --- /dev/null +++ b/core/SkTime.h @@ -0,0 +1,64 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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/core/SkTrace.h b/core/SkTrace.h new file mode 100644 index 0000000..e6e7e2c --- /dev/null +++ b/core/SkTrace.h @@ -0,0 +1,45 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTrace_DEFINED +#define SkTrace_DEFINED + +#ifdef SK_USER_TRACE_INCLUDE_FILE + +/* If your system embeds skia and has complex event logging, in + src/config/SkUserConfig.h: + - define the three SK_TRACE_EVENT macros to map to your system's + equivalents, + - define the name of the include file in SK_USER_TRACE_INCLUDE_FILE + A trivial example is given in src/utils/SkDebugTrace.h. + + All arguments are const char*. Skia typically passes the name of + the object and function (and sometimes region of interest within + the function) separated by double colons for 'event'. + + SK_TRACE_EVENT1 and SK_TRACE_EVENT2 take one or two arbitrary + name-value pairs that you also want to log. SkStringPrintf() is useful + for formatting these values. + + For example: + SK_TRACE_EVENT0("GrContext::createAndLockTexture"); + SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses", + "verts", SkStringPrintf("%i", vert - base).c_str()); +*/ + + #include SK_USER_TRACE_INCLUDE_FILE + +#else + + #define SK_TRACE_EVENT0(event) + #define SK_TRACE_EVENT1(event, name1, value1) + #define SK_TRACE_EVENT2(event, name1, value1, name2, value2) + +#endif + +#endif diff --git a/core/SkTypeface.h b/core/SkTypeface.h new file mode 100644 index 0000000..ca88a1b --- /dev/null +++ b/core/SkTypeface.h @@ -0,0 +1,336 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTypeface_DEFINED +#define SkTypeface_DEFINED + +#include "SkAdvancedTypefaceMetrics.h" +#include "SkWeakRefCnt.h" + +class SkDescriptor; +class SkFontDescriptor; +class SkScalerContext; +struct SkScalerContextRec; +class SkStream; +class SkAdvancedTypefaceMetrics; +class SkWStream; + +typedef uint32_t SkFontID; +/** Machine endian. */ +typedef uint32_t SkFontTableTag; + +/** \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 shared between threads. +*/ +class SK_API SkTypeface : public SkWeakRefCnt { +public: + SK_DECLARE_INST_COUNT(SkTypeface) + + /** 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; } + + /** 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; } + + /** Returns true if the typeface claims to be fixed-pitch. + * This is a style bit, advance widths may vary even if this returns true. + */ + bool isFixedPitch() const { return fIsFixedPitch; } + + /** Return a 32bit value for this typeface, unique for the underlying font + data. Will never return 0. + */ + SkFontID 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. Will never + return 0. + */ + static SkFontID UniqueID(const SkTypeface* face); + + /** Returns true if the two typefaces reference the same underlying font, + handling either being null (treating null as the default font) + */ + static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); + + /** + * Returns a ref() to the default typeface. The caller must call unref() + * when they are done referencing the object. Never returns NULL. + */ + static SkTypeface* RefDefault(Style style = SkTypeface::kNormal); + + /** 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* CreateFromName(const char familyName[], Style style); + + /** 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); + + /** 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); + + /** Write a unique signature to a stream, sufficient to reconstruct a + typeface referencing the same font when Deserialize is called. + */ + void serialize(SkWStream*) const; + + /** Given the data previously written by serialize(), return a new instance + to a typeface referring to the same font. If that font is not available, + return null. If an instance is returned, the caller is responsible for + calling unref() when they are done with it. + */ + static SkTypeface* Deserialize(SkStream*); + + /** Retrieve detailed typeface metrics. Used by the PDF backend. + @param perGlyphInfo Indicate what glyph specific information (advances, + names, etc.) should be populated. + @param glyphIDs For per-glyph info, specify subset of the font by + giving glyph ids. Each integer represents a glyph + id. Passing NULL means all glyphs in the font. + @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if + glyphIDs is NULL. + @return The returned object has already been referenced. + */ + SkAdvancedTypefaceMetrics* getAdvancedTypefaceMetrics( + SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, + const uint32_t* glyphIDs = NULL, + uint32_t glyphIDsCount = 0) const; + + enum Encoding { + kUTF8_Encoding, + kUTF16_Encoding, + kUTF32_Encoding + }; + + /** + * Given an array of character codes, of the specified encoding, + * optionally return their corresponding glyph IDs (if glyphs is not NULL). + * + * @param chars pointer to the array of character codes + * @param encoding how the characteds are encoded + * @param glyphs (optional) returns the corresponding glyph IDs for each + * character code, up to glyphCount values. If a character code is + * not found in the typeface, the corresponding glyph ID will be 0. + * @param glyphCount number of code points in 'chars' to process. If glyphs + * is not NULL, then it must point sufficient memory to write + * glyphCount values into it. + * @return the number of number of continuous non-zero glyph IDs computed + * from the beginning of chars. This value is valid, even if the + * glyphs parameter is NULL. + */ + int charsToGlyphs(const void* chars, Encoding encoding, uint16_t glyphs[], + int glyphCount) const; + + /** + * Return the number of glyphs in the typeface. + */ + int countGlyphs() const; + + // Table getters -- may fail if the underlying font format is not organized + // as 4-byte tables. + + /** Return the number of tables in the font. */ + int countTables() const; + + /** Copy into tags[] (allocated by the caller) the list of table tags in + * the font, and return the number. This will be the same as CountTables() + * or 0 if an error occured. If tags == NULL, this only returns the count + * (the same as calling countTables()). + */ + int getTableTags(SkFontTableTag tags[]) const; + + /** Given a table tag, return the size of its contents, or 0 if not present + */ + size_t getTableSize(SkFontTableTag) const; + + /** Copy the contents of a table into data (allocated by the caller). Note + * that the contents of the table will be in their native endian order + * (which for most truetype tables is big endian). If the table tag is + * not found, or there is an error copying the data, then 0 is returned. + * If this happens, it is possible that some or all of the memory pointed + * to by data may have been written to, even though an error has occured. + * + * @param fontID the font to copy the table from + * @param tag The table tag whose contents are to be copied + * @param offset The offset in bytes into the table's contents where the + * copy should start from. + * @param length The number of bytes, starting at offset, of table data + * to copy. + * @param data storage address where the table contents are copied to + * @return the number of bytes actually copied into data. If offset+length + * exceeds the table's size, then only the bytes up to the table's + * size are actually copied, and this is the value returned. If + * offset > the table's size, or tag is not a valid table, + * then 0 is returned. + */ + size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, + void* data) const; + + /** + * Return the units-per-em value for this typeface, or zero if there is an + * error. + */ + int getUnitsPerEm() const; + + struct LocalizedString { + SkString fString; + SkString fLanguage; + }; + class LocalizedStrings : ::SkNoncopyable { + public: + virtual ~LocalizedStrings() { } + virtual bool next(LocalizedString* localizedString) = 0; + void unref() { SkDELETE(this); } + }; + /** + * Returns an iterator which will attempt to enumerate all of the + * family names specified by the font. + * It is the caller's responsibility to unref() the returned pointer. + */ + LocalizedStrings* createFamilyNameIterator() const; + + /** + * Return the family name for this typeface. It will always be returned + * encoded as UTF8, but the language of the name is whatever the host + * platform chooses. + */ + void getFamilyName(SkString* name) const; + + /** + * Return a stream for the contents of the font data, or NULL on failure. + * If ttcIndex is not null, it is set to the TrueTypeCollection index + * of this typeface within the stream, or 0 if the stream is not a + * collection. + */ + SkStream* openStream(int* ttcIndex) const; + + /** + * Search within this typeface's family for a best match to the + * specified style, and return a ref to that typeface. Note: the + * returned object could be this, if it is the best match, or it + * could be a different typeface. Either way, the caller must balance + * this call with unref() on the returned object. + * + * Will never return NULL. + */ + SkTypeface* refMatchingStyle(Style) const; + + /** + * Return a scalercontext for the given descriptor. If this fails, then + * if allowFailure is true, this returns NULL, else it returns a + * dummy scalercontext that will not crash, but will draw nothing. + */ + SkScalerContext* createScalerContext(const SkDescriptor*, + bool allowFailure = false) const; + + // PRIVATE / EXPERIMENTAL -- do not call + void filterRec(SkScalerContextRec* rec) const { + this->onFilterRec(rec); + } + // PRIVATE / EXPERIMENTAL -- do not call + void getFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + this->onGetFontDescriptor(desc, isLocal); + } + +protected: + /** uniqueID must be unique and non-zero + */ + SkTypeface(Style style, SkFontID uniqueID, bool isFixedPitch = false); + virtual ~SkTypeface(); + + /** Sets the fixedPitch bit. If used, must be called in the constructor. */ + void setIsFixedPitch(bool isFixedPitch) { fIsFixedPitch = isFixedPitch; } + + friend class SkScalerContext; + static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal); + + virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const = 0; + virtual void onFilterRec(SkScalerContextRec*) const = 0; + virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( + SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, + const uint32_t* glyphIDs, + uint32_t glyphIDsCount) const = 0; + virtual SkStream* onOpenStream(int* ttcIndex) const = 0; + virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; + + virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], + int glyphCount) const; + virtual int onCountGlyphs() const = 0; + + virtual int onGetUPEM() const = 0; + + virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0; + + virtual int onGetTableTags(SkFontTableTag tags[]) const = 0; + virtual size_t onGetTableData(SkFontTableTag, size_t offset, + size_t length, void* data) const = 0; + + virtual SkTypeface* onRefMatchingStyle(Style styleBits) const = 0; + +private: + SkFontID fUniqueID; + Style fStyle; + bool fIsFixedPitch; + + friend class SkPaint; + friend class SkGlyphCache; // GetDefaultTypeface + // just so deprecated fonthost can call protected methods + friend class SkFontHost; + + typedef SkWeakRefCnt INHERITED; +}; + +#endif diff --git a/core/SkTypes.h b/core/SkTypes.h new file mode 100644 index 0000000..0393691 --- /dev/null +++ b/core/SkTypes.h @@ -0,0 +1,607 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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 +*/ + +/** See SkGraphics::GetVersion() to retrieve these at runtime + */ +#define SKIA_VERSION_MAJOR 1 +#define SKIA_VERSION_MINOR 0 +#define SKIA_VERSION_PATCH 0 + +/* + 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. +*/ +SK_API 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. +*/ +SK_API 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(). +*/ +SK_API 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 +*/ +SK_API 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. +*/ +SK_API extern void* sk_realloc_throw(void* buffer, size_t size); +/** Free memory returned by sk_malloc(). It is safe to pass null. +*/ +SK_API extern void sk_free(void*); + +// bzero is safer than memset, but we can't rely on it, so... sk_bzero() +static inline void sk_bzero(void* buffer, size_t size) { + memset(buffer, 0, size); +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_OVERRIDE_GLOBAL_NEW +#include <new> + +inline void* operator new(size_t size) { + return sk_malloc_throw(size); +} + +inline void operator delete(void* p) { + sk_free(p); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#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 SkDEBUGFAIL(message) SkASSERT(false && message) + #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 SkDEBUGFAIL(message) + #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 + +#ifdef SK_DEVELOPER + #define SkDEVCODE(code) code + // the 'toString' helper functions convert Sk* objects to human-readable + // form in developer mode + #define SK_DEVELOPER_TO_STRING() virtual void toString(SkString* str) const SK_OVERRIDE; +#else + #define SkDEVCODE(code) + #define SK_DEVELOPER_TO_STRING() +#endif + +template <bool> +struct SkCompileAssert { +}; + +#define SK_COMPILE_ASSERT(expr, msg) \ + typedef SkCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] SK_UNUSED + +/* + * Usage: SK_MACRO_CONCAT(a, b) to construct the symbol ab + * + * SK_MACRO_CONCAT_IMPL_PRIV just exists to make this work. Do not use directly + * + */ +#define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y) +#define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y + +/* + * Usage: SK_MACRO_APPEND_LINE(foo) to make foo123, where 123 is the current + * line number. Easy way to construct + * unique names for local functions or + * variables. + */ +#define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__) + +/////////////////////////////////////////////////////////////////////// + +/** + * 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 unsigned U8CPU; + +/** + * Fast type for signed 16 bits. Use for parameter passing and local variables, + * not for storage + */ +typedef int S16CPU; + +/** + * 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 + SK_API int8_t SkToS8(intmax_t); + SK_API uint8_t SkToU8(uintmax_t); + SK_API int16_t SkToS16(intmax_t); + SK_API uint16_t SkToU16(uintmax_t); + SK_API int32_t SkToS32(intmax_t); + SK_API uint32_t SkToU32(uintmax_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 -SK_MaxS32 +#define SK_MaxU32 0xFFFFFFFF +#define SK_MinU32 0 +#define SK_NaN32 (1 << 31) + +/** Returns true if the value can be represented with signed 16bits + */ +static inline bool SkIsS16(long x) { + return (int16_t)x == x; +} + +/** Returns true if the value can be represented with unsigned 16bits + */ +static inline bool SkIsU16(long x) { + return (uint16_t)x == x; +} + +////////////////////////////////////////////////////////////////////////////// +#ifndef SK_OFFSETOF + #define SK_OFFSETOF(type, field) (size_t)((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])) + +#define SkAlign2(x) (((x) + 1) >> 1 << 1) +#define SkIsAlign2(x) (0 == ((x) & 1)) + +#define SkAlign4(x) (((x) + 3) >> 2 << 2) +#define SkIsAlign4(x) (0 == ((x) & 3)) + +#define SkAlign8(x) (((x) + 7) >> 3 << 3) +#define SkIsAlign8(x) (0 == ((x) & 7)) + +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 +*/ +static inline int Sk32ToBool(uint32_t n) { + return (n | (0-n)) >> 31; +} + +/** Generic swap function. Classes with efficient swaps should specialize this function to take + their fast path. This function is used by SkTSort. */ +template <typename T> inline void SkTSwap(T& a, T& b) { + T c(a); + a = b; + b = c; +} + +static inline int32_t SkAbs32(int32_t value) { + if (value < 0) { + value = -value; + } + return value; +} + +template <typename T> inline T SkTAbs(T value) { + if (value < 0) { + value = -value; + } + return value; +} + +static inline int32_t SkMax32(int32_t a, int32_t b) { + if (a < b) + a = b; + return a; +} + +static inline int32_t SkMin32(int32_t a, int32_t b) { + if (a > b) + a = b; + return a; +} + +template <typename T> const T& SkTMin(const T& a, const T& b) { + return (a < b) ? a : b; +} + +template <typename T> const T& SkTMax(const T& a, const T& b) { + return (b < a) ? a : b; +} + +static inline int32_t SkSign32(int32_t a) { + return (a >> 31) | ((unsigned) -a >> 31); +} + +static inline int32_t SkFastMin32(int32_t value, int32_t max) { + if (value > max) { + value = max; + } + return value; +} + +/** Returns signed 32 bit value pinned between min and max, inclusively +*/ +static inline int32_t SkPin32(int32_t value, int32_t min, int32_t max) { + if (value < min) { + value = min; + } + if (value > max) { + value = max; + } + return value; +} + +static 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); +} + +static inline uint32_t SkSetClearMask(uint32_t bits, bool cond, + uint32_t mask) { + return cond ? bits | mask : bits & ~mask; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** Use to combine multiple bits in a bitmask in a type safe way. + */ +template <typename T> +T SkTBitOr(T a, T b) { + return (T)(a | b); +} + +/** + * Use to cast a pointer to a different type, and maintaining strict-aliasing + */ +template <typename Dst> Dst SkTCast(const void* ptr) { + union { + const void* src; + Dst dst; + } data; + data.src = ptr; + return data.dst; +} + +////////////////////////////////////////////////////////////////////////////// + +/** \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 SK_API 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&); +}; + +/** + * Manage an allocated block of heap memory. This object is the sole manager of + * the lifetime of the block, so the caller must not call sk_free() or delete + * on the block, unless detach() was called. + */ +class SkAutoMalloc : public SkNoncopyable { +public: + explicit SkAutoMalloc(size_t size = 0) { + fPtr = size ? sk_malloc_throw(size) : NULL; + fSize = size; + } + + ~SkAutoMalloc() { + sk_free(fPtr); + } + + /** + * Passed to reset to specify what happens if the requested size is smaller + * than the current size (and the current block was dynamically allocated). + */ + enum OnShrink { + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, free the old block and + * malloc a new block of the smaller size. + */ + kAlloc_OnShrink, + + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, just return the old + * block. + */ + kReuse_OnShrink + }; + + /** + * Reallocates the block to a new size. The ptr may or may not change. + */ + void* reset(size_t size, OnShrink shrink = kAlloc_OnShrink, bool* didChangeAlloc = NULL) { + if (size == fSize || (kReuse_OnShrink == shrink && size < fSize)) { + if (NULL != didChangeAlloc) { + *didChangeAlloc = false; + } + return fPtr; + } + + sk_free(fPtr); + fPtr = size ? sk_malloc_throw(size) : NULL; + fSize = size; + if (NULL != didChangeAlloc) { + *didChangeAlloc = true; + } + + return fPtr; + } + + /** + * Releases the block back to the heap + */ + void free() { + this->reset(0); + } + + /** + * Return the allocated block. + */ + void* get() { return fPtr; } + const void* get() const { return fPtr; } + + /** 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() { + void* ptr = fPtr; + fPtr = NULL; + fSize = 0; + return ptr; + } + +private: + void* fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) +}; + +/** + * Manage an allocated block of memory. If the requested size is <= kSize, then + * the allocation will come from the stack rather than the heap. This object + * is the sole manager of the lifetime of the block, so the caller must not + * call sk_free() or delete on the block. + */ +template <size_t kSize> class SkAutoSMalloc : SkNoncopyable { +public: + /** + * Creates initially empty storage. get() returns a ptr, but it is to + * a zero-byte allocation. Must call reset(size) to return an allocated + * block. + */ + SkAutoSMalloc() { + fPtr = fStorage; + fSize = kSize; + } + + /** + * Allocate a block of the specified size. If size <= kSize, then the + * allocation will come from the stack, otherwise it will be dynamically + * allocated. + */ + explicit SkAutoSMalloc(size_t size) { + fPtr = fStorage; + fSize = kSize; + this->reset(size); + } + + /** + * Free the allocated block (if any). If the block was small enought to + * have been allocated on the stack (size <= kSize) then this does nothing. + */ + ~SkAutoSMalloc() { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + } + + /** + * Return the allocated block. May return non-null even if the block is + * of zero size. Since this may be on the stack or dynamically allocated, + * the caller must not call sk_free() on it, but must rely on SkAutoSMalloc + * to manage it. + */ + void* get() const { return fPtr; } + + /** + * Return a new block of the requested size, freeing (as necessary) any + * previously allocated block. As with the constructor, if size <= kSize + * then the return block may be allocated locally, rather than from the + * heap. + */ + void* reset(size_t size, + SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink, + bool* didChangeAlloc = NULL) { + size = (size < kSize) ? kSize : size; + bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize); + if (NULL != didChangeAlloc) { + *didChangeAlloc = alloc; + } + if (alloc) { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + + if (size == kSize) { + SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc. + fPtr = fStorage; + } else { + fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + + fSize = size; + } + SkASSERT(fSize >= size && fSize >= kSize); + SkASSERT((fPtr == fStorage) || fSize > kSize); + return fPtr; + } + +private: + void* fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) + uint32_t fStorage[(kSize + 3) >> 2]; +}; + +#endif /* C++ */ + +#endif diff --git a/core/SkUnPreMultiply.h b/core/SkUnPreMultiply.h new file mode 100644 index 0000000..4fa5d57 --- /dev/null +++ b/core/SkUnPreMultiply.h @@ -0,0 +1,56 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + + + +#ifndef SkUnPreMultiply_DEFINED +#define SkUnPreMultiply_DEFINED + +#include "SkColor.h" + +class SK_API 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/core/SkUnitMapper.h b/core/SkUnitMapper.h new file mode 100644 index 0000000..754be26 --- /dev/null +++ b/core/SkUnitMapper.h @@ -0,0 +1,35 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkUnitMapper_DEFINED +#define SkUnitMapper_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" + +#include "SkFlattenable.h" + +class SkUnitMapper : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkUnitMapper) + + 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) {} + +private: + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/core/SkUtils.h b/core/SkUtils.h new file mode 100644 index 0000000..e29367d --- /dev/null +++ b/core/SkUtils.h @@ -0,0 +1,117 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#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); +typedef void (*SkMemset16Proc)(uint16_t dst[], uint16_t value, int count); +SkMemset16Proc SkMemset16GetPlatformProc(); + +/** 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); +typedef void (*SkMemset32Proc)(uint32_t dst[], uint32_t value, int count); +SkMemset32Proc SkMemset32GetPlatformProc(); + +#ifndef sk_memset16 +extern SkMemset16Proc sk_memset16; +#endif + +#ifndef sk_memset32 +extern SkMemset32Proc sk_memset32; +#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); + +inline bool SkUnichar_IsVariationSelector(SkUnichar uni) { +/* The 'true' ranges are: + * 0x180B <= uni <= 0x180D + * 0xFE00 <= uni <= 0xFE0F + * 0xE0100 <= uni <= 0xE01EF + */ + if (uni < 0x180B || uni > 0xE01EF) { + return false; + } + if ((uni > 0x180D && uni < 0xFE00) || (uni > 0xFE0F && uni < 0xE0100)) { + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +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; +}; + +#endif diff --git a/core/SkWeakRefCnt.h b/core/SkWeakRefCnt.h new file mode 100644 index 0000000..e6871fe --- /dev/null +++ b/core/SkWeakRefCnt.h @@ -0,0 +1,159 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWeakRefCnt_DEFINED +#define SkWeakRefCnt_DEFINED + +#include "SkRefCnt.h" +#include "SkThread.h" + +/** \class SkWeakRefCnt + + SkWeakRefCnt is the base class for objects that may be shared by multiple + objects. When an existing strong owner wants to share a reference, it calls + ref(). When a strong owner wants to release its reference, it calls + unref(). When the shared object's strong reference count goes to zero as + the result of an unref() call, its (virtual) weak_dispose method 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. + + In addition to strong ownership, an owner may instead obtain a weak + reference by calling weak_ref(). A call to weak_ref() must be balanced my a + call to weak_unref(). To obtain a strong reference from a weak reference, + call try_ref(). If try_ref() returns true, the owner's pointer is now also + a strong reference on which unref() must be called. Note that this does not + affect the original weak reference, weak_unref() must still be called. When + the weak reference count goes to zero, the object is deleted. While the + weak reference count is positive and the strong reference count is zero the + object still exists, but will be in the disposed state. It is up to the + object to define what this means. + + Note that a strong reference implicitly implies a weak reference. As a + result, it is allowable for the owner of a strong ref to call try_ref(). + This will have the same effect as calling ref(), but may be more expensive. + + Example: + + SkWeakRefCnt myRef = strongRef.weak_ref(); + ... // strongRef.unref() may or may not be called + if (myRef.try_ref()) { + ... // use myRef + myRef.unref(); + } else { + // myRef is in the disposed state + } + myRef.weak_unref(); +*/ +class SK_API SkWeakRefCnt : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkWeakRefCnt) + + /** Default construct, initializing the reference counts to 1. + The strong references collectively hold one weak reference. When the + strong reference count goes to zero, the collectively held weak + reference is released. + */ + SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} + + /** Destruct, asserting that the weak reference count is 1. + */ + virtual ~SkWeakRefCnt() { +#ifdef SK_DEBUG + SkASSERT(fWeakCnt == 1); + fWeakCnt = 0; +#endif + } + + /** Return the weak reference count. + */ + int32_t getWeakCnt() const { return fWeakCnt; } + + void validate() const { + SkRefCnt::validate(); + SkASSERT(fWeakCnt > 0); + } + + /** Creates a strong reference from a weak reference, if possible. The + caller must already be an owner. If try_ref() returns true the owner + is in posession of an additional strong reference. Both the original + reference and new reference must be properly unreferenced. If try_ref() + returns false, no strong reference could be created and the owner's + reference is in the same state as before the call. + */ + bool SK_WARN_UNUSED_RESULT try_ref() const { + if (sk_atomic_conditional_inc(&fRefCnt) != 0) { + // Aquire barrier (L/SL), if not provided above. + // Prevents subsequent code from happening before the increment. + sk_membar_aquire__after_atomic_conditional_inc(); + return true; + } + return false; + } + + /** Increment the weak reference count. Must be balanced by a call to + weak_unref(). + */ + void weak_ref() const { + SkASSERT(fRefCnt > 0); + SkASSERT(fWeakCnt > 0); + sk_atomic_inc(&fWeakCnt); // No barrier required. + } + + /** Decrement the weak reference count. If the weak 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 weak_unref() const { + SkASSERT(fWeakCnt > 0); + // Release barrier (SL/S), if not provided below. + if (sk_atomic_dec(&fWeakCnt) == 1) { + // Aquire barrier (L/SL), if not provided above. + // Prevents code in destructor from happening before the decrement. + sk_membar_aquire__after_atomic_dec(); +#ifdef SK_DEBUG + // so our destructor won't complain + fWeakCnt = 1; +#endif + SkRefCnt::internal_dispose(); + } + } + + /** Returns true if there are no strong references to the object. When this + is the case all future calls to try_ref() will return false. + */ + bool weak_expired() const { + return fRefCnt == 0; + } + +protected: + /** Called when the strong reference count goes to zero. This allows the + object to free any resources it may be holding. Weak references may + still exist and their level of allowed access to the object is defined + by the object's class. + */ + virtual void weak_dispose() const { + } + +private: + /** Called when the strong reference count goes to zero. Calls weak_dispose + on the object and releases the implicit weak reference held + collectively by the strong references. + */ + virtual void internal_dispose() const SK_OVERRIDE { + weak_dispose(); + weak_unref(); + } + + /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ + mutable int32_t fWeakCnt; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/core/SkWriter32.h b/core/SkWriter32.h new file mode 100644 index 0000000..b07c080 --- /dev/null +++ b/core/SkWriter32.h @@ -0,0 +1,303 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkWriter32_DEFINED +#define SkWriter32_DEFINED + +#include "SkTypes.h" + +#include "SkScalar.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkRRect.h" +#include "SkMatrix.h" +#include "SkRegion.h" + +class SkStream; +class SkWStream; + +class SkWriter32 : SkNoncopyable { + struct BlockHeader; +public: + /** + * The caller can specify an initial block of storage, which the caller manages. + * SkWriter32 will not attempt to free this in its destructor. It is up to the + * implementation to decide if, and how much, of the storage to utilize, and it + * is possible that it may be ignored entirely. + */ + SkWriter32(size_t minSize, void* initialStorage, size_t storageSize); + + SkWriter32(size_t minSize) + : fHead(NULL) + , fTail(NULL) + , fMinSize(minSize) + , fSize(0) + , fWrittenBeforeLastBlock(0) + {} + + ~SkWriter32(); + + // return the current offset (will always be a multiple of 4) + uint32_t bytesWritten() const { return fSize; } + // DEPRECATED: use bytesWritten instead TODO(mtklein): clean up + uint32_t size() const { return this->bytesWritten(); } + + // Returns true if we've written only into the storage passed into constructor or reset. + // (You may be able to use this to avoid a call to flatten.) + bool wroteOnlyToStorage() const { + return fHead == &fExternalBlock && this->bytesWritten() <= fExternalBlock.fSizeOfBlock; + } + + void reset(); + void reset(void* storage, size_t size); + + // size MUST be multiple of 4 + uint32_t* reserve(size_t size) { + SkASSERT(SkAlign4(size) == size); + + Block* block = fTail; + if (NULL == block || block->available() < size) { + block = this->doReserve(size); + } + fSize += size; + return block->alloc(size); + } + + 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 writePtr(void* ptr) { + // Since we "know" that we're always 4-byte aligned, we can tell the + // compiler that here, by assigning to an int32 ptr. + int32_t* addr = (int32_t*)this->reserve(sizeof(void*)); + if (4 == sizeof(void*)) { + *(void**)addr = ptr; + } else { + memcpy(addr, &ptr, sizeof(void*)); + } + } + + 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; + } + + void writeIRect(const SkIRect& rect) { + *(SkIRect*)this->reserve(sizeof(rect)) = rect; + } + + void writeRRect(const SkRRect& rrect) { + rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory)); + } + + void writePath(const SkPath& path) { + size_t size = path.writeToMemory(NULL); + SkASSERT(SkAlign4(size) == size); + path.writeToMemory(this->reserve(size)); + } + + void writeMatrix(const SkMatrix& matrix) { + size_t size = matrix.writeToMemory(NULL); + SkASSERT(SkAlign4(size) == size); + matrix.writeToMemory(this->reserve(size)); + } + + void writeRegion(const SkRegion& rgn) { + size_t size = rgn.writeToMemory(NULL); + SkASSERT(SkAlign4(size) == size); + rgn.writeToMemory(this->reserve(size)); + } + + // write count bytes (must be a multiple of 4) + void writeMul4(const void* values, size_t size) { + this->write(values, size); + } + + /** + * Write size bytes from values. size must be a multiple of 4, though + * values need not be 4-byte aligned. + */ + void write(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); + } + + /** + * Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be + * filled in with zeroes. + */ + uint32_t* reservePad(size_t size); + + /** + * Write size bytes from src, and pad to 4 byte alignment with zeroes. + */ + void writePad(const void* src, size_t size); + + /** + * Writes a string to the writer, which can be retrieved with + * SkReader32::readString(). + * The length can be specified, or if -1 is passed, it will be computed by + * calling strlen(). The length must be < 0xFFFF + */ + void writeString(const char* str, size_t len = (size_t)-1); + + /** + * Computes the size (aligned to multiple of 4) need to write the string + * in a call to writeString(). If the length is not specified, it will be + * computed by calling strlen(). + */ + static size_t WriteStringSize(const char* str, size_t len = (size_t)-1); + + // 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); + + /** + * Move the cursor back to offset bytes from the beginning. + * This has the same restrictions as peek32: offset must be <= size() and + * offset must be a multiple of 4. + */ + void rewindToOffset(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: + struct Block { + Block* fNext; + char* fBasePtr; + size_t fSizeOfBlock; // total space allocated (after this) + size_t fAllocatedSoFar; // space used so far + + size_t available() const { return fSizeOfBlock - fAllocatedSoFar; } + char* base() { return fBasePtr; } + const char* base() const { return fBasePtr; } + + uint32_t* alloc(size_t size) { + SkASSERT(SkAlign4(size) == size); + SkASSERT(this->available() >= size); + void* ptr = this->base() + fAllocatedSoFar; + fAllocatedSoFar += size; + SkASSERT(fAllocatedSoFar <= fSizeOfBlock); + return (uint32_t*)ptr; + } + + uint32_t* peek32(size_t offset) { + SkASSERT(offset <= fAllocatedSoFar + 4); + void* ptr = this->base() + offset; + return (uint32_t*)ptr; + } + + void rewind() { + fNext = NULL; + fAllocatedSoFar = 0; + // keep fSizeOfBlock as is + } + + static Block* Create(size_t size) { + SkASSERT(SkIsAlign4(size)); + Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); + block->fNext = NULL; + block->fBasePtr = (char*)(block + 1); + block->fSizeOfBlock = size; + block->fAllocatedSoFar = 0; + return block; + } + + Block* initFromStorage(void* storage, size_t size) { + SkASSERT(SkIsAlign4((intptr_t)storage)); + SkASSERT(SkIsAlign4(size)); + Block* block = this; + block->fNext = NULL; + block->fBasePtr = (char*)storage; + block->fSizeOfBlock = size; + block->fAllocatedSoFar = 0; + return block; + } + }; + + enum { + MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t) + }; + + Block fExternalBlock; + Block* fHead; + Block* fTail; + size_t fMinSize; + uint32_t fSize; + // sum of bytes written in all blocks *before* fTail + uint32_t fWrittenBeforeLastBlock; + + bool isHeadExternallyAllocated() const { + return fHead == &fExternalBlock; + } + + Block* newBlock(size_t bytes); + + // only call from reserve() + Block* doReserve(size_t bytes); + + SkDEBUGCODE(void validate() const;) +}; + +/** + * Helper class to allocated SIZE bytes as part of the writer, and to provide + * that storage to the constructor as its initial storage buffer. + * + * This wrapper ensures proper alignment rules are met for the storage. + */ +template <size_t SIZE> class SkSWriter32 : public SkWriter32 { +public: + SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {} + +private: + union { + void* fPtrAlignment; + double fDoubleAlignment; + char fStorage[SIZE]; + } fData; +}; + +#endif diff --git a/core/SkXfermode.h b/core/SkXfermode.h new file mode 100644 index 0000000..ef00f71 --- /dev/null +++ b/core/SkXfermode.h @@ -0,0 +1,280 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkXfermode_DEFINED +#define SkXfermode_DEFINED + +#include "SkFlattenable.h" +#include "SkColor.h" + +class GrContext; +class GrEffectRef; +class GrTexture; +class SkString; + +/** \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 SK_API SkXfermode : public SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkXfermode) + + SkXfermode() {} + + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const; + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const; + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const; + + /** Enum of possible coefficients to describe some xfermodes + */ + enum Coeff { + kZero_Coeff, /** 0 */ + kOne_Coeff, /** 1 */ + kSC_Coeff, /** src color */ + kISC_Coeff, /** inverse src color (i.e. 1 - sc) */ + kDC_Coeff, /** dst color */ + kIDC_Coeff, /** inverse dst color (i.e. 1 - dc) */ + kSA_Coeff, /** src alpha */ + kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */ + kDA_Coeff, /** dst alpha */ + kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */ + + kCoeffCount + }; + + /** If the xfermode can be expressed as an equation using the coefficients + in Coeff, then asCoeff() returns true, and sets (if not null) src and + dst accordingly. + + result = src_coeff * src_color + dst_coeff * dst_color; + + As examples, here are some of the porterduff coefficients + + MODE SRC_COEFF DST_COEFF + clear zero zero + src one zero + dst zero one + srcover one isa + dstover ida one + */ + virtual bool asCoeff(Coeff* src, Coeff* dst) const; + + /** + * The same as calling xfermode->asCoeff(..), except that this also checks + * if the xfermode is NULL, and if so, treats it as kSrcOver_Mode. + */ + static bool AsCoeff(const SkXfermode*, Coeff* src, Coeff* dst); + + /** List of predefined xfermodes. + 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. + The modes are ordered by those that can be expressed as a pair of Coeffs, followed by those + that aren't Coeffs but have separable r,g,b computations, and finally + those that are not separable. + */ + 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] + kPlus_Mode, //!< [Sa + Da, Sc + Dc] + kModulate_Mode, // multiplies all components (= alpha and color) + + // Following blend modes are defined in the CSS Compositing standard: + // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending + kScreen_Mode, + kLastCoeffMode = kScreen_Mode, + + kOverlay_Mode, + kDarken_Mode, + kLighten_Mode, + kColorDodge_Mode, + kColorBurn_Mode, + kHardLight_Mode, + kSoftLight_Mode, + kDifference_Mode, + kExclusion_Mode, + kMultiply_Mode, + kLastSeparableMode = kMultiply_Mode, + + kHue_Mode, + kSaturation_Mode, + kColor_Mode, + kLuminosity_Mode, + kLastMode = kLuminosity_Mode + }; + + /** + * Gets the name of the Mode as a string. + */ + static const char* ModeName(Mode); + + /** + * If the xfermode is one of the modes in the Mode enum, then asMode() + * returns true and sets (if not null) mode accordingly. Otherwise it + * returns false and ignores the mode parameter. + */ + virtual bool asMode(Mode* mode) const; + + /** + * The same as calling xfermode->asMode(mode), except that this also checks + * if the xfermode is NULL, and if so, treats it as kSrcOver_Mode. + */ + static bool AsMode(const SkXfermode*, Mode* mode); + + /** + * Returns true if the xfermode claims to be the specified Mode. This works + * correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus + * you can say this without checking for a null... + * + * If (SkXfermode::IsMode(paint.getXfermode(), + * SkXfermode::kDstOver_Mode)) { + * ... + * } + */ + static bool IsMode(const SkXfermode* xfer, Mode mode); + + /** Return an SkXfermode object for the specified mode. + */ + static SkXfermode* Create(Mode mode); + + /** Return a function pointer to a routine that applies the specified + porter-duff transfer mode. + */ + static SkXfermodeProc GetProc(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 GetProc16(Mode mode, SkColor srcColor); + + /** + * If the specified mode can be represented by a pair of Coeff, then return + * true and set (if not NULL) the corresponding coeffs. If the mode is + * not representable as a pair of Coeffs, return false and ignore the + * src and dst parameters. + */ + static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); + + // DEPRECATED: call AsMode(...) + static bool IsMode(const SkXfermode* xfer, Mode* mode) { + return AsMode(xfer, mode); + } + + /** A subclass may implement this factory function to work with the GPU backend. It is legal + to call this with all but the context param NULL to simply test the return value. effect, + src, and dst must all be NULL or all non-NULL. If effect is non-NULL then the xfermode may + optionally allocate an effect to return and the caller as *effect. The caller will install + it and own a ref to it. Since the xfermode may or may not assign *effect, the caller should + set *effect to NULL beforehand. If the function returns true and *effect is NULL then the + src and dst coeffs will be applied to the draw. When *effect is non-NULL the coeffs are + ignored. background specifies the texture to use as the background for compositing, and + should be accessed in the effect's fragment shader. If NULL, the effect should request + access to destination color (setWillReadDstColor()), and use that in the fragment shader + (builder->dstColor()). + */ + virtual bool asNewEffectOrCoeff(GrContext*, + GrEffectRef** effect, + Coeff* src, + Coeff* dst, + GrTexture* background = NULL) const; + + /** + * The same as calling xfermode->asNewEffect(...), except that this also checks if the xfermode + * is NULL, and if so, treats it as kSrcOver_Mode. + */ + static bool AsNewEffectOrCoeff(SkXfermode*, + GrContext*, + GrEffectRef** effect, + Coeff* src, + Coeff* dst, + GrTexture* background = NULL); + + SkDEVCODE(virtual void toString(SkString* str) const = 0;) + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +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) const; + +private: + enum { + kModeCount = kLastMode + 1 + }; + 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[]) const SK_OVERRIDE; + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcXfermode) + +protected: + SkProcXfermode(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + // allow subclasses to update this after we unflatten + void setProc(SkXfermodeProc proc) { + fProc = proc; + } + +private: + SkXfermodeProc fProc; + + typedef SkXfermode INHERITED; +}; + +#endif diff --git a/device/xps/SkConstexprMath.h b/device/xps/SkConstexprMath.h new file mode 100644 index 0000000..9625d51 --- /dev/null +++ b/device/xps/SkConstexprMath.h @@ -0,0 +1,54 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkConstexprMath_DEFINED +#define SkConstexprMath_DEFINED + +#include "SkTypes.h" +#include <limits.h> + +template <uintmax_t N, uintmax_t B> +struct SK_LOG { + //! Compile-time constant ceiling(logB(N)). + static const uintmax_t value = 1 + SK_LOG<N/B, B>::value; +}; +template <uintmax_t B> +struct SK_LOG<1, B> { + static const uintmax_t value = 0; +}; +template <uintmax_t B> +struct SK_LOG<0, B> { + static const uintmax_t value = 0; +}; + +template<uintmax_t N> +struct SK_2N1 { + //! Compile-time constant (2^N)-1. + static const uintmax_t value = (SK_2N1<N-1>::value << 1) + 1; +}; +template<> +struct SK_2N1<1> { + static const uintmax_t value = 1; +}; + +/** Compile-time constant number of base n digits in type t + if the bits of type t are considered as unsigned base two. +*/ +#define SK_BASE_N_DIGITS_IN(n, t) (\ + SK_LOG<SK_2N1<(sizeof(t) * CHAR_BIT)>::value, n>::value\ +) +/** Compile-time constant number of base 10 digits in type t + if the bits of type t are considered as unsigned base two. +*/ +#define SK_DIGITS_IN(t) SK_BASE_N_DIGITS_IN(10, (t)) + +// Compile-time constant maximum value of two unsigned values. +template <uintmax_t a, uintmax_t b> struct SkTUMax { + static const uintmax_t value = (b < a) ? a : b; +}; + +#endif diff --git a/device/xps/SkXPSDevice.h b/device/xps/SkXPSDevice.h new file mode 100644 index 0000000..dab8d1f --- /dev/null +++ b/device/xps/SkXPSDevice.h @@ -0,0 +1,324 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkXPSDevice_DEFINED +#define SkXPSDevice_DEFINED + +#include "SkTypes.h" +#include <ObjBase.h> +#include <XpsObjectModel.h> + +#include "SkAutoCoInitialize.h" +#include "SkBitSet.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkDevice.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkShader.h" +#include "SkSize.h" +#include "SkTArray.h" +#include "SkTScopedComPtr.h" +#include "SkTypeface.h" + +/** \class SkXPSDevice + + The drawing context for the XPS backend. +*/ +class SkXPSDevice : public SkDevice { +public: + SK_API SkXPSDevice(); + SK_API virtual ~SkXPSDevice(); + + virtual bool beginPortfolio(SkWStream* outputStream); + /** + @param unitsPerMeter converts geometry units into physical units. + @param pixelsPerMeter resolution to use when geometry must be rasterized. + @param trimSize final page size in physical units. + The top left of the trim is the origin of physical space. + @param mediaBox The size of the physical media in physical units. + The top and left must be less than zero. + The bottom and right must be greater than the trimSize. + The default is to coincide with the trimSize. + @param bleedBox The size of the bleed box in physical units. + Must be contained within the mediaBox. + The default is to coincide with the mediaBox. + @param artBox The size of the content box in physical units. + Must be contained within the trimSize. + The default is to coincide with the trimSize. + @param cropBox The size of the recommended view port in physical units. + Must be contained within the mediaBox. + The default is to coincide with the mediaBox. + */ + virtual bool beginSheet( + const SkVector& unitsPerMeter, + const SkVector& pixelsPerMeter, + const SkSize& trimSize, + const SkRect* mediaBox = NULL, + const SkRect* bleedBox = NULL, + const SkRect* artBox = NULL, + const SkRect* cropBox = NULL); + + virtual bool endSheet(); + virtual bool endPortfolio(); + + virtual uint32_t getDeviceCapabilities() SK_OVERRIDE; + +protected: + virtual void clear(SkColor color) SK_OVERRIDE; + + virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; + + virtual void drawPoints( + const SkDraw&, + SkCanvas::PointMode mode, + size_t count, const SkPoint[], + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawRect( + const SkDraw&, + const SkRect& r, + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawPath( + const SkDraw&, + const SkPath& platonicPath, + const SkPaint& paint, + const SkMatrix* prePathMatrix, + bool pathIsMutable) SK_OVERRIDE; + + virtual void drawBitmap( + const SkDraw&, + const SkBitmap& bitmap, + const SkMatrix& matrix, + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawSprite( + const SkDraw&, + const SkBitmap& bitmap, + int x, int y, + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawText( + const SkDraw&, + const void* text, size_t len, + SkScalar x, SkScalar y, + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawPosText( + const SkDraw&, + const void* text, size_t len, + const SkScalar pos[], SkScalar constY, int scalarsPerPos, + const SkPaint& paint) SK_OVERRIDE; + + virtual void drawTextOnPath( + const SkDraw&, + const void* text, size_t len, + const SkPath& path, + const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + + 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) SK_OVERRIDE; + + virtual void drawDevice( + const SkDraw&, + SkDevice* device, + int x, int y, + const SkPaint& paint) SK_OVERRIDE; + + virtual bool onReadPixels(const SkBitmap& bitmap, + int x, + int y, + SkCanvas::Config8888) SK_OVERRIDE; + + virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE; + +private: + class TypefaceUse : ::SkNoncopyable { + public: + SkFontID typefaceId; + int ttcIndex; + SkStream* fontData; + IXpsOMFontResource* xpsFont; + SkBitSet* glyphsUsed; + + explicit TypefaceUse(); + ~TypefaceUse(); + }; + friend static HRESULT subset_typeface(TypefaceUse* current); + + SkXPSDevice(IXpsOMObjectFactory* xpsFactory); + + SkAutoCoInitialize fAutoCo; + SkTScopedComPtr<IXpsOMObjectFactory> fXpsFactory; + SkTScopedComPtr<IStream> fOutputStream; + SkTScopedComPtr<IXpsOMPackageWriter> fPackageWriter; + + unsigned int fCurrentPage; + SkTScopedComPtr<IXpsOMCanvas> fCurrentXpsCanvas; + SkSize fCurrentCanvasSize; + SkVector fCurrentUnitsPerMeter; + SkVector fCurrentPixelsPerMeter; + + SkTArray<TypefaceUse, true> fTypefaces; + + HRESULT initXpsDocumentWriter(IXpsOMImageResource* image); + + HRESULT createXpsPage( + const XPS_SIZE& pageSize, + IXpsOMPage** page); + + HRESULT createXpsThumbnail( + IXpsOMPage* page, const unsigned int pageNumber, + IXpsOMImageResource** image); + + void internalDrawRect( + const SkDraw&, + const SkRect& r, + bool transformRect, + const SkPaint& paint); + + HRESULT createXpsBrush( + const SkPaint& skPaint, + IXpsOMBrush** xpsBrush, + const SkMatrix* parentTransform = NULL); + + HRESULT createXpsSolidColorBrush( + const SkColor skColor, const SkAlpha alpha, + IXpsOMBrush** xpsBrush); + + HRESULT createXpsImageBrush( + const SkBitmap& bitmap, + const SkMatrix& localMatrix, + const SkShader::TileMode (&xy)[2], + const SkAlpha alpha, + IXpsOMTileBrush** xpsBrush); + + HRESULT createXpsLinearGradient( + SkShader::GradientInfo info, + const SkAlpha alpha, + const SkMatrix& localMatrix, + IXpsOMMatrixTransform* xpsMatrixToUse, + IXpsOMBrush** xpsBrush); + + HRESULT createXpsRadialGradient( + SkShader::GradientInfo info, + const SkAlpha alpha, + const SkMatrix& localMatrix, + IXpsOMMatrixTransform* xpsMatrixToUse, + IXpsOMBrush** xpsBrush); + + HRESULT createXpsGradientStop( + const SkColor skColor, + const SkScalar offset, + IXpsOMGradientStop** xpsGradStop); + + HRESULT createXpsTransform( + const SkMatrix& matrix, + IXpsOMMatrixTransform ** xpsTransform); + + HRESULT createXpsRect( + const SkRect& rect, + BOOL stroke, BOOL fill, + IXpsOMGeometryFigure** xpsRect); + + HRESULT createXpsQuad( + const SkPoint (&points)[4], + BOOL stroke, BOOL fill, + IXpsOMGeometryFigure** xpsQuad); + + HRESULT CreateTypefaceUse( + const SkPaint& paint, + TypefaceUse** fontResource); + + HRESULT AddGlyphs( + const SkDraw& d, + IXpsOMObjectFactory* xpsFactory, + IXpsOMCanvas* canvas, + TypefaceUse* font, + LPCWSTR text, + XPS_GLYPH_INDEX* xpsGlyphs, + UINT32 xpsGlyphsLen, + XPS_POINT *origin, + FLOAT fontSize, + XPS_STYLE_SIMULATION sims, + const SkMatrix& transform, + const SkPaint& paint); + + HRESULT addXpsPathGeometry( + IXpsOMGeometryFigureCollection* figures, + BOOL stroke, BOOL fill, const SkPath& path); + + HRESULT createPath( + IXpsOMGeometryFigure* figure, + IXpsOMVisualCollection* visuals, + IXpsOMPath** path); + + HRESULT sideOfClamp( + const SkRect& leftPoints, const XPS_RECT& left, + IXpsOMImageResource* imageResource, + IXpsOMVisualCollection* visuals); + + HRESULT cornerOfClamp( + const SkRect& tlPoints, + const SkColor color, + IXpsOMVisualCollection* visuals); + + HRESULT clip( + IXpsOMVisual* xpsVisual, + const SkDraw& d); + HRESULT clipToPath( + IXpsOMVisual* xpsVisual, + const SkPath& clipPath, + XPS_FILL_RULE fillRule); + + HRESULT drawInverseWindingPath( + const SkDraw& d, + const SkPath& devicePath, + IXpsOMPath* xpsPath); + + HRESULT shadePath( + IXpsOMPath* shadedPath, + const SkPaint& shaderPaint, + const SkMatrix& matrix, + BOOL* fill, BOOL* stroke); + + void convertToPpm( + const SkMaskFilter* filter, + SkMatrix* matrix, + SkVector* ppuScale, + const SkIRect& clip, SkIRect* clipIRect); + + HRESULT applyMask( + const SkDraw& d, + const SkMask& mask, + const SkVector& ppuScale, + IXpsOMPath* shadedPath); + + // override from SkDevice + virtual SkDevice* onCreateCompatibleDevice( + SkBitmap::Config config, + int width, int height, + bool isOpaque, + Usage usage) SK_OVERRIDE; + + // Disable the default copy and assign implementation. + SkXPSDevice(const SkXPSDevice&); + void operator=(const SkXPSDevice&); + + typedef SkDevice INHERITED; +}; + +#endif diff --git a/effects/Sk1DPathEffect.h b/effects/Sk1DPathEffect.h new file mode 100644 index 0000000..4599276 --- /dev/null +++ b/effects/Sk1DPathEffect.h @@ -0,0 +1,79 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef Sk1DPathEffect_DEFINED +#define Sk1DPathEffect_DEFINED + +#include "SkPathEffect.h" +#include "SkPath.h" + +class SkPathMeasure; + +// This class is not exported to java. +class SK_API Sk1DPathEffect : public SkPathEffect { +public: + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + +protected: + /** Called at the start of each contour, returns the initial offset + into that contour. + */ + virtual SkScalar begin(SkScalar contourLength) const = 0; + /** Called with the current distance along the path, with the current matrix + for the point/tangent at the specified distance. + Return the distance to travel for the next call. If return <= 0, then that + contour is done. + */ + virtual SkScalar next(SkPath* dst, SkScalar dist, SkPathMeasure&) const = 0; + +private: + typedef SkPathEffect INHERITED; +}; + +class SK_API SkPath1DPathEffect : public Sk1DPathEffect { +public: + enum Style { + kTranslate_Style, // translate the shape to each position + kRotate_Style, // rotate the shape about its center + kMorph_Style, // transform each point, and turn lines into curves + + kStyleCount + }; + + /** Dash by replicating the specified path. + @param path The path to replicate (dash) + @param advance The space between instances of path + @param phase distance (mod advance) along path for its initial position + @param style how to transform path at each point (based on the current + position and tangent) + */ + SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style); + + virtual bool filterPath(SkPath*, const SkPath&, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPath1DPathEffect) + +protected: + SkPath1DPathEffect(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + // overrides from Sk1DPathEffect + virtual SkScalar begin(SkScalar contourLength) const SK_OVERRIDE; + virtual SkScalar next(SkPath*, SkScalar, SkPathMeasure&) const SK_OVERRIDE; + +private: + SkPath fPath; // copied from constructor + SkScalar fAdvance; // copied from constructor + SkScalar fInitialOffset; // computed from phase + Style fStyle; // copied from constructor + + typedef Sk1DPathEffect INHERITED; +}; + +#endif diff --git a/effects/Sk2DPathEffect.h b/effects/Sk2DPathEffect.h new file mode 100644 index 0000000..ed7f674 --- /dev/null +++ b/effects/Sk2DPathEffect.h @@ -0,0 +1,104 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef Sk2DPathEffect_DEFINED +#define Sk2DPathEffect_DEFINED + +#include "SkPath.h" +#include "SkPathEffect.h" +#include "SkMatrix.h" + +class SK_API Sk2DPathEffect : public SkPathEffect { +public: + Sk2DPathEffect(const SkMatrix& mat); + + virtual bool filterPath(SkPath*, const SkPath&, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Sk2DPathEffect) + +protected: + /** New virtual, to be overridden by subclasses. + This is called once from filterPath, and provides the + uv parameter bounds for the path. Subsequent calls to + next() will receive u and v values within these bounds, + and then a call to end() will signal the end of processing. + */ + virtual void begin(const SkIRect& uvBounds, SkPath* dst) const; + virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const; + virtual void end(SkPath* dst) const; + + /** Low-level virtual called per span of locations in the u-direction. + The default implementation calls next() repeatedly with each + location. + */ + virtual void nextSpan(int u, int v, int ucount, SkPath* dst) const; + + const SkMatrix& getMatrix() const { return fMatrix; } + + // protected so that subclasses can call this during unflattening + Sk2DPathEffect(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkMatrix fMatrix, fInverse; + bool fMatrixIsInvertible; + + // illegal + Sk2DPathEffect(const Sk2DPathEffect&); + Sk2DPathEffect& operator=(const Sk2DPathEffect&); + + friend class Sk2DPathEffectBlitter; + typedef SkPathEffect INHERITED; +}; + +class SK_API SkLine2DPathEffect : public Sk2DPathEffect { +public: + SkLine2DPathEffect(SkScalar width, const SkMatrix& matrix) + : Sk2DPathEffect(matrix), fWidth(width) {} + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLine2DPathEffect) + +protected: + virtual void nextSpan(int u, int v, int ucount, SkPath*) const SK_OVERRIDE; + + SkLine2DPathEffect(SkFlattenableReadBuffer&); + + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkScalar fWidth; + + typedef Sk2DPathEffect INHERITED; +}; + +class SK_API SkPath2DPathEffect : public Sk2DPathEffect { +public: + /** + * Stamp the specified path to fill the shape, using the matrix to define + * the latice. + */ + SkPath2DPathEffect(const SkMatrix&, const SkPath&); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPath2DPathEffect) + +protected: + SkPath2DPathEffect(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual void next(const SkPoint&, int u, int v, SkPath*) const SK_OVERRIDE; + +private: + SkPath fPath; + + typedef Sk2DPathEffect INHERITED; +}; + +#endif diff --git a/effects/SkArithmeticMode.h b/effects/SkArithmeticMode.h new file mode 100644 index 0000000..9de332c --- /dev/null +++ b/effects/SkArithmeticMode.h @@ -0,0 +1,34 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkArithmeticMode_DEFINED +#define SkArithmeticMode_DEFINED + +#include "SkXfermode.h" + +class SK_API SkArithmeticMode : public SkXfermode { +public: + /** + * result = clamp[k1 * src * dst + k2 * src + k3 * dst + k4] + * + * src and dst are treated as being [0.0 .. 1.0]. The polynomial is + * evaluated on their unpremultiplied components. + * + * k1=k2=k3=0, k4=1.0 results in returning opaque white + * k1=k3=k4=0, k2=1.0 results in returning the src + * k1=k2=k4=0, k3=1.0 results in returning the dst + */ + static SkXfermode* Create(SkScalar k1, SkScalar k2, + SkScalar k3, SkScalar k4); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); + +private: + typedef SkXfermode INHERITED; +}; + +#endif diff --git a/effects/SkAvoidXfermode.h b/effects/SkAvoidXfermode.h new file mode 100644 index 0000000..4950b64 --- /dev/null +++ b/effects/SkAvoidXfermode.h @@ -0,0 +1,65 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAvoidXfermode_DEFINED +#define SkAvoidXfermode_DEFINED + +#include "SkXfermode.h" + +/** \class SkAvoidXfermode + + This xfermode will draw the src everywhere except on top of the specified + color. +*/ +class SK_API SkAvoidXfermode : public SkXfermode { +public: + enum Mode { + kAvoidColor_Mode, //!< draw everywhere except on the opColor + kTargetColor_Mode //!< draw only on top of the opColor + }; + + /** This xfermode draws, or doesn't draw, based on the destination's + distance from an op-color. + + There are two modes, and each mode interprets a tolerance value. + + Avoid: In this mode, drawing is allowed only on destination pixels that + are different from the op-color. + Tolerance near 0: avoid any colors even remotely similar to the op-color + Tolerance near 255: avoid only colors nearly identical to the op-color + + Target: In this mode, drawing only occurs on destination pixels that + are similar to the op-color + Tolerance near 0: draw only on colors that are nearly identical to the op-color + Tolerance near 255: draw on any colors even remotely similar to the op-color + */ + SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode); + + // overrides from SkXfermode + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAvoidXfermode) + +protected: + SkAvoidXfermode(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkColor fOpColor; + uint32_t fDistMul; // x.14 + Mode fMode; + + typedef SkXfermode INHERITED; +}; + +#endif diff --git a/effects/SkBicubicImageFilter.h b/effects/SkBicubicImageFilter.h new file mode 100644 index 0000000..bd918eb --- /dev/null +++ b/effects/SkBicubicImageFilter.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBicubicImageFilter_DEFINED +#define SkBicubicImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkScalar.h" +#include "SkSize.h" +#include "SkPoint.h" + +/*! \class SkBicubicImageFilter + Bicubic resampling image filter. This filter does a 16-tap bicubic + filter using the given matrix. + */ + +class SK_API SkBicubicImageFilter : public SkImageFilter { +public: + /** Construct a (scaling-only) bicubic resampling image filter. + @param scale How much to scale the image. + @param coefficients The 16 coefficients of the bicubic matrix. + @param input The input image filter. If NULL, the src bitmap + passed to filterImage() is used instead. + */ + + SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], + SkImageFilter* input = NULL); + static SkBicubicImageFilter* CreateMitchell(const SkSize& scale, SkImageFilter* input = NULL); + virtual ~SkBicubicImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBicubicImageFilter) + +protected: + SkBicubicImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + +#if SK_SUPPORT_GPU + virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; } + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#endif + +private: + SkSize fScale; + SkScalar fCoefficients[16]; + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkBitmapSource.h b/effects/SkBitmapSource.h new file mode 100644 index 0000000..138987e --- /dev/null +++ b/effects/SkBitmapSource.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBitmapSource_DEFINED +#define SkBitmapSource_DEFINED + +#include "SkImageFilter.h" +#include "SkBitmap.h" + +class SK_API SkBitmapSource : public SkImageFilter { +public: + explicit SkBitmapSource(const SkBitmap& bitmap); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapSource) + +protected: + explicit SkBitmapSource(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; + +private: + SkBitmap fBitmap; + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkBlurDrawLooper.h b/effects/SkBlurDrawLooper.h new file mode 100644 index 0000000..e968857 --- /dev/null +++ b/effects/SkBlurDrawLooper.h @@ -0,0 +1,70 @@ +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBlurDrawLooper_DEFINED +#define SkBlurDrawLooper_DEFINED + +#include "SkDrawLooper.h" +#include "SkColor.h" + +class SkMaskFilter; +class SkColorFilter; + +/** \class SkBlurDrawLooper + This class draws a shadow of the object (possibly offset), and then draws + the original object in its original position. + should there be an option to just draw the shadow/blur layer? webkit? +*/ +class SK_API SkBlurDrawLooper : public SkDrawLooper { +public: + enum BlurFlags { + kNone_BlurFlag = 0x00, + /** + The blur layer's dx/dy/radius aren't affected by the canvas + transform. + */ + kIgnoreTransform_BlurFlag = 0x01, + kOverrideColor_BlurFlag = 0x02, + kHighQuality_BlurFlag = 0x04, + /** mask for all blur flags */ + kAll_BlurFlag = 0x07 + }; + + SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, SkColor color, + uint32_t flags = kNone_BlurFlag); + virtual ~SkBlurDrawLooper(); + + // overrides from SkDrawLooper + virtual void init(SkCanvas*); + virtual bool next(SkCanvas*, SkPaint* paint); + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurDrawLooper) + +protected: + SkBlurDrawLooper(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkMaskFilter* fBlur; + SkColorFilter* fColorFilter; + SkScalar fDx, fDy; + SkColor fBlurColor; + uint32_t fBlurFlags; + + enum State { + kBeforeEdge, + kAfterEdge, + kDone + }; + State fState; + + typedef SkDrawLooper INHERITED; +}; + +#endif diff --git a/effects/SkBlurImageFilter.h b/effects/SkBlurImageFilter.h new file mode 100644 index 0000000..ef03a99 --- /dev/null +++ b/effects/SkBlurImageFilter.h @@ -0,0 +1,39 @@ +/* + * Copyright 2011 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlurImageFilter_DEFINED +#define SkBlurImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkSize.h" + +class SK_API SkBlurImageFilter : public SkImageFilter { +public: + SkBlurImageFilter(SkScalar sigmaX, + SkScalar sigmaY, + SkImageFilter* input = NULL, + const SkIRect* cropRect = NULL); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurImageFilter) + +protected: + explicit SkBlurImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; + + bool canFilterImageGPU() const SK_OVERRIDE { return true; } + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; + +private: + SkSize fSigma; + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkBlurMaskFilter.h b/effects/SkBlurMaskFilter.h new file mode 100644 index 0000000..2ab321a --- /dev/null +++ b/effects/SkBlurMaskFilter.h @@ -0,0 +1,61 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBlurMaskFilter_DEFINED +#define SkBlurMaskFilter_DEFINED + +// we include this since our callers will need to at least be able to ref/unref +#include "SkMaskFilter.h" +#include "SkScalar.h" + +class SK_API SkBlurMaskFilter { +public: + enum BlurStyle { + kNormal_BlurStyle, //!< fuzzy inside and outside + kSolid_BlurStyle, //!< solid inside, fuzzy outside + kOuter_BlurStyle, //!< nothing inside, fuzzy outside + kInner_BlurStyle, //!< fuzzy inside, nothing outside + + kBlurStyleCount + }; + + enum BlurFlags { + kNone_BlurFlag = 0x00, + /** The blur layer's radius is not affected by transforms */ + kIgnoreTransform_BlurFlag = 0x01, + /** Use a smother, higher qulity blur algorithm */ + kHighQuality_BlurFlag = 0x02, + /** mask for all blur flags */ + kAll_BlurFlag = 0x03 + }; + + /** Create a blur maskfilter. + @param radius The radius to extend the blur from the original mask. Must be > 0. + @param style The BlurStyle to use + @param flags Flags to use - defaults to none + @return The new blur maskfilter + */ + static SkMaskFilter* Create(SkScalar radius, BlurStyle style, + uint32_t flags = kNone_BlurFlag); + + /** Create an emboss maskfilter + @param direction array of 3 scalars [x, y, z] specifying the direction of the light source + @param ambient 0...1 amount of ambient light + @param specular coefficient for specular highlights (e.g. 8) + @param blurRadius amount to blur before applying lighting (e.g. 3) + @return the emboss maskfilter + */ + static SkMaskFilter* CreateEmboss( const SkScalar direction[3], + SkScalar ambient, SkScalar specular, + SkScalar blurRadius); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +private: + SkBlurMaskFilter(); // can't be instantiated +}; + +#endif diff --git a/effects/SkColorFilterImageFilter.h b/effects/SkColorFilterImageFilter.h new file mode 100755 index 0000000..314ab07 --- /dev/null +++ b/effects/SkColorFilterImageFilter.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorFilterImageFilter_DEFINED +#define SkColorFilterImageFilter_DEFINED + +#include "SkImageFilter.h" + +class SkColorFilter; + +class SK_API SkColorFilterImageFilter : public SkImageFilter { +public: + static SkColorFilterImageFilter* Create(SkColorFilter* cf, + SkImageFilter* input = NULL, + const SkIRect* cropRect = NULL); + virtual ~SkColorFilterImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorFilterImageFilter) + +protected: + SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + + virtual bool asColorFilter(SkColorFilter**) const SK_OVERRIDE; + +private: + SkColorFilterImageFilter(SkColorFilter* cf, + SkImageFilter* input, + const SkIRect* cropRect = NULL); + SkColorFilter* fColorFilter; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkColorMatrix.h b/effects/SkColorMatrix.h new file mode 100644 index 0000000..84a3b7c --- /dev/null +++ b/effects/SkColorMatrix.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorMatrix_DEFINED +#define SkColorMatrix_DEFINED + +#include "SkScalar.h" + +class SK_API SkColorMatrix { +public: + SkScalar fMat[20]; + + void setIdentity(); + void setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, + SkScalar aScale = SK_Scalar1); + void preScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, + SkScalar aScale = SK_Scalar1); + void postScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, + SkScalar aScale = SK_Scalar1); + + enum Axis { + kR_Axis = 0, + kG_Axis = 1, + kB_Axis = 2 + }; + void setRotate(Axis, SkScalar degrees); + void setSinCos(Axis, SkScalar sine, SkScalar cosine); + void preRotate(Axis, SkScalar degrees); + void postRotate(Axis, SkScalar degrees); + + void setConcat(const SkColorMatrix& a, const SkColorMatrix& b); + void preConcat(const SkColorMatrix& mat) { this->setConcat(*this, mat); } + void postConcat(const SkColorMatrix& mat) { this->setConcat(mat, *this); } + + void setSaturation(SkScalar sat); + void setRGB2YUV(); + void setYUV2RGB(); + + bool operator==(const SkColorMatrix& other) const { + return 0 == memcmp(fMat, other.fMat, sizeof(fMat)); + } + + bool operator!=(const SkColorMatrix& other) const { return !((*this) == other); } +}; + +#endif diff --git a/effects/SkColorMatrixFilter.h b/effects/SkColorMatrixFilter.h new file mode 100644 index 0000000..ca7c086 --- /dev/null +++ b/effects/SkColorMatrixFilter.h @@ -0,0 +1,56 @@ +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorMatrixFilter_DEFINED +#define SkColorMatrixFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkColorMatrix.h" + +class SK_API SkColorMatrixFilter : public SkColorFilter { +public: + explicit SkColorMatrixFilter(const SkColorMatrix&); + SkColorMatrixFilter(const SkScalar array[20]); + + // overrides from SkColorFilter + virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const SK_OVERRIDE; + virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]) const SK_OVERRIDE; + virtual uint32_t getFlags() const SK_OVERRIDE; + virtual bool asColorMatrix(SkScalar matrix[20]) const SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual GrEffectRef* asNewEffect(GrContext*) const SK_OVERRIDE; +#endif + + struct State { + int32_t fArray[20]; + int fShift; + }; + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorMatrixFilter) + +protected: + SkColorMatrixFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkColorMatrix fMatrix; + + typedef void (*Proc)(const State&, unsigned r, unsigned g, unsigned b, + unsigned a, int32_t result[4]); + + Proc fProc; + State fState; + uint32_t fFlags; + + void initState(const SkScalar array[20]); + + typedef SkColorFilter INHERITED; +}; + +#endif diff --git a/effects/SkComposeImageFilter.h b/effects/SkComposeImageFilter.h new file mode 100644 index 0000000..45f530b --- /dev/null +++ b/effects/SkComposeImageFilter.h @@ -0,0 +1,31 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkComposeImageFilter_DEFINED +#define SkComposeImageFilter_DEFINED + +#include "SkImageFilter.h" + +class SK_API SkComposeImageFilter : public SkImageFilter { +public: + SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) : INHERITED(outer, inner) {} + virtual ~SkComposeImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeImageFilter) + +protected: + explicit SkComposeImageFilter(SkFlattenableReadBuffer& buffer); + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE; + +private: + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkCornerPathEffect.h b/effects/SkCornerPathEffect.h new file mode 100644 index 0000000..704b7fb --- /dev/null +++ b/effects/SkCornerPathEffect.h @@ -0,0 +1,41 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCornerPathEffect_DEFINED +#define SkCornerPathEffect_DEFINED + +#include "SkPathEffect.h" + +/** \class SkCornerPathEffect + + SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners + into various treatments (e.g. rounded corners) +*/ +class SK_API SkCornerPathEffect : public SkPathEffect { +public: + /** radius must be > 0 to have an effect. It specifies the distance from each corner + that should be "rounded". + */ + SkCornerPathEffect(SkScalar radius); + virtual ~SkCornerPathEffect(); + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkCornerPathEffect) + +protected: + SkCornerPathEffect(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkScalar fRadius; + + typedef SkPathEffect INHERITED; +}; + +#endif diff --git a/effects/SkDashPathEffect.h b/effects/SkDashPathEffect.h new file mode 100644 index 0000000..9c0775d --- /dev/null +++ b/effects/SkDashPathEffect.h @@ -0,0 +1,70 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDashPathEffect_DEFINED +#define SkDashPathEffect_DEFINED + +#include "SkPathEffect.h" + +/** \class SkDashPathEffect + + SkDashPathEffect is a subclass of SkPathEffect that implements dashing +*/ +class SK_API SkDashPathEffect : public SkPathEffect { +public: + /** intervals: array containing an even number of entries (>=2), with + the even indices specifying the length of "on" intervals, and the odd + indices specifying the length of "off" intervals. + count: number of elements in the intervals array + phase: offset into the intervals array (mod the sum of all of the + intervals). + + For example: if intervals[] = {10, 20}, count = 2, and phase = 25, + this will set up a dashed path like so: + 5 pixels off + 10 pixels on + 20 pixels off + 10 pixels on + 20 pixels off + ... + A phase of -5, 25, 55, 85, etc. would all result in the same path, + because the sum of all the intervals is 30. + + Note: only affects stroked paths. + */ + SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase, + bool scaleToFit = false); + virtual ~SkDashPathEffect(); + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + virtual bool asPoints(PointData* results, const SkPath& src, + const SkStrokeRec&, const SkMatrix&, + const SkRect*) const SK_OVERRIDE; + + virtual Factory getFactory() SK_OVERRIDE; + + static SkFlattenable* CreateProc(SkFlattenableReadBuffer&); + +protected: + SkDashPathEffect(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkScalar* fIntervals; + int32_t fCount; + // computed from phase + SkScalar fInitialDashLength; + int32_t fInitialDashIndex; + SkScalar fIntervalLength; + bool fScaleToFit; + + typedef SkPathEffect INHERITED; +}; + +#endif diff --git a/effects/SkDiscretePathEffect.h b/effects/SkDiscretePathEffect.h new file mode 100644 index 0000000..999ea04 --- /dev/null +++ b/effects/SkDiscretePathEffect.h @@ -0,0 +1,40 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDiscretePathEffect_DEFINED +#define SkDiscretePathEffect_DEFINED + +#include "SkPathEffect.h" + +/** \class SkDiscretePathEffect + + This path effect chops a path into discrete segments, and randomly displaces them. +*/ +class SK_API SkDiscretePathEffect : public SkPathEffect { +public: + /** Break the path into segments of segLength length, and randomly move the endpoints + away from the original path by a maximum of deviation. + Note: works on filled or framed paths + */ + SkDiscretePathEffect(SkScalar segLength, SkScalar deviation); + + virtual bool filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const SK_OVERRIDE; + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiscretePathEffect) + +protected: + SkDiscretePathEffect(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkScalar fSegLength, fPerterb; + + typedef SkPathEffect INHERITED; +}; + +#endif diff --git a/effects/SkDisplacementMapEffect.h b/effects/SkDisplacementMapEffect.h new file mode 100644 index 0000000..ed9d15b --- /dev/null +++ b/effects/SkDisplacementMapEffect.h @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDisplacementMapEffect_DEFINED +#define SkDisplacementMapEffect_DEFINED + +#include "SkImageFilter.h" +#include "SkBitmap.h" + +class SK_API SkDisplacementMapEffect : public SkImageFilter { +public: + enum ChannelSelectorType { + kUnknown_ChannelSelectorType, + kR_ChannelSelectorType, + kG_ChannelSelectorType, + kB_ChannelSelectorType, + kA_ChannelSelectorType, + kKeyBits = 3 // Max value is 4, so 3 bits are required at most + }; + + SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, SkImageFilter* displacement, + SkImageFilter* color = NULL); + + ~SkDisplacementMapEffect(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDisplacementMapEffect) + + virtual bool onFilterImage(Proxy* proxy, + const SkBitmap& src, + const SkMatrix& ctm, + SkBitmap* dst, + SkIPoint* offset) SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; } + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#endif + +protected: + explicit SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + ChannelSelectorType fXChannelSelector; + ChannelSelectorType fYChannelSelector; + SkScalar fScale; + typedef SkImageFilter INHERITED; + SkImageFilter* getDisplacementInput() { return getInput(0); } + SkImageFilter* getColorInput() { return getInput(1); } +}; + +#endif diff --git a/effects/SkDrawExtraPathEffect.h b/effects/SkDrawExtraPathEffect.h new file mode 100644 index 0000000..392a46b --- /dev/null +++ b/effects/SkDrawExtraPathEffect.h @@ -0,0 +1,15 @@ +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SK_DRAW_EXTRA_PATH_EFFECT_H +#define SK_DRAW_EXTRA_PATH_EFFECT_H + +class SkAnimator; + +void InitializeSkExtraPathEffects(SkAnimator* animator); + +#endif diff --git a/effects/SkDropShadowImageFilter.h b/effects/SkDropShadowImageFilter.h new file mode 100644 index 0000000..501df7c --- /dev/null +++ b/effects/SkDropShadowImageFilter.h @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColor.h" +#include "SkImageFilter.h" +#include "SkScalar.h" + +class SK_API SkDropShadowImageFilter : public SkImageFilter { +public: + SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor, SkImageFilter* input = NULL); + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDropShadowImageFilter) + +protected: + explicit SkDropShadowImageFilter(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + virtual bool onFilterImage(Proxy*, const SkBitmap& source, const SkMatrix&, SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + +private: + SkScalar fDx, fDy, fSigma; + SkColor fColor; + typedef SkImageFilter INHERITED; +}; diff --git a/effects/SkEmbossMaskFilter.h b/effects/SkEmbossMaskFilter.h new file mode 100644 index 0000000..c667920 --- /dev/null +++ b/effects/SkEmbossMaskFilter.h @@ -0,0 +1,49 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEmbossMaskFilter_DEFINED +#define SkEmbossMaskFilter_DEFINED + +#include "SkMaskFilter.h" + +/** \class SkEmbossMaskFilter + + This mask filter creates a 3D emboss look, by specifying a light and blur amount. +*/ +class SK_API SkEmbossMaskFilter : public SkMaskFilter { +public: + struct Light { + SkScalar fDirection[3]; // x,y,z + uint16_t fPad; + uint8_t fAmbient; + uint8_t fSpecular; // exponent, 4.4 right now + }; + + SkEmbossMaskFilter(const Light& light, SkScalar blurRadius); + + // overrides from SkMaskFilter + // This method is not exported to java. + virtual SkMask::Format getFormat() const SK_OVERRIDE; + // This method is not exported to java. + virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const SK_OVERRIDE; + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmbossMaskFilter) + +protected: + SkEmbossMaskFilter(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + Light fLight; + SkScalar fBlurRadius; + + typedef SkMaskFilter INHERITED; +}; + +#endif diff --git a/effects/SkGradientShader.h b/effects/SkGradientShader.h new file mode 100644 index 0000000..ed0f1bf --- /dev/null +++ b/effects/SkGradientShader.h @@ -0,0 +1,147 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGradientShader_DEFINED +#define SkGradientShader_DEFINED + +#include "SkShader.h" + +class SkUnitMapper; + +/** \class SkGradientShader + + SkGradientShader hosts factories for creating subclasses of SkShader that + render linear and radial gradients. +*/ +class SK_API SkGradientShader { +public: + enum Flags { + /** By default gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. By setting this flag, the + * gradients will premultiply their colors first, and then interpolate + * between them. + */ + kInterpolateColorsInPremul_Flag = 1 << 0, + }; + + /** Returns a shader that generates a linear gradient between the two + specified points. + <p /> + CreateLinear returns a shader with a reference count of 1. + The caller should decrement the shader's reference count when done with the shader. + It is an error for count to be < 2. + @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the start and end point. + If this is not null, the values must begin with 0, end with 1.0, and + intermediate values must be strictly increasing. + @param count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + @param mapper May be NULL. Callback to modify the spread of the colors. + */ + static SkShader* CreateLinear(const SkPoint pts[2], + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode, + SkUnitMapper* mapper = NULL, + uint32_t flags = 0); + + /** Returns a shader that generates a radial gradient given the center and radius. + <p /> + CreateRadial returns a shader with a reference count of 1. + The caller should decrement the shader's reference count when done with the shader. + It is an error for colorCount to be < 2, or for radius to be <= 0. + @param center The center of the circle for this gradient + @param radius Must be positive. The radius of the circle for this gradient + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must begin with 0, end with 1.0, and + intermediate values must be strictly increasing. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + @param mapper May be NULL. Callback to modify the spread of the colors. + */ + static SkShader* CreateRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode, + SkUnitMapper* mapper = NULL, + uint32_t flags = 0); + + /** Returns a shader that generates a radial gradient given the start position, start radius, end position and end radius. + <p /> + CreateTwoPointRadial returns a shader with a reference count of 1. + The caller should decrement the shader's reference count when done with the shader. + It is an error for colorCount to be < 2, for startRadius or endRadius to be < 0, or for + startRadius to be equal to endRadius. + @param start The center of the start circle for this gradient + @param startRadius Must be positive. The radius of the start circle for this gradient. + @param end The center of the end circle for this gradient + @param endRadius Must be positive. The radius of the end circle for this gradient. + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must begin with 0, end with 1.0, and + intermediate values must be strictly increasing. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + @param mapper May be NULL. Callback to modify the spread of the colors. + */ + static SkShader* CreateTwoPointRadial(const SkPoint& start, + SkScalar startRadius, + const SkPoint& end, + SkScalar endRadius, + const SkColor colors[], + const SkScalar pos[], int count, + SkShader::TileMode mode, + SkUnitMapper* mapper = NULL, + uint32_t flags = 0); + + /** + * Returns a shader that generates a conical gradient given two circles, or + * returns NULL if the inputs are invalid. The gradient interprets the + * two circles according to the following HTML spec. + * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient + */ + static SkShader* CreateTwoPointConical(const SkPoint& start, + SkScalar startRadius, + const SkPoint& end, + SkScalar endRadius, + const SkColor colors[], + const SkScalar pos[], int count, + SkShader::TileMode mode, + SkUnitMapper* mapper = NULL, + uint32_t flags = 0); + + /** Returns a shader that generates a sweep gradient given a center. + <p /> + CreateSweep returns a shader with a reference count of 1. + The caller should decrement the shader's reference count when done with the shader. + It is an error for colorCount to be < 2. + @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must begin with 0, end with 1.0, and + intermediate values must be strictly increasing. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mapper May be NULL. Callback to modify the spread of the colors. + */ + static SkShader* CreateSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], + int count, SkUnitMapper* mapper = NULL, + uint32_t flags = 0); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +}; + +#endif diff --git a/effects/SkKernel33MaskFilter.h b/effects/SkKernel33MaskFilter.h new file mode 100644 index 0000000..3404b73 --- /dev/null +++ b/effects/SkKernel33MaskFilter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkKernel33MaskFilter_DEFINED +#define SkKernel33MaskFilter_DEFINED + +#include "SkMaskFilter.h" + +class SK_API SkKernel33ProcMaskFilter : public SkMaskFilter { +public: + SkKernel33ProcMaskFilter(unsigned percent256 = 256) + : fPercent256(percent256) {} + + virtual uint8_t computeValue(uint8_t* const* srcRows) const = 0; + + virtual SkMask::Format getFormat() const SK_OVERRIDE; + virtual bool filterMask(SkMask*, const SkMask&, const SkMatrix&, + SkIPoint*) const SK_OVERRIDE; + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + +protected: + SkKernel33ProcMaskFilter(SkFlattenableReadBuffer& rb); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + int fPercent256; + + typedef SkMaskFilter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SK_API SkKernel33MaskFilter : public SkKernel33ProcMaskFilter { +public: + SkKernel33MaskFilter(const int coeff[3][3], int shift, int percent256 = 256) + : SkKernel33ProcMaskFilter(percent256) { + memcpy(fKernel, coeff, 9 * sizeof(int)); + fShift = shift; + } + + // override from SkKernel33ProcMaskFilter + virtual uint8_t computeValue(uint8_t* const* srcRows) const SK_OVERRIDE; + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkKernel33MaskFilter) + +private: + int fKernel[3][3]; + int fShift; + + SkKernel33MaskFilter(SkFlattenableReadBuffer& rb); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + typedef SkKernel33ProcMaskFilter INHERITED; +}; + +#endif diff --git a/effects/SkLayerDrawLooper.h b/effects/SkLayerDrawLooper.h new file mode 100644 index 0000000..adf07a9 --- /dev/null +++ b/effects/SkLayerDrawLooper.h @@ -0,0 +1,139 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLayerDrawLooper_DEFINED +#define SkLayerDrawLooper_DEFINED + +#include "SkDrawLooper.h" +#include "SkPaint.h" +#include "SkPoint.h" +#include "SkXfermode.h" + +class SK_API SkLayerDrawLooper : public SkDrawLooper { +public: + SK_DECLARE_INST_COUNT(SkLayerDrawLooper) + + SkLayerDrawLooper(); + virtual ~SkLayerDrawLooper(); + + /** + * Bits specifies which aspects of the layer's paint should replace the + * corresponding aspects on the draw's paint. + * kEntirePaint_Bits means use the layer's paint completely. + * 0 means ignore the layer's paint... except that LayerInfo's fFlagsMask + * and fColorMode are always applied. + */ + enum Bits { + kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings + kTextSkewX_Bit = 1 << 1, //!< use this layer's textskewx + kPathEffect_Bit = 1 << 2, //!< use this layer's patheffect + kMaskFilter_Bit = 1 << 3, //!< use this layer's maskfilter + kShader_Bit = 1 << 4, //!< use this layer's shader + kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter + kXfermode_Bit = 1 << 6, //!< use this layer's xfermode + + /** + * Use the layer's paint entirely, with these exceptions: + * - We never override the draw's paint's text_encoding, since that is + * used to interpret the text/len parameters in draw[Pos]Text. + * - Flags and Color are always computed using the LayerInfo's + * fFlagsMask and fColorMode. + */ + kEntirePaint_Bits = -1 + + }; + typedef int32_t BitFlags; + + /** + * Info for how to apply the layer's paint and offset. + * + * fFlagsMask selects which flags in the layer's paint should be applied. + * result = (draw-flags & ~fFlagsMask) | (layer-flags & fFlagsMask) + * In the extreme: + * If fFlagsMask is 0, we ignore all of the layer's flags + * If fFlagsMask is -1, we use all of the layer's flags + * + * fColorMode controls how we compute the final color for the layer: + * The layer's paint's color is treated as the SRC + * The draw's paint's color is treated as the DST + * final-color = Mode(layers-color, draws-color); + * Any SkXfermode::Mode will work. Two common choices are: + * kSrc_Mode: to use the layer's color, ignoring the draw's + * kDst_Mode: to just keep the draw's color, ignoring the layer's + */ + struct SK_API LayerInfo { + uint32_t fFlagsMask; // SkPaint::Flags + BitFlags fPaintBits; + SkXfermode::Mode fColorMode; + SkVector fOffset; + bool fPostTranslate; //!< applies to fOffset + + /** + * Initial the LayerInfo. Defaults to settings that will draw the + * layer with no changes: e.g. + * fPaintBits == 0 + * fColorMode == kDst_Mode + * fOffset == (0, 0) + */ + LayerInfo(); + }; + + /** + * Call for each layer you want to add (from top to bottom). + * This returns a paint you can modify, but that ptr is only valid until + * the next call made to addLayer(). + */ + SkPaint* addLayer(const LayerInfo&); + + /** + * This layer will draw with the original paint, at the specified offset + */ + void addLayer(SkScalar dx, SkScalar dy); + + /** + * This layer will with the original paint and no offset. + */ + void addLayer() { this->addLayer(0, 0); } + + /// Similar to addLayer, but adds a layer to the top. + SkPaint* addLayerOnTop(const LayerInfo&); + + // overrides from SkDrawLooper + virtual void init(SkCanvas*); + virtual bool next(SkCanvas*, SkPaint* paint); + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLayerDrawLooper) + +protected: + SkLayerDrawLooper(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + struct Rec { + Rec* fNext; + SkPaint fPaint; + LayerInfo fInfo; + }; + Rec* fRecs; + Rec* fTopRec; + int fCount; + + // state-machine during the init/next cycle + Rec* fCurrRec; + + static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); + + class MyRegistrar : public SkFlattenable::Registrar { + public: + MyRegistrar(); + }; + + typedef SkDrawLooper INHERITED; +}; + +#endif diff --git a/effects/SkLayerRasterizer.h b/effects/SkLayerRasterizer.h new file mode 100644 index 0000000..65d1be0 --- /dev/null +++ b/effects/SkLayerRasterizer.h @@ -0,0 +1,52 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkLayerRasterizer_DEFINED +#define SkLayerRasterizer_DEFINED + +#include "SkRasterizer.h" +#include "SkDeque.h" +#include "SkScalar.h" + +class SkPaint; + +class SK_API SkLayerRasterizer : public SkRasterizer { +public: + SkLayerRasterizer(); + virtual ~SkLayerRasterizer(); + + void addLayer(const SkPaint& paint) { + this->addLayer(paint, 0, 0); + } + + /** Add a new layer (above any previous layers) to the rasterizer. + The layer will extract those fields that affect the mask from + the specified paint, but will not retain a reference to the paint + object itself, so it may be reused without danger of side-effects. + */ + void addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLayerRasterizer) + +protected: + SkLayerRasterizer(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + // override from SkRasterizer + virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix, + const SkIRect* clipBounds, + SkMask* mask, SkMask::CreateMode mode) const; + +private: + SkDeque fLayers; + + typedef SkRasterizer INHERITED; +}; + +#endif diff --git a/effects/SkLerpXfermode.h b/effects/SkLerpXfermode.h new file mode 100644 index 0000000..6151f3d --- /dev/null +++ b/effects/SkLerpXfermode.h @@ -0,0 +1,46 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLerpXfermode_DEFINED +#define SkLerpXfermode_DEFINED + +#include "SkXfermode.h" + +class SK_API SkLerpXfermode : public SkXfermode { +public: + /** + * result = scale * src + (1 - scale) * dst + * + * When scale == 1, this is the same as kSrc_Mode + * When scale == 0, this is the same as kDst_Mode + */ + static SkXfermode* Create(SkScalar scale); + + // overrides from SkXfermode + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, + const SkAlpha aa[]) const SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLerpXfermode) + +protected: + SkLerpXfermode(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkLerpXfermode(unsigned scale256); + + unsigned fScale256; // 0..256 + + typedef SkXfermode INHERITED; +}; + +#endif diff --git a/effects/SkLightingImageFilter.h b/effects/SkLightingImageFilter.h new file mode 100644 index 0000000..07f713b --- /dev/null +++ b/effects/SkLightingImageFilter.h @@ -0,0 +1,92 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkLightingImageFilter_DEFINED +#define SkLightingImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkColor.h" + +class SK_API SkPoint3 { +public: + SkPoint3() {} + SkPoint3(SkScalar x, SkScalar y, SkScalar z) + : fX(x), fY(y), fZ(z) {} + SkScalar dot(const SkPoint3& other) const { + return SkScalarMul(fX, other.fX) + + SkScalarMul(fY, other.fY) + + SkScalarMul(fZ, other.fZ); + } + SkScalar maxComponent() const { + return fX > fY ? (fX > fZ ? fX : fZ) : (fY > fZ ? fY : fZ); + } + void normalize() { + SkScalar scale = SkScalarInvert(SkScalarSqrt(dot(*this))); + fX = SkScalarMul(fX, scale); + fY = SkScalarMul(fY, scale); + fZ = SkScalarMul(fZ, scale); + } + SkPoint3 operator*(SkScalar scalar) const { + return SkPoint3(SkScalarMul(fX, scalar), + SkScalarMul(fY, scalar), + SkScalarMul(fZ, scalar)); + } + SkPoint3 operator-(const SkPoint3& other) const { + return SkPoint3(fX - other.fX, fY - other.fY, fZ - other.fZ); + } + bool operator==(const SkPoint3& other) const { + return fX == other.fX && fY == other.fY && fZ == other.fZ; + } + SkScalar fX, fY, fZ; +}; + +class SkLight; + +class SK_API SkLightingImageFilter : public SkImageFilter { +public: + static SkImageFilter* CreateDistantLitDiffuse(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + static SkImageFilter* CreatePointLitDiffuse(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + static SkImageFilter* CreateSpotLitDiffuse(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + static SkImageFilter* CreateDistantLitSpecular(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + static SkImageFilter* CreatePointLitSpecular(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + static SkImageFilter* CreateSpotLitSpecular(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const SkIRect* cropRect = NULL); + ~SkLightingImageFilter(); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +protected: + SkLightingImageFilter(SkLight* light, + SkScalar surfaceScale, + SkImageFilter* input, + const SkIRect* cropRect = NULL); + explicit SkLightingImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + const SkLight* light() const { return fLight; } + SkScalar surfaceScale() const { return fSurfaceScale; } + +private: + typedef SkImageFilter INHERITED; + SkLight* fLight; + SkScalar fSurfaceScale; +}; + +#endif diff --git a/effects/SkMagnifierImageFilter.h b/effects/SkMagnifierImageFilter.h new file mode 100644 index 0000000..b5cbd74 --- /dev/null +++ b/effects/SkMagnifierImageFilter.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMagnifierImageFilter_DEFINED +#define SkMagnifierImageFilter_DEFINED + +#include "SkRect.h" +#include "SkImageFilter.h" + +class SK_API SkMagnifierImageFilter : public SkImageFilter { +public: + SkMagnifierImageFilter(SkRect srcRect, SkScalar inset); + +#if SK_SUPPORT_GPU + virtual bool asNewEffect(GrEffectRef** effect, GrTexture* texture, const SkIPoint& offset) const SK_OVERRIDE; +#endif + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMagnifierImageFilter) + +protected: + explicit SkMagnifierImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; + +private: + SkRect fSrcRect; + SkScalar fInset; + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkMatrixConvolutionImageFilter.h b/effects/SkMatrixConvolutionImageFilter.h new file mode 100644 index 0000000..71c8938 --- /dev/null +++ b/effects/SkMatrixConvolutionImageFilter.h @@ -0,0 +1,86 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMatrixConvolutionImageFilter_DEFINED +#define SkMatrixConvolutionImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkScalar.h" +#include "SkSize.h" +#include "SkPoint.h" + +/*! \class SkMatrixConvolutionImageFilter + Matrix convolution image filter. This filter applies an NxM image + processing kernel to a given input image. This can be used to produce + effects such as sharpening, blurring, edge detection, etc. + */ + +class SK_API SkMatrixConvolutionImageFilter : public SkImageFilter { +public: + /*! \enum TileMode */ + enum TileMode { + kClamp_TileMode, /*!< Clamp to the image's edge pixels. */ + kRepeat_TileMode, /*!< Wrap around to the image's opposite edge. */ + kClampToBlack_TileMode, /*!< Fill with transparent black. */ + }; + + /** Construct a matrix convolution image filter. + @param kernelSize The kernel size in pixels, in each dimension (N by M). + @param kernel The image processing kernel. Must contain N * M + elements, in row order. + @param gain A scale factor applied to each pixel after + convolution. This can be used to normalize the + kernel, if it does not sum to 1. + @param bias A bias factor added to each pixel after convolution. + @param target An offset applied to each pixel coordinate before + convolution. This can be used to center the kernel + over the image (e.g., a 3x3 kernel should have a + target of {1, 1}). + @param tileMode How accesses outside the image are treated. (@see + TileMode). + @param convolveAlpha If true, all channels are convolved. If false, + only the RGB channels are convolved, and + alpha is copied from the source image. + @param input The input image filter. If NULL, the src bitmap + passed to filterImage() is used instead. + */ + + SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input = NULL); + virtual ~SkMatrixConvolutionImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter) + +protected: + SkMatrixConvolutionImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + +#if SK_SUPPORT_GPU + virtual bool asNewEffect(GrEffectRef** effect, GrTexture*, const SkIPoint& offset) const SK_OVERRIDE; +#endif + +private: + SkISize fKernelSize; + SkScalar* fKernel; + SkScalar fGain; + SkScalar fBias; + SkIPoint fTarget; + TileMode fTileMode; + bool fConvolveAlpha; + typedef SkImageFilter INHERITED; + + template <class PixelFetcher, bool convolveAlpha> + void filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect); + template <class PixelFetcher> + void filterPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect); + void filterInteriorPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect); + void filterBorderPixels(const SkBitmap& src, SkBitmap* result, const SkIRect& rect); +}; + +#endif diff --git a/effects/SkMergeImageFilter.h b/effects/SkMergeImageFilter.h new file mode 100755 index 0000000..8c4313d --- /dev/null +++ b/effects/SkMergeImageFilter.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMergeImageFilter_DEFINED +#define SkMergeImageFilter_DEFINED + +#include "SkImageFilter.h" + +#include "SkXfermode.h" + +class SK_API SkMergeImageFilter : public SkImageFilter { +public: + SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second, + SkXfermode::Mode = SkXfermode::kSrcOver_Mode); + SkMergeImageFilter(SkImageFilter* filters[], int count, + const SkXfermode::Mode modes[] = NULL); + virtual ~SkMergeImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMergeImageFilter) + +protected: + SkMergeImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE; + +private: + uint8_t* fModes; // SkXfermode::Mode + + // private storage, to avoid dynamically allocating storage for our copy + // of the modes (unless the count is so large we can't fit). + intptr_t fStorage[16]; + + void initAllocModes(); + void initModes(const SkXfermode::Mode []); + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkMorphologyImageFilter.h b/effects/SkMorphologyImageFilter.h new file mode 100644 index 0000000..def01e8 --- /dev/null +++ b/effects/SkMorphologyImageFilter.h @@ -0,0 +1,75 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMorphologyImageFilter_DEFINED +#define SkMorphologyImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkSize.h" + +class SK_API SkMorphologyImageFilter : public SkImageFilter { +public: + SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input); + +protected: + SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; } +#endif + + SkISize radius() const { return fRadius; } + +private: + SkISize fRadius; + typedef SkImageFilter INHERITED; +}; + +class SK_API SkDilateImageFilter : public SkMorphologyImageFilter { +public: + SkDilateImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL) + : INHERITED(radiusX, radiusY, input) {} + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#endif + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter) + +protected: + SkDilateImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + typedef SkMorphologyImageFilter INHERITED; +}; + +class SK_API SkErodeImageFilter : public SkMorphologyImageFilter { +public: + SkErodeImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL) + : INHERITED(radiusX, radiusY, input) {} + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#endif + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter) + +protected: + SkErodeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + +private: + typedef SkMorphologyImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkOffsetImageFilter.h b/effects/SkOffsetImageFilter.h new file mode 100644 index 0000000..62b5fa6 --- /dev/null +++ b/effects/SkOffsetImageFilter.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOffsetImageFilter_DEFINED +#define SkOffsetImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkPoint.h" + +class SK_API SkOffsetImageFilter : public SkImageFilter { +public: + SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkImageFilter* input = NULL); + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOffsetImageFilter) + +protected: + SkOffsetImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE; + +private: + SkVector fOffset; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkPaintFlagsDrawFilter.h b/effects/SkPaintFlagsDrawFilter.h new file mode 100644 index 0000000..cb2a8b7 --- /dev/null +++ b/effects/SkPaintFlagsDrawFilter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPaintFlagsDrawFilter_DEFINED +#define SkPaintFlagsDrawFilter_DEFINED + +#include "SkDrawFilter.h" + +class SK_API SkPaintFlagsDrawFilter : public SkDrawFilter { +public: + SkPaintFlagsDrawFilter(uint32_t clearFlags, uint32_t setFlags); + + virtual bool filter(SkPaint*, Type) SK_OVERRIDE; + +private: + uint16_t fClearFlags; // user specified + uint16_t fSetFlags; // user specified +}; + +#endif diff --git a/effects/SkPerlinNoiseShader.h b/effects/SkPerlinNoiseShader.h new file mode 100644 index 0000000..22cb892 --- /dev/null +++ b/effects/SkPerlinNoiseShader.h @@ -0,0 +1,111 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPerlinNoiseShader_DEFINED +#define SkPerlinNoiseShader_DEFINED + +#include "SkShader.h" + +/** \class SkPerlinNoiseShader + + SkPerlinNoiseShader creates an image using the Perlin turbulence function. + + It can produce tileable noise if asked to stitch tiles and provided a tile size. + In order to fill a large area with repeating noise, set the stitchTiles flag to + true, and render exactly a single tile of noise. Without this flag, the result + will contain visible seams between tiles. + + The algorithm used is described here : + http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement +*/ +class SK_API SkPerlinNoiseShader : public SkShader { + struct PaintingData; +public: + struct StitchData; + + /** + * About the noise types : the difference between the 2 is just minor tweaks to the algorithm, + * they're not 2 entirely different noises. The output looks different, but once the noise is + * generated in the [1, -1] range, the output is brought back in the [0, 1] range by doing : + * kFractalNoise_Type : noise * 0.5 + 0.5 + * kTurbulence_Type : abs(noise) + * Very little differences between the 2 types, although you can tell the difference visually. + */ + enum Type { + kFractalNoise_Type, + kTurbulence_Type, + kFirstType = kFractalNoise_Type, + kLastType = kTurbulence_Type + }; + /** + * This will construct Perlin noise of the given type (Fractal Noise or Turbulence). + * + * Both base frequencies (X and Y) have a usual range of (0..1). + * + * The number of octaves provided should be fairly small, although no limit is enforced. + * Each octave doubles the frequency, so 10 octaves would produce noise from + * baseFrequency * 1, * 2, * 4, ..., * 512, which quickly yields insignificantly small + * periods and resembles regular unstructured noise rather than Perlin noise. + * + * If tileSize isn't NULL or an empty size, the tileSize parameter will be used to modify + * the frequencies so that the noise will be tileable for the given tile size. If tileSize + * is NULL or an empty size, the frequencies will be used as is without modification. + */ + static SkShader* CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = NULL); + static SkShader* CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = NULL); + + virtual bool setContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix); + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE; + + virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShader) + +protected: + SkPerlinNoiseShader(SkFlattenableReadBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, SkScalar baseFrequencyX, + SkScalar baseFrequencyY, int numOctaves, SkScalar seed, + const SkISize* tileSize = NULL); + virtual ~SkPerlinNoiseShader(); + + void setTileSize(const SkISize&); + + void initPaint(PaintingData& paintingData); + + SkScalar noise2D(int channel, const PaintingData& paintingData, + const StitchData& stitchData, const SkPoint& noiseVector); + + SkScalar calculateTurbulenceValueForPoint(int channel, const PaintingData& paintingData, + StitchData& stitchData, const SkPoint& point); + + SkPMColor shade(const SkPoint& point, StitchData& stitchData); + + SkPerlinNoiseShader::Type fType; + SkScalar fBaseFrequencyX; + SkScalar fBaseFrequencyY; + int fNumOctaves; + SkScalar fSeed; + SkISize fTileSize; + bool fStitchTiles; + SkMatrix fMatrix; + + PaintingData* fPaintingData; + + typedef SkShader INHERITED; +}; + +#endif diff --git a/effects/SkPixelXorXfermode.h b/effects/SkPixelXorXfermode.h new file mode 100644 index 0000000..5411b12 --- /dev/null +++ b/effects/SkPixelXorXfermode.h @@ -0,0 +1,38 @@ +/* + * Copyright 2007 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPixelXorXfermode_DEFINED +#define SkPixelXorXfermode_DEFINED + +#include "SkXfermode.h" + +/** SkPixelXorXfermode implements a simple pixel xor (op ^ src ^ dst). + This transformation does not follow premultiplied conventions, therefore + this proc *always* returns an opaque color (alpha == 255). Thus it is + not really usefull for operating on blended colors. +*/ +class SK_API SkPixelXorXfermode : public SkXfermode { +public: + SkPixelXorXfermode(SkColor opColor) : fOpColor(opColor) {} + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPixelXorXfermode) + +protected: + SkPixelXorXfermode(SkFlattenableReadBuffer& rb); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + // override from SkXfermode + virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const; + +private: + SkColor fOpColor; + + typedef SkXfermode INHERITED; +}; + +#endif diff --git a/effects/SkPorterDuff.h b/effects/SkPorterDuff.h new file mode 100644 index 0000000..c5f5492 --- /dev/null +++ b/effects/SkPorterDuff.h @@ -0,0 +1,81 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPorterDuff_DEFINED +#define SkPorterDuff_DEFINED + +#include "SkColor.h" +#include "SkXfermode.h" + +class SkXfermode; + +/** DEPRECATED - use SkXfermode::Mode instead + */ +class SK_API 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)] + kModulate_Mode, //!< [Sa * Da, Sc * Dc] multiplies all components + kScreen_Mode, //!< [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] + kAdd_Mode, //!< Saturate(S + D) +#ifdef SK_BUILD_FOR_ANDROID + kOverlay_Mode, +#endif + + 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); + + /** Return the corersponding SkXfermode::Mode + */ + static SkXfermode::Mode ToXfermodeMode(Mode); +}; + +#endif diff --git a/effects/SkRectShaderImageFilter.h b/effects/SkRectShaderImageFilter.h new file mode 100644 index 0000000..a71ee42 --- /dev/null +++ b/effects/SkRectShaderImageFilter.h @@ -0,0 +1,43 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRectShaderImageFilter_DEFINED +#define SkRectShaderImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkRect.h" + +class SkShader; + +class SK_API SkRectShaderImageFilter : public SkImageFilter { +public: + /** + * The SkShader object will have its refcnt increased as it becomes a member of the + * SkRectShaderImageFilter object returned by this function. It cannot be NULL. + * The region parameter is used to specify on which region the shader is applied. + */ + static SkRectShaderImageFilter* Create(SkShader* s, const SkRect& rect); + virtual ~SkRectShaderImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRectShaderImageFilter) + +protected: + SkRectShaderImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + +private: + SkRectShaderImageFilter(SkShader* s, const SkRect& rect); + SkShader* fShader; + SkRect fRect; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkStippleMaskFilter.h b/effects/SkStippleMaskFilter.h new file mode 100644 index 0000000..8f6d20d --- /dev/null +++ b/effects/SkStippleMaskFilter.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkStippleMaskFilter_DEFINED +#define SkStippleMaskFilter_DEFINED + +#include "SkMaskFilter.h" + +/** + * Simple MaskFilter that creates a screen door stipple pattern. + */ +class SK_API SkStippleMaskFilter : public SkMaskFilter { +public: + SkStippleMaskFilter() : INHERITED() { + } + + virtual bool filterMask(SkMask* dst, const SkMask& src, + const SkMatrix& matrix, + SkIPoint* margin) const SK_OVERRIDE; + + // getFormat is from SkMaskFilter + virtual SkMask::Format getFormat() const SK_OVERRIDE { + return SkMask::kA8_Format; + } + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkStippleMaskFilter); + +protected: + SkStippleMaskFilter(SkFlattenableReadBuffer& buffer) + : SkMaskFilter(buffer) { + } + +private: + typedef SkMaskFilter INHERITED; +}; + +#endif // SkStippleMaskFilter_DEFINED diff --git a/effects/SkTableColorFilter.h b/effects/SkTableColorFilter.h new file mode 100644 index 0000000..5714d07 --- /dev/null +++ b/effects/SkTableColorFilter.h @@ -0,0 +1,36 @@ + +#ifndef SkTableColorFilter_DEFINED +#define SkTableColorFilter_DEFINED + +#include "SkColorFilter.h" + +class SK_API SkTableColorFilter { +public: + /** + * Create a table colorfilter, copying the table into the filter, and + * applying it to all 4 components. + * a' = table[a]; + * r' = table[r]; + * g' = table[g]; + * b' = table[b]; + * Compoents are operated on in unpremultiplied space. If the incomming + * colors are premultiplied, they are temporarily unpremultiplied, then + * the table is applied, and then the result is remultiplied. + */ + static SkColorFilter* Create(const uint8_t table[256]); + + /** + * Create a table colorfilter, with a different table for each + * component [A, R, G, B]. If a given table is NULL, then it is + * treated as identity, with the component left unchanged. If a table + * is not null, then its contents are copied into the filter. + */ + static SkColorFilter* CreateARGB(const uint8_t tableA[256], + const uint8_t tableR[256], + const uint8_t tableG[256], + const uint8_t tableB[256]); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +}; + +#endif diff --git a/effects/SkTableMaskFilter.h b/effects/SkTableMaskFilter.h new file mode 100644 index 0000000..ac33266 --- /dev/null +++ b/effects/SkTableMaskFilter.h @@ -0,0 +1,63 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTableMaskFilter_DEFINED +#define SkTableMaskFilter_DEFINED + +#include "SkMaskFilter.h" +#include "SkScalar.h" + +/** \class SkTableMaskFilter + + Applies a table lookup on each of the alpha values in the mask. + Helper methods create some common tables (e.g. gamma, clipping) + */ +class SK_API SkTableMaskFilter : public SkMaskFilter { +public: + SkTableMaskFilter(); + SkTableMaskFilter(const uint8_t table[256]); + virtual ~SkTableMaskFilter(); + + /** Utility that sets the gamma table + */ + static void MakeGammaTable(uint8_t table[256], SkScalar gamma); + + /** Utility that creates a clipping table: clamps values below min to 0 + and above max to 255, and rescales the remaining into 0..255 + */ + static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); + + static SkTableMaskFilter* CreateGamma(SkScalar gamma) { + uint8_t table[256]; + MakeGammaTable(table, gamma); + return SkNEW_ARGS(SkTableMaskFilter, (table)); + } + + static SkTableMaskFilter* CreateClip(uint8_t min, uint8_t max) { + uint8_t table[256]; + MakeClipTable(table, min, max); + return SkNEW_ARGS(SkTableMaskFilter, (table)); + } + + virtual SkMask::Format getFormat() const SK_OVERRIDE; + virtual bool filterMask(SkMask*, const SkMask&, const SkMatrix&, + SkIPoint*) const SK_OVERRIDE; + + SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTableMaskFilter) + +protected: + SkTableMaskFilter(SkFlattenableReadBuffer& rb); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + uint8_t fTable[256]; + + typedef SkMaskFilter INHERITED; +}; + +#endif diff --git a/effects/SkTestImageFilters.h b/effects/SkTestImageFilters.h new file mode 100755 index 0000000..e848ff1 --- /dev/null +++ b/effects/SkTestImageFilters.h @@ -0,0 +1,27 @@ +#ifndef _SkTestImageFilters_h +#define _SkTestImageFilters_h + +#include "SkImageFilter.h" +#include "SkPoint.h" + +// Fun mode that scales down (only) and then scales back up to look pixelated +class SK_API SkDownSampleImageFilter : public SkImageFilter { +public: + SkDownSampleImageFilter(SkScalar scale) : INHERITED(0), fScale(scale) {} + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDownSampleImageFilter) + +protected: + SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, + SkBitmap* result, SkIPoint* loc) SK_OVERRIDE; + +private: + SkScalar fScale; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/effects/SkTransparentShader.h b/effects/SkTransparentShader.h new file mode 100644 index 0000000..bee9a02 --- /dev/null +++ b/effects/SkTransparentShader.h @@ -0,0 +1,37 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTransparentShader_DEFINED +#define SkTransparentShader_DEFINED + +#include "SkShader.h" + +class SK_API SkTransparentShader : public SkShader { +public: + SkTransparentShader() {} + + virtual uint32_t getFlags() SK_OVERRIDE; + virtual bool setContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix) SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + + SK_DEVELOPER_TO_STRING() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTransparentShader) + +private: + // these are a cache from the call to setContext() + const SkBitmap* fDevice; + uint8_t fAlpha; + + SkTransparentShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + + typedef SkShader INHERITED; +}; + +#endif diff --git a/effects/SkXfermodeImageFilter.h b/effects/SkXfermodeImageFilter.h new file mode 100644 index 0000000..89a2773 --- /dev/null +++ b/effects/SkXfermodeImageFilter.h @@ -0,0 +1,51 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkXfermodeImageFilter_DEFINED +#define SkXfermodeImageFilter_DEFINED + +#include "SkImageFilter.h" + +class SkBitmap; +class SkXfermode; + +class SK_API SkXfermodeImageFilter : public SkImageFilter { + /** + * This filter takes an xfermode, and uses it to composite the foreground + * over the background. If foreground or background is NULL, the input + * bitmap (src) is used instead. + */ + +public: + SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background, + SkImageFilter* foreground = NULL); + + virtual ~SkXfermodeImageFilter(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkXfermodeImageFilter) + + virtual bool onFilterImage(Proxy* proxy, + const SkBitmap& src, + const SkMatrix& ctm, + SkBitmap* dst, + SkIPoint* offset) SK_OVERRIDE; +#if SK_SUPPORT_GPU + virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; } + virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; +#endif + +protected: + explicit SkXfermodeImageFilter(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkXfermode* fMode; + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/gpu/GrAARectRenderer.h b/gpu/GrAARectRenderer.h new file mode 100644 index 0000000..607329a --- /dev/null +++ b/gpu/GrAARectRenderer.h @@ -0,0 +1,114 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrAARectRenderer_DEFINED +#define GrAARectRenderer_DEFINED + +#include "GrRefCnt.h" +#include "SkMatrix.h" +#include "SkRect.h" + +class GrGpu; +class GrDrawTarget; +class GrIndexBuffer; + +/* + * This class wraps helper functions that draw AA rects (filled & stroked) + */ +class GrAARectRenderer : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrAARectRenderer) + + GrAARectRenderer() + : fAAFillRectIndexBuffer(NULL) + , fAAStrokeRectIndexBuffer(NULL) { + } + + void reset(); + + ~GrAARectRenderer() { + this->reset(); + } + + // TODO: potentialy fuse the fill & stroke methods and differentiate + // between them by passing in strokeWidth (<0 means fill). + + void fillAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& rect, + const SkMatrix& combinedMatrix, + const SkRect& devRect, + bool useVertexCoverage) { +#ifdef SHADER_AA_FILL_RECT + if (combinedMatrix.rectStaysRect()) { + this->shaderFillAlignedAARect(gpu, target, + rect, combinedMatrix); + } else { + this->shaderFillAARect(gpu, target, + rect, combinedMatrix); + } +#else + this->geometryFillAARect(gpu, target, + rect, combinedMatrix, + devRect, useVertexCoverage); +#endif + } + + void strokeAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& rect, + const SkMatrix& combinedMatrix, + const SkRect& devRect, + SkScalar width, + bool useVertexCoverage); + + // First rect is outer; second rect is inner + void fillAANestedRects(GrGpu* gpu, + GrDrawTarget* target, + const SkRect rects[2], + const SkMatrix& combinedMatrix, + bool useVertexCoverage); + +private: + GrIndexBuffer* fAAFillRectIndexBuffer; + GrIndexBuffer* fAAStrokeRectIndexBuffer; + + GrIndexBuffer* aaFillRectIndexBuffer(GrGpu* gpu); + + static int aaStrokeRectIndexCount(); + GrIndexBuffer* aaStrokeRectIndexBuffer(GrGpu* gpu); + + // TODO: Remove the useVertexCoverage boolean. Just use it all the time + // since we now have a coverage vertex attribute + void geometryFillAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& rect, + const SkMatrix& combinedMatrix, + const SkRect& devRect, + bool useVertexCoverage); + + void shaderFillAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& rect, + const SkMatrix& combinedMatrix); + + void shaderFillAlignedAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& rect, + const SkMatrix& combinedMatrix); + + void geometryStrokeAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& devOutside, + const SkRect& devInside, + bool useVertexCoverage); + + typedef GrRefCnt INHERITED; +}; + +#endif // GrAARectRenderer_DEFINED diff --git a/gpu/GrBackendEffectFactory.h b/gpu/GrBackendEffectFactory.h new file mode 100644 index 0000000..2811443 --- /dev/null +++ b/gpu/GrBackendEffectFactory.h @@ -0,0 +1,86 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendEffectFactory_DEFINED +#define GrBackendEffectFactory_DEFINED + +#include "GrTypes.h" +#include "SkTemplates.h" +#include "SkThread_platform.h" +#include "GrNoncopyable.h" + +/** Given a GrEffect of a particular type, creates the corresponding graphics-backend-specific + effect object. Also tracks equivalence of shaders generated via a key. Each factory instance + is assigned a generation ID at construction. The ID of the return of GrEffect::getFactory() + is used as a type identifier. Thus a GrEffect subclass must return a singleton from + getFactory(). GrEffect subclasses should use the derived class GrTBackendEffectFactory that is + templated on the GrEffect subclass as their factory object. It requires that the GrEffect + subclass has a nested class (or typedef) GLEffect which is its GL implementation and a subclass + of GrGLEffect. + */ + +class GrEffectRef; +class GrGLEffect; +class GrGLCaps; +class GrDrawEffect; + +class GrBackendEffectFactory : public GrNoncopyable { +public: + typedef uint32_t EffectKey; + enum { + kNoEffectKey = 0, + kEffectKeyBits = 15, + /** + * Some aspects of the generated code may be determined by the particular textures that are + * associated with the effect. These manipulations are performed by GrGLShaderBuilder beyond + * GrGLEffects' control. So there is a dedicated part of the key which is combined + * automatically with the bits produced by GrGLEffect::GenKey(). + */ + kTextureKeyBits = 6, + kAttribKeyBits = 6 + }; + + virtual EffectKey glEffectKey(const GrDrawEffect&, const GrGLCaps&) const = 0; + virtual GrGLEffect* createGLInstance(const GrDrawEffect&) const = 0; + + bool operator ==(const GrBackendEffectFactory& b) const { + return fEffectClassID == b.fEffectClassID; + } + bool operator !=(const GrBackendEffectFactory& b) const { + return !(*this == b); + } + + virtual const char* name() const = 0; + +protected: + enum { + kIllegalEffectClassID = 0, + }; + + GrBackendEffectFactory() { + fEffectClassID = kIllegalEffectClassID; + } + virtual ~GrBackendEffectFactory() {} + + static EffectKey GenID() { + GR_DEBUGCODE(static const int32_t kClassIDBits = 8 * sizeof(EffectKey) - + kTextureKeyBits - kEffectKeyBits - kAttribKeyBits); + // fCurrEffectClassID has been initialized to kIllegalEffectClassID. The + // atomic inc returns the old value not the incremented value. So we add + // 1 to the returned value. + int32_t id = sk_atomic_inc(&fCurrEffectClassID) + 1; + GrAssert(id < (1 << kClassIDBits)); + return static_cast<EffectKey>(id); + } + + EffectKey fEffectClassID; + +private: + static int32_t fCurrEffectClassID; +}; + +#endif diff --git a/gpu/GrClipData.h b/gpu/GrClipData.h new file mode 100644 index 0000000..bced741 --- /dev/null +++ b/gpu/GrClipData.h @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrClip_DEFINED +#define GrClip_DEFINED + +#include "SkClipStack.h" + +class GrSurface; +struct SkIRect; + +/** + * GrClipData encapsulates the information required to construct the clip + * masks. 'fOrigin' is only non-zero when saveLayer has been called + * with an offset bounding box. The clips in 'fClipStack' are in + * device coordinates (i.e., they have been translated by -fOrigin w.r.t. + * the canvas' device coordinates). + */ +class GrClipData : public SkNoncopyable { +public: + const SkClipStack* fClipStack; + SkIPoint fOrigin; + + GrClipData() + : fClipStack(NULL) { + fOrigin.setZero(); + } + + bool operator==(const GrClipData& other) const { + if (fOrigin != other.fOrigin) { + return false; + } + + if (NULL != fClipStack && NULL != other.fClipStack) { + return *fClipStack == *other.fClipStack; + } + + return fClipStack == other.fClipStack; + } + + bool operator!=(const GrClipData& other) const { + return !(*this == other); + } + + void getConservativeBounds(const GrSurface* surface, + SkIRect* devResult, + bool* isIntersectionOfRects = NULL) const; +}; + +#endif diff --git a/gpu/GrColor.h b/gpu/GrColor.h new file mode 100644 index 0000000..3ded8fb --- /dev/null +++ b/gpu/GrColor.h @@ -0,0 +1,127 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrColor_DEFINED +#define GrColor_DEFINED + +#include "GrTypes.h" + +/** + * GrColor is 4 bytes for R, G, B, A, in a compile-time specific order. The + * components are stored premultiplied. + */ +typedef uint32_t GrColor; + + +// shift amount to assign a component to a GrColor int +// These shift values are chosen for compatibility with GL attrib arrays +// ES doesn't allow BGRA vertex attrib order so if they were not in this order +// we'd have to swizzle in shaders. Note the assumption that the cpu is little +// endian. +#define GrColor_SHIFT_R 0 +#define GrColor_SHIFT_G 8 +#define GrColor_SHIFT_B 16 +#define GrColor_SHIFT_A 24 + +/** + * Pack 4 components (RGBA) into a GrColor int + */ +static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, + unsigned b, unsigned a) { + GrAssert((uint8_t)r == r); + GrAssert((uint8_t)g == g); + GrAssert((uint8_t)b == b); + GrAssert((uint8_t)a == a); + return (r << GrColor_SHIFT_R) | + (g << GrColor_SHIFT_G) | + (b << GrColor_SHIFT_B) | + (a << GrColor_SHIFT_A); +} + +// extract a component (byte) from a GrColor int + +#define GrColorUnpackR(color) (((color) >> GrColor_SHIFT_R) & 0xFF) +#define GrColorUnpackG(color) (((color) >> GrColor_SHIFT_G) & 0xFF) +#define GrColorUnpackB(color) (((color) >> GrColor_SHIFT_B) & 0xFF) +#define GrColorUnpackA(color) (((color) >> GrColor_SHIFT_A) & 0xFF) + +/** + * Since premultiplied means that alpha >= color, we construct a color with + * each component==255 and alpha == 0 to be "illegal" + */ +#define GrColor_ILLEGAL (~(0xFF << GrColor_SHIFT_A)) + +/** Converts a GrColor to an rgba array of GrGLfloat */ +static inline void GrColorToRGBAFloat(GrColor color, float rgba[4]) { + static const float ONE_OVER_255 = 1.f / 255.f; + rgba[0] = GrColorUnpackR(color) * ONE_OVER_255; + rgba[1] = GrColorUnpackG(color) * ONE_OVER_255; + rgba[2] = GrColorUnpackB(color) * ONE_OVER_255; + rgba[3] = GrColorUnpackA(color) * ONE_OVER_255; +} + +/** + * Flags used for bitfields of color components. They are defined so that the bit order reflects the + * GrColor shift order. + */ +enum GrColorComponentFlags { + kR_GrColorComponentFlag = 1 << (GrColor_SHIFT_R / 8), + kG_GrColorComponentFlag = 1 << (GrColor_SHIFT_G / 8), + kB_GrColorComponentFlag = 1 << (GrColor_SHIFT_B / 8), + kA_GrColorComponentFlag = 1 << (GrColor_SHIFT_A / 8), + + kRGB_GrColorComponentFlags = (kR_GrColorComponentFlag | kG_GrColorComponentFlag | + kB_GrColorComponentFlag), + + kRGBA_GrColorComponentFlags = (kR_GrColorComponentFlag | kG_GrColorComponentFlag | + kB_GrColorComponentFlag | kA_GrColorComponentFlag) +}; + +static inline char GrColorComponentFlagToChar(GrColorComponentFlags component) { + GrAssert(GrIsPow2(component)); + switch (component) { + case kR_GrColorComponentFlag: + return 'r'; + case kG_GrColorComponentFlag: + return 'g'; + case kB_GrColorComponentFlag: + return 'b'; + case kA_GrColorComponentFlag: + return 'a'; + default: + GrCrash("Invalid color component flag."); + return '\0'; + } +} + +static inline uint32_t GrPixelConfigComponentMask(GrPixelConfig config) { + GrAssert(config >= 0 && config < kGrPixelConfigCnt); + static const uint32_t kFlags[] = { + 0, // kUnknown_GrPixelConfig + kA_GrColorComponentFlag, // kAlpha_8_GrPixelConfig + kRGBA_GrColorComponentFlags, // kIndex_8_GrPixelConfig + kRGB_GrColorComponentFlags, // kRGB_565_GrPixelConfig + kRGBA_GrColorComponentFlags, // kRGBA_4444_GrPixelConfig + kRGBA_GrColorComponentFlags, // kRGBA_8888_GrPixelConfig + kRGBA_GrColorComponentFlags, // kBGRA_8888_GrPixelConfig + }; + return kFlags[config]; + + GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); + GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); + GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); + GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); + GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); + GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); + GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); + GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFlags) == kGrPixelConfigCnt); +} + +#endif diff --git a/gpu/GrConfig.h b/gpu/GrConfig.h new file mode 100644 index 0000000..95e518a --- /dev/null +++ b/gpu/GrConfig.h @@ -0,0 +1,387 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrConfig_DEFINED +#define GrConfig_DEFINED + +#include "SkTypes.h" + +/////////////////////////////////////////////////////////////////////////////// +// preconfig section: +// +// All the work before including GrUserConfig.h should center around guessing +// what platform we're on, and defining low-level symbols based on that. +// +// A build environment may have already defined symbols, so we first check +// for that +// + +// hack to ensure we know what sort of Apple platform we're on +#if defined(__APPLE_CPP__) || defined(__APPLE_CC__) + #include <TargetConditionals.h> +#endif + +/** + * Gr defines are set to 0 or 1, rather than being undefined or defined + */ + +#if !defined(GR_ANDROID_BUILD) + #define GR_ANDROID_BUILD 0 +#endif +#if !defined(GR_IOS_BUILD) + #define GR_IOS_BUILD 0 +#endif +#if !defined(GR_LINUX_BUILD) + #define GR_LINUX_BUILD 0 +#endif +#if !defined(GR_MAC_BUILD) + #define GR_MAC_BUILD 0 +#endif +#if !defined(GR_WIN32_BUILD) + #define GR_WIN32_BUILD 0 +#endif +#if !defined(GR_QNX_BUILD) + #define GR_QNX_BUILD 0 +#endif +#if !defined(GR_CACHE_STATS) + #define GR_CACHE_STATS 0 +#endif + +/** + * If no build target has been defined, attempt to infer. + */ +#if !GR_ANDROID_BUILD && !GR_IOS_BUILD && !GR_LINUX_BUILD && !GR_MAC_BUILD && !GR_WIN32_BUILD && !GR_QNX_BUILD + #if defined(_WIN32) + #undef GR_WIN32_BUILD + #define GR_WIN32_BUILD 1 +// #error "WIN" + #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #undef GR_IOS_BUILD + #define GR_IOS_BUILD 1 +// #error "IOS" + #elif defined(SK_BUILD_FOR_ANDROID) + #undef GR_ANDROID_BUILD + #define GR_ANDROID_BUILD 1 +// #error "ANDROID" + #elif TARGET_OS_MAC + #undef GR_MAC_BUILD + #define GR_MAC_BUILD 1 +// #error "MAC" + #elif TARGET_OS_QNX || defined(__QNXNTO__) + #undef GR_QNX_BUILD + #define GR_QNX_BUILD 1 +// #error "QNX" + #else + #undef GR_LINUX_BUILD + #define GR_LINUX_BUILD 1 +// #error "LINUX" + #endif +#endif + +// we need both GR_DEBUG and GR_RELEASE to be defined as 0 or 1 +// +#ifndef GR_DEBUG + #ifdef GR_RELEASE + #define GR_DEBUG !GR_RELEASE + #else + #ifdef NDEBUG + #define GR_DEBUG 0 + #else + #define GR_DEBUG 1 + #endif + #endif +#endif + +#ifndef GR_RELEASE + #define GR_RELEASE !GR_DEBUG +#endif + +#if GR_DEBUG == GR_RELEASE + #error "GR_DEBUG and GR_RELEASE must not be the same" +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#if GR_WIN32_BUILD +// VC8 doesn't support stdint.h, so we define those types here. +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* + * Include stdint.h with defines that trigger declaration of C99 limit/const + * macros here before anyone else has a chance to include stdint.h without + * these. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +#include <stdint.h> +#endif + +/* + * The "user config" file can be empty, and everything should work. It is + * meant to store a given platform/client's overrides of our guess-work. + * + * A alternate user config file can be specified by defining + * GR_USER_CONFIG_FILE. It should be defined relative to GrConfig.h + * + * e.g. it can specify GR_DEBUG/GR_RELEASE as it please, change the BUILD + * target, or supply its own defines for anything else (e.g. GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT) + */ +#if !defined(GR_USER_CONFIG_FILE) + #include "GrUserConfig.h" +#else + #include GR_USER_CONFIG_FILE +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// postconfig section: +// + +// GR_IMPLEMENTATION should be define to 1 when building Gr and 0 when including +// it in another dependent build. The Gr makefile/ide-project should define this +// to 1. +#if !defined(GR_IMPLEMENTATION) + #define GR_IMPLEMENTATION 0 +#endif + +// If Gr is built as a shared library then GR_DLL should be defined to 1 (both +// when building Gr and when including its headers in dependent builds). Only +// currently supported minimally for Chrome's Win32 Multi-DLL build (TODO: +// correctly exort all of the public API correctly and support shared lib on +// other platforms). +#if !defined(GR_DLL) + #define GR_DLL 0 +#endif + +#if GR_DLL + #if GR_WIN32_BUILD + #if GR_IMPLEMENTATION + #define GR_API __declspec(dllexport) + #else + #define GR_API __declspec(dllimport) + #endif + #else + #define GR_API __attribute__((visibility("default"))) + #endif +#else + #define GR_API +#endif + +// By now we must have a GR_..._BUILD symbol set to 1, and a decision about +// debug -vs- release +// + +#define GrPrintf SkDebugf + +/** + * GR_STRING makes a string of X where X is expanded before conversion to a string + * if X itself contains macros. + */ +#define GR_STRING(X) GR_STRING_IMPL(X) +#define GR_STRING_IMPL(X) #X + +/** + * GR_CONCAT concatenates X and Y where each is expanded before + * contanenation if either contains macros. + */ +#define GR_CONCAT(X,Y) GR_CONCAT_IMPL(X,Y) +#define GR_CONCAT_IMPL(X,Y) X##Y + +/** + * Creates a string of the form "<filename>(<linenumber>) : " + */ +#define GR_FILE_AND_LINE_STR __FILE__ "(" GR_STRING(__LINE__) ") : " + +/** + * Compilers have different ways of issuing warnings. This macro + * attempts to abstract them, but may need to be specialized for your + * particular compiler. + * To insert compiler warnings use "#pragma message GR_WARN(<string>)" + */ +#if defined(_MSC_VER) && _MSC_VER + #define GR_WARN(MSG) (GR_FILE_AND_LINE_STR "WARNING: " MSG) +#else//__GNUC__ - may need other defines for different compilers + #define GR_WARN(MSG) ("WARNING: " MSG) +#endif + +/** + * GR_ALWAYSBREAK is an unconditional break in all builds. + */ +#if !defined(GR_ALWAYSBREAK) + #if GR_WIN32_BUILD + #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); __debugbreak() + #else + // TODO: do other platforms really not have continuable breakpoints? + // sign extend for 64bit architectures to be sure this is + // in the high address range + #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); *((int*)(int64_t)(int32_t)0xbeefcafe) = 0; + #endif +#endif + +/** + * GR_DEBUGBREAK is an unconditional break in debug builds. + */ +#if !defined(GR_DEBUGBREAK) + #if GR_DEBUG + #define GR_DEBUGBREAK GR_ALWAYSBREAK + #else + #define GR_DEBUGBREAK + #endif +#endif + +/** + * GR_ALWAYSASSERT is an assertion in all builds. + */ +#if !defined(GR_ALWAYSASSERT) + #define GR_ALWAYSASSERT(COND) \ + do { \ + if (!(COND)) { \ + GrPrintf("%s %s failed\n", GR_FILE_AND_LINE_STR, #COND); \ + GR_ALWAYSBREAK; \ + } \ + } while (false) +#endif + +/** + * GR_DEBUGASSERT is an assertion in debug builds only. + */ +#if !defined(GR_DEBUGASSERT) + #if GR_DEBUG + #define GR_DEBUGASSERT(COND) GR_ALWAYSASSERT(COND) + #else + #define GR_DEBUGASSERT(COND) + #endif +#endif + +/** + * Prettier forms of the above macros. + */ +#define GrAssert(COND) GR_DEBUGASSERT(COND) +#define GrAlwaysAssert(COND) GR_ALWAYSASSERT(COND) + +/** + * Crash from unrecoverable condition, optionally with a message. The debug variants only + * crash in a debug build. The message versions print the message regardless of release vs debug. + */ +inline void GrCrash() { GrAlwaysAssert(false); } +inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); } +inline void GrDebugCrash() { GrAssert(false); } +inline void GrDebugCrash(const char* msg) { GrPrintf(msg); GrAssert(false); } + +/** + * GR_DEBUGCODE compiles the code X in debug builds only + */ +#if !defined(GR_DEBUGCODE) + #if GR_DEBUG + #define GR_DEBUGCODE(X) X + #else + #define GR_DEBUGCODE(X) + #endif +#endif + +/** + * GR_STATIC_ASSERT is a compile time assertion. Depending on the platform + * it may print the message in the compiler log. Obviously, the condition must + * be evaluatable at compile time. + */ +// VS 2010 and GCC compiled with c++0x or gnu++0x support the new +// static_assert. +#if !defined(GR_STATIC_ASSERT) + #if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__) + #define GR_STATIC_ASSERT(CONDITION) static_assert(CONDITION, "bug") + #else + template <bool> class GR_STATIC_ASSERT_FAILURE; + template <> class GR_STATIC_ASSERT_FAILURE<true> {}; + #define GR_STATIC_ASSERT(CONDITION) \ + enum {GR_CONCAT(X,__LINE__) = \ + sizeof(GR_STATIC_ASSERT_FAILURE<CONDITION>)} + #endif +#endif + +/** + * GR_GEOM_BUFFER_LOCK_THRESHOLD gives a threshold (in bytes) for when Gr should + * lock a GrGeometryBuffer to update its contents. It will use lock() if the + * size of the updated region is greater than the threshold. Otherwise it will + * use updateData(). + */ +#if !defined(GR_GEOM_BUFFER_LOCK_THRESHOLD) + #define GR_GEOM_BUFFER_LOCK_THRESHOLD (1 << 15) +#endif + +/** + * GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT gives a threshold (in megabytes) for the + * maximum size of the texture cache in vram. The value is only a default and + * can be overridden at runtime. + */ +#if !defined(GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT) + #define GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT 96 +#endif + +/** + * GR_STROKE_PATH_RENDERING controls whether or not the GrStrokePathRenderer can be selected + * as a path renderer. GrStrokePathRenderer is currently an experimental path renderer. + */ +#if !defined(GR_STROKE_PATH_RENDERING) + #define GR_STROKE_PATH_RENDERING 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// tail section: +// +// Now we just assert if we are missing some required define, or if we detect +// and inconsistent combination of defines +// + + +/** + * Only one build target macro should be 1 and the rest should be 0. + */ +#define GR_BUILD_SUM (GR_WIN32_BUILD + GR_MAC_BUILD + GR_IOS_BUILD + GR_ANDROID_BUILD + GR_LINUX_BUILD + GR_QNX_BUILD) +#if 0 == GR_BUILD_SUM + #error "Missing a GR_BUILD define" +#elif 1 != GR_BUILD_SUM + #error "More than one GR_BUILD defined" +#endif + +#if 0 +#if GR_WIN32_BUILD +// #pragma message GR_WARN("GR_WIN32_BUILD") +#endif +#if GR_MAC_BUILD +// #pragma message GR_WARN("GR_MAC_BUILD") +#endif +#if GR_IOS_BUILD +// #pragma message GR_WARN("GR_IOS_BUILD") +#endif +#if GR_ANDROID_BUILD +// #pragma message GR_WARN("GR_ANDROID_BUILD") +#endif +#if GR_LINUX_BUILD +// #pragma message GR_WARN("GR_LINUX_BUILD") +#endif +#if GR_QNX_BUILD +// #pragma message GR_WARN("GR_QNX_BUILD") +#endif +#endif + +#endif diff --git a/gpu/GrContext.h b/gpu/GrContext.h new file mode 100644 index 0000000..ced251b --- /dev/null +++ b/gpu/GrContext.h @@ -0,0 +1,1021 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContext_DEFINED +#define GrContext_DEFINED + +#include "GrColor.h" +#include "GrAARectRenderer.h" +#include "GrClipData.h" +#include "SkMatrix.h" +#include "GrPaint.h" +#include "GrPathRendererChain.h" +#include "GrPoint.h" +#include "GrRenderTarget.h" +#include "GrRefCnt.h" +#include "GrTexture.h" + +class GrAutoScratchTexture; +class GrDrawState; +class GrDrawTarget; +class GrEffect; +class GrFontCache; +class GrGpu; +class GrIndexBuffer; +class GrIndexBufferAllocPool; +class GrInOrderDrawBuffer; +class GrOvalRenderer; +class GrPathRenderer; +class GrResourceEntry; +class GrResourceCache; +class GrStencilBuffer; +class GrTextureParams; +class GrVertexBuffer; +class GrVertexBufferAllocPool; +class GrSoftwarePathRenderer; +class SkStrokeRec; + +class GR_API GrContext : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrContext) + + /** + * Creates a GrContext for a backend context. + */ + static GrContext* Create(GrBackend, GrBackendContext); + + /** + * Returns the number of GrContext instances for the current thread. + */ + static int GetThreadInstanceCount(); + + virtual ~GrContext(); + + /** + * The GrContext normally assumes that no outsider is setting state + * within the underlying 3D API's context/device/whatever. This call informs + * the context that the state was modified and it should resend. Shouldn't + * be called frequently for good performance. + * The flag bits, state, is dpendent on which backend is used by the + * context, either GL or D3D (possible in future). + */ + void resetContext(uint32_t state = kAll_GrBackendState); + + /** + * Callback function to allow classes to cleanup on GrContext destruction. + * The 'info' field is filled in with the 'info' passed to addCleanUp. + */ + typedef void (*PFCleanUpFunc)(const GrContext* context, void* info); + + /** + * Add a function to be called from within GrContext's destructor. + * This gives classes a chance to free resources held on a per context basis. + * The 'info' parameter will be stored and passed to the callback function. + */ + void addCleanUp(PFCleanUpFunc cleanUp, void* info) { + CleanUpData* entry = fCleanUpData.push(); + + entry->fFunc = cleanUp; + entry->fInfo = info; + } + + /** + * Abandons all GPU resources, assumes 3D API state is unknown. Call this + * if you have lost the associated GPU context, and thus internal texture, + * buffer, etc. references/IDs are now invalid. Should be called even when + * GrContext is no longer going to be used for two reasons: + * 1) ~GrContext will not try to free the objects in the 3D API. + * 2) If you've created GrResources that outlive the GrContext they will + * be marked as invalid (GrResource::isValid()) and won't attempt to + * free their underlying resource in the 3D API. + * Content drawn since the last GrContext::flush() may be lost. + */ + void contextLost(); + + /** + * Similar to contextLost, but makes no attempt to reset state. + * Use this method when GrContext destruction is pending, but + * the graphics context is destroyed first. + */ + void contextDestroyed(); + + /** + * Frees GPU created by the context. Can be called to reduce GPU memory + * pressure. + */ + void freeGpuResources(); + + /** + * Returns the number of bytes of GPU memory hosted by the texture cache. + */ + size_t getGpuTextureCacheBytes() const; + + /////////////////////////////////////////////////////////////////////////// + // Textures + + /** + * Creates a new entry, based on the specified key and texture and returns it. The caller owns a + * ref on the returned texture which must be balanced by a call to unref. + * + * @param params The texture params used to draw a texture may help determine + * the cache entry used. (e.g. different versions may exist + * for different wrap modes on GPUs with limited NPOT + * texture support). NULL implies clamp wrap modes. + * @param desc Description of the texture properties. + * @param cacheID Cache-specific properties (e.g., texture gen ID) + * @param srcData Pointer to the pixel values. + * @param rowBytes The number of bytes between rows of the texture. Zero + * implies tightly packed rows. + */ + GrTexture* createTexture(const GrTextureParams* params, + const GrTextureDesc& desc, + const GrCacheID& cacheID, + void* srcData, size_t rowBytes); + + /** + * Search for an entry based on key and dimensions. If found, ref it and return it. The return + * value will be NULL if not found. The caller must balance with a call to unref. + * + * @param desc Description of the texture properties. + * @param cacheID Cache-specific properties (e.g., texture gen ID) + * @param params The texture params used to draw a texture may help determine + * the cache entry used. (e.g. different versions may exist + * for different wrap modes on GPUs with limited NPOT + * texture support). NULL implies clamp wrap modes. + */ + GrTexture* findAndRefTexture(const GrTextureDesc& desc, + const GrCacheID& cacheID, + const GrTextureParams* params); + /** + * Determines whether a texture is in the cache. If the texture is found it + * will not be locked or returned. This call does not affect the priority of + * the texture for deletion. + */ + bool isTextureInCache(const GrTextureDesc& desc, + const GrCacheID& cacheID, + const GrTextureParams* params) const; + + /** + * Enum that determines how closely a returned scratch texture must match + * a provided GrTextureDesc. + */ + enum ScratchTexMatch { + /** + * Finds a texture that exactly matches the descriptor. + */ + kExact_ScratchTexMatch, + /** + * Finds a texture that approximately matches the descriptor. Will be + * at least as large in width and height as desc specifies. If desc + * specifies that texture is a render target then result will be a + * render target. If desc specifies a render target and doesn't set the + * no stencil flag then result will have a stencil. Format and aa level + * will always match. + */ + kApprox_ScratchTexMatch + }; + + /** + * Returns a texture matching the desc. It's contents are unknown. Subsequent + * requests with the same descriptor are not guaranteed to return the same + * texture. The same texture is guaranteed not be returned again until it is + * unlocked. Call must be balanced with an unlockTexture() call. The caller + * owns a ref on the returned texture and must balance with a call to unref. + * + * Textures created by createAndLockTexture() hide the complications of + * tiling non-power-of-two textures on APIs that don't support this (e.g. + * unextended GLES2). Tiling a NPOT texture created by lockScratchTexture on + * such an API will create gaps in the tiling pattern. This includes clamp + * mode. (This may be addressed in a future update.) + */ + GrTexture* lockAndRefScratchTexture(const GrTextureDesc&, ScratchTexMatch match); + + /** + * When done with an entry, call unlockScratchTexture(entry) on it, which returns + * it to the cache, where it may be purged. This does not unref the texture. + */ + void unlockScratchTexture(GrTexture* texture); + + /** + * This method should be called whenever a GrTexture is unreffed or + * switched from exclusive to non-exclusive. This + * gives the resource cache a chance to discard unneeded textures. + * Note: this entry point will be removed once totally ref-driven + * cache maintenance is implemented + */ + void purgeCache(); + + /** + * Creates a texture that is outside the cache. Does not count against + * cache's budget. + */ + GrTexture* createUncachedTexture(const GrTextureDesc& desc, + void* srcData, + size_t rowBytes); + + /** + * Returns true if the specified use of an indexed texture is supported. + * Support may depend upon whether the texture params indicate that the + * texture will be tiled. Passing NULL for the texture params indicates + * clamp mode. + */ + bool supportsIndex8PixelConfig(const GrTextureParams*, + int width, + int height) const; + + /** + * Return the current texture cache limits. + * + * @param maxTextures If non-null, returns maximum number of textures that + * can be held in the cache. + * @param maxTextureBytes If non-null, returns maximum number of bytes of + * texture memory that can be held in the cache. + */ + void getTextureCacheLimits(int* maxTextures, size_t* maxTextureBytes) const; + + /** + * Specify the texture cache limits. If the current cache exceeds either + * of these, it will be purged (LRU) to keep the cache within these limits. + * + * @param maxTextures The maximum number of textures that can be held in + * the cache. + * @param maxTextureBytes The maximum number of bytes of texture memory + * that can be held in the cache. + */ + void setTextureCacheLimits(int maxTextures, size_t maxTextureBytes); + + /** + * Return the max width or height of a texture supported by the current GPU. + */ + int getMaxTextureSize() const; + + /** + * Temporarily override the true max texture size. Note: an override + * larger then the true max texture size will have no effect. + * This entry point is mainly meant for testing texture size dependent + * features and is only available if defined outside of Skia (see + * bleed GM. + */ + void setMaxTextureSizeOverride(int maxTextureSizeOverride); + + /////////////////////////////////////////////////////////////////////////// + // Render targets + + /** + * Sets the render target. + * @param target the render target to set. + */ + void setRenderTarget(GrRenderTarget* target) { + fRenderTarget.reset(SkSafeRef(target)); + } + + /** + * Gets the current render target. + * @return the currently bound render target. + */ + const GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); } + GrRenderTarget* getRenderTarget() { return fRenderTarget.get(); } + + GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; } + + /** + * Can the provided configuration act as a color render target? + */ + bool isConfigRenderable(GrPixelConfig config) const; + + /** + * Return the max width or height of a render target supported by the + * current GPU. + */ + int getMaxRenderTargetSize() const; + + /** + * Returns the max sample count for a render target. It will be 0 if MSAA + * is not supported. + */ + int getMaxSampleCount() const; + + /////////////////////////////////////////////////////////////////////////// + // Backend Surfaces + + /** + * Wraps an existing texture with a GrTexture object. + * + * OpenGL: if the object is a texture Gr may change its GL texture params + * when it is drawn. + * + * @param desc description of the object to create. + * + * @return GrTexture object or NULL on failure. + */ + GrTexture* wrapBackendTexture(const GrBackendTextureDesc& desc); + + /** + * Wraps an existing render target with a GrRenderTarget object. It is + * similar to wrapBackendTexture but can be used to draw into surfaces + * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that + * the client will resolve to a texture). + * + * @param desc description of the object to create. + * + * @return GrTexture object or NULL on failure. + */ + GrRenderTarget* wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc); + + /////////////////////////////////////////////////////////////////////////// + // Matrix state + + /** + * Gets the current transformation matrix. + * @return the current matrix. + */ + const SkMatrix& getMatrix() const { return fViewMatrix; } + + /** + * Sets the transformation matrix. + * @param m the matrix to set. + */ + void setMatrix(const SkMatrix& m) { fViewMatrix = m; } + + /** + * Sets the current transformation matrix to identity. + */ + void setIdentityMatrix() { fViewMatrix.reset(); } + + /** + * Concats the current matrix. The passed matrix is applied before the + * current matrix. + * @param m the matrix to concat. + */ + void concatMatrix(const SkMatrix& m) { fViewMatrix.preConcat(m); } + + + /////////////////////////////////////////////////////////////////////////// + // Clip state + /** + * Gets the current clip. + * @return the current clip. + */ + const GrClipData* getClip() const { return fClip; } + + /** + * Sets the clip. + * @param clipData the clip to set. + */ + void setClip(const GrClipData* clipData) { fClip = clipData; } + + /////////////////////////////////////////////////////////////////////////// + // Draws + + /** + * Clear the entire or rect of the render target, ignoring any clips. + * @param rect the rect to clear or the whole thing if rect is NULL. + * @param color the color to clear to. + * @param target if non-NULL, the render target to clear otherwise clear + * the current render target + */ + void clear(const SkIRect* rect, GrColor color, + GrRenderTarget* target = NULL); + + /** + * Draw everywhere (respecting the clip) with the paint. + */ + void drawPaint(const GrPaint& paint); + + /** + * Draw the rect using a paint. + * @param paint describes how to color pixels. + * @param strokeWidth If strokeWidth < 0, then the rect is filled, else + * the rect is mitered stroked based on strokeWidth. If + * strokeWidth == 0, then the stroke is always a single + * pixel thick. + * @param matrix Optional matrix applied to the rect. Applied before + * context's matrix or the paint's matrix. + * The rects coords are used to access the paint (through texture matrix) + */ + void drawRect(const GrPaint& paint, + const SkRect&, + SkScalar strokeWidth = -1, + const SkMatrix* matrix = NULL); + + /** + * Maps a rect of local coordinates onto the a rect of destination + * coordinates. Each rect can optionally be transformed. The localRect + * is stretched over the dstRect. The dstRect is transformed by the + * context's matrix. Additional optional matrices for both rects can be + * provided by parameters. + * + * @param paint describes how to color pixels. + * @param dstRect the destination rect to draw. + * @param localRect rect of local coordinates to be mapped onto dstRect + * @param dstMatrix Optional matrix to transform dstRect. Applied before context's matrix. + * @param localMatrix Optional matrix to transform localRect. + */ + void drawRectToRect(const GrPaint& paint, + const SkRect& dstRect, + const SkRect& localRect, + const SkMatrix* dstMatrix = NULL, + const SkMatrix* localMatrix = NULL); + + /** + * Draw a roundrect using a paint. + * + * @param paint describes how to color pixels. + * @param rrect the roundrect to draw + * @param stroke the stroke information (width, join, cap) + */ + void drawRRect(const GrPaint& paint, + const SkRRect& rrect, + const SkStrokeRec& stroke); + + /** + * Draws a path. + * + * @param paint describes how to color pixels. + * @param path the path to draw + * @param stroke the stroke information (width, join, cap) + */ + void drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke); + + /** + * Draws vertices with a paint. + * + * @param paint describes how to color pixels. + * @param primitiveType primitives type to draw. + * @param vertexCount number of vertices. + * @param positions array of vertex positions, required. + * @param texCoords optional array of texture coordinates used + * to access the paint. + * @param colors optional array of per-vertex colors, supercedes + * the paint's color field. + * @param indices optional array of indices. If NULL vertices + * are drawn non-indexed. + * @param indexCount if indices is non-null then this is the + * number of indices. + */ + void drawVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + int vertexCount, + const GrPoint positions[], + const GrPoint texs[], + const GrColor colors[], + const uint16_t indices[], + int indexCount); + + /** + * Draws an oval. + * + * @param paint describes how to color pixels. + * @param oval the bounding rect of the oval. + * @param stroke the stroke information (width, style) + */ + void drawOval(const GrPaint& paint, + const SkRect& oval, + const SkStrokeRec& stroke); + + /////////////////////////////////////////////////////////////////////////// + // Misc. + + /** + * Flags that affect flush() behavior. + */ + enum FlushBits { + /** + * A client may reach a point where it has partially rendered a frame + * through a GrContext that it knows the user will never see. This flag + * causes the flush to skip submission of deferred content to the 3D API + * during the flush. + */ + kDiscard_FlushBit = 0x2, + }; + + /** + * Call to ensure all drawing to the context has been issued to the + * underlying 3D API. + * @param flagsBitfield flags that control the flushing behavior. See + * FlushBits. + */ + void flush(int flagsBitfield = 0); + + /** + * These flags can be used with the read/write pixels functions below. + */ + enum PixelOpsFlags { + /** The GrContext will not be flushed. This means that the read or write may occur before + previous draws have executed. */ + kDontFlush_PixelOpsFlag = 0x1, + /** The src for write or dst read is unpremultiplied. This is only respected if both the + config src and dst configs are an RGBA/BGRA 8888 format. */ + kUnpremul_PixelOpsFlag = 0x2, + }; + + /** + * Reads a rectangle of pixels from a render target. + * @param target the render target to read from. NULL means the current render target. + * @param left left edge of the rectangle to read (inclusive) + * @param top top edge of the rectangle to read (inclusive) + * @param width width of rectangle to read in pixels. + * @param height height of rectangle to read in pixels. + * @param config the pixel config of the destination buffer + * @param buffer memory to read the rectangle into. + * @param rowBytes number of bytes bewtween consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * + * @return true if the read succeeded, false if not. The read can fail because of an unsupported + * pixel config or because no render target is currently set and NULL was passed for + * target. + */ + bool readRenderTargetPixels(GrRenderTarget* target, + int left, int top, int width, int height, + GrPixelConfig config, void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0); + + /** + * Copy the src pixels [buffer, row bytes, pixel config] into a render target at the specified + * rectangle. + * @param target the render target to write into. NULL means the current render target. + * @param left left edge of the rectangle to write (inclusive) + * @param top top edge of the rectangle to write (inclusive) + * @param width width of rectangle to write in pixels. + * @param height height of rectangle to write in pixels. + * @param config the pixel config of the source buffer + * @param buffer memory to read the rectangle from. + * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * + * @return true if the write succeeded, false if not. The write can fail because of an + * unsupported combination of target and pixel configs. + */ + bool writeRenderTargetPixels(GrRenderTarget* target, + int left, int top, int width, int height, + GrPixelConfig config, const void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0); + + /** + * Reads a rectangle of pixels from a texture. + * @param texture the texture to read from. + * @param left left edge of the rectangle to read (inclusive) + * @param top top edge of the rectangle to read (inclusive) + * @param width width of rectangle to read in pixels. + * @param height height of rectangle to read in pixels. + * @param config the pixel config of the destination buffer + * @param buffer memory to read the rectangle into. + * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * + * @return true if the read succeeded, false if not. The read can fail because of an unsupported + * pixel config. + */ + bool readTexturePixels(GrTexture* texture, + int left, int top, int width, int height, + GrPixelConfig config, void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0); + + /** + * Writes a rectangle of pixels to a texture. + * @param texture the render target to read from. + * @param left left edge of the rectangle to write (inclusive) + * @param top top edge of the rectangle to write (inclusive) + * @param width width of rectangle to write in pixels. + * @param height height of rectangle to write in pixels. + * @param config the pixel config of the source buffer + * @param buffer memory to read pixels from + * @param rowBytes number of bytes between consecutive rows. Zero + * means rows are tightly packed. + * @param pixelOpsFlags see PixelOpsFlags enum above. + * @return true if the write succeeded, false if not. The write can fail because of an + * unsupported combination of texture and pixel configs. + */ + bool writeTexturePixels(GrTexture* texture, + int left, int top, int width, int height, + GrPixelConfig config, const void* buffer, + size_t rowBytes, + uint32_t pixelOpsFlags = 0); + + + /** + * Copies a rectangle of texels from src to dst. The size of dst is the size of the rectangle + * copied and topLeft is the position of the rect in src. The rectangle is clipped to src's + * bounds. + * @param src the texture to copy from. + * @param dst the render target to copy to. + * @param topLeft the point in src that will be copied to the top-left of dst. If NULL, + * (0, 0) will be used. + */ + void copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft = NULL); + + /** + * Resolves a render target that has MSAA. The intermediate MSAA buffer is + * down-sampled to the associated GrTexture (accessible via + * GrRenderTarget::asTexture()). Any pending draws to the render target will + * be executed before the resolve. + * + * This is only necessary when a client wants to access the object directly + * using the backend API directly. GrContext will detect when it must + * perform a resolve to a GrTexture used as the source of a draw or before + * reading pixels back from a GrTexture or GrRenderTarget. + */ + void resolveRenderTarget(GrRenderTarget* target); + + /////////////////////////////////////////////////////////////////////////// + // Helpers + + class AutoRenderTarget : public ::GrNoncopyable { + public: + AutoRenderTarget(GrContext* context, GrRenderTarget* target) { + fPrevTarget = context->getRenderTarget(); + GrSafeRef(fPrevTarget); + context->setRenderTarget(target); + fContext = context; + } + AutoRenderTarget(GrContext* context) { + fPrevTarget = context->getRenderTarget(); + GrSafeRef(fPrevTarget); + fContext = context; + } + ~AutoRenderTarget() { + if (NULL != fContext) { + fContext->setRenderTarget(fPrevTarget); + } + GrSafeUnref(fPrevTarget); + } + private: + GrContext* fContext; + GrRenderTarget* fPrevTarget; + }; + + /** + * Save/restore the view-matrix in the context. It can optionally adjust a paint to account + * for a coordinate system change. Here is an example of how the paint param can be used: + * + * A GrPaint is setup with GrEffects. The stages will have access to the pre-matrix source + * geometry positions when the draw is executed. Later on a decision is made to transform the + * geometry to device space on the CPU. The effects now need to know that the space in which + * the geometry will be specified has changed. + * + * Note that when restore is called (or in the destructor) the context's matrix will be + * restored. However, the paint will not be restored. The caller must make a copy of the + * paint if necessary. Hint: use SkTCopyOnFirstWrite if the AutoMatrix is conditionally + * initialized. + */ + class AutoMatrix : GrNoncopyable { + public: + AutoMatrix() : fContext(NULL) {} + + ~AutoMatrix() { this->restore(); } + + /** + * Initializes by pre-concat'ing the context's current matrix with the preConcat param. + */ + void setPreConcat(GrContext* context, const SkMatrix& preConcat, GrPaint* paint = NULL) { + GrAssert(NULL != context); + + this->restore(); + + fContext = context; + fMatrix = context->getMatrix(); + this->preConcat(preConcat, paint); + } + + /** + * Sets the context's matrix to identity. Returns false if the inverse matrix is required to + * update a paint but the matrix cannot be inverted. + */ + bool setIdentity(GrContext* context, GrPaint* paint = NULL) { + GrAssert(NULL != context); + + this->restore(); + + if (NULL != paint) { + if (!paint->localCoordChangeInverse(context->getMatrix())) { + return false; + } + } + fMatrix = context->getMatrix(); + fContext = context; + context->setIdentityMatrix(); + return true; + } + + /** + * Replaces the context's matrix with a new matrix. Returns false if the inverse matrix is + * required to update a paint but the matrix cannot be inverted. + */ + bool set(GrContext* context, const SkMatrix& newMatrix, GrPaint* paint = NULL) { + if (NULL != paint) { + if (!this->setIdentity(context, paint)) { + return false; + } + this->preConcat(newMatrix, paint); + } else { + this->restore(); + fContext = context; + fMatrix = context->getMatrix(); + context->setMatrix(newMatrix); + } + return true; + } + + /** + * If this has been initialized then the context's matrix will be further updated by + * pre-concat'ing the preConcat param. The matrix that will be restored remains unchanged. + * The paint is assumed to be relative to the context's matrix at the time this call is + * made, not the matrix at the time AutoMatrix was first initialized. In other words, this + * performs an incremental update of the paint. + */ + void preConcat(const SkMatrix& preConcat, GrPaint* paint = NULL) { + if (NULL != paint) { + paint->localCoordChange(preConcat); + } + fContext->concatMatrix(preConcat); + } + + /** + * Returns false if never initialized or the inverse matrix was required to update a paint + * but the matrix could not be inverted. + */ + bool succeeded() const { return NULL != fContext; } + + /** + * If this has been initialized then the context's original matrix is restored. + */ + void restore() { + if (NULL != fContext) { + fContext->setMatrix(fMatrix); + fContext = NULL; + } + } + + private: + GrContext* fContext; + SkMatrix fMatrix; + }; + + class AutoClip : GrNoncopyable { + public: + // This enum exists to require a caller of the constructor to acknowledge that the clip will + // initially be wide open. It also could be extended if there are other desirable initial + // clip states. + enum InitialClip { + kWideOpen_InitialClip, + }; + + AutoClip(GrContext* context, InitialClip initialState) + : fContext(context) { + GrAssert(kWideOpen_InitialClip == initialState); + fNewClipData.fClipStack = &fNewClipStack; + + fOldClip = context->getClip(); + context->setClip(&fNewClipData); + } + + AutoClip(GrContext* context, const SkRect& newClipRect) + : fContext(context) + , fNewClipStack(newClipRect) { + fNewClipData.fClipStack = &fNewClipStack; + + fOldClip = fContext->getClip(); + fContext->setClip(&fNewClipData); + } + + ~AutoClip() { + if (NULL != fContext) { + fContext->setClip(fOldClip); + } + } + private: + GrContext* fContext; + const GrClipData* fOldClip; + + SkClipStack fNewClipStack; + GrClipData fNewClipData; + }; + + class AutoWideOpenIdentityDraw { + public: + AutoWideOpenIdentityDraw(GrContext* ctx, GrRenderTarget* rt) + : fAutoClip(ctx, AutoClip::kWideOpen_InitialClip) + , fAutoRT(ctx, rt) { + fAutoMatrix.setIdentity(ctx); + // should never fail with no paint param. + GrAssert(fAutoMatrix.succeeded()); + } + + private: + AutoClip fAutoClip; + AutoRenderTarget fAutoRT; + AutoMatrix fAutoMatrix; + }; + + /////////////////////////////////////////////////////////////////////////// + // Functions intended for internal use only. + GrGpu* getGpu() { return fGpu; } + const GrGpu* getGpu() const { return fGpu; } + GrFontCache* getFontCache() { return fFontCache; } + GrDrawTarget* getTextTarget(); + const GrIndexBuffer* getQuadIndexBuffer() const; + + /** + * Stencil buffers add themselves to the cache using addStencilBuffer. findStencilBuffer is + * called to check the cache for a SB that matches an RT's criteria. + */ + void addStencilBuffer(GrStencilBuffer* sb); + GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt); + + GrPathRenderer* getPathRenderer( + const SkPath& path, + const SkStrokeRec& stroke, + const GrDrawTarget* target, + bool allowSW, + GrPathRendererChain::DrawType drawType = GrPathRendererChain::kColor_DrawType, + GrPathRendererChain::StencilSupport* stencilSupport = NULL); + +#if GR_CACHE_STATS + void printCacheStats() const; +#endif + +private: + // Used to indicate whether a draw should be performed immediately or queued in fDrawBuffer. + enum BufferedDraw { + kYes_BufferedDraw, + kNo_BufferedDraw, + }; + BufferedDraw fLastDrawWasBuffered; + + GrGpu* fGpu; + SkMatrix fViewMatrix; + SkAutoTUnref<GrRenderTarget> fRenderTarget; + const GrClipData* fClip; // TODO: make this ref counted + GrDrawState* fDrawState; + + GrResourceCache* fTextureCache; + GrFontCache* fFontCache; + + GrPathRendererChain* fPathRendererChain; + GrSoftwarePathRenderer* fSoftwarePathRenderer; + + GrVertexBufferAllocPool* fDrawBufferVBAllocPool; + GrIndexBufferAllocPool* fDrawBufferIBAllocPool; + GrInOrderDrawBuffer* fDrawBuffer; + + GrAARectRenderer* fAARectRenderer; + GrOvalRenderer* fOvalRenderer; + + bool fDidTestPMConversions; + int fPMToUPMConversion; + int fUPMToPMConversion; + + struct CleanUpData { + PFCleanUpFunc fFunc; + void* fInfo; + }; + + SkTDArray<CleanUpData> fCleanUpData; + + int fMaxTextureSizeOverride; + + GrContext(); // init must be called after the constructor. + bool init(GrBackend, GrBackendContext); + + void setupDrawBuffer(); + + class AutoRestoreEffects; + /// Sets the paint and returns the target to draw into. The paint can be NULL in which case the + /// draw state is left unmodified. + GrDrawTarget* prepareToDraw(const GrPaint*, BufferedDraw, AutoRestoreEffects*); + + void internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path, + const SkStrokeRec& stroke); + + GrTexture* createResizedTexture(const GrTextureDesc& desc, + const GrCacheID& cacheID, + void* srcData, + size_t rowBytes, + bool filter); + + // Needed so GrTexture's returnToCache helper function can call + // addExistingTextureToCache + friend class GrTexture; + + // Add an existing texture to the texture cache. This is intended solely + // for use with textures released from an GrAutoScratchTexture. + void addExistingTextureToCache(GrTexture* texture); + + /** + * These functions create premul <-> unpremul effects if it is possible to generate a pair + * of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they + * return NULL. + */ + const GrEffectRef* createPMToUPMEffect(GrTexture* texture, + bool swapRAndB, + const SkMatrix& matrix); + const GrEffectRef* createUPMToPMEffect(GrTexture* texture, + bool swapRAndB, + const SkMatrix& matrix); + + /** + * This callback allows the resource cache to callback into the GrContext + * when the cache is still overbudget after a purge. + */ + static bool OverbudgetCB(void* data); + + typedef GrRefCnt INHERITED; +}; + +/** + * Gets and locks a scratch texture from a descriptor using either exact or approximate criteria. + * Unlocks texture in the destructor. + */ +class GrAutoScratchTexture : ::GrNoncopyable { +public: + GrAutoScratchTexture() + : fContext(NULL) + , fTexture(NULL) { + } + + GrAutoScratchTexture(GrContext* context, + const GrTextureDesc& desc, + GrContext::ScratchTexMatch match = GrContext::kApprox_ScratchTexMatch) + : fContext(NULL) + , fTexture(NULL) { + this->set(context, desc, match); + } + + ~GrAutoScratchTexture() { + this->reset(); + } + + void reset() { + if (NULL != fContext && NULL != fTexture) { + fContext->unlockScratchTexture(fTexture); + fTexture->unref(); + fTexture = NULL; + } + } + + /* + * When detaching a texture we do not unlock it in the texture cache but + * we do set the returnToCache flag. In this way the texture remains + * "locked" in the texture cache until it is freed and recycled in + * GrTexture::internal_dispose. In reality, the texture has been removed + * from the cache (because this is in AutoScratchTexture) and by not + * calling unlockScratchTexture we simply don't re-add it. It will be + * reattached in GrTexture::internal_dispose. + * + * Note that the caller is assumed to accept and manage the ref to the + * returned texture. + */ + GrTexture* detach() { + if (NULL == fTexture) { + return NULL; + } + GrTexture* texture = fTexture; + fTexture = NULL; + + // This GrAutoScratchTexture has a ref from lockAndRefScratchTexture, which we give up now. + // The cache also has a ref which we are lending to the caller of detach(). When the caller + // lets go of the ref and the ref count goes to 0 internal_dispose will see this flag is + // set and re-ref the texture, thereby restoring the cache's ref. + GrAssert(texture->getRefCnt() > 1); + texture->setFlag((GrTextureFlags) GrTexture::kReturnToCache_FlagBit); + texture->unref(); + GrAssert(NULL != texture->getCacheEntry()); + + return texture; + } + + GrTexture* set(GrContext* context, + const GrTextureDesc& desc, + GrContext::ScratchTexMatch match = GrContext::kApprox_ScratchTexMatch) { + this->reset(); + + fContext = context; + if (NULL != fContext) { + fTexture = fContext->lockAndRefScratchTexture(desc, match); + if (NULL == fTexture) { + fContext = NULL; + } + return fTexture; + } else { + return NULL; + } + } + + GrTexture* texture() { return fTexture; } + +private: + GrContext* fContext; + GrTexture* fTexture; +}; + +#endif diff --git a/gpu/GrContextFactory.h b/gpu/GrContextFactory.h new file mode 100644 index 0000000..3d9f1a3 --- /dev/null +++ b/gpu/GrContextFactory.h @@ -0,0 +1,172 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContextFactory_DEFINED +#define GrContextFactory_DEFINED + +#if SK_ANGLE + #include "gl/SkANGLEGLContext.h" +#endif +#include "gl/SkDebugGLContext.h" +#if SK_MESA + #include "gl/SkMesaGLContext.h" +#endif +#include "gl/SkNativeGLContext.h" +#include "gl/SkNullGLContext.h" + +#include "GrContext.h" +#include "SkTArray.h" + +/** + * This is a simple class that is useful in test apps that use different + * GrContexts backed by different types of GL contexts. It manages creating the + * GL context and a GrContext that uses it. The GL/Gr contexts persist until the + * factory is destroyed (though the caller can always grab a ref on the returned + * GrContext to make it outlive the factory). + */ +class GrContextFactory : GrNoncopyable { +public: + /** + * Types of GL contexts supported. + */ + enum GLContextType { + kNative_GLContextType, +#if SK_ANGLE + kANGLE_GLContextType, +#endif +#if SK_MESA + kMESA_GLContextType, +#endif + kNull_GLContextType, + kDebug_GLContextType, + + kLastGLContextType = kDebug_GLContextType + }; + + static const int kGLContextTypeCnt = kLastGLContextType + 1; + + static bool IsRenderingGLContext(GLContextType type) { + switch (type) { + case kNull_GLContextType: + case kDebug_GLContextType: + return false; + default: + return true; + } + } + + static const char* GLContextTypeName(GLContextType type) { + switch (type) { + case kNative_GLContextType: + return "native"; + case kNull_GLContextType: + return "null"; +#if SK_ANGLE + case kANGLE_GLContextType: + return "angle"; +#endif +#if SK_MESA + case kMESA_GLContextType: + return "mesa"; +#endif + case kDebug_GLContextType: + return "debug"; + default: + GrCrash("Unknown GL Context type."); + } + } + + GrContextFactory() { + } + + ~GrContextFactory() { this->destroyContexts(); } + + void destroyContexts() { + for (int i = 0; i < fContexts.count(); ++i) { + fContexts[i].fGrContext->unref(); + fContexts[i].fGLContext->unref(); + } + fContexts.reset(); + } + + /** + * Get a GrContext initialized with a type of GL context. It also makes the GL context current. + */ + GrContext* get(GLContextType type) { + + for (int i = 0; i < fContexts.count(); ++i) { + if (fContexts[i].fType == type) { + fContexts[i].fGLContext->makeCurrent(); + return fContexts[i].fGrContext; + } + } + SkAutoTUnref<SkGLContextHelper> glCtx; + SkAutoTUnref<GrContext> grCtx; + switch (type) { + case kNative_GLContextType: + glCtx.reset(SkNEW(SkNativeGLContext)); + break; +#ifdef SK_ANGLE + case kANGLE_GLContextType: + glCtx.reset(SkNEW(SkANGLEGLContext)); + break; +#endif +#ifdef SK_MESA + case kMESA_GLContextType: + glCtx.reset(SkNEW(SkMesaGLContext)); + break; +#endif + case kNull_GLContextType: + glCtx.reset(SkNEW(SkNullGLContext)); + break; + case kDebug_GLContextType: + glCtx.reset(SkNEW(SkDebugGLContext)); + break; + } + static const int kBogusSize = 1; + if (!glCtx.get()) { + return NULL; + } + if (!glCtx.get()->init(kBogusSize, kBogusSize)) { + return NULL; + } + GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glCtx.get()->gl()); + grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx)); + if (!grCtx.get()) { + return NULL; + } + GPUContext& ctx = fContexts.push_back(); + ctx.fGLContext = glCtx.get(); + ctx.fGLContext->ref(); + ctx.fGrContext = grCtx.get(); + ctx.fGrContext->ref(); + ctx.fType = type; + return ctx.fGrContext; + } + + // Returns the GLContext of the given type. If it has not been created yet, + // NULL is returned instead. + SkGLContextHelper* getGLContext(GLContextType type) { + for (int i = 0; i < fContexts.count(); ++i) { + if (fContexts[i].fType == type) { + return fContexts[i].fGLContext; + } + } + + return NULL; + } + +private: + struct GPUContext { + GLContextType fType; + SkGLContextHelper* fGLContext; + GrContext* fGrContext; + }; + SkTArray<GPUContext, true> fContexts; +}; + +#endif diff --git a/gpu/GrDrawEffect.h b/gpu/GrDrawEffect.h new file mode 100644 index 0000000..005de41 --- /dev/null +++ b/gpu/GrDrawEffect.h @@ -0,0 +1,51 @@ + +#ifndef GrDrawEffect_DEFINED +#define GrDrawEffect_DEFINED + +#include "GrEffectStage.h" + +/** + * This class is used to communicate the particular GrEffect used in a draw to the backend-specific + * effect subclass (e.g. GrGLEffect). It is used to by the backend-specific class to generate a + * cache key for the effect, generate code on a program cache miss, and to upload uniform values to + * the program. + * In addition to the effect, it also communicates any changes between the relationship between + * the view matrix and local coordinate system since the effect was installed in its GrDrawState. + * The typical use case is that sometime after an effect was installed a decision was made to draw + * in device coordinates (i.e. use an identity view-matrix). In such a case the GrDrawEffect's + * coord-change-matrix would be the inverse of the view matrix that was set when the effect was + * installed. GrGLEffectMatrix is a handy class that implements a local coordinate matrix that + * automatically accounts for the coord-change matrix. + */ +class GrDrawEffect { +public: + GrDrawEffect(const GrEffectStage& stage, bool explicitLocalCoords) + : fEffectStage(&stage) + , fExplicitLocalCoords(explicitLocalCoords) { + GrAssert(NULL != fEffectStage); + GrAssert(NULL != fEffectStage->getEffect()); + } + const GrEffectRef* effect() const { return fEffectStage->getEffect(); } + + template <typename T> + const T& castEffect() const { return *static_cast<const T*>(this->effect()->get()); } + + const SkMatrix& getCoordChangeMatrix() const { + if (fExplicitLocalCoords) { + return SkMatrix::I(); + } else { + return fEffectStage->getCoordChangeMatrix(); + } + } + + bool programHasExplicitLocalCoords() const { return fExplicitLocalCoords; } + + const int* getVertexAttribIndices() const { return fEffectStage->getVertexAttribIndices(); } + int getVertexAttribIndexCount() const { return fEffectStage->getVertexAttribIndexCount(); } + +private: + const GrEffectStage* fEffectStage; + bool fExplicitLocalCoords; +}; + +#endif diff --git a/gpu/GrEffect.h b/gpu/GrEffect.h new file mode 100644 index 0000000..20dc5da --- /dev/null +++ b/gpu/GrEffect.h @@ -0,0 +1,345 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrEffect_DEFINED +#define GrEffect_DEFINED + +#include "GrColor.h" +#include "GrEffectUnitTest.h" +#include "GrNoncopyable.h" +#include "GrRefCnt.h" +#include "GrTexture.h" +#include "GrTextureAccess.h" +#include "GrTypesPriv.h" + +class GrBackendEffectFactory; +class GrContext; +class GrEffect; +class SkString; + +/** + * A Wrapper class for GrEffect. Its ref-count will track owners that may use effects to enqueue + * new draw operations separately from ownership within a deferred drawing queue. When the + * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled + * in service of later draws. However, the deferred draw queue may still own direct references to + * the underlying GrEffect. + * + * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when + * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread + * termination. + */ +class GrEffectRef : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(GrEffectRef); + virtual ~GrEffectRef(); + + GrEffect* get() { return fEffect; } + const GrEffect* get() const { return fEffect; } + + const GrEffect* operator-> () { return fEffect; } + const GrEffect* operator-> () const { return fEffect; } + + void* operator new(size_t size); + void operator delete(void* target); + + void* operator new(size_t size, void* placement) { + return ::operator new(size, placement); + } + void operator delete(void* target, void* placement) { + ::operator delete(target, placement); + } + +private: + friend class GrEffect; // to construct these + + explicit GrEffectRef(GrEffect* effect); + + GrEffect* fEffect; + + typedef SkRefCnt INHERITED; +}; + +/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the + Ganesh shading pipeline. + Subclasses must have a function that produces a human-readable name: + static const char* Name(); + GrEffect objects *must* be immutable: after being constructed, their fields may not change. + + GrEffect subclass objects should be created by factory functions that return GrEffectRef. + There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static + member function of a GrEffect subclass. + + Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we + privately inherit from GrRefCnt to help prevent accidental direct ref'ing/unref'ing of effects. + + Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread + memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool + is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below. + */ +class GrEffect : private GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrEffect) + + /** + * The types of vertex coordinates available to an effect in the vertex shader. Effects can + * require their own vertex attribute but these coordinates are made available by the framework + * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords + * is used (usually an explicit vertex attribute) but its meaning is determined by the effect + * subclass. + */ + enum CoordsType { + kLocal_CoordsType, + kPosition_CoordsType, + + kCustom_CoordsType, + }; + + virtual ~GrEffect(); + + /** + * This function is used to perform optimizations. When called the color and validFlags params + * indicate whether the input components to this effect in the FS will have known values. + * validFlags is a bitfield of GrColorComponentFlags. The function updates both params to + * indicate known values of its output. A component of the color param only has meaning if the + * corresponding bit in validFlags is set. + */ + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const = 0; + + /** This object, besides creating back-end-specific helper objects, is used for run-time-type- + identification. The factory should be an instance of templated class, + GrTBackendEffectFactory. It is templated on the subclass of GrEffect. The subclass must have + a nested type (or typedef) named GLEffect which will be the subclass of GrGLEffect created + by the factory. + + Example: + class MyCustomEffect : public GrEffect { + ... + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { + return GrTBackendEffectFactory<MyCustomEffect>::getInstance(); + } + ... + }; + */ + virtual const GrBackendEffectFactory& getFactory() const = 0; + + /** Returns true if this and other effect conservatively draw identically. It can only return + true when the two effects are of the same subclass (i.e. they return the same object from + from getFactory()). + + A return value of true from isEqual() should not be used to test whether the effects would + generate the same shader code. To test for identical code generation use the EffectKey + computed by the GrBackendEffectFactory: + effectA.getFactory().glEffectKey(effectA) == effectB.getFactory().glEffectKey(effectB). + */ + bool isEqual(const GrEffectRef& other) const { + return this->isEqual(*other.get()); + } + + /** Human-meaningful string to identify this effect; may be embedded + in generated shader code. */ + const char* name() const; + + int numTextures() const { return fTextureAccesses.count(); } + + /** Returns the access pattern for the texture at index. index must be valid according to + numTextures(). */ + const GrTextureAccess& textureAccess(int index) const { return *fTextureAccesses[index]; } + + /** Shortcut for textureAccess(index).texture(); */ + GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } + + /** Will this effect read the destination pixel value? */ + bool willReadDstColor() const { return fWillReadDstColor; } + + /** Will this effect read the fragment position? */ + bool willReadFragmentPosition() const { return fWillReadFragmentPosition; } + + int numVertexAttribs() const { return fVertexAttribTypes.count(); } + + GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; } + + static const int kMaxVertexAttribs = 2; + + /** Useful for effects that want to insert a texture matrix that is implied by the texture + dimensions */ + static inline SkMatrix MakeDivByTextureWHMatrix(const GrTexture* texture) { + GrAssert(NULL != texture); + SkMatrix mat; + mat.setIDiv(texture->width(), texture->height()); + return mat; + } + + void* operator new(size_t size); + void operator delete(void* target); + + void* operator new(size_t size, void* placement) { + return ::operator new(size, placement); + } + void operator delete(void* target, void* placement) { + ::operator delete(target, placement); + } + + /** These functions are used when recording effects into a deferred drawing queue. The inc call + keeps the effect alive outside of GrEffectRef while allowing any resources owned by the + effect to be returned to the cache for reuse. The dec call must balance the inc call. */ + void incDeferredRefCounts() const { + this->ref(); + int count = fTextureAccesses.count(); + for (int t = 0; t < count; ++t) { + fTextureAccesses[t]->getTexture()->incDeferredRefCount(); + } + } + void decDeferredRefCounts() const { + int count = fTextureAccesses.count(); + for (int t = 0; t < count; ++t) { + fTextureAccesses[t]->getTexture()->decDeferredRefCount(); + } + this->unref(); + } + +protected: + /** + * Subclasses call this from their constructor to register GrTextureAccesses. The effect + * subclass manages the lifetime of the accesses (this function only stores a pointer). This + * must only be called from the constructor because GrEffects are immutable. + */ + void addTextureAccess(const GrTextureAccess* textureAccess); + + /** + * Subclasses call this from their constructor to register vertex attributes (at most + * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are + * immutable. + */ + void addVertexAttrib(GrSLType type); + + GrEffect() : fWillReadDstColor(false), fWillReadFragmentPosition(false), fEffectRef(NULL) {} + + /** This should be called by GrEffect subclass factories. See the comment on AutoEffectUnref for + an example factory function. */ + static GrEffectRef* CreateEffectRef(GrEffect* effect) { + if (NULL == effect->fEffectRef) { + effect->fEffectRef = SkNEW_ARGS(GrEffectRef, (effect)); + } else { + effect->fEffectRef->ref(); + } + return effect->fEffectRef; + } + + static const GrEffectRef* CreateEffectRef(const GrEffect* effect) { + return CreateEffectRef(const_cast<GrEffect*>(effect)); + } + + /** Used by GR_CREATE_STATIC_EFFECT below */ + static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) { + GrAssert(NULL == effect->fEffectRef); + effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect)); + return effect->fEffectRef; + } + + + /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a + GrEffectRef. E.g.: + + class EffectSubclass : public GrEffect { + public: + GrEffectRef* Create(ParamType1 param1, ParamType2 param2, ...) { + AutoEffectUnref effect(SkNEW_ARGS(EffectSubclass, (param1, param2, ...))); + return CreateEffectRef(effect); + } + */ + class AutoEffectUnref { + public: + AutoEffectUnref(GrEffect* effect) : fEffect(effect) { } + ~AutoEffectUnref() { fEffect->unref(); } + operator GrEffect*() { return fEffect; } + private: + GrEffect* fEffect; + }; + + /** Helper for getting the GrEffect out of a GrEffectRef and down-casting to a GrEffect subclass + */ + template <typename T> + static const T& CastEffect(const GrEffect& effectRef) { + return *static_cast<const T*>(&effectRef); + } + + /** + * If the effect subclass will read the destination pixel value then it must call this function + * from its constructor. Otherwise, when its generated backend-specific effect class attempts + * to generate code that reads the destination pixel it will fail. + */ + void setWillReadDstColor() { fWillReadDstColor = true; } + + /** + * If the effect will generate a backend-specific effect that will read the fragment position + * in the FS then it must call this method from its constructor. Otherwise, the request to + * access the fragment position will be denied. + */ + void setWillReadFragmentPosition() { fWillReadFragmentPosition = true; } + +private: + bool isEqual(const GrEffect& other) const { + if (&this->getFactory() != &other.getFactory()) { + return false; + } + bool result = this->onIsEqual(other); +#if GR_DEBUG + if (result) { + GrAssert(this->numTextures() == other.numTextures()); + for (int i = 0; i < this->numTextures(); ++i) { + GrAssert(*fTextureAccesses[i] == *other.fTextureAccesses[i]); + } + } +#endif + return result; + } + + /** Subclass implements this to support isEqual(). It will only be called if it is known that + the two effects are of the same subclass (i.e. they return the same object from + getFactory()).*/ + virtual bool onIsEqual(const GrEffect& other) const = 0; + + void EffectRefDestroyed() { fEffectRef = NULL; } + + friend class GrEffectRef; // to call EffectRefDestroyed() + friend class GrEffectStage; // to rewrap GrEffect in GrEffectRef when restoring an effect-stage + // from deferred state, to call isEqual on naked GrEffects, and + // to inc/dec deferred ref counts. + + SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; + SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes; + bool fWillReadDstColor; + bool fWillReadFragmentPosition; + GrEffectRef* fEffectRef; + + typedef GrRefCnt INHERITED; +}; + +inline GrEffectRef::GrEffectRef(GrEffect* effect) { + GrAssert(NULL != effect); + effect->ref(); + fEffect = effect; +} + +/** + * This creates an effect outside of the effect memory pool. The effect's destructor will be called + * at global destruction time. NAME will be the name of the created GrEffectRef. + */ +#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS) \ +enum { \ + k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8), \ + k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef) \ +}; \ +static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage; \ +static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset; \ +static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\ +static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect); \ +static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect)); \ +static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME) + + +#endif diff --git a/gpu/GrEffectStage.h b/gpu/GrEffectStage.h new file mode 100644 index 0000000..08fb159 --- /dev/null +++ b/gpu/GrEffectStage.h @@ -0,0 +1,223 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrEffectStage_DEFINED +#define GrEffectStage_DEFINED + +#include "GrBackendEffectFactory.h" +#include "GrEffect.h" +#include "SkMatrix.h" +#include "GrTypes.h" + +#include "SkShader.h" + +class GrEffectStage { +public: + explicit GrEffectStage(const GrEffectRef* effectRef, int attrIndex0 = -1, int attrIndex1 = -1) + : fEffectRef(SkRef(effectRef)) { + fCoordChangeMatrixSet = false; + fVertexAttribIndices[0] = attrIndex0; + fVertexAttribIndices[1] = attrIndex1; + } + + GrEffectStage(const GrEffectStage& other) { + *this = other; + } + + class DeferredStage; + // This constructor balances DeferredStage::saveFrom(). + explicit GrEffectStage(const DeferredStage& deferredStage) { + deferredStage.restoreTo(this); + } + + GrEffectStage& operator= (const GrEffectStage& other) { + fCoordChangeMatrixSet = other.fCoordChangeMatrixSet; + if (other.fCoordChangeMatrixSet) { + fCoordChangeMatrix = other.fCoordChangeMatrix; + } + fEffectRef.reset(SkRef(other.fEffectRef.get())); + memcpy(fVertexAttribIndices, other.fVertexAttribIndices, sizeof(fVertexAttribIndices)); + return *this; + } + + bool operator== (const GrEffectStage& other) const { + GrAssert(NULL != fEffectRef.get()); + GrAssert(NULL != other.fEffectRef.get()); + + if (!(*this->getEffect())->isEqual(*other.getEffect())) { + return false; + } + + if (fCoordChangeMatrixSet != other.fCoordChangeMatrixSet) { + return false; + } + + if (!fCoordChangeMatrixSet) { + return true; + } + + return fCoordChangeMatrix == other.fCoordChangeMatrix; + } + + bool operator!= (const GrEffectStage& s) const { return !(*this == s); } + + /** + * This is called when the coordinate system in which the geometry is specified will change. + * + * @param matrix The transformation from the old coord system in which geometry is specified + * to the new one from which it will actually be drawn. + */ + void localCoordChange(const SkMatrix& matrix) { + if (fCoordChangeMatrixSet) { + fCoordChangeMatrix.preConcat(matrix); + } else { + fCoordChangeMatrixSet = true; + fCoordChangeMatrix = matrix; + } + } + + class SavedCoordChange { + private: + bool fCoordChangeMatrixSet; + SkMatrix fCoordChangeMatrix; + GR_DEBUGCODE(mutable SkAutoTUnref<const GrEffectRef> fEffectRef;) + + friend class GrEffectStage; + }; + + /** + * This gets the current coordinate system change. It is the accumulation of + * localCoordChange calls since the effect was installed. It is used when then caller + * wants to temporarily change the source geometry coord system, draw something, and then + * restore the previous coord system (e.g. temporarily draw in device coords). + */ + void saveCoordChange(SavedCoordChange* savedCoordChange) const { + savedCoordChange->fCoordChangeMatrixSet = fCoordChangeMatrixSet; + if (fCoordChangeMatrixSet) { + savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix; + } + GrAssert(NULL == savedCoordChange->fEffectRef.get()); + GR_DEBUGCODE(SkRef(fEffectRef.get());) + GR_DEBUGCODE(savedCoordChange->fEffectRef.reset(fEffectRef.get());) + } + + /** + * This balances the saveCoordChange call. + */ + void restoreCoordChange(const SavedCoordChange& savedCoordChange) { + fCoordChangeMatrixSet = savedCoordChange.fCoordChangeMatrixSet; + if (fCoordChangeMatrixSet) { + fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix; + } + GrAssert(savedCoordChange.fEffectRef.get() == fEffectRef); + GR_DEBUGCODE(savedCoordChange.fEffectRef.reset(NULL);) + } + + /** + * Used when storing a deferred GrDrawState. The DeferredStage allows resources owned by its + * GrEffect to be recycled through the cache. + */ + class DeferredStage { + public: + DeferredStage() : fEffect(NULL) { + SkDEBUGCODE(fInitialized = false;) + } + + ~DeferredStage() { + if (NULL != fEffect) { + fEffect->decDeferredRefCounts(); + } + } + + void saveFrom(const GrEffectStage& stage) { + GrAssert(!fInitialized); + GrAssert(NULL != stage.fEffectRef.get()); + stage.fEffectRef->get()->incDeferredRefCounts(); + fEffect = stage.fEffectRef->get(); + fCoordChangeMatrixSet = stage.fCoordChangeMatrixSet; + if (fCoordChangeMatrixSet) { + fCoordChangeMatrix = stage.fCoordChangeMatrix; + } + fVertexAttribIndices[0] = stage.fVertexAttribIndices[0]; + fVertexAttribIndices[1] = stage.fVertexAttribIndices[1]; + SkDEBUGCODE(fInitialized = true;) + } + + void restoreTo(GrEffectStage* stage) const { + GrAssert(fInitialized); + stage->fEffectRef.reset(GrEffect::CreateEffectRef(fEffect)); + stage->fCoordChangeMatrixSet = fCoordChangeMatrixSet; + if (fCoordChangeMatrixSet) { + stage->fCoordChangeMatrix = fCoordChangeMatrix; + } + stage->fVertexAttribIndices[0] = fVertexAttribIndices[0]; + stage->fVertexAttribIndices[1] = fVertexAttribIndices[1]; + } + + bool isEqual(const GrEffectStage& stage, bool ignoreCoordChange) const { + if (fVertexAttribIndices[0] != stage.fVertexAttribIndices[0] || + fVertexAttribIndices[1] != stage.fVertexAttribIndices[1]) { + return false; + } + + if (!(*stage.getEffect())->isEqual(*fEffect)) { + return false; + } + + if (ignoreCoordChange) { + // ignore the coordinate change matrix since there are + // explicit uv coordinates + return true; + } + + if (fCoordChangeMatrixSet != stage.fCoordChangeMatrixSet) { + return false; + } + + if (!fCoordChangeMatrixSet) { + return true; + } + + return fCoordChangeMatrix == stage.fCoordChangeMatrix; + } + + private: + const GrEffect* fEffect; + bool fCoordChangeMatrixSet; + SkMatrix fCoordChangeMatrix; + int fVertexAttribIndices[2]; + SkDEBUGCODE(bool fInitialized;) + }; + + /** + * Gets the matrix representing all changes of coordinate system since the GrEffect was + * installed in the stage. + */ + const SkMatrix& getCoordChangeMatrix() const { + if (fCoordChangeMatrixSet) { + return fCoordChangeMatrix; + } else { + return SkMatrix::I(); + } + } + + const GrEffectRef* getEffect() const { return fEffectRef.get(); } + + const int* getVertexAttribIndices() const { return fVertexAttribIndices; } + int getVertexAttribIndexCount() const { return fEffectRef->get()->numVertexAttribs(); } + +private: + bool fCoordChangeMatrixSet; + SkMatrix fCoordChangeMatrix; + SkAutoTUnref<const GrEffectRef> fEffectRef; + int fVertexAttribIndices[2]; +}; + +#endif diff --git a/gpu/GrEffectUnitTest.h b/gpu/GrEffectUnitTest.h new file mode 100644 index 0000000..557602f --- /dev/null +++ b/gpu/GrEffectUnitTest.h @@ -0,0 +1,101 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrEffectUnitTest_DEFINED +#define GrEffectUnitTest_DEFINED + +#include "GrNoncopyable.h" +#include "SkRandom.h" +#include "SkTArray.h" + +class SkMatrix; +class GrDrawTargetCaps; + +namespace GrEffectUnitTest { +// Used to access the dummy textures in TestCreate procs. +enum { + kSkiaPMTextureIdx = 0, + kAlphaTextureIdx = 1, +}; + +/** + * A helper for use in GrEffect::TestCreate functions. + */ +const SkMatrix& TestMatrix(SkMWCRandom*); + +} + +#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS + +class GrContext; +class GrEffectRef; +class GrTexture; + +class GrEffectTestFactory : GrNoncopyable { +public: + + typedef GrEffectRef* (*CreateProc)(SkMWCRandom*, + GrContext*, + const GrDrawTargetCaps& caps, + GrTexture* dummyTextures[]); + + GrEffectTestFactory(CreateProc createProc) { + fCreateProc = createProc; + GetFactories()->push_back(this); + } + + static GrEffectRef* CreateStage(SkMWCRandom* random, + GrContext* context, + const GrDrawTargetCaps& caps, + GrTexture* dummyTextures[]) { + uint32_t idx = random->nextRangeU(0, GetFactories()->count() - 1); + GrEffectTestFactory* factory = (*GetFactories())[idx]; + return factory->fCreateProc(random, context, caps, dummyTextures); + } + +private: + CreateProc fCreateProc; + static SkTArray<GrEffectTestFactory*, true>* GetFactories(); +}; + +/** GrEffect subclasses should insert this macro in their declaration to be included in the + * program generation unit test. + */ +#define GR_DECLARE_EFFECT_TEST \ + static GrEffectTestFactory gTestFactory; \ + static GrEffectRef* TestCreate(SkMWCRandom*, \ + GrContext*, \ + const GrDrawTargetCaps&, \ + GrTexture* dummyTextures[2]) + +/** GrEffect subclasses should insert this macro in their implementation file. They must then + * also implement this static function: + * GrEffect* TestCreate(SkMWCRandom*, + * GrContext*, + * const GrDrawTargetCaps&, + * GrTexture* dummyTextures[2]); + * dummyTextures[] are valid textures that can optionally be used to construct GrTextureAccesses. + * The first texture has config kSkia8888_GrPixelConfig and the second has + * kAlpha_8_GrPixelConfig. TestCreate functions are also free to create additional textures using + * the GrContext. + */ +#define GR_DEFINE_EFFECT_TEST(Effect) \ + GrEffectTestFactory Effect :: gTestFactory(Effect :: TestCreate) + +#else // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS + +// The unit test relies on static initializers. Just declare the TestCreate function so that +// its definitions will compile. +#define GR_DECLARE_EFFECT_TEST \ + static GrEffectRef* TestCreate(SkMWCRandom*, \ + GrContext*, \ + const GrDrawTargetCaps&, \ + GrTexture* dummyTextures[2]) +#define GR_DEFINE_EFFECT_TEST(X) + +#endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS +#endif diff --git a/gpu/GrFontScaler.h b/gpu/GrFontScaler.h new file mode 100644 index 0000000..f5dcf53 --- /dev/null +++ b/gpu/GrFontScaler.h @@ -0,0 +1,38 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrFontScaler_DEFINED +#define GrFontScaler_DEFINED + +#include "GrGlyph.h" +#include "GrKey.h" + +class SkPath; + +/** + * This is a virtual base class which Gr's interface to the host platform's + * font scaler. + * + * The client is responsible for subclassing, and instantiating this. The + * instance is create for a specific font+size+matrix. + */ +class GrFontScaler : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrFontScaler) + + virtual const GrKey* getKey() = 0; + virtual GrMaskFormat getMaskFormat() = 0; + virtual bool getPackedGlyphBounds(GrGlyph::PackedID, SkIRect* bounds) = 0; + virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height, + int rowBytes, void* image) = 0; + virtual bool getGlyphPath(uint16_t glyphID, SkPath*) = 0; + +private: + typedef GrRefCnt INHERITED; +}; + +#endif diff --git a/gpu/GrGlyph.h b/gpu/GrGlyph.h new file mode 100644 index 0000000..c730f24 --- /dev/null +++ b/gpu/GrGlyph.h @@ -0,0 +1,78 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGlyph_DEFINED +#define GrGlyph_DEFINED + +#include "GrRect.h" +#include "SkPath.h" + +class GrAtlas; + +/* Need this to be quad-state: + - complete w/ image + - just metrics + - failed to get image, but has metrics + - failed to get metrics + */ +struct GrGlyph { + typedef uint32_t PackedID; + + GrAtlas* fAtlas; + SkPath* fPath; + PackedID fPackedID; + GrIRect16 fBounds; + GrIPoint16 fAtlasLocation; + + void init(GrGlyph::PackedID packed, const SkIRect& bounds) { + fAtlas = NULL; + fPath = NULL; + fPackedID = packed; + fBounds.set(bounds); + fAtlasLocation.set(0, 0); + } + + void free() { + if (fPath) { + delete fPath; + fPath = NULL; + } + } + + int width() const { return fBounds.width(); } + int height() const { return fBounds.height(); } + bool isEmpty() const { return fBounds.isEmpty(); } + uint16_t glyphID() const { return UnpackID(fPackedID); } + + /////////////////////////////////////////////////////////////////////////// + + static inline unsigned ExtractSubPixelBitsFromFixed(GrFixed pos) { + // two most significant fraction bits from fixed-point + return (pos >> 14) & 3; + } + + static inline PackedID Pack(uint16_t glyphID, GrFixed x, GrFixed y) { + x = ExtractSubPixelBitsFromFixed(x); + y = ExtractSubPixelBitsFromFixed(y); + return (x << 18) | (y << 16) | glyphID; + } + + static inline GrFixed UnpackFixedX(PackedID packed) { + return ((packed >> 18) & 3) << 14; + } + + static inline GrFixed UnpackFixedY(PackedID packed) { + return ((packed >> 16) & 3) << 14; + } + + static inline uint16_t UnpackID(PackedID packed) { + return (uint16_t)packed; + } +}; + + +#endif diff --git a/gpu/GrKey.h b/gpu/GrKey.h new file mode 100644 index 0000000..80eb537 --- /dev/null +++ b/gpu/GrKey.h @@ -0,0 +1,43 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrKey_DEFINED +#define GrKey_DEFINED + +#include "GrRefCnt.h" + +class GrKey : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrKey) + + typedef intptr_t Hash; + + explicit GrKey(Hash hash) : fHash(hash) {} + + intptr_t getHash() const { return fHash; } + + bool operator<(const GrKey& rh) const { + return fHash < rh.fHash || (fHash == rh.fHash && this->lt(rh)); + } + bool operator==(const GrKey& rh) const { + return fHash == rh.fHash && this->eq(rh); + } + +protected: + virtual bool lt(const GrKey& rh) const = 0; + virtual bool eq(const GrKey& rh) const = 0; + +private: + const Hash fHash; + + typedef GrRefCnt INHERITED; +}; + +#endif diff --git a/gpu/GrNoncopyable.h b/gpu/GrNoncopyable.h new file mode 100644 index 0000000..3d47170 --- /dev/null +++ b/gpu/GrNoncopyable.h @@ -0,0 +1,30 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrNoncopyable_DEFINED +#define GrNoncopyable_DEFINED + +#include "GrTypes.h" + +/** + * Base for classes that want to disallow copying themselves. It makes its + * copy-constructor and assignment operators private (and unimplemented). + */ +class GR_API GrNoncopyable { +public: + GrNoncopyable() {} + +private: + // illegal + GrNoncopyable(const GrNoncopyable&); + GrNoncopyable& operator=(const GrNoncopyable&); +}; + +#endif diff --git a/gpu/GrOvalRenderer.h b/gpu/GrOvalRenderer.h new file mode 100644 index 0000000..08d3d3d --- /dev/null +++ b/gpu/GrOvalRenderer.h @@ -0,0 +1,55 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrOvalRenderer_DEFINED +#define GrOvalRenderer_DEFINED + +#include "GrContext.h" +#include "GrPaint.h" +#include "GrRefCnt.h" + +class GrContext; +class GrDrawTarget; +class GrPaint; +struct SkRect; +class SkStrokeRec; + +/* + * This class wraps helper functions that draw ovals and roundrects (filled & stroked) + */ +class GrOvalRenderer : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrOvalRenderer) + + GrOvalRenderer() : fRRectIndexBuffer(NULL) {} + ~GrOvalRenderer() { + this->reset(); + } + + void reset(); + + bool drawOval(GrDrawTarget* target, const GrContext* context, bool useAA, + const SkRect& oval, const SkStrokeRec& stroke); + bool drawSimpleRRect(GrDrawTarget* target, GrContext* context, bool useAA, + const SkRRect& rrect, const SkStrokeRec& stroke); + +private: + bool drawEllipse(GrDrawTarget* target, bool useAA, + const SkRect& ellipse, + const SkStrokeRec& stroke); + void drawCircle(GrDrawTarget* target, bool useAA, + const SkRect& circle, + const SkStrokeRec& stroke); + + GrIndexBuffer* rRectIndexBuffer(GrGpu* gpu); + + GrIndexBuffer* fRRectIndexBuffer; + + typedef GrRefCnt INHERITED; +}; + +#endif // GrOvalRenderer_DEFINED diff --git a/gpu/GrPaint.h b/gpu/GrPaint.h new file mode 100644 index 0000000..9e326f0 --- /dev/null +++ b/gpu/GrPaint.h @@ -0,0 +1,254 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrPaint_DEFINED +#define GrPaint_DEFINED + +#include "GrColor.h" +#include "GrEffectStage.h" + +#include "SkXfermode.h" + +/** + * The paint describes how color and coverage are computed at each pixel by GrContext draw + * functions and the how color is blended with the destination pixel. + * + * The paint allows installation of custom color and coverage stages. New types of stages are + * created by subclassing GrEffect. + * + * The primitive color computation starts with the color specified by setColor(). This color is the + * input to the first color stage. Each color stage feeds its output to the next color stage. The + * final color stage's output color is input to the color filter specified by + * setXfermodeColorFilter which produces the final source color, S. + * + * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified + * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained + * together in the same manner as color stages. The output of the last stage is modulated by any + * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C. + * + * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value + * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination + * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S). + * + * Note that the coverage is applied after the blend. This is why they are computed as distinct + * values. + * + * TODO: Encapsulate setXfermodeColorFilter in a GrEffect and remove from GrPaint. + */ +class GrPaint { +public: + GrPaint() { this->reset(); } + + GrPaint(const GrPaint& paint) { *this = paint; } + + ~GrPaint() {} + + /** + * Sets the blending coefficients to use to blend the final primitive color with the + * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode). + */ + void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + fSrcBlendCoeff = srcCoeff; + fDstBlendCoeff = dstCoeff; + } + GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; } + GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; } + + /** + * The initial color of the drawn primitive. Defaults to solid white. + */ + void setColor(GrColor color) { fColor = color; } + GrColor getColor() const { return fColor; } + + /** + * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff. + */ + void setCoverage(uint8_t coverage) { fCoverage = coverage; } + uint8_t getCoverage() const { return fCoverage; } + + /** + * Should primitives be anti-aliased or not. Defaults to false. + */ + void setAntiAlias(bool aa) { fAntiAlias = aa; } + bool isAntiAlias() const { return fAntiAlias; } + + /** + * Should dithering be applied. Defaults to false. + */ + void setDither(bool dither) { fDither = dither; } + bool isDither() const { return fDither; } + + /** + * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant + * color passed to this function is considered the "src" color and the primitive's color is + * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through + * the primitive color unmodified. + */ + void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) { + fColorFilterColor = color; + fColorFilterXfermode = mode; + } + SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; } + GrColor getColorFilterColor() const { return fColorFilterColor; } + + /** + * Disables the SkXfermode::Mode color filter. + */ + void resetColorFilter() { + fColorFilterXfermode = SkXfermode::kDst_Mode; + fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); + } + + /** + * Appends an additional color effect to the color computation. + */ + const GrEffectRef* addColorEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { + GrAssert(NULL != effect); + SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1)); + return effect; + } + + /** + * Appends an additional coverage effect to the coverage computation. + */ + const GrEffectRef* addCoverageEffect(const GrEffectRef* effect, int attr0 = -1, int attr1 = -1) { + GrAssert(NULL != effect); + SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1)); + return effect; + } + + /** + * Helpers for adding color or coverage effects that sample a texture. The matrix is applied + * to the src space position to compute texture coordinates. + */ + void addColorTextureEffect(GrTexture* texture, const SkMatrix& matrix); + void addCoverageTextureEffect(GrTexture* texture, const SkMatrix& matrix); + + void addColorTextureEffect(GrTexture* texture, + const SkMatrix& matrix, + const GrTextureParams& params); + void addCoverageTextureEffect(GrTexture* texture, + const SkMatrix& matrix, + const GrTextureParams& params); + + int numColorStages() const { return fColorStages.count(); } + int numCoverageStages() const { return fCoverageStages.count(); } + int numTotalStages() const { return this->numColorStages() + this->numCoverageStages(); } + + const GrEffectStage& getColorStage(int s) const { return fColorStages[s]; } + const GrEffectStage& getCoverageStage(int s) const { return fCoverageStages[s]; } + + GrPaint& operator=(const GrPaint& paint) { + fSrcBlendCoeff = paint.fSrcBlendCoeff; + fDstBlendCoeff = paint.fDstBlendCoeff; + fAntiAlias = paint.fAntiAlias; + fDither = paint.fDither; + + fColor = paint.fColor; + fCoverage = paint.fCoverage; + + fColorFilterColor = paint.fColorFilterColor; + fColorFilterXfermode = paint.fColorFilterXfermode; + + fColorStages = paint.fColorStages; + fCoverageStages = paint.fCoverageStages; + + return *this; + } + + /** + * Resets the paint to the defaults. + */ + void reset() { + this->resetBlend(); + this->resetOptions(); + this->resetColor(); + this->resetCoverage(); + this->resetStages(); + this->resetColorFilter(); + } + +private: + /** + * Called when the source coord system from which geometry is rendered changes. It ensures that + * the local coordinates seen by effects remains unchanged. oldToNew gives the transformation + * from the previous coord system to the new coord system. + */ + void localCoordChange(const SkMatrix& oldToNew) { + for (int i = 0; i < fColorStages.count(); ++i) { + fColorStages[i].localCoordChange(oldToNew); + } + for (int i = 0; i < fCoverageStages.count(); ++i) { + fCoverageStages[i].localCoordChange(oldToNew); + } + } + + bool localCoordChangeInverse(const SkMatrix& newToOld) { + SkMatrix oldToNew; + bool computed = false; + for (int i = 0; i < fColorStages.count(); ++i) { + if (!computed && !newToOld.invert(&oldToNew)) { + return false; + } else { + computed = true; + } + fColorStages[i].localCoordChange(oldToNew); + } + for (int i = 0; i < fCoverageStages.count(); ++i) { + if (!computed && !newToOld.invert(&oldToNew)) { + return false; + } else { + computed = true; + } + fCoverageStages[i].localCoordChange(oldToNew); + } + return true; + } + + friend class GrContext; // To access above two functions + + SkSTArray<4, GrEffectStage> fColorStages; + SkSTArray<2, GrEffectStage> fCoverageStages; + + GrBlendCoeff fSrcBlendCoeff; + GrBlendCoeff fDstBlendCoeff; + bool fAntiAlias; + bool fDither; + + GrColor fColor; + uint8_t fCoverage; + + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; + + void resetBlend() { + fSrcBlendCoeff = kOne_GrBlendCoeff; + fDstBlendCoeff = kZero_GrBlendCoeff; + } + + void resetOptions() { + fAntiAlias = false; + fDither = false; + } + + void resetColor() { + fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); + } + + void resetCoverage() { + fCoverage = 0xff; + } + + void resetStages() { + fColorStages.reset(); + fCoverageStages.reset(); + } +}; + +#endif diff --git a/gpu/GrPathRendererChain.h b/gpu/GrPathRendererChain.h new file mode 100644 index 0000000..d51a4bb --- /dev/null +++ b/gpu/GrPathRendererChain.h @@ -0,0 +1,83 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrPathRendererChain_DEFINED +#define GrPathRendererChain_DEFINED + +#include "GrRefCnt.h" +#include "SkTArray.h" + +class GrContext; +class GrDrawTarget; +class GrPathRenderer; +class SkPath; +class SkStrokeRec; + +/** + * Keeps track of an ordered list of path renderers. When a path needs to be + * drawn this list is scanned to find the most preferred renderer. To add your + * path renderer to the list implement the GrPathRenderer::AddPathRenderers + * function. + */ +class GrPathRendererChain : public SkRefCnt { +public: + // See comments in GrPathRenderer.h + enum StencilSupport { + kNoSupport_StencilSupport, + kStencilOnly_StencilSupport, + kNoRestriction_StencilSupport, + }; + + SK_DECLARE_INST_COUNT(GrPathRendererChain) + + GrPathRendererChain(GrContext* context); + + ~GrPathRendererChain(); + + // takes a ref and unrefs in destructor + GrPathRenderer* addPathRenderer(GrPathRenderer* pr); + + /** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR + returned by getPathRenderer */ + enum DrawType { + kColor_DrawType, // draw to the color buffer, no AA + kColorAntiAlias_DrawType, // draw to color buffer, with partial coverage AA + kStencilOnly_DrawType, // draw just to the stencil buffer + kStencilAndColor_DrawType, // draw the stencil and color buffer, no AA + kStencilAndColorAntiAlias_DrawType // draw the stencil and color buffer, with partial + // coverage AA. + }; + /** Returns a GrPathRenderer compatible with the request if one is available. If the caller + is drawing the path to the stencil buffer then stencilSupport can be used to determine + whether the path can be rendered with arbitrary stencil rules or not. See comments on + StencilSupport in GrPathRenderer.h. */ + GrPathRenderer* getPathRenderer(const SkPath& path, + const SkStrokeRec& rec, + const GrDrawTarget* target, + DrawType drawType, + StencilSupport* stencilSupport); + +private: + + GrPathRendererChain(); + + void init(); + + enum { + kPreAllocCount = 8, + }; + bool fInit; + GrContext* fOwner; + SkSTArray<kPreAllocCount, GrPathRenderer*, true> fChain; + + typedef SkRefCnt INHERITED; +}; + + +#endif diff --git a/gpu/GrPoint.h b/gpu/GrPoint.h new file mode 100644 index 0000000..c987b01 --- /dev/null +++ b/gpu/GrPoint.h @@ -0,0 +1,30 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrPoint_DEFINED +#define GrPoint_DEFINED + +#include "GrTypes.h" +#include "SkScalar.h" +#include "SkPoint.h" + +#define GrPoint SkPoint +#define GrVec SkVector + +struct GrIPoint16 { + int16_t fX, fY; + + void set(intptr_t x, intptr_t y) { + fX = GrToS16(x); + fY = GrToS16(y); + } +}; + +#endif diff --git a/gpu/GrRect.h b/gpu/GrRect.h new file mode 100644 index 0000000..cacc511 --- /dev/null +++ b/gpu/GrRect.h @@ -0,0 +1,30 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRect_DEFINED +#define GrRect_DEFINED + +#include "SkTypes.h" +#include "SkRect.h" + +struct GrIRect16 { + int16_t fLeft, fTop, fRight, fBottom; + + int width() const { return fRight - fLeft; } + int height() const { return fBottom - fTop; } + int area() const { return this->width() * this->height(); } + bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + + void set(const SkIRect& r) { + fLeft = SkToS16(r.fLeft); + fTop = SkToS16(r.fTop); + fRight = SkToS16(r.fRight); + fBottom = SkToS16(r.fBottom); + } +}; + +#endif diff --git a/gpu/GrRefCnt.h b/gpu/GrRefCnt.h new file mode 100644 index 0000000..31aa80d --- /dev/null +++ b/gpu/GrRefCnt.h @@ -0,0 +1,33 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrRefCnt_DEFINED +#define GrRefCnt_DEFINED + +#include "GrTypes.h" +#include "SkRefCnt.h" + +typedef SkRefCnt GrRefCnt; +typedef SkAutoRef GrAutoRef; +typedef SkAutoUnref GrAutoUnref; + +#define GrSafeRef SkSafeRef +#define GrSafeUnref SkSafeUnref +#define GrSafeAssign(a, b) SkRefCnt_SafeAssign(a, b) + +template<typename T> +static inline void GrSafeSetNull(T*& obj) { + if (NULL != obj) { + obj->unref(); + obj = NULL; + } +} + +#endif diff --git a/gpu/GrRenderTarget.h b/gpu/GrRenderTarget.h new file mode 100644 index 0000000..eab65b5 --- /dev/null +++ b/gpu/GrRenderTarget.h @@ -0,0 +1,171 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRenderTarget_DEFINED +#define GrRenderTarget_DEFINED + +#include "GrSurface.h" +#include "SkRect.h" + +class GrStencilBuffer; +class GrTexture; + +/** + * GrRenderTarget represents a 2D buffer of pixels that can be rendered to. + * A context's render target is set by setRenderTarget(). Render targets are + * created by a createTexture with the kRenderTarget_TextureFlag flag. + * Additionally, GrContext provides methods for creating GrRenderTargets + * that wrap externally created render targets. + */ +class GrRenderTarget : public GrSurface { +public: + SK_DECLARE_INST_COUNT(GrRenderTarget) + + // GrResource overrides + virtual size_t sizeInBytes() const SK_OVERRIDE; + + // GrSurface overrides + /** + * @return the texture associated with the render target, may be NULL. + */ + virtual GrTexture* asTexture() SK_OVERRIDE { return fTexture; } + virtual const GrTexture* asTexture() const SK_OVERRIDE { return fTexture; } + + /** + * @return this render target. + */ + virtual GrRenderTarget* asRenderTarget() SK_OVERRIDE { return this; } + virtual const GrRenderTarget* asRenderTarget() const SK_OVERRIDE { + return this; + } + + virtual bool readPixels(int left, int top, int width, int height, + GrPixelConfig config, + void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) SK_OVERRIDE; + + virtual void writePixels(int left, int top, int width, int height, + GrPixelConfig config, + const void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) SK_OVERRIDE; + + // GrRenderTarget + /** + * If this RT is multisampled, this is the multisample buffer + * @return the 3D API's handle to this object (e.g. FBO ID in OpenGL) + */ + virtual GrBackendObject getRenderTargetHandle() const = 0; + + /** + * If this RT is multisampled, this is the buffer it is resolved to. + * Otherwise, same as getRenderTargetHandle(). + * (In GL a separate FBO ID is used for the MSAA and resolved buffers) + * @return the 3D API's handle to this object (e.g. FBO ID in OpenGL) + */ + virtual GrBackendObject getRenderTargetResolvedHandle() const = 0; + + /** + * @return true if the surface is multisampled, false otherwise + */ + bool isMultisampled() const { return 0 != fDesc.fSampleCnt; } + + /** + * @return the number of samples-per-pixel or zero if non-MSAA. + */ + int numSamples() const { return fDesc.fSampleCnt; } + + /** + * Call to indicate the multisample contents were modified such that the + * render target needs to be resolved before it can be used as texture. Gr + * tracks this for its own drawing and thus this only needs to be called + * when the render target has been modified outside of Gr. This has no + * effect on wrapped backend render targets. + * + * @param rect a rect bounding the area needing resolve. NULL indicates + * the whole RT needs resolving. + */ + void flagAsNeedingResolve(const SkIRect* rect = NULL); + + /** + * Call to override the region that needs to be resolved. + */ + void overrideResolveRect(const SkIRect rect); + + /** + * Call to indicate that GrRenderTarget was externally resolved. This may + * allow Gr to skip a redundant resolve step. + */ + void flagAsResolved() { fResolveRect.setLargestInverted(); } + + /** + * @return true if the GrRenderTarget requires MSAA resolving + */ + bool needsResolve() const { return !fResolveRect.isEmpty(); } + + /** + * Returns a rect bounding the region needing resolving. + */ + const SkIRect& getResolveRect() const { return fResolveRect; } + + /** + * If the render target is multisampled this will perform a multisample + * resolve. Any pending draws to the target are first flushed. This only + * applies to render targets that are associated with GrTextures. After the + * function returns the GrTexture will contain the resolved pixels. + */ + void resolve(); + + // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO + // 0 in GL), or be unresolvable because the client didn't give us the + // resolve destination. + enum ResolveType { + kCanResolve_ResolveType, + kAutoResolves_ResolveType, + kCantResolve_ResolveType, + }; + virtual ResolveType getResolveType() const = 0; + + /** + * GrStencilBuffer is not part of the public API. + */ + GrStencilBuffer* getStencilBuffer() const { return fStencilBuffer; } + void setStencilBuffer(GrStencilBuffer* stencilBuffer); + +protected: + GrRenderTarget(GrGpu* gpu, + bool isWrapped, + GrTexture* texture, + const GrTextureDesc& desc) + : INHERITED(gpu, isWrapped, desc) + , fStencilBuffer(NULL) + , fTexture(texture) { + fResolveRect.setLargestInverted(); + } + + // override of GrResource + virtual void onAbandon() SK_OVERRIDE; + virtual void onRelease() SK_OVERRIDE; + +private: + friend class GrTexture; + // called by ~GrTexture to remove the non-ref'ed back ptr. + void owningTextureDestroyed() { + GrAssert(NULL != fTexture); + fTexture = NULL; + } + + GrStencilBuffer* fStencilBuffer; + GrTexture* fTexture; // not ref'ed + + SkIRect fResolveRect; + + typedef GrSurface INHERITED; +}; + +#endif diff --git a/gpu/GrResource.h b/gpu/GrResource.h new file mode 100644 index 0000000..72e6928 --- /dev/null +++ b/gpu/GrResource.h @@ -0,0 +1,117 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrResource_DEFINED +#define GrResource_DEFINED + +#include "GrRefCnt.h" + +#include "SkTInternalLList.h" + +class GrGpu; +class GrContext; +class GrResourceEntry; + +/** + * Base class for the GPU resources created by a GrContext. + */ +class GrResource : public GrRefCnt { +public: + SK_DECLARE_INST_COUNT(GrResource) + + /** + * Frees the resource in the underlying 3D API. It must be safe to call this + * when the resource has been previously abandoned. + */ + void release(); + + /** + * Removes references to objects in the underlying 3D API without freeing + * them. Used when the API context has been torn down before the GrContext. + */ + void abandon(); + + /** + * Tests whether a resource has been abandoned or released. All resources + * will be in this state after their creating GrContext is destroyed or has + * contextLost called. It's up to the client to test isValid() before + * attempting to use a resource if it holds refs on resources across + * ~GrContext, freeResources with the force flag, or contextLost. + * + * @return true if the resource has been released or abandoned, + * false otherwise. + */ + bool isValid() const { return NULL != fGpu; } + + /** + * Retrieves the size of the object in GPU memory. This is approximate since + * we aren't aware of additional padding or copies made by the driver. + * + * @return the size of the buffer in bytes + */ + virtual size_t sizeInBytes() const = 0; + + /** + * Retrieves the context that owns the resource. Note that it is possible + * for this to return NULL. When resources have been release()ed or + * abandon()ed they no longer have an owning context. Destroying a + * GrContext automatically releases all its resources. + */ + const GrContext* getContext() const; + GrContext* getContext(); + + void setCacheEntry(GrResourceEntry* cacheEntry) { fCacheEntry = cacheEntry; } + GrResourceEntry* getCacheEntry() { return fCacheEntry; } + + void incDeferredRefCount() const { GrAssert(fDeferredRefCount >= 0); ++fDeferredRefCount; } + void decDeferredRefCount() const { GrAssert(fDeferredRefCount > 0); --fDeferredRefCount; } + +protected: + /** + * isWrapped indicates we have wrapped a client-created backend resource in a GrResource. If it + * is true then the client is responsible for the lifetime of the underlying backend resource. + * Otherwise, our onRelease() should free the resource. + */ + GrResource(GrGpu* gpu, bool isWrapped); + virtual ~GrResource(); + + GrGpu* getGpu() const { return fGpu; } + + // Derived classes should always call their parent class' onRelease + // and onAbandon methods in their overrides. + virtual void onRelease() {}; + virtual void onAbandon() {}; + + bool isInCache() const { return NULL != fCacheEntry; } + bool isWrapped() const { return kWrapped_Flag & fFlags; } + +private: +#if GR_DEBUG + friend class GrGpu; // for assert in GrGpu to access getGpu +#endif + + // We're in an internal doubly linked list + SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResource); + + GrGpu* fGpu; // not reffed. The GrGpu can be deleted while there + // are still live GrResources. It will call + // release() on all such resources in its + // destructor. + GrResourceEntry* fCacheEntry; // NULL if not in cache + mutable int fDeferredRefCount; // How many references in deferred drawing buffers. + + enum Flags { + kWrapped_Flag = 0x1, + }; + uint32_t fFlags; + + typedef GrRefCnt INHERITED; +}; + +#endif diff --git a/gpu/GrSurface.h b/gpu/GrSurface.h new file mode 100644 index 0000000..52a5665 --- /dev/null +++ b/gpu/GrSurface.h @@ -0,0 +1,134 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrSurface_DEFINED +#define GrSurface_DEFINED + +#include "GrTypes.h" +#include "GrResource.h" + +class GrTexture; +class GrRenderTarget; + +class GrSurface : public GrResource { +public: + SK_DECLARE_INST_COUNT(GrSurface); + + /** + * Retrieves the width of the surface. + * + * @return the width in texels + */ + int width() const { return fDesc.fWidth; } + + /** + * Retrieves the height of the surface. + * + * @return the height in texels + */ + int height() const { return fDesc.fHeight; } + + GrSurfaceOrigin origin() const { + GrAssert(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin || kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin); + return fDesc.fOrigin; + } + + /** + * Retrieves the pixel config specified when the surface was created. + * For render targets this can be kUnknown_GrPixelConfig + * if client asked us to render to a target that has a pixel + * config that isn't equivalent with one of our configs. + */ + GrPixelConfig config() const { return fDesc.fConfig; } + + /** + * Return the descriptor describing the surface + */ + const GrTextureDesc& desc() const { return fDesc; } + + /** + * @return the texture associated with the surface, may be NULL. + */ + virtual GrTexture* asTexture() = 0; + virtual const GrTexture* asTexture() const = 0; + + /** + * @return the render target underlying this surface, may be NULL. + */ + virtual GrRenderTarget* asRenderTarget() = 0; + virtual const GrRenderTarget* asRenderTarget() const = 0; + + /** + * Checks whether this GrSurface refers to the same GPU object as other. This + * catches the case where a GrTexture and GrRenderTarget refer to the same + * GPU memory. + */ + bool isSameAs(const GrSurface* other) const { + const GrRenderTarget* thisRT = this->asRenderTarget(); + if (NULL != thisRT) { + return thisRT == other->asRenderTarget(); + } else { + const GrTexture* thisTex = this->asTexture(); + GrAssert(NULL != thisTex); // We must be one or the other + return thisTex == other->asTexture(); + } + } + + /** + * Reads a rectangle of pixels from the surface. + * @param left left edge of the rectangle to read (inclusive) + * @param top top edge of the rectangle to read (inclusive) + * @param width width of rectangle to read in pixels. + * @param height height of rectangle to read in pixels. + * @param config the pixel config of the destination buffer + * @param buffer memory to read the rectangle into. + * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags See the GrContext::PixelOpsFlags enum. + * + * @return true if the read succeeded, false if not. The read can fail because of an unsupported + * pixel config. + */ + virtual bool readPixels(int left, int top, int width, int height, + GrPixelConfig config, + void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) = 0; + + /** + * Copy the src pixels [buffer, rowbytes, pixelconfig] into the surface at the specified + * rectangle. + * @param left left edge of the rectangle to write (inclusive) + * @param top top edge of the rectangle to write (inclusive) + * @param width width of rectangle to write in pixels. + * @param height height of rectangle to write in pixels. + * @param config the pixel config of the source buffer + * @param buffer memory to read the rectangle from. + * @param rowBytes number of bytes between consecutive rows. Zero means rows are tightly + * packed. + * @param pixelOpsFlags See the GrContext::PixelOpsFlags enum. + */ + virtual void writePixels(int left, int top, int width, int height, + GrPixelConfig config, + const void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) = 0; + +protected: + GrSurface(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc) + : INHERITED(gpu, isWrapped) + , fDesc(desc) { + } + + GrTextureDesc fDesc; + +private: + typedef GrResource INHERITED; +}; + +#endif // GrSurface_DEFINED diff --git a/gpu/GrTBackendEffectFactory.h b/gpu/GrTBackendEffectFactory.h new file mode 100644 index 0000000..813f54b --- /dev/null +++ b/gpu/GrTBackendEffectFactory.h @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTBackendEffectFactory_DEFINED +#define GrTBackendEffectFactory_DEFINED + +#include "GrBackendEffectFactory.h" +#include "GrDrawEffect.h" + +/** + * Implements GrBackendEffectFactory for a GrEffect subclass as a singleton. + */ +template <typename EffectClass> +class GrTBackendEffectFactory : public GrBackendEffectFactory { + +public: + typedef typename EffectClass::GLEffect GLEffect; + + /** Returns a human-readable name that is accessible via GrEffect or + GrGLEffect and is consistent between the two of them. + */ + virtual const char* name() const SK_OVERRIDE { return EffectClass::Name(); } + + /** Returns a value that identifies the GLSL shader code generated by + a GrEffect. This enables caching of generated shaders. Part of the + id identifies the GrEffect subclass. The remainder is based + on the aspects of the GrEffect object's configuration that affect + GLSL code generation. */ + virtual EffectKey glEffectKey(const GrDrawEffect& drawEffect, + const GrGLCaps& caps) const SK_OVERRIDE { + GrAssert(kIllegalEffectClassID != fEffectClassID); + EffectKey effectKey = GLEffect::GenKey(drawEffect, caps); + EffectKey textureKey = GLEffect::GenTextureKey(drawEffect, caps); + EffectKey attribKey = GLEffect::GenAttribKey(drawEffect); +#if GR_DEBUG + static const EffectKey kIllegalIDMask = (uint16_t) (~((1U << kEffectKeyBits) - 1)); + GrAssert(!(kIllegalIDMask & effectKey)); + + static const EffectKey kIllegalTextureKeyMask = (uint16_t) (~((1U << kTextureKeyBits) - 1)); + GrAssert(!(kIllegalTextureKeyMask & textureKey)); + + static const EffectKey kIllegalAttribKeyMask = (uint16_t) (~((1U << kAttribKeyBits) - 1)); + GrAssert(!(kIllegalAttribKeyMask & textureKey)); +#endif + return fEffectClassID | (attribKey << (kEffectKeyBits+kTextureKeyBits)) | + (textureKey << kEffectKeyBits) | effectKey; + } + + /** Returns a new instance of the appropriate *GL* implementation class + for the given GrEffect; caller is responsible for deleting + the object. */ + virtual GLEffect* createGLInstance(const GrDrawEffect& drawEffect) const SK_OVERRIDE { + return SkNEW_ARGS(GLEffect, (*this, drawEffect)); + } + + /** This class is a singleton. This function returns the single instance. + */ + static const GrBackendEffectFactory& getInstance() { + static SkAlignedSTStorage<1, GrTBackendEffectFactory> gInstanceMem; + static const GrTBackendEffectFactory* gInstance; + if (!gInstance) { + gInstance = SkNEW_PLACEMENT(gInstanceMem.get(), + GrTBackendEffectFactory); + } + return *gInstance; + } + +protected: + GrTBackendEffectFactory() { + fEffectClassID = GenID() << (kAttribKeyBits + kEffectKeyBits + kTextureKeyBits) ; + } +}; + +#endif diff --git a/gpu/GrTextContext.h b/gpu/GrTextContext.h new file mode 100644 index 0000000..5204da4 --- /dev/null +++ b/gpu/GrTextContext.h @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextContext_DEFINED +#define GrTextContext_DEFINED + +#include "GrContext.h" +#include "GrGlyph.h" +#include "GrPaint.h" + +class GrContext; +class GrTextStrike; +class GrFontScaler; +class GrDrawTarget; + +class GrTextContext { +public: + GrTextContext(GrContext*, const GrPaint&); + ~GrTextContext(); + + void drawPackedGlyph(GrGlyph::PackedID, GrFixed left, GrFixed top, + GrFontScaler*); + + void flush(); // optional; automatically called by destructor + +private: + GrPaint fPaint; + GrContext* fContext; + GrDrawTarget* fDrawTarget; + + GrFontScaler* fScaler; + GrTextStrike* fStrike; + + inline void flushGlyphs(); + void setupDrawTarget(); + + enum { + kMinRequestedGlyphs = 1, + kDefaultRequestedGlyphs = 64, + kMinRequestedVerts = kMinRequestedGlyphs * 4, + kDefaultRequestedVerts = kDefaultRequestedGlyphs * 4, + }; + + SkPoint* fVertices; + int32_t fMaxVertices; + GrTexture* fCurrTexture; + int fCurrVertex; + + SkIRect fClipRect; + GrContext::AutoMatrix fAutoMatrix; +}; + +#endif diff --git a/gpu/GrTexture.h b/gpu/GrTexture.h new file mode 100644 index 0000000..1fb575c --- /dev/null +++ b/gpu/GrTexture.h @@ -0,0 +1,213 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTexture_DEFINED +#define GrTexture_DEFINED + +#include "GrSurface.h" +#include "SkPoint.h" +#include "GrRenderTarget.h" + +class GrResourceKey; +class GrTextureParams; + +class GrTexture : public GrSurface { + +public: + SK_DECLARE_INST_COUNT(GrTexture) + // from GrResource + /** + * Informational texture flags + */ + enum FlagBits { + kFirstBit = (kLastPublic_GrTextureFlagBit << 1), + + /** + * This texture should be returned to the texture cache when + * it is no longer reffed + */ + kReturnToCache_FlagBit = kFirstBit, + }; + + void setFlag(GrTextureFlags flags) { + fDesc.fFlags = fDesc.fFlags | flags; + } + void resetFlag(GrTextureFlags flags) { + fDesc.fFlags = fDesc.fFlags & ~flags; + } + bool isSetFlag(GrTextureFlags flags) const { + return 0 != (fDesc.fFlags & flags); + } + + void dirtyMipMaps(bool mipMapsDirty) { + fMipMapsDirty = mipMapsDirty; + } + + bool mipMapsAreDirty() const { + return fMipMapsDirty; + } + + /** + * Approximate number of bytes used by the texture + */ + virtual size_t sizeInBytes() const SK_OVERRIDE { + return (size_t) fDesc.fWidth * + fDesc.fHeight * + GrBytesPerPixel(fDesc.fConfig); + } + + // GrSurface overrides + virtual bool readPixels(int left, int top, int width, int height, + GrPixelConfig config, + void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) SK_OVERRIDE; + + virtual void writePixels(int left, int top, int width, int height, + GrPixelConfig config, + const void* buffer, + size_t rowBytes = 0, + uint32_t pixelOpsFlags = 0) SK_OVERRIDE; + + /** + * @return this texture + */ + virtual GrTexture* asTexture() SK_OVERRIDE { return this; } + virtual const GrTexture* asTexture() const SK_OVERRIDE { return this; } + + /** + * Retrieves the render target underlying this texture that can be passed to + * GrGpu::setRenderTarget(). + * + * @return handle to render target or NULL if the texture is not a + * render target + */ + virtual GrRenderTarget* asRenderTarget() SK_OVERRIDE { + return fRenderTarget.get(); + } + virtual const GrRenderTarget* asRenderTarget() const SK_OVERRIDE { + return fRenderTarget.get(); + } + + // GrTexture + /** + * Convert from texels to normalized texture coords for POT textures + * only. + */ + GrFixed normalizeFixedX(GrFixed x) const { + GrAssert(GrIsPow2(fDesc.fWidth)); + return x >> fShiftFixedX; + } + GrFixed normalizeFixedY(GrFixed y) const { + GrAssert(GrIsPow2(fDesc.fHeight)); + return y >> fShiftFixedY; + } + + /** + * Return the native ID or handle to the texture, depending on the + * platform. e.g. on OpenGL, return the texture ID. + */ + virtual GrBackendObject getTextureHandle() const = 0; + + /** + * Call this when the state of the native API texture object is + * altered directly, without being tracked by skia. + */ + virtual void invalidateCachedState() = 0; + +#if GR_DEBUG + void validate() const { + this->INHERITED::validate(); + + this->validateDesc(); + } +#else + void validate() const {} +#endif + static GrResourceKey ComputeKey(const GrGpu* gpu, + const GrTextureParams* params, + const GrTextureDesc& desc, + const GrCacheID& cacheID); + static GrResourceKey ComputeScratchKey(const GrTextureDesc& desc); + static bool NeedsResizing(const GrResourceKey& key); + static bool NeedsBilerp(const GrResourceKey& key); + +protected: + // A texture refs its rt representation but not vice-versa. It is up to + // the subclass constructor to initialize this pointer. + SkAutoTUnref<GrRenderTarget> fRenderTarget; + + GrTexture(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc) + : INHERITED(gpu, isWrapped, desc) + , fRenderTarget(NULL) + , fMipMapsDirty(true) { + + // only make sense if alloc size is pow2 + fShiftFixedX = 31 - SkCLZ(fDesc.fWidth); + fShiftFixedY = 31 - SkCLZ(fDesc.fHeight); + } + virtual ~GrTexture(); + + // GrResource overrides + virtual void onRelease() SK_OVERRIDE; + virtual void onAbandon() SK_OVERRIDE; + + void validateDesc() const; + +private: + // these two shift a fixed-point value into normalized coordinates + // for this texture if the texture is power of two sized. + int fShiftFixedX; + int fShiftFixedY; + + bool fMipMapsDirty; + + virtual void internal_dispose() const SK_OVERRIDE; + + typedef GrSurface INHERITED; +}; + +/** + * Represents a texture that is intended to be accessed in device coords with an offset. + */ +class GrDeviceCoordTexture { +public: + GrDeviceCoordTexture() { fOffset.set(0, 0); } + + GrDeviceCoordTexture(const GrDeviceCoordTexture& other) { + *this = other; + } + + GrDeviceCoordTexture(GrTexture* texture, const SkIPoint& offset) + : fTexture(SkSafeRef(texture)) + , fOffset(offset) { + } + + GrDeviceCoordTexture& operator=(const GrDeviceCoordTexture& other) { + fTexture.reset(SkSafeRef(other.fTexture.get())); + fOffset = other.fOffset; + return *this; + } + + const SkIPoint& offset() const { return fOffset; } + + void setOffset(const SkIPoint& offset) { fOffset = offset; } + void setOffset(int ox, int oy) { fOffset.set(ox, oy); } + + GrTexture* texture() const { return fTexture.get(); } + + GrTexture* setTexture(GrTexture* texture) { + fTexture.reset(SkSafeRef(texture)); + return texture; + } +private: + SkAutoTUnref<GrTexture> fTexture; + SkIPoint fOffset; +}; + +#endif diff --git a/gpu/GrTextureAccess.h b/gpu/GrTextureAccess.h new file mode 100644 index 0000000..8100b7a --- /dev/null +++ b/gpu/GrTextureAccess.h @@ -0,0 +1,188 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTextureAccess_DEFINED +#define GrTextureAccess_DEFINED + +#include "GrNoncopyable.h" +#include "SkRefCnt.h" +#include "SkShader.h" + +class GrTexture; + +/** + * Represents the filtering and tile modes used to access a texture. It is mostly used with + * GrTextureAccess (defined below). Also, some of the texture cache methods require knowledge about + * filtering and tiling to perform a cache lookup. If it wasn't for this latter usage this would + * be folded into GrTextureAccess. + */ +class GrTextureParams { +public: + GrTextureParams() { + this->reset(); + } + + enum FilterMode { + kNone_FilterMode, + kBilerp_FilterMode, + kMipMap_FilterMode + }; + + GrTextureParams(SkShader::TileMode tileXAndY, FilterMode filterMode) { + this->reset(tileXAndY, filterMode); + } + + GrTextureParams(SkShader::TileMode tileModes[2], FilterMode filterMode) { + this->reset(tileModes, filterMode); + } + + GrTextureParams(const GrTextureParams& params) { + *this = params; + } + + GrTextureParams& operator= (const GrTextureParams& params) { + fTileModes[0] = params.fTileModes[0]; + fTileModes[1] = params.fTileModes[1]; + fFilterMode = params.fFilterMode; + return *this; + } + + void reset() { + this->reset(SkShader::kClamp_TileMode, kNone_FilterMode); + } + + void reset(SkShader::TileMode tileXAndY, FilterMode filterMode) { + fTileModes[0] = fTileModes[1] = tileXAndY; + fFilterMode = filterMode; + } + + void reset(SkShader::TileMode tileModes[2], FilterMode filterMode) { + fTileModes[0] = tileModes[0]; + fTileModes[1] = tileModes[1]; + fFilterMode = filterMode; + } + + void setClampNoFilter() { + fTileModes[0] = fTileModes[1] = SkShader::kClamp_TileMode; + fFilterMode = kNone_FilterMode; + } + + void setClamp() { + fTileModes[0] = fTileModes[1] = SkShader::kClamp_TileMode; + } + + void setFilterMode(FilterMode filterMode) { fFilterMode = filterMode; } + + void setTileModeX(const SkShader::TileMode tm) { fTileModes[0] = tm; } + void setTileModeY(const SkShader::TileMode tm) { fTileModes[1] = tm; } + void setTileModeXAndY(const SkShader::TileMode tm) { fTileModes[0] = fTileModes[1] = tm; } + + SkShader::TileMode getTileModeX() const { return fTileModes[0]; } + + SkShader::TileMode getTileModeY() const { return fTileModes[1]; } + + bool isTiled() const { + return SkShader::kClamp_TileMode != fTileModes[0] || + SkShader::kClamp_TileMode != fTileModes[1]; + } + + FilterMode filterMode() const { return fFilterMode; } + + bool operator== (const GrTextureParams& other) const { + return fTileModes[0] == other.fTileModes[0] && + fTileModes[1] == other.fTileModes[1] && + fFilterMode == other.fFilterMode; + } + + bool operator!= (const GrTextureParams& other) const { return !(*this == other); } + +private: + + SkShader::TileMode fTileModes[2]; + FilterMode fFilterMode; +}; + +/** A class representing the swizzle access pattern for a texture. Note that if the texture is + * an alpha-only texture then the alpha channel is substituted for other components. Any mangling + * to handle the r,g,b->a conversions for alpha textures is automatically included in the stage + * key. However, if a GrEffect uses different swizzles based on its input then it must + * consider that variation in its key-generation. + */ +class GrTextureAccess : GrNoncopyable { +public: + /** + * A default GrTextureAccess must have reset() called on it in a GrEffect subclass's + * constructor if it will be accessible via GrEffect::textureAccess(). + */ + GrTextureAccess(); + + /** + * Uses the default swizzle, "rgba". + */ + GrTextureAccess(GrTexture*, const GrTextureParams&); + explicit GrTextureAccess(GrTexture*, + GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); + + /** + * swizzle must be a string between one and four (inclusive) characters containing only 'r', + * 'g', 'b', and/or 'a'. + */ + GrTextureAccess(GrTexture*, const char* swizzle, const GrTextureParams&); + GrTextureAccess(GrTexture*, + const char* swizzle, + GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); + + void reset(GrTexture*, const GrTextureParams&); + void reset(GrTexture*, + GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); + void reset(GrTexture*, const char* swizzle, const GrTextureParams&); + void reset(GrTexture*, + const char* swizzle, + GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, + SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode); + + bool operator== (const GrTextureAccess& other) const { +#if GR_DEBUG + // below assumes all chars in fSwizzle are initialized even if string is < 4 chars long. + GrAssert(memcmp(fSwizzle, other.fSwizzle, sizeof(fSwizzle)-1) == + strcmp(fSwizzle, other.fSwizzle)); +#endif + return fParams == other.fParams && + (fTexture.get() == other.fTexture.get()) && + (0 == memcmp(fSwizzle, other.fSwizzle, sizeof(fSwizzle)-1)); + } + + bool operator!= (const GrTextureAccess& other) const { return !(*this == other); } + + GrTexture* getTexture() const { return fTexture.get(); } + + /** + * Returns a string representing the swizzle. The string is is null-terminated. + */ + const char* getSwizzle() const { return fSwizzle; } + + /** Returns a mask indicating which components are referenced in the swizzle. The return + is a bitfield of GrColorComponentFlags. */ + uint32_t swizzleMask() const { return fSwizzleMask; } + + const GrTextureParams& getParams() const { return fParams; } + +private: + void setSwizzle(const char*); + + GrTextureParams fParams; + SkAutoTUnref<GrTexture> fTexture; + uint32_t fSwizzleMask; + char fSwizzle[5]; + + typedef GrNoncopyable INHERITED; +}; + +#endif diff --git a/gpu/GrTypes.h b/gpu/GrTypes.h new file mode 100644 index 0000000..18aedc5 --- /dev/null +++ b/gpu/GrTypes.h @@ -0,0 +1,630 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTypes_DEFINED +#define GrTypes_DEFINED + +#include "SkTypes.h" +#include "GrConfig.h" +#include "SkMath.h" + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Defines overloaded bitwise operators to make it easier to use an enum as a + * bitfield. + */ +#define GR_MAKE_BITFIELD_OPS(X) \ + inline X operator | (X a, X b) { \ + return (X) (+a | +b); \ + } \ + \ + inline X operator & (X a, X b) { \ + return (X) (+a & +b); \ + } \ + template <typename T> \ + inline X operator & (T a, X b) { \ + return (X) (+a & +b); \ + } \ + template <typename T> \ + inline X operator & (X a, T b) { \ + return (X) (+a & +b); \ + } \ + +#define GR_DECL_BITFIELD_OPS_FRIENDS(X) \ + friend X operator | (X a, X b); \ + \ + friend X operator & (X a, X b); \ + \ + template <typename T> \ + friend X operator & (T a, X b); \ + \ + template <typename T> \ + friend X operator & (X a, T b); \ +//////////////////////////////////////////////////////////////////////////////// + + +/** + * Macro to round n up to the next multiple of 4, or return it unchanged if + * n is already a multiple of 4 + */ +#define GrALIGN4(n) SkAlign4(n) +#define GrIsALIGN4(n) SkIsAlign4(n) + +template <typename T> const T& GrMin(const T& a, const T& b) { + return (a < b) ? a : b; +} + +template <typename T> const T& GrMax(const T& a, const T& b) { + return (b < a) ? a : b; +} + +// compile time versions of min/max +#define GR_CT_MAX(a, b) (((b) < (a)) ? (a) : (b)) +#define GR_CT_MIN(a, b) (((b) < (a)) ? (b) : (a)) + +/** + * divide, rounding up + */ +static inline int32_t GrIDivRoundUp(int x, int y) { + GrAssert(y > 0); + return (x + (y-1)) / y; +} +static inline uint32_t GrUIDivRoundUp(uint32_t x, uint32_t y) { + return (x + (y-1)) / y; +} +static inline size_t GrSizeDivRoundUp(size_t x, size_t y) { + return (x + (y-1)) / y; +} + +// compile time, evaluates Y multiple times +#define GR_CT_DIV_ROUND_UP(X, Y) (((X) + ((Y)-1)) / (Y)) + +/** + * align up + */ +static inline uint32_t GrUIAlignUp(uint32_t x, uint32_t alignment) { + return GrUIDivRoundUp(x, alignment) * alignment; +} +static inline size_t GrSizeAlignUp(size_t x, size_t alignment) { + return GrSizeDivRoundUp(x, alignment) * alignment; +} + +// compile time, evaluates A multiple times +#define GR_CT_ALIGN_UP(X, A) (GR_CT_DIV_ROUND_UP((X),(A)) * (A)) + +/** + * amount of pad needed to align up + */ +static inline uint32_t GrUIAlignUpPad(uint32_t x, uint32_t alignment) { + return (alignment - x % alignment) % alignment; +} +static inline size_t GrSizeAlignUpPad(size_t x, size_t alignment) { + return (alignment - x % alignment) % alignment; +} + +/** + * align down + */ +static inline uint32_t GrUIAlignDown(uint32_t x, uint32_t alignment) { + return (x / alignment) * alignment; +} +static inline size_t GrSizeAlignDown(size_t x, uint32_t alignment) { + return (x / alignment) * alignment; +} + +/** + * Count elements in an array + */ +#define GR_ARRAY_COUNT(array) SK_ARRAY_COUNT(array) + +//!< allocate a block of memory, will never return NULL +extern void* GrMalloc(size_t bytes); + +//!< free block allocated by GrMalloc. ptr may be NULL +extern void GrFree(void* ptr); + +static inline void Gr_bzero(void* dst, size_t size) { + memset(dst, 0, size); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Return true if n is a power of 2 + */ +static inline bool GrIsPow2(unsigned n) { + return n && 0 == (n & (n - 1)); +} + +/** + * Return the next power of 2 >= n. + */ +static inline uint32_t GrNextPow2(uint32_t n) { + return n ? (1 << (32 - SkCLZ(n - 1))) : 1; +} + +static inline int GrNextPow2(int n) { + GrAssert(n >= 0); // this impl only works for non-neg. + return n ? (1 << (32 - SkCLZ(n - 1))) : 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * 16.16 fixed point type + */ +typedef int32_t GrFixed; + +#if GR_DEBUG + +static inline int16_t GrToS16(intptr_t x) { + GrAssert((int16_t)x == x); + return (int16_t)x; +} + +#else + +#define GrToS16(x) x + +#endif + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Possible 3D APIs that may be used by Ganesh. + */ +enum GrBackend { + kOpenGL_GrBackend, +}; + +/** + * Backend-specific 3D context handle + * GrGLInterface* for OpenGL. If NULL will use the default GL interface. + */ +typedef intptr_t GrBackendContext; + +/////////////////////////////////////////////////////////////////////////////// + +/** +* Geometric primitives used for drawing. +*/ +enum GrPrimitiveType { + kTriangles_GrPrimitiveType, + kTriangleStrip_GrPrimitiveType, + kTriangleFan_GrPrimitiveType, + kPoints_GrPrimitiveType, + kLines_GrPrimitiveType, // 1 pix wide only + kLineStrip_GrPrimitiveType // 1 pix wide only +}; + +static inline bool GrIsPrimTypeLines(GrPrimitiveType type) { + return kLines_GrPrimitiveType == type || kLineStrip_GrPrimitiveType == type; +} + +static inline bool GrIsPrimTypeTris(GrPrimitiveType type) { + return kTriangles_GrPrimitiveType == type || + kTriangleStrip_GrPrimitiveType == type || + kTriangleFan_GrPrimitiveType == type; +} + +/** + * Coeffecients for alpha-blending. + */ +enum GrBlendCoeff { + kInvalid_GrBlendCoeff = -1, + + kZero_GrBlendCoeff, //<! 0 + kOne_GrBlendCoeff, //<! 1 + kSC_GrBlendCoeff, //<! src color + kISC_GrBlendCoeff, //<! one minus src color + kDC_GrBlendCoeff, //<! dst color + kIDC_GrBlendCoeff, //<! one minus dst color + kSA_GrBlendCoeff, //<! src alpha + kISA_GrBlendCoeff, //<! one minus src alpha + kDA_GrBlendCoeff, //<! dst alpha + kIDA_GrBlendCoeff, //<! one minus dst alpha + kConstC_GrBlendCoeff, //<! constant color + kIConstC_GrBlendCoeff, //<! one minus constant color + kConstA_GrBlendCoeff, //<! constant color alpha + kIConstA_GrBlendCoeff, //<! one minus constant color alpha + + kPublicGrBlendCoeffCount +}; + +/** + * Formats for masks, used by the font cache. + * Important that these are 0-based. + */ +enum GrMaskFormat { + kA8_GrMaskFormat, //!< 1-byte per pixel + kA565_GrMaskFormat, //!< 2-bytes per pixel + kA888_GrMaskFormat, //!< 4-bytes per pixel + + kCount_GrMaskFormats //!< used to allocate arrays sized for mask formats +}; + +/** + * Return the number of bytes-per-pixel for the specified mask format. + */ +static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) { + GrAssert((unsigned)format <= 2); + // kA8 (0) -> 1 + // kA565 (1) -> 2 + // kA888 (2) -> 4 + return 1 << (int)format; +} + +/** + * Pixel configurations. + */ +enum GrPixelConfig { + kUnknown_GrPixelConfig, + kAlpha_8_GrPixelConfig, + kIndex_8_GrPixelConfig, + kRGB_565_GrPixelConfig, + /** + * Premultiplied + */ + kRGBA_4444_GrPixelConfig, + /** + * Premultiplied. Byte order is r,g,b,a. + */ + kRGBA_8888_GrPixelConfig, + /** + * Premultiplied. Byte order is b,g,r,a. + */ + kBGRA_8888_GrPixelConfig, + + kLast_GrPixelConfig = kBGRA_8888_GrPixelConfig +}; +static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1; + +// Aliases for pixel configs that match skia's byte order. +#ifndef SK_CPU_LENDIAN + #error "Skia gpu currently assumes little endian" +#endif +#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) + static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig; +#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) + static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig; +#else + #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format." +#endif + +// Returns true if the pixel config is 32 bits per pixel +static inline bool GrPixelConfigIs8888(GrPixelConfig config) { + switch (config) { + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + return true; + default: + return false; + } +} + +// Takes a config and returns the equivalent config with the R and B order +// swapped if such a config exists. Otherwise, kUnknown_GrPixelConfig +static inline GrPixelConfig GrPixelConfigSwapRAndB(GrPixelConfig config) { + switch (config) { + case kBGRA_8888_GrPixelConfig: + return kRGBA_8888_GrPixelConfig; + case kRGBA_8888_GrPixelConfig: + return kBGRA_8888_GrPixelConfig; + default: + return kUnknown_GrPixelConfig; + } +} + +static inline size_t GrBytesPerPixel(GrPixelConfig config) { + switch (config) { + case kAlpha_8_GrPixelConfig: + case kIndex_8_GrPixelConfig: + return 1; + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + return 2; + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + return 4; + default: + return 0; + } +} + +static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) { + switch (config) { + case kRGB_565_GrPixelConfig: + return true; + default: + return false; + } +} + +static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) { + switch (config) { + case kAlpha_8_GrPixelConfig: + return true; + default: + return false; + } +} + +/** + * Optional bitfield flags that can be passed to createTexture. + */ +enum GrTextureFlags { + kNone_GrTextureFlags = 0x0, + /** + * Creates a texture that can be rendered to as a GrRenderTarget. Use + * GrTexture::asRenderTarget() to access. + */ + kRenderTarget_GrTextureFlagBit = 0x1, + /** + * By default all render targets have an associated stencil buffer that + * may be required for path filling. This flag overrides stencil buffer + * creation. + * MAKE THIS PRIVATE? + */ + kNoStencil_GrTextureFlagBit = 0x2, + /** + * Hint that the CPU may modify this texture after creation. + */ + kDynamicUpdate_GrTextureFlagBit = 0x4, + /** + * Indicates that all allocations (color buffer, FBO completeness, etc) + * should be verified. + */ + kCheckAllocation_GrTextureFlagBit = 0x8, + + kDummy_GrTextureFlagBit, + kLastPublic_GrTextureFlagBit = kDummy_GrTextureFlagBit-1, +}; + +GR_MAKE_BITFIELD_OPS(GrTextureFlags) + +enum { + /** + * For Index8 pixel config, the colortable must be 256 entries + */ + kGrColorTableSize = 256 * 4 //sizeof(GrColor) +}; + +/** + * Some textures will be stored such that the upper and left edges of the content meet at the + * the origin (in texture coord space) and for other textures the lower and left edges meet at + * the origin. kDefault_GrSurfaceOrigin sets textures to TopLeft, and render targets + * to BottomLeft. + */ + +enum GrSurfaceOrigin { + kDefault_GrSurfaceOrigin, // DEPRECATED; to be removed + kTopLeft_GrSurfaceOrigin, + kBottomLeft_GrSurfaceOrigin, +}; + +/** + * Describes a texture to be created. + */ +struct GrTextureDesc { + GrTextureDesc() + : fFlags(kNone_GrTextureFlags) + , fOrigin(kDefault_GrSurfaceOrigin) + , fWidth(0) + , fHeight(0) + , fConfig(kUnknown_GrPixelConfig) + , fSampleCnt(0) { + } + + GrTextureFlags fFlags; //!< bitfield of TextureFlags + GrSurfaceOrigin fOrigin; //!< origin of the texture + int fWidth; //!< Width of the texture + int fHeight; //!< Height of the texture + + /** + * Format of source data of the texture. Not guaranteed to be the same as + * internal format used by 3D API. + */ + GrPixelConfig fConfig; + + /** + * The number of samples per pixel or 0 to disable full scene AA. This only + * applies if the kRenderTarget_GrTextureFlagBit is set. The actual number + * of samples may not exactly match the request. The request will be rounded + * up to the next supported sample count, or down if it is larger than the + * max supported count. + */ + int fSampleCnt; +}; + +/** + * GrCacheID is used create and find cached GrResources (e.g. GrTextures). The ID has two parts: + * the domain and the key. Domains simply allow multiple clients to use 0-based indices as their + * cache key without colliding. The key uniquely identifies a GrResource within the domain. + * Users of the cache must obtain a domain via GenerateDomain(). + */ +struct GrCacheID { +public: + typedef uint8_t Domain; + + struct Key { + union { + uint8_t fData8[16]; + uint32_t fData32[4]; + uint64_t fData64[2]; + }; + }; + + /** + * A default cache ID is invalid; a set method must be called before the object is used. + */ + GrCacheID() { fDomain = kInvalid_Domain; } + + /** + * Initialize the cache ID to a domain and key. + */ + GrCacheID(Domain domain, const Key& key) { + GrAssert(kInvalid_Domain != domain); + this->reset(domain, key); + } + + void reset(Domain domain, const Key& key) { + fDomain = domain; + memcpy(&fKey, &key, sizeof(Key)); + } + + /** Has this been initialized to a valid domain */ + bool isValid() const { return kInvalid_Domain != fDomain; } + + const Key& getKey() const { GrAssert(this->isValid()); return fKey; } + Domain getDomain() const { GrAssert(this->isValid()); return fDomain; } + + /** Creates a new unique ID domain. */ + static Domain GenerateDomain(); + +private: + Key fKey; + Domain fDomain; + + static const Domain kInvalid_Domain = 0; +}; + +/** + * Clips are composed from these objects. + */ +enum GrClipType { + kRect_ClipType, + kPath_ClipType +}; + +/////////////////////////////////////////////////////////////////////////////// + +// opaque type for 3D API object handles +typedef intptr_t GrBackendObject; + +/** + * Gr can wrap an existing texture created by the client with a GrTexture + * object. The client is responsible for ensuring that the texture lives at + * least as long as the GrTexture object wrapping it. We require the client to + * explicitly provide information about the texture, such as width, height, + * and pixel config, rather than querying the 3D APIfor these values. We expect + * these to be immutable even if the 3D API doesn't require this (OpenGL). + * + * Textures that are also render targets are supported as well. Gr will manage + * any ancillary 3D API (stencil buffer, FBO id, etc) objects necessary for + * Gr to draw into the render target. To access the render target object + * call GrTexture::asRenderTarget(). + * + * If in addition to the render target flag, the caller also specifies a sample + * count Gr will create an MSAA buffer that resolves into the texture. Gr auto- + * resolves when it reads from the texture. The client can explictly resolve + * using the GrRenderTarget interface. + * + * Note: These flags currently form a subset of GrTexture's flags. + */ + +enum GrBackendTextureFlags { + /** + * No flags enabled + */ + kNone_GrBackendTextureFlag = kNone_GrTextureFlags, + /** + * Indicates that the texture is also a render target, and thus should have + * a GrRenderTarget object. + * + * D3D (future): client must have created the texture with flags that allow + * it to be used as a render target. + */ + kRenderTarget_GrBackendTextureFlag = kRenderTarget_GrTextureFlagBit, +}; +GR_MAKE_BITFIELD_OPS(GrBackendTextureFlags) + +struct GrBackendTextureDesc { + GrBackendTextureDesc() { memset(this, 0, sizeof(*this)); } + GrBackendTextureFlags fFlags; + GrSurfaceOrigin fOrigin; + int fWidth; //<! width in pixels + int fHeight; //<! height in pixels + GrPixelConfig fConfig; //<! color format + /** + * If the render target flag is set and sample count is greater than 0 + * then Gr will create an MSAA buffer that resolves to the texture. + */ + int fSampleCnt; + /** + * Handle to the 3D API object. + * OpenGL: Texture ID. + */ + GrBackendObject fTextureHandle; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Gr can wrap an existing render target created by the client in the 3D API + * with a GrRenderTarget object. The client is responsible for ensuring that the + * underlying 3D API object lives at least as long as the GrRenderTarget object + * wrapping it. We require the client to explicitly provide information about + * the target, such as width, height, and pixel config rather than querying the + * 3D API for these values. We expect these properties to be immutable even if + * the 3D API doesn't require this (OpenGL). + */ + +struct GrBackendRenderTargetDesc { + GrBackendRenderTargetDesc() { memset(this, 0, sizeof(*this)); } + int fWidth; //<! width in pixels + int fHeight; //<! height in pixels + GrPixelConfig fConfig; //<! color format + GrSurfaceOrigin fOrigin; //<! pixel origin + /** + * The number of samples per pixel. Gr uses this to influence decisions + * about applying other forms of anti-aliasing. + */ + int fSampleCnt; + /** + * Number of bits of stencil per-pixel. + */ + int fStencilBits; + /** + * Handle to the 3D API object. + * OpenGL: FBO ID + */ + GrBackendObject fRenderTargetHandle; +}; + +/** + * The GrContext's cache of backend context state can be partially invalidated. + * These enums are specific to the GL backend and we'd add a new set for an alternative backend. + */ +enum GrGLBackendState { + kRenderTarget_GrGLBackendState = 1 << 0, + kTextureBinding_GrGLBackendState = 1 << 1, + // View state stands for scissor and viewport + kView_GrGLBackendState = 1 << 2, + kBlend_GrGLBackendState = 1 << 3, + kAA_GrGLBackendState = 1 << 4, + kVertex_GrGLBackendState = 1 << 5, + kStencil_GrGLBackendState = 1 << 6, + kPixelStore_GrGLBackendState = 1 << 7, + kProgram_GrGLBackendState = 1 << 8, + kPathStencil_GrGLBackendState = 1 << 9, + kMisc_GrGLBackendState = 1 << 10, + kALL_GrGLBackendState = 0xffff +}; + +/** + * This value translates to reseting all the context state for any backend. + */ +static const uint32_t kAll_GrBackendState = 0xffffffff; + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/gpu/GrTypesPriv.h b/gpu/GrTypesPriv.h new file mode 100644 index 0000000..3538f38 --- /dev/null +++ b/gpu/GrTypesPriv.h @@ -0,0 +1,169 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTypesPriv_DEFINED +#define GrTypesPriv_DEFINED + +#include "GrTypes.h" +#include "SkTArray.h" + +/** + * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, + * but should be applicable to other shader languages.) + */ +enum GrSLType { + kVoid_GrSLType, + kFloat_GrSLType, + kVec2f_GrSLType, + kVec3f_GrSLType, + kVec4f_GrSLType, + kMat33f_GrSLType, + kMat44f_GrSLType, + kSampler2D_GrSLType, + + kLast_GrSLType = kSampler2D_GrSLType +}; +static const int kGrSLTypeCount = kLast_GrSLType + 1; + +/** + * Gets the vector size of the SLType. Returns -1 for void, matrices, and samplers. + */ +static inline int GrSLTypeVectorCount(GrSLType type) { + GrAssert(type >= 0 && type < static_cast<GrSLType>(kGrSLTypeCount)); + static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1 }; + return kCounts[type]; + + GR_STATIC_ASSERT(0 == kVoid_GrSLType); + GR_STATIC_ASSERT(1 == kFloat_GrSLType); + GR_STATIC_ASSERT(2 == kVec2f_GrSLType); + GR_STATIC_ASSERT(3 == kVec3f_GrSLType); + GR_STATIC_ASSERT(4 == kVec4f_GrSLType); + GR_STATIC_ASSERT(5 == kMat33f_GrSLType); + GR_STATIC_ASSERT(6 == kMat44f_GrSLType); + GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); + GR_STATIC_ASSERT(GR_ARRAY_COUNT(kCounts) == kGrSLTypeCount); +} + +/** Return the type enum for a vector of floats of length n (1..4), + e.g. 1 -> kFloat_GrSLType, 2 -> kVec2_GrSLType, ... */ +static inline GrSLType GrSLFloatVectorType(int count) { + GrAssert(count > 0 && count <= 4); + return (GrSLType)(count); + + GR_STATIC_ASSERT(kFloat_GrSLType == 1); + GR_STATIC_ASSERT(kVec2f_GrSLType == 2); + GR_STATIC_ASSERT(kVec3f_GrSLType == 3); + GR_STATIC_ASSERT(kVec4f_GrSLType == 4); +} + +/** + * Types used to describe format of vertices in arrays. + */ +enum GrVertexAttribType { + kFloat_GrVertexAttribType = 0, + kVec2f_GrVertexAttribType, + kVec3f_GrVertexAttribType, + kVec4f_GrVertexAttribType, + kVec4ub_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors + + kLast_GrVertexAttribType = kVec4ub_GrVertexAttribType +}; +static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; + +/** + * Returns the vector size of the type. + */ +static inline int GrVertexAttribTypeVectorCount(GrVertexAttribType type) { + GrAssert(type >= 0 && type < kGrVertexAttribTypeCount); + static const int kCounts[] = { 1, 2, 3, 4, 4 }; + return kCounts[type]; + + GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); + GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); + GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); + GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); + GR_STATIC_ASSERT(4 == kVec4ub_GrVertexAttribType); + GR_STATIC_ASSERT(GR_ARRAY_COUNT(kCounts) == kGrVertexAttribTypeCount); +} + +/** + * Returns the size of the attrib type in bytes. + */ +static inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) { + GrAssert(type >= 0 && type < kGrVertexAttribTypeCount); + static const size_t kSizes[] = { + sizeof(float), // kFloat_GrVertexAttribType + 2*sizeof(float), // kVec2f_GrVertexAttribType + 3*sizeof(float), // kVec3f_GrVertexAttribType + 4*sizeof(float), // kVec4f_GrVertexAttribType + 4*sizeof(char) // kVec4ub_GrVertexAttribType + }; + return kSizes[type]; + + GR_STATIC_ASSERT(0 == kFloat_GrVertexAttribType); + GR_STATIC_ASSERT(1 == kVec2f_GrVertexAttribType); + GR_STATIC_ASSERT(2 == kVec3f_GrVertexAttribType); + GR_STATIC_ASSERT(3 == kVec4f_GrVertexAttribType); + GR_STATIC_ASSERT(4 == kVec4ub_GrVertexAttribType); + GR_STATIC_ASSERT(GR_ARRAY_COUNT(kSizes) == kGrVertexAttribTypeCount); +} + +/** + * Semantic bindings for vertex attributes. kEffect means that the attribute is input to a GrEffect. + * Each binding other than kEffect may not appear more than once in the current set of attributes. + * kPosition must be appear for exactly one attribute. + */ +enum GrVertexAttribBinding { + kPosition_GrVertexAttribBinding, // required, must have vector count of 2 + kLocalCoord_GrVertexAttribBinding, // must have vector count of 2 + kColor_GrVertexAttribBinding, // must have vector count of 4 + kCoverage_GrVertexAttribBinding, // must have vector count of 4 + + kLastFixedFunction_GrVertexAttribBinding = kCoverage_GrVertexAttribBinding, + + kEffect_GrVertexAttribBinding, // vector length must agree with + // GrEffect::vertexAttribType() for each effect input to + // which the attribute is mapped by GrDrawState::setEffect() + kLast_GrVertexAttribBinding = kEffect_GrVertexAttribBinding +}; + +static const int kGrVertexAttribBindingCnt = kLast_GrVertexAttribBinding + 1; +static const int kGrFixedFunctionVertexAttribBindingCnt = + kLastFixedFunction_GrVertexAttribBinding + 1; + +static inline int GrFixedFunctionVertexAttribVectorCount(GrVertexAttribBinding binding) { + GrAssert(binding >= 0 && binding < kGrFixedFunctionVertexAttribBindingCnt); + static const int kVecCounts[] = { 2, 2, 4, 4 }; + + return kVecCounts[binding]; + + GR_STATIC_ASSERT(0 == kPosition_GrVertexAttribBinding); + GR_STATIC_ASSERT(1 == kLocalCoord_GrVertexAttribBinding); + GR_STATIC_ASSERT(2 == kColor_GrVertexAttribBinding); + GR_STATIC_ASSERT(3 == kCoverage_GrVertexAttribBinding); + GR_STATIC_ASSERT(kGrFixedFunctionVertexAttribBindingCnt == SK_ARRAY_COUNT(kVecCounts)); +} + +struct GrVertexAttrib { + inline void set(GrVertexAttribType type, size_t offset, GrVertexAttribBinding binding) { + fType = type; + fOffset = offset; + fBinding = binding; + } + bool operator==(const GrVertexAttrib& other) const { + return fType == other.fType && fOffset == other.fOffset && fBinding == other.fBinding; + }; + bool operator!=(const GrVertexAttrib& other) const { return !(*this == other); } + + GrVertexAttribType fType; + size_t fOffset; + GrVertexAttribBinding fBinding; +}; + +template <int N> class GrVertexAttribArray : public SkSTArray<N, GrVertexAttrib, true> {}; + +#endif diff --git a/gpu/GrUserConfig.h b/gpu/GrUserConfig.h new file mode 100644 index 0000000..a10d339 --- /dev/null +++ b/gpu/GrUserConfig.h @@ -0,0 +1,37 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrUserConfig_DEFINED +#define GrUserConfig_DEFINED + +#if defined(GR_USER_CONFIG_FILE) + #error "default user config pulled in but GR_USER_CONFIG_FILE is defined." +#endif + +#if 0 + #undef GR_RELEASE + #undef GR_DEBUG + #define GR_RELEASE 0 + #define GR_DEBUG 1 +#endif + +/** + * This gives a threshold in bytes of when to lock a GrGeometryBuffer vs using + * updateData. (Note the depending on the underlying 3D API the update functions + * may always be implemented using a lock) + */ +//#define GR_GEOM_BUFFER_LOCK_THRESHOLD (1<<15) + +/** + * This gives a threshold in megabytes for the maximum size of the texture cache + * in vram. The value is only a default and can be overridden at runtime. + */ +//#define GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT 96 + +#endif diff --git a/gpu/SkGpuDevice.h b/gpu/SkGpuDevice.h new file mode 100644 index 0000000..32f8749 --- /dev/null +++ b/gpu/SkGpuDevice.h @@ -0,0 +1,194 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkGpuDevice_DEFINED +#define SkGpuDevice_DEFINED + +#include "SkGr.h" +#include "SkBitmap.h" +#include "SkDevice.h" +#include "SkRegion.h" +#include "GrContext.h" + +struct SkDrawProcs; +struct GrSkDrawProcs; +class GrTextContext; + +/** + * Subclass of SkDevice, which directs all drawing to the GrGpu owned by the + * canvas. + */ +class SK_API SkGpuDevice : public SkDevice { +public: + + /** + * Creates an SkGpuDevice from a GrSurface. This will fail if the surface is not a render + * target. The caller owns a ref on the returned device. + */ + static SkGpuDevice* Create(GrSurface* surface); + + /** + * New device that will create an offscreen renderTarget based on the + * config, width, height, and sampleCount. The device's storage will not + * count against the GrContext's texture cache budget. The device's pixels + * will be uninitialized. TODO: This can fail, replace with a factory function. + */ + SkGpuDevice(GrContext*, SkBitmap::Config, int width, int height, int sampleCount = 0); + + /** + * New device that will render to the specified renderTarget. + * DEPRECATED: Use Create(surface) + */ + SkGpuDevice(GrContext*, GrRenderTarget*); + + /** + * New device that will render to the texture (as a rendertarget). + * The GrTexture's asRenderTarget() must be non-NULL or device will not + * function. + * DEPRECATED: Use Create(surface) + */ + SkGpuDevice(GrContext*, GrTexture*); + + virtual ~SkGpuDevice(); + + GrContext* context() const { return fContext; } + + virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE; + + // overrides from SkDevice + + virtual void clear(SkColor color) SK_OVERRIDE; + virtual void writePixels(const SkBitmap& bitmap, int x, int y, + SkCanvas::Config8888 config8888) SK_OVERRIDE; + + virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, + const SkPoint[], const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkDraw&, const SkRect& r, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawRRect(const SkDraw&, const SkRRect& r, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawOval(const SkDraw&, const SkRect& oval, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawPath(const SkDraw&, const SkPath& path, + const SkPaint& paint, const SkMatrix* prePathMatrix, + bool pathIsMutable) SK_OVERRIDE; + virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + const SkMatrix&, const SkPaint&) SK_OVERRIDE; + virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, + const SkRect* srcOrNull, const SkRect& dst, + const SkPaint& paint) SK_OVERRIDE; + 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&) SK_OVERRIDE; + virtual void drawPosText(const SkDraw&, const void* text, size_t len, + const SkScalar pos[], SkScalar constY, + int scalarsPerPos, const SkPaint&) SK_OVERRIDE; + virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint&) SK_OVERRIDE; + 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&) SK_OVERRIDE; + virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&) SK_OVERRIDE; + virtual bool filterTextFlags(const SkPaint&, TextFlags*) SK_OVERRIDE; + + virtual void flush(); + + virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; + virtual void onDetachFromCanvas() SK_OVERRIDE; + + /** + * Make's this device's rendertarget current in the underlying 3D API. + * Also implicitly flushes. + */ + virtual void makeRenderTargetCurrent(); + + virtual bool canHandleImageFilter(SkImageFilter*) SK_OVERRIDE; + virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&, + SkBitmap*, SkIPoint*) SK_OVERRIDE; + + class SkAutoCachedTexture; // used internally + +protected: + // overrides from SkDevice + virtual bool onReadPixels(const SkBitmap& bitmap, + int x, int y, + SkCanvas::Config8888 config8888) SK_OVERRIDE; + +private: + GrContext* fContext; + + GrSkDrawProcs* fDrawProcs; + + GrClipData fClipData; + + // state for our render-target + GrRenderTarget* fRenderTarget; + bool fNeedClear; + + // called from rt and tex cons + void initFromRenderTarget(GrContext*, GrRenderTarget*, bool cached); + + // used by createCompatibleDevice + SkGpuDevice(GrContext*, GrTexture* texture, bool needClear); + + // override from SkDevice + virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config, + int width, int height, + bool isOpaque, + Usage usage) SK_OVERRIDE; + + SkDrawProcs* initDrawForText(GrTextContext*); + + // sets the render target, clip, and matrix on GrContext. Use forceIdenity to override + // SkDraw's matrix and draw in device coords. + void prepareDraw(const SkDraw&, bool forceIdentity); + + /** + * Implementation for both drawBitmap and drawBitmapRect. + */ + void drawBitmapCommon(const SkDraw&, + const SkBitmap& bitmap, + const SkRect* srcRectPtr, + const SkMatrix&, + const SkPaint&); + + /** + * Helper functions called by drawBitmapCommon. By the time these are called the SkDraw's + * matrix has already been set on GrContext + */ + bool shouldTileBitmap(const SkBitmap& bitmap, + const GrTextureParams& sampler, + const SkRect* srcRectPtr) const; + void internalDrawBitmap(const SkBitmap&, + const SkRect&, + const SkMatrix&, + const GrTextureParams& params, + const SkPaint& paint); + void drawTiledBitmap(const SkBitmap& bitmap, + const SkRect& srcRect, + const SkMatrix& m, + const GrTextureParams& params, + const SkPaint& paint); + + /** + * Returns non-initialized instance. + */ + GrTextContext* getTextContext(); + + typedef SkDevice INHERITED; +}; + +#endif diff --git a/gpu/SkGr.h b/gpu/SkGr.h new file mode 100644 index 0000000..1f72fbc --- /dev/null +++ b/gpu/SkGr.h @@ -0,0 +1,101 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkGr_DEFINED +#define SkGr_DEFINED + +#include <stddef.h> + +// Gr headers +#include "GrTypes.h" +#include "GrContext.h" +#include "GrFontScaler.h" + +// skia headers +#include "SkBitmap.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkRegion.h" +#include "SkClipStack.h" + +#if (GR_DEBUG && defined(SK_RELEASE)) || (GR_RELEASE && defined(SK_DEBUG)) +// #error "inconsistent GR_DEBUG and SK_DEBUG" +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Sk to Gr Type conversions + +GR_STATIC_ASSERT((int)kZero_GrBlendCoeff == (int)SkXfermode::kZero_Coeff); +GR_STATIC_ASSERT((int)kOne_GrBlendCoeff == (int)SkXfermode::kOne_Coeff); +GR_STATIC_ASSERT((int)kSC_GrBlendCoeff == (int)SkXfermode::kSC_Coeff); +GR_STATIC_ASSERT((int)kISC_GrBlendCoeff == (int)SkXfermode::kISC_Coeff); +GR_STATIC_ASSERT((int)kDC_GrBlendCoeff == (int)SkXfermode::kDC_Coeff); +GR_STATIC_ASSERT((int)kIDC_GrBlendCoeff == (int)SkXfermode::kIDC_Coeff); +GR_STATIC_ASSERT((int)kSA_GrBlendCoeff == (int)SkXfermode::kSA_Coeff); +GR_STATIC_ASSERT((int)kISA_GrBlendCoeff == (int)SkXfermode::kISA_Coeff); +GR_STATIC_ASSERT((int)kDA_GrBlendCoeff == (int)SkXfermode::kDA_Coeff); +GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff); + +#define sk_blend_to_grblend(X) ((GrBlendCoeff)(X)) + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkColorPriv.h" + +/** + * Convert the SkBitmap::Config to the corresponding PixelConfig, or + * kUnknown_PixelConfig if the conversion cannot be done. + */ +GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config); + +static inline GrColor SkColor2GrColor(SkColor c) { + SkPMColor pm = SkPreMultiplyColor(c); + unsigned r = SkGetPackedR32(pm); + unsigned g = SkGetPackedG32(pm); + unsigned b = SkGetPackedB32(pm); + unsigned a = SkGetPackedA32(pm); + return GrColorPackRGBA(r, g, b, a); +} + +//////////////////////////////////////////////////////////////////////////////// + +bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*); + +GrTexture* GrLockAndRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*); + +void GrUnlockAndUnrefCachedBitmapTexture(GrTexture*); + +//////////////////////////////////////////////////////////////////////////////// +// Classes + +class SkGlyphCache; + +class SkGrFontScaler : public GrFontScaler { +public: + explicit SkGrFontScaler(SkGlyphCache* strike); + virtual ~SkGrFontScaler(); + + // overrides + virtual const GrKey* getKey(); + virtual GrMaskFormat getMaskFormat(); + virtual bool getPackedGlyphBounds(GrGlyph::PackedID, SkIRect* bounds); + virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height, + int rowBytes, void* image); + virtual bool getGlyphPath(uint16_t glyphID, SkPath*); + +private: + SkGlyphCache* fStrike; + GrKey* fKey; +// DECLARE_INSTANCE_COUNTER(SkGrFontScaler); +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/gpu/SkGrPixelRef.h b/gpu/SkGrPixelRef.h new file mode 100644 index 0000000..da4b8fa --- /dev/null +++ b/gpu/SkGrPixelRef.h @@ -0,0 +1,70 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkGrPixelRef_DEFINED +#define SkGrPixelRef_DEFINED + +#include "SkBitmap.h" +#include "SkPixelRef.h" +#include "GrTexture.h" +#include "GrRenderTarget.h" + + +/** + * Common baseclass that implements onLockPixels() by calling onReadPixels(). + * Since it has a copy, it always returns false for onLockPixelsAreWritable(). + */ +class SK_API SkROLockPixelsPixelRef : public SkPixelRef { +public: + SkROLockPixelsPixelRef(); + virtual ~SkROLockPixelsPixelRef(); + +protected: + // override from SkPixelRef + virtual void* onLockPixels(SkColorTable** ptr); + virtual void onUnlockPixels(); + virtual bool onLockPixelsAreWritable() const; // return false; + +private: + SkBitmap fBitmap; + typedef SkPixelRef INHERITED; +}; + +/** + * PixelRef that wraps a GrSurface + */ +class SK_API SkGrPixelRef : public SkROLockPixelsPixelRef { +public: + /** + * Constructs a pixel ref around a GrSurface. If the caller has locked the GrSurface in the + * cache and would like the pixel ref to unlock it in its destructor then transferCacheLock + * should be set to true. + */ + SkGrPixelRef(GrSurface* surface, bool transferCacheLock = false); + virtual ~SkGrPixelRef(); + + // override from SkPixelRef + virtual GrTexture* getTexture() SK_OVERRIDE; + + SK_DECLARE_UNFLATTENABLE_OBJECT() + +protected: + // overrides from SkPixelRef + virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset) SK_OVERRIDE; + virtual SkPixelRef* deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) SK_OVERRIDE; + +private: + GrSurface* fSurface; + bool fUnlock; // if true the pixel ref owns a texture cache lock on fSurface + + typedef SkROLockPixelsPixelRef INHERITED; +}; + +#endif diff --git a/gpu/SkGrTexturePixelRef.h b/gpu/SkGrTexturePixelRef.h new file mode 100644 index 0000000..7129512 --- /dev/null +++ b/gpu/SkGrTexturePixelRef.h @@ -0,0 +1,19 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkGrTexturePixelRef_DEFINED +#define SkGrTexturePixelRef_DEFINED + +#include "SkGrPixelRef.h" + +typedef SkGrPixelRef SkGrTexturePixelRef; +typedef SkGrPixelRef SkGrRenderTargetPixelRef; + +#endif diff --git a/gpu/gl/GrGLConfig.h b/gpu/gl/GrGLConfig.h new file mode 100644 index 0000000..81cba1b --- /dev/null +++ b/gpu/gl/GrGLConfig.h @@ -0,0 +1,194 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrGLConfig_DEFINED +#define GrGLConfig_DEFINED + +#include "GrTypes.h" + +/** + * Optional GL config file. + */ +#ifdef GR_GL_CUSTOM_SETUP_HEADER + #include GR_GL_CUSTOM_SETUP_HEADER +#endif + +#if !defined(GR_GL_FUNCTION_TYPE) + #define GR_GL_FUNCTION_TYPE +#endif + +/** + * The following are optional defines that can be enabled at the compiler + * command line, in a IDE project, in a GrUserConfig.h file, or in a GL custom + * file (if one is in use). If a GR_GL_CUSTOM_SETUP_HEADER is used they can + * also be placed there. + * + * GR_GL_LOG_CALLS: if 1 Gr can print every GL call using GrPrintf. Defaults to + * 0. Logging can be enabled and disabled at runtime using a debugger via to + * global gLogCallsGL. The initial value of gLogCallsGL is controlled by + * GR_GL_LOG_CALLS_START. + * + * GR_GL_LOG_CALLS_START: controls the initial value of gLogCallsGL when + * GR_GL_LOG_CALLS is 1. Defaults to 0. + * + * GR_GL_CHECK_ERROR: if enabled Gr can do a glGetError() after every GL call. + * Defaults to 1 if GR_DEBUG is set, otherwise 0. When GR_GL_CHECK_ERROR is 1 + * this can be toggled in a debugger using the gCheckErrorGL global. The initial + * value of gCheckErrorGL is controlled by by GR_GL_CHECK_ERROR_START. + * + * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL + * when GR_GL_CHECK_ERROR is 1. Defaults to 1. + * + * GR_GL_NO_CONSTANT_ATTRIBUTES: if this evaluates to true then the GL backend + * will use uniforms instead of attributes in all cases when there is not + * per-vertex data. This is important when the underlying GL implementation + * doesn't actually support immediate style attribute values (e.g. when + * the GL stream is converted to DX as in ANGLE on Chrome). Defaults to 0. + * + * GR_GL_USE_BUFFER_DATA_NULL_HINT: When specifing new data for a vertex/index + * buffer that replaces old data Ganesh can give a hint to the driver that the + * previous data will not be used in future draws like this: + * glBufferData(GL_..._BUFFER, size, NULL, usage); //<--hint, NULL means + * glBufferSubData(GL_..._BUFFER, 0, lessThanSize, data) // old data can't be + * // used again. + * However, this can be an unoptimization on some platforms, esp. Chrome. + * Chrome's cmd buffer will create a new allocation and memset the whole thing + * to zero (for security reasons). Defaults to 1 (enabled). + * + * GR_GL_PER_GL_FUNC_CALLBACK: When set to 1 the GrGLInterface object provides + * a function pointer that is called just before every gl function. The ptr must + * be valid (i.e. there is no NULL check). However, by default the callback will + * be set to a function that does nothing. The signature of the function is: + * void function(const GrGLInterface*) + * It is not extern "C". + * The GrGLInterface field fCallback specifies the function ptr and there is an + * additional field fCallbackData of type intptr_t for client data. + * + * GR_GL_RGBA_8888_PIXEL_OPS_SLOW: Set this to 1 if it is known that performing + * glReadPixels / glTex(Sub)Image with format=GL_RGBA, type=GL_UNISIGNED_BYTE is + * significantly slower than format=GL_BGRA, type=GL_UNISIGNED_BYTE. + * + * GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL: Set this to 1 if calling + * glReadPixels to read the entire framebuffer is faster than calling it with + * the same sized rectangle but with a framebuffer bound that is larger than + * the rectangle read. + * + * GR_GL_CHECK_ALLOC_WITH_GET_ERROR: If set to 1 this will then glTexImage, + * glBufferData, glRenderbufferStorage, etc will be checked for errors. This + * amounts to ensuring the error is GL_NO_ERROR, calling the allocating + * function, and then checking that the error is still GL_NO_ERROR. When the + * value is 0 we will assume no error was generated without checking. + * + * GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT: We will normally check the FBO status + * every time we bind a texture or renderbuffer to an FBO. However, in some + * environments CheckFrameBufferStatus is very expensive. If this is set we will + * check the first time we use a color format or a combination of color / + * stencil formats as attachments. If the FBO is complete we will assume + * subsequent attachments with the same formats are complete as well. + * + * GR_GL_USE_NV_PATH_RENDERING: Enable experimental support for + * GL_NV_path_rendering. There are known issues with clipping, non-AA paths, and + * perspective. + * + * GR_GL_MUST_USE_VBO: Indicates that all vertices and indices must be rendered + * from VBOs. Chromium's command buffer doesn't allow glVertexAttribArray with + * ARARY_BUFFER 0 bound or glDrawElements with ELEMENT_ARRAY_BUFFER 0 bound. + * + * GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE is for compatibility with the new version + * of the OpenGLES2.0 headers from Khronos. glShaderSource now takes a const char * const *, + * instead of a const char + */ + +#if !defined(GR_GL_LOG_CALLS) + #define GR_GL_LOG_CALLS GR_DEBUG +#endif + +#if !defined(GR_GL_LOG_CALLS_START) + #define GR_GL_LOG_CALLS_START 0 +#endif + +#if !defined(GR_GL_CHECK_ERROR) + #define GR_GL_CHECK_ERROR GR_DEBUG +#endif + +#if !defined(GR_GL_CHECK_ERROR_START) + #define GR_GL_CHECK_ERROR_START 1 +#endif + +#if !defined(GR_GL_NO_CONSTANT_ATTRIBUTES) + #define GR_GL_NO_CONSTANT_ATTRIBUTES 0 +#endif + +#if !defined(GR_GL_USE_BUFFER_DATA_NULL_HINT) + #define GR_GL_USE_BUFFER_DATA_NULL_HINT 1 +#endif + +#if !defined(GR_GL_PER_GL_FUNC_CALLBACK) + #define GR_GL_PER_GL_FUNC_CALLBACK 0 +#endif + +#if !defined(GR_GL_RGBA_8888_PIXEL_OPS_SLOW) + #define GR_GL_RGBA_8888_PIXEL_OPS_SLOW 0 +#endif + +#if !defined(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL) + #define GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL 0 +#endif + +#if !defined(GR_GL_CHECK_ALLOC_WITH_GET_ERROR) + #define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 1 +#endif + +#if !defined(GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT) + #define GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT 0 +#endif + +#if !defined(GR_GL_USE_NV_PATH_RENDERING) + #define GR_GL_USE_NV_PATH_RENDERING 0 +#endif + +#if !defined(GR_GL_MUST_USE_VBO) + #define GR_GL_MUST_USE_VBO 0 +#endif + +#if !defined(GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE) + #define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE 0 +#endif + +/** + * There is a strange bug that occurs on Macs with NVIDIA GPUs. We don't + * fully understand it. When (element) array buffers are continually + * respecified using glBufferData performance can fall off of a cliff. The + * driver winds up performing many DMA mapping / unmappings and chews up ~50% of + * the core. However, it has been observed that occaisonally respecifiying the + * buffer using glBufferData and then writing data using glBufferSubData + * prevents the bad behavior. + * + * There is a lot of uncertainty around this issue. In Chrome backgrounding + * the tab somehow initiates this behavior and we don't know what the connection + * is. Another observation is that Chrome's cmd buffer server will actually + * create a buffer full of zeros when it sees a NULL data param (for security + * reasons). If this is disabled and NULL is actually passed all the way to the + * driver then the workaround doesn't help. + * + * The issue is tracked at: + * http://code.google.com/p/chromium/issues/detail?id=114865 + * + * When the workaround is enabled we will use the glBufferData / glBufferSubData + * trick every 128 array buffer uploads. + * + * Hopefully we will understand this better and have a cleaner fix or get a + * OS/driver level fix. + */ +#define GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND \ + (GR_MAC_BUILD && \ + !GR_GL_USE_BUFFER_DATA_NULL_HINT) + +#endif diff --git a/gpu/gl/GrGLConfig_chrome.h b/gpu/gl/GrGLConfig_chrome.h new file mode 100644 index 0000000..e08692f --- /dev/null +++ b/gpu/gl/GrGLConfig_chrome.h @@ -0,0 +1,44 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef GrGLConfig_chrome_DEFINED +#define GrGLConfig_chrome_DEFINED + +// glGetError() forces a sync with gpu process on chrome +#define GR_GL_CHECK_ERROR_START 0 + +// ANGLE creates a temp VB for vertex attributes not specified per-vertex. +#define GR_GL_NO_CONSTANT_ATTRIBUTES GR_WIN32_BUILD + +// For RGBA teximage/readpixels ANGLE will sw-convert to/from BGRA. +#define GR_GL_RGBA_8888_PIXEL_OPS_SLOW GR_WIN32_BUILD + +// ANGLE can go faster if the entire fbo is read rather than a subrect +#define GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL GR_WIN32_BUILD + +// cmd buffer allocates memory and memsets it to zero when it sees glBufferData +// with NULL. +#define GR_GL_USE_BUFFER_DATA_NULL_HINT 0 + +// chrome uses this to set the context on each GL call. +#define GR_GL_PER_GL_FUNC_CALLBACK 1 + +// Check error is even more expensive in chrome (cmd buffer flush). The +// compositor also doesn't check its allocations. +#define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 0 + +// CheckFramebufferStatus in chrome synchronizes the gpu and renderer processes. +#define GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT 1 + +// Non-VBO vertices and indices are not allowed in Chromium. +#define GR_GL_MUST_USE_VBO 1 + +// Use updated Khronos signature for glShaderSource +// (const char* const instead of char**). +#define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE 1 + +#endif diff --git a/gpu/gl/GrGLExtensions.h b/gpu/gl/GrGLExtensions.h new file mode 100644 index 0000000..f4e950a --- /dev/null +++ b/gpu/gl/GrGLExtensions.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLExtensions_DEFINED +#define GrGLExtensions_DEFINED + +#include "GrGLInterface.h" +#include "SkString.h" +#include "SkTArray.h" + +/** + * This helper queries the current GL context for its extensions, remembers them, and can be + * queried. It supports both glGetString- and glGetStringi-style extension string APIs and will + * use the latter if it is available. + */ +class GrGLExtensions { +public: + bool init(GrGLBinding binding, const GrGLInterface* iface) { + GrAssert(binding & iface->fBindingsExported); + return this->init(binding, iface->fGetString, iface->fGetStringi, iface->fGetIntegerv); + } + /** + * We sometimes need to use this class without having yet created a GrGLInterface. This version + * of init expects that getString is always non-NULL while getIntegerv and getStringi are non- + * NULL if on desktop GL with version 3.0 or higher. Otherwise it will fail. + */ + bool init(GrGLBinding binding, + GrGLGetStringProc getString, + GrGLGetStringiProc getStringi, + GrGLGetIntegervProc getIntegerv); + + /** + * Queries whether an extension is present. This will fail if init() has not been called. + */ + bool has(const char*) const; + + void reset() { fStrings.reset(); } + + void print(const char* sep = "\n") const; + +private: + SkTArray<SkString> fStrings; +}; + +#endif diff --git a/gpu/gl/GrGLFunctions.h b/gpu/gl/GrGLFunctions.h new file mode 100644 index 0000000..b30ef3a --- /dev/null +++ b/gpu/gl/GrGLFunctions.h @@ -0,0 +1,231 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLFunctions_DEFINED +#define GrGLFunctions_DEFINED + +#include "GrGLConfig.h" + +/** + * Declares typedefs for all the GL functions used in GrGLInterface + */ + +/////////////////////////////////////////////////////////////////////////////// + +typedef unsigned int GrGLenum; +typedef unsigned char GrGLboolean; +typedef unsigned int GrGLbitfield; +typedef signed char GrGLbyte; +typedef char GrGLchar; +typedef short GrGLshort; +typedef int GrGLint; +typedef int GrGLsizei; +typedef int64_t GrGLint64; +typedef unsigned char GrGLubyte; +typedef unsigned short GrGLushort; +typedef unsigned int GrGLuint; +typedef uint64_t GrGLuint64; +typedef float GrGLfloat; +typedef float GrGLclampf; +typedef double GrGLdouble; +typedef double GrGLclampd; +typedef void GrGLvoid; +typedef long GrGLintptr; +typedef long GrGLsizeiptr; + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" { + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLActiveTextureProc)(GrGLenum texture); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLAttachShaderProc)(GrGLuint program, GrGLuint shader); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBeginQueryProc)(GrGLenum target, GrGLuint id); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindAttribLocationProc)(GrGLuint program, GrGLuint index, const char* name); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindBufferProc)(GrGLenum target, GrGLuint buffer); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFramebufferProc)(GrGLenum target, GrGLuint framebuffer); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindRenderbufferProc)(GrGLenum target, GrGLuint renderbuffer); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindTextureProc)(GrGLenum target, GrGLuint texture); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBlendColorProc)(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFragDataLocationProc)(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindFragDataLocationIndexedProc)(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar * name); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBindVertexArrayProc)(GrGLuint array); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBlendFuncProc)(GrGLenum sfactor, GrGLenum dfactor); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBlitFramebufferProc)(GrGLint srcX0, GrGLint srcY0, GrGLint srcX1, GrGLint srcY1, GrGLint dstX0, GrGLint dstY0, GrGLint dstX1, GrGLint dstY1, GrGLbitfield mask, GrGLenum filter); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBufferDataProc)(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLBufferSubDataProc)(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const GrGLvoid* data); + typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLCheckFramebufferStatusProc)(GrGLenum target); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearProc)(GrGLbitfield mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearColorProc)(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearStencilProc)(GrGLint s); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLColorMaskProc)(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCompileShaderProc)(GrGLuint shader); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCompressedTexImage2DProc)(GrGLenum target, GrGLint level, GrGLenum internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLsizei imageSize, const GrGLvoid* data); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCopyTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); + typedef GrGLuint (GR_GL_FUNCTION_TYPE* GrGLCreateProgramProc)(void); + typedef GrGLuint (GR_GL_FUNCTION_TYPE* GrGLCreateShaderProc)(GrGLenum type); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCullFaceProc)(GrGLenum mode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteBuffersProc)(GrGLsizei n, const GrGLuint* buffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteFramebuffersProc)(GrGLsizei n, const GrGLuint *framebuffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteProgramProc)(GrGLuint program); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteQueriesProc)(GrGLsizei n, const GrGLuint *ids); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteRenderbuffersProc)(GrGLsizei n, const GrGLuint *renderbuffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteShaderProc)(GrGLuint shader); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteTexturesProc)(GrGLsizei n, const GrGLuint* textures); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteVertexArraysProc)(GrGLsizei n, const GrGLuint *arrays); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDepthMaskProc)(GrGLboolean flag); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDisableProc)(GrGLenum cap); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDisableVertexAttribArrayProc)(GrGLuint index); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysProc)(GrGLenum mode, GrGLint first, GrGLsizei count); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBufferProc)(GrGLenum mode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBuffersProc)(GrGLsizei n, const GrGLenum* bufs); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsProc)(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableProc)(GrGLenum cap); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableVertexAttribArrayProc)(GrGLuint index); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEndQueryProc)(GrGLenum target); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFinishProc)(); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFlushProc)(); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFramebufferRenderbufferProc)(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFramebufferTexture2DProc)(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFramebufferTexture2DMultisampleProc)(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level, GrGLsizei samples); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFrontFaceProc)(GrGLenum mode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenBuffersProc)(GrGLsizei n, GrGLuint* buffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenFramebuffersProc)(GrGLsizei n, GrGLuint *framebuffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenerateMipmapProc)(GrGLenum target); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenQueriesProc)(GrGLsizei n, GrGLuint *ids); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenRenderbuffersProc)(GrGLsizei n, GrGLuint *renderbuffers); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenTexturesProc)(GrGLsizei n, GrGLuint* textures); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGenVertexArraysProc)(GrGLsizei n, GrGLuint *arrays); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetBufferParameterivProc)(GrGLenum target, GrGLenum pname, GrGLint* params); + typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLGetErrorProc)(); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetFramebufferAttachmentParameterivProc)(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetIntegervProc)(GrGLenum pname, GrGLint* params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetProgramInfoLogProc)(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetProgramivProc)(GrGLuint program, GrGLenum pname, GrGLint* params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetQueryivProc)(GrGLenum GLtarget, GrGLenum pname, GrGLint *params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetQueryObjecti64vProc)(GrGLuint id, GrGLenum pname, GrGLint64 *params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetQueryObjectivProc)(GrGLuint id, GrGLenum pname, GrGLint *params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetQueryObjectui64vProc)(GrGLuint id, GrGLenum pname, GrGLuint64 *params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetQueryObjectuivProc)(GrGLuint id, GrGLenum pname, GrGLuint *params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetRenderbufferParameterivProc)(GrGLenum target, GrGLenum pname, GrGLint* params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetShaderInfoLogProc)(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, char* infolog); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetShaderivProc)(GrGLuint shader, GrGLenum pname, GrGLint* params); + typedef const GrGLubyte* (GR_GL_FUNCTION_TYPE* GrGLGetStringProc)(GrGLenum name); + typedef const GrGLubyte* (GR_GL_FUNCTION_TYPE* GrGLGetStringiProc)(GrGLenum name, GrGLuint index); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetTexLevelParameterivProc)(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint* params); + typedef GrGLint (GR_GL_FUNCTION_TYPE* GrGLGetUniformLocationProc)(GrGLuint program, const char* name); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLLineWidthProc)(GrGLfloat width); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLLinkProgramProc)(GrGLuint program); + typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapBufferProc)(GrGLenum target, GrGLenum access); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPixelStoreiProc)(GrGLenum pname, GrGLint param); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLQueryCounterProc)(GrGLuint id, GrGLenum target); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLReadBufferProc)(GrGLenum src); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLReadPixelsProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLRenderbufferStorageProc)(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLRenderbufferStorageMultisampleProc)(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLRenderbufferStorageMultisampleCoverageProc)(GrGLenum target, GrGLsizei coverageSamples, GrGLsizei colorSamples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLResolveMultisampleFramebufferProc)(); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLScissorProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +#if GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLShaderSourceProc)(GrGLuint shader, GrGLsizei count, const char* const * str, const GrGLint* length); +#else + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLShaderSourceProc)(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length); +#endif + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilFuncProc)(GrGLenum func, GrGLint ref, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilFuncSeparateProc)(GrGLenum face, GrGLenum func, GrGLint ref, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilMaskProc)(GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilMaskSeparateProc)(GrGLenum face, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilOpProc)(GrGLenum fail, GrGLenum zfail, GrGLenum zpass); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilOpSeparateProc)(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexImage2DProc)(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexParameteriProc)(GrGLenum target, GrGLenum pname, GrGLint param); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexParameterivProc)(GrGLenum target, GrGLenum pname, const GrGLint* params); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexStorage2DProc)(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDiscardFramebufferProc)(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform1fProc)(GrGLint location, GrGLfloat v0); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform1iProc)(GrGLint location, GrGLint v0); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform1fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform1ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform2fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform2iProc)(GrGLint location, GrGLint v0, GrGLint v1); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform2fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform2ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform3fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform3iProc)(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform3fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform3ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform4fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform4iProc)(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform4fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniform4ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniformMatrix2fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniformMatrix3fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUniformMatrix4fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); + typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLUnmapBufferProc)(GrGLenum target); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLUseProgramProc)(GrGLuint program); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLVertexAttrib4fvProc)(GrGLuint indx, const GrGLfloat* values); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLVertexAttribPointerProc)(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLViewportProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); + + // Experimental: Functions for GL_NV_path_rendering. These will be + // alphabetized with the above functions once this is fully supported + // (and functions we are unlikely to use will possibly be omitted). + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLMatrixModeProc)(GrGLenum); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLLoadIdentityProc)(); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLLoadMatrixfProc)(const GrGLfloat* m); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathCommandsProc)(GrGLuint path, GrGLsizei numCommands, const GrGLubyte *commands, GrGLsizei numCoords, GrGLenum coordType, const GrGLvoid *coords); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathCoordsProc)(GrGLuint path, GrGLsizei numCoords, GrGLenum coordType, const GrGLvoid *coords); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathSubCommandsProc)(GrGLuint path, GrGLsizei commandStart, GrGLsizei commandsToDelete, GrGLsizei numCommands, const GrGLubyte *commands, GrGLsizei numCoords, GrGLenum coordType, const GrGLvoid *coords); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathSubCoordsProc)(GrGLuint path, GrGLsizei coordStart, GrGLsizei numCoords, GrGLenum coordType, const GrGLvoid *coords); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathStringProc)(GrGLuint path, GrGLenum format, GrGLsizei length, const GrGLvoid *pathString); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathGlyphsProc)(GrGLuint firstPathName, GrGLenum fontTarget, const GrGLvoid *fontName, GrGLbitfield fontStyle, GrGLsizei numGlyphs, GrGLenum type, const GrGLvoid *charcodes, GrGLenum handleMissingGlyphs, GrGLuint pathParameterTemplate, GrGLfloat emScale); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathGlyphRangeProc)(GrGLuint firstPathName, GrGLenum fontTarget, const GrGLvoid *fontName, GrGLbitfield fontStyle, GrGLuint firstGlyph, GrGLsizei numGlyphs, GrGLenum handleMissingGlyphs, GrGLuint pathParameterTemplate, GrGLfloat emScale); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLWeightPathsProc)(GrGLuint resultPath, GrGLsizei numPaths, const GrGLuint paths[], const GrGLfloat weights[]); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCopyPathProc)(GrGLuint resultPath, GrGLuint srcPath); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLInterpolatePathsProc)(GrGLuint resultPath, GrGLuint pathA, GrGLuint pathB, GrGLfloat weight); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTransformPathProc)(GrGLuint resultPath, GrGLuint srcPath, GrGLenum transformType, const GrGLfloat *transformValues); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathParameterivProc)(GrGLuint path, GrGLenum pname, const GrGLint *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathParameteriProc)(GrGLuint path, GrGLenum pname, GrGLint value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathParameterfvProc)(GrGLuint path, GrGLenum pname, const GrGLfloat *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathParameterfProc)(GrGLuint path, GrGLenum pname, GrGLfloat value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathDashArrayProc)(GrGLuint path, GrGLsizei dashCount, const GrGLfloat *dashArray); + typedef GrGLuint (GR_GL_FUNCTION_TYPE* GrGLGenPathsProc)(GrGLsizei range); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeletePathsProc)(GrGLuint path, GrGLsizei range); + typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLIsPathProc)(GrGLuint path); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathStencilFuncProc)(GrGLenum func, GrGLint ref, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathStencilDepthOffsetProc)(GrGLfloat factor, GrGLfloat units); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilFillPathProc)(GrGLuint path, GrGLenum fillMode, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilStrokePathProc)(GrGLuint path, GrGLint reference, GrGLuint mask); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum transformType, const GrGLfloat *transformValues); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum transformType, const GrGLfloat *transformValues); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathCoverDepthFuncProc)(GrGLenum zfunc); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathColorGenProc)(GrGLenum color, GrGLenum genMode, GrGLenum colorFormat, const GrGLfloat *coeffs); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathTexGenProc)(GrGLenum texCoordSet, GrGLenum genMode, GrGLint components, const GrGLfloat *coeffs); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPathFogGenProc)(GrGLenum genMode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverFillPathProc)(GrGLuint path, GrGLenum coverMode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathProc)(GrGLuint name, GrGLenum coverMode); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathParameterivProc)(GrGLuint name, GrGLenum param, GrGLint *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathParameterfvProc)(GrGLuint name, GrGLenum param, GrGLfloat *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathCommandsProc)(GrGLuint name, GrGLubyte *commands); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathCoordsProc)(GrGLuint name, GrGLfloat *coords); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathDashArrayProc)(GrGLuint name, GrGLfloat *dashArray); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathMetricsProc)(GrGLbitfield metricQueryMask, GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLsizei stride, GrGLfloat *metrics); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathMetricRangeProc)(GrGLbitfield metricQueryMask, GrGLuint fistPathName, GrGLsizei numPaths, GrGLsizei stride, GrGLfloat *metrics); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathSpacingProc)(GrGLenum pathListMode, GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLfloat advanceScale, GrGLfloat kerningScale, GrGLenum transformType, GrGLfloat *returnedSpacing); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathColorGenivProc)(GrGLenum color, GrGLenum pname, GrGLint *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathColorGenfvProc)(GrGLenum color, GrGLenum pname, GrGLfloat *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathTexGenivProc)(GrGLenum texCoordSet, GrGLenum pname, GrGLint *value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetPathTexGenfvProc)(GrGLenum texCoordSet, GrGLenum pname, GrGLfloat *value); + typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLIsPointInFillPathProc)(GrGLuint path, GrGLuint mask, GrGLfloat x, GrGLfloat y); + typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLIsPointInStrokePathProc)(GrGLuint path, GrGLfloat x, GrGLfloat y); + typedef GrGLfloat (GR_GL_FUNCTION_TYPE* GrGLGetPathLengthProc)(GrGLuint path, GrGLsizei startSegment, GrGLsizei numSegments); + typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLPointAlongPathProc)(GrGLuint path, GrGLsizei startSegment, GrGLsizei numSegments, GrGLfloat distance, GrGLfloat *x, GrGLfloat *y, GrGLfloat *tangentX, GrGLfloat *tangentY); +} // extern "C" + +#endif diff --git a/gpu/gl/GrGLInterface.h b/gpu/gl/GrGLInterface.h new file mode 100644 index 0000000..6a51adc --- /dev/null +++ b/gpu/gl/GrGLInterface.h @@ -0,0 +1,329 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef GrGLInterface_DEFINED +#define GrGLInterface_DEFINED + +#include "GrGLFunctions.h" +#include "GrRefCnt.h" + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Classifies GL contexts (currently as Desktop vs. ES2). This is a bitfield. + * A GrGLInterface (defined below) may support multiple bindings. + */ +enum GrGLBinding { + kNone_GrGLBinding = 0x0, + + kDesktop_GrGLBinding = 0x01, + kES2_GrGLBinding = 0x02, + + // for iteration of GrGLBindings + kFirstGrGLBinding = kDesktop_GrGLBinding, + kLastGrGLBinding = kES2_GrGLBinding +}; + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Rather than depend on platform-specific GL headers and libraries, we require + * the client to provide a struct of GL function pointers. This struct can be + * specified per-GrContext as a parameter to GrContext::Create. If NULL is + * passed to Create then the "default" GL interface is used. If the default is + * also NULL GrContext creation will fail. + * + * The default interface is returned by GrGLDefaultInterface. This function's + * implementation is platform-specific. Several have been provided, along with + * an implementation that simply returns NULL. It is implementation-specific + * whether the same GrGLInterface is returned or whether a new one is created + * at each call. Some platforms may not be able to use a single GrGLInterface + * because extension function ptrs vary across contexts. Note that GrGLInterface + * is ref-counted. So if the same object is returned by multiple calls to + * GrGLDefaultInterface, each should bump the ref count. + * + * By defining GR_GL_PER_GL_CALL_IFACE_CALLBACK to 1 the client can specify a + * callback function that will be called prior to each GL function call. See + * comments in GrGLConfig.h + */ + +struct GrGLInterface; + +const GrGLInterface* GrGLDefaultInterface(); + +/** + * Creates a GrGLInterface for a "native" GL context (e.g. WGL on windows, + * GLX on linux, AGL on Mac). On platforms that have context-specific function + * pointers for GL extensions (e.g. windows) the returned interface is only + * valid for the context that was current at creation. + */ +const GrGLInterface* GrGLCreateNativeInterface(); + +#if SK_MESA +/** + * Creates a GrGLInterface for an OSMesa context. + */ +const GrGLInterface* GrGLCreateMesaInterface(); +#endif + +#if SK_ANGLE +/** + * Creates a GrGLInterface for an ANGLE context. + */ +const GrGLInterface* GrGLCreateANGLEInterface(); +#endif + +/** + * Creates a null GrGLInterface that doesn't draw anything. Used for measuring + * CPU overhead. + */ +const GrGLInterface* GrGLCreateNullInterface(); + +/** + * Creates a debugging GrGLInterface that doesn't draw anything. Used for + * finding memory leaks and invalid memory accesses. + */ +const GrGLInterface* GrGLCreateDebugInterface(); + +#if GR_GL_PER_GL_FUNC_CALLBACK +typedef void (*GrGLInterfaceCallbackProc)(const GrGLInterface*); +typedef intptr_t GrGLInterfaceCallbackData; +#endif + +/* + * GrContext uses the following interface to make all calls into OpenGL. When a + * GrContext is created it is given a GrGLInterface. The interface's function + * pointers must be valid for the OpenGL context associated with the GrContext. + * On some platforms, such as Windows, function pointers for OpenGL extensions + * may vary between OpenGL contexts. So the caller must be careful to use a + * GrGLInterface initialized for the correct context. All functions that should + * be available based on the OpenGL's version and extension string must be + * non-NULL or GrContext creation will fail. This can be tested with the + * validate() method when the OpenGL context has been made current. + */ +struct GR_API GrGLInterface : public GrRefCnt { +private: + // simple wrapper class that exists only to initialize a pointer to NULL + template <typename FNPTR_TYPE> class GLPtr { + public: + GLPtr() : fPtr(NULL) {} + GLPtr operator =(FNPTR_TYPE ptr) { fPtr = ptr; return *this; } + operator FNPTR_TYPE() const { return fPtr; } + private: + FNPTR_TYPE fPtr; + }; + + typedef GrRefCnt INHERITED; + +public: + SK_DECLARE_INST_COUNT(GrGLInterface) + + GrGLInterface(); + + // Validates that the GrGLInterface supports a binding. This means that + // the GrGLinterface advertises the binding in fBindingsExported and all + // the necessary function pointers have been initialized. The interface is + // validated for the current OpenGL context. + bool validate(GrGLBinding binding) const; + + // Indicator variable specifying the type of GL implementation + // exported: GLES2 and/or Desktop. + GrGLBinding fBindingsExported; + + GLPtr<GrGLActiveTextureProc> fActiveTexture; + GLPtr<GrGLAttachShaderProc> fAttachShader; + GLPtr<GrGLBeginQueryProc> fBeginQuery; + GLPtr<GrGLBindAttribLocationProc> fBindAttribLocation; + GLPtr<GrGLBindBufferProc> fBindBuffer; + GLPtr<GrGLBindFragDataLocationProc> fBindFragDataLocation; + GLPtr<GrGLBindFragDataLocationIndexedProc> fBindFragDataLocationIndexed; + GLPtr<GrGLBindFramebufferProc> fBindFramebuffer; + GLPtr<GrGLBindRenderbufferProc> fBindRenderbuffer; + GLPtr<GrGLBindTextureProc> fBindTexture; + GLPtr<GrGLBindVertexArrayProc> fBindVertexArray; + GLPtr<GrGLBlendColorProc> fBlendColor; + GLPtr<GrGLBlendFuncProc> fBlendFunc; + GLPtr<GrGLBlitFramebufferProc> fBlitFramebuffer; + GLPtr<GrGLBufferDataProc> fBufferData; + GLPtr<GrGLBufferSubDataProc> fBufferSubData; + GLPtr<GrGLCheckFramebufferStatusProc> fCheckFramebufferStatus; + GLPtr<GrGLClearProc> fClear; + GLPtr<GrGLClearColorProc> fClearColor; + GLPtr<GrGLClearStencilProc> fClearStencil; + GLPtr<GrGLColorMaskProc> fColorMask; + GLPtr<GrGLCompileShaderProc> fCompileShader; + GLPtr<GrGLCompressedTexImage2DProc> fCompressedTexImage2D; + GLPtr<GrGLCopyTexSubImage2DProc> fCopyTexSubImage2D; + GLPtr<GrGLCreateProgramProc> fCreateProgram; + GLPtr<GrGLCreateShaderProc> fCreateShader; + GLPtr<GrGLCullFaceProc> fCullFace; + GLPtr<GrGLDeleteBuffersProc> fDeleteBuffers; + GLPtr<GrGLDeleteFramebuffersProc> fDeleteFramebuffers; + GLPtr<GrGLDeleteProgramProc> fDeleteProgram; + GLPtr<GrGLDeleteQueriesProc> fDeleteQueries; + GLPtr<GrGLDeleteRenderbuffersProc> fDeleteRenderbuffers; + GLPtr<GrGLDeleteShaderProc> fDeleteShader; + GLPtr<GrGLDeleteTexturesProc> fDeleteTextures; + GLPtr<GrGLDeleteVertexArraysProc> fDeleteVertexArrays; + GLPtr<GrGLDepthMaskProc> fDepthMask; + GLPtr<GrGLDisableProc> fDisable; + GLPtr<GrGLDisableVertexAttribArrayProc> fDisableVertexAttribArray; + GLPtr<GrGLDrawArraysProc> fDrawArrays; + GLPtr<GrGLDrawBufferProc> fDrawBuffer; + GLPtr<GrGLDrawBuffersProc> fDrawBuffers; + GLPtr<GrGLDrawElementsProc> fDrawElements; + GLPtr<GrGLEnableProc> fEnable; + GLPtr<GrGLEnableVertexAttribArrayProc> fEnableVertexAttribArray; + GLPtr<GrGLEndQueryProc> fEndQuery; + GLPtr<GrGLFinishProc> fFinish; + GLPtr<GrGLFlushProc> fFlush; + GLPtr<GrGLFramebufferRenderbufferProc> fFramebufferRenderbuffer; + GLPtr<GrGLFramebufferTexture2DProc> fFramebufferTexture2D; + GLPtr<GrGLFramebufferTexture2DMultisampleProc> fFramebufferTexture2DMultisample; + GLPtr<GrGLFrontFaceProc> fFrontFace; + GLPtr<GrGLGenBuffersProc> fGenBuffers; + GLPtr<GrGLGenFramebuffersProc> fGenFramebuffers; + GLPtr<GrGLGenerateMipmapProc> fGenerateMipmap; + GLPtr<GrGLGenQueriesProc> fGenQueries; + GLPtr<GrGLGenRenderbuffersProc> fGenRenderbuffers; + GLPtr<GrGLGenTexturesProc> fGenTextures; + GLPtr<GrGLGenVertexArraysProc> fGenVertexArrays; + GLPtr<GrGLGetBufferParameterivProc> fGetBufferParameteriv; + GLPtr<GrGLGetErrorProc> fGetError; + GLPtr<GrGLGetFramebufferAttachmentParameterivProc> fGetFramebufferAttachmentParameteriv; + GLPtr<GrGLGetIntegervProc> fGetIntegerv; + GLPtr<GrGLGetQueryObjecti64vProc> fGetQueryObjecti64v; + GLPtr<GrGLGetQueryObjectivProc> fGetQueryObjectiv; + GLPtr<GrGLGetQueryObjectui64vProc> fGetQueryObjectui64v; + GLPtr<GrGLGetQueryObjectuivProc> fGetQueryObjectuiv; + GLPtr<GrGLGetQueryivProc> fGetQueryiv; + GLPtr<GrGLGetProgramInfoLogProc> fGetProgramInfoLog; + GLPtr<GrGLGetProgramivProc> fGetProgramiv; + GLPtr<GrGLGetRenderbufferParameterivProc> fGetRenderbufferParameteriv; + GLPtr<GrGLGetShaderInfoLogProc> fGetShaderInfoLog; + GLPtr<GrGLGetShaderivProc> fGetShaderiv; + GLPtr<GrGLGetStringProc> fGetString; + GLPtr<GrGLGetStringiProc> fGetStringi; + GLPtr<GrGLGetTexLevelParameterivProc> fGetTexLevelParameteriv; + GLPtr<GrGLGetUniformLocationProc> fGetUniformLocation; + GLPtr<GrGLLineWidthProc> fLineWidth; + GLPtr<GrGLLinkProgramProc> fLinkProgram; + GLPtr<GrGLMapBufferProc> fMapBuffer; + GLPtr<GrGLPixelStoreiProc> fPixelStorei; + GLPtr<GrGLQueryCounterProc> fQueryCounter; + GLPtr<GrGLReadBufferProc> fReadBuffer; + GLPtr<GrGLReadPixelsProc> fReadPixels; + GLPtr<GrGLRenderbufferStorageProc> fRenderbufferStorage; + GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisample; + GLPtr<GrGLRenderbufferStorageMultisampleCoverageProc> fRenderbufferStorageMultisampleCoverage; + GLPtr<GrGLResolveMultisampleFramebufferProc> fResolveMultisampleFramebuffer; + GLPtr<GrGLScissorProc> fScissor; + GLPtr<GrGLShaderSourceProc> fShaderSource; + GLPtr<GrGLStencilFuncProc> fStencilFunc; + GLPtr<GrGLStencilFuncSeparateProc> fStencilFuncSeparate; + GLPtr<GrGLStencilMaskProc> fStencilMask; + GLPtr<GrGLStencilMaskSeparateProc> fStencilMaskSeparate; + GLPtr<GrGLStencilOpProc> fStencilOp; + GLPtr<GrGLStencilOpSeparateProc> fStencilOpSeparate; + GLPtr<GrGLTexImage2DProc> fTexImage2D; + GLPtr<GrGLTexParameteriProc> fTexParameteri; + GLPtr<GrGLTexParameterivProc> fTexParameteriv; + GLPtr<GrGLTexSubImage2DProc> fTexSubImage2D; + GLPtr<GrGLTexStorage2DProc> fTexStorage2D; + GLPtr<GrGLDiscardFramebufferProc> fDiscardFramebuffer; + GLPtr<GrGLUniform1fProc> fUniform1f; + GLPtr<GrGLUniform1iProc> fUniform1i; + GLPtr<GrGLUniform1fvProc> fUniform1fv; + GLPtr<GrGLUniform1ivProc> fUniform1iv; + GLPtr<GrGLUniform2fProc> fUniform2f; + GLPtr<GrGLUniform2iProc> fUniform2i; + GLPtr<GrGLUniform2fvProc> fUniform2fv; + GLPtr<GrGLUniform2ivProc> fUniform2iv; + GLPtr<GrGLUniform3fProc> fUniform3f; + GLPtr<GrGLUniform3iProc> fUniform3i; + GLPtr<GrGLUniform3fvProc> fUniform3fv; + GLPtr<GrGLUniform3ivProc> fUniform3iv; + GLPtr<GrGLUniform4fProc> fUniform4f; + GLPtr<GrGLUniform4iProc> fUniform4i; + GLPtr<GrGLUniform4fvProc> fUniform4fv; + GLPtr<GrGLUniform4ivProc> fUniform4iv; + GLPtr<GrGLUniformMatrix2fvProc> fUniformMatrix2fv; + GLPtr<GrGLUniformMatrix3fvProc> fUniformMatrix3fv; + GLPtr<GrGLUniformMatrix4fvProc> fUniformMatrix4fv; + GLPtr<GrGLUnmapBufferProc> fUnmapBuffer; + GLPtr<GrGLUseProgramProc> fUseProgram; + GLPtr<GrGLVertexAttrib4fvProc> fVertexAttrib4fv; + GLPtr<GrGLVertexAttribPointerProc> fVertexAttribPointer; + GLPtr<GrGLViewportProc> fViewport; + + // Experimental: Functions for GL_NV_path_rendering. These will be + // alphabetized with the above functions once this is fully supported + // (and functions we are unlikely to use will possibly be omitted). + GLPtr<GrGLMatrixModeProc> fMatrixMode; + GLPtr<GrGLLoadIdentityProc> fLoadIdentity; + GLPtr<GrGLLoadMatrixfProc> fLoadMatrixf; + GLPtr<GrGLPathCommandsProc> fPathCommands; + GLPtr<GrGLPathCoordsProc> fPathCoords; + GLPtr<GrGLPathSubCommandsProc> fPathSubCommands; + GLPtr<GrGLPathSubCoordsProc> fPathSubCoords; + GLPtr<GrGLPathStringProc> fPathString; + GLPtr<GrGLPathGlyphsProc> fPathGlyphs; + GLPtr<GrGLPathGlyphRangeProc> fPathGlyphRange; + GLPtr<GrGLWeightPathsProc> fWeightPaths; + GLPtr<GrGLCopyPathProc> fCopyPath; + GLPtr<GrGLInterpolatePathsProc> fInterpolatePaths; + GLPtr<GrGLTransformPathProc> fTransformPath; + GLPtr<GrGLPathParameterivProc> fPathParameteriv; + GLPtr<GrGLPathParameteriProc> fPathParameteri; + GLPtr<GrGLPathParameterfvProc> fPathParameterfv; + GLPtr<GrGLPathParameterfProc> fPathParameterf; + GLPtr<GrGLPathDashArrayProc> fPathDashArray; + GLPtr<GrGLGenPathsProc> fGenPaths; + GLPtr<GrGLDeletePathsProc> fDeletePaths; + GLPtr<GrGLIsPathProc> fIsPath; + GLPtr<GrGLPathStencilFuncProc> fPathStencilFunc; + GLPtr<GrGLPathStencilDepthOffsetProc> fPathStencilDepthOffset; + GLPtr<GrGLStencilFillPathProc> fStencilFillPath; + GLPtr<GrGLStencilStrokePathProc> fStencilStrokePath; + GLPtr<GrGLStencilFillPathInstancedProc> fStencilFillPathInstanced; + GLPtr<GrGLStencilStrokePathInstancedProc> fStencilStrokePathInstanced; + GLPtr<GrGLPathCoverDepthFuncProc> fPathCoverDepthFunc; + GLPtr<GrGLPathColorGenProc> fPathColorGen; + GLPtr<GrGLPathTexGenProc> fPathTexGen; + GLPtr<GrGLPathFogGenProc> fPathFogGen; + GLPtr<GrGLCoverFillPathProc> fCoverFillPath; + GLPtr<GrGLCoverStrokePathProc> fCoverStrokePath; + GLPtr<GrGLCoverFillPathInstancedProc> fCoverFillPathInstanced; + GLPtr<GrGLCoverStrokePathInstancedProc> fCoverStrokePathInstanced; + GLPtr<GrGLGetPathParameterivProc> fGetPathParameteriv; + GLPtr<GrGLGetPathParameterfvProc> fGetPathParameterfv; + GLPtr<GrGLGetPathCommandsProc> fGetPathCommands; + GLPtr<GrGLGetPathCoordsProc> fGetPathCoords; + GLPtr<GrGLGetPathDashArrayProc> fGetPathDashArray; + GLPtr<GrGLGetPathMetricsProc> fGetPathMetrics; + GLPtr<GrGLGetPathMetricRangeProc> fGetPathMetricRange; + GLPtr<GrGLGetPathSpacingProc> fGetPathSpacing; + GLPtr<GrGLGetPathColorGenivProc> fGetPathColorGeniv; + GLPtr<GrGLGetPathColorGenfvProc> fGetPathColorGenfv; + GLPtr<GrGLGetPathTexGenivProc> fGetPathTexGeniv; + GLPtr<GrGLGetPathTexGenfvProc> fGetPathTexGenfv; + GLPtr<GrGLIsPointInFillPathProc> fIsPointInFillPath; + GLPtr<GrGLIsPointInStrokePathProc> fIsPointInStrokePath; + GLPtr<GrGLGetPathLengthProc> fGetPathLength; + GLPtr<GrGLPointAlongPathProc> fPointAlongPath; + + // Per-GL func callback +#if GR_GL_PER_GL_FUNC_CALLBACK + GrGLInterfaceCallbackProc fCallback; + GrGLInterfaceCallbackData fCallbackData; +#endif + +}; + +#endif diff --git a/gpu/gl/SkANGLEGLContext.h b/gpu/gl/SkANGLEGLContext.h new file mode 100644 index 0000000..63765a0 --- /dev/null +++ b/gpu/gl/SkANGLEGLContext.h @@ -0,0 +1,49 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkANGLEGLContext_DEFINED +#define SkANGLEGLContext_DEFINED + +#if SK_ANGLE + +#include "SkGLContextHelper.h" + +#include <GLES2/gl2.h> +#include <EGL/egl.h> + +class SkANGLEGLContext : public SkGLContextHelper { +public: + SkANGLEGLContext(); + + virtual ~SkANGLEGLContext(); + + virtual void makeCurrent() const SK_OVERRIDE; + + class AutoContextRestore { + public: + AutoContextRestore(); + ~AutoContextRestore(); + + private: + EGLContext fOldEGLContext; + EGLDisplay fOldDisplay; + EGLSurface fOldSurface; + }; + +protected: + virtual const GrGLInterface* createGLContext() SK_OVERRIDE; + virtual void destroyGLContext() SK_OVERRIDE; + +private: + EGLContext fContext; + EGLDisplay fDisplay; + EGLSurface fSurface; +}; + +#endif + +#endif diff --git a/gpu/gl/SkDebugGLContext.h b/gpu/gl/SkDebugGLContext.h new file mode 100644 index 0000000..2437aae --- /dev/null +++ b/gpu/gl/SkDebugGLContext.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkDebugGLContext_DEFINED +#define SkDebugGLContext_DEFINED + +#include "SkGLContextHelper.h" + +class SkDebugGLContext : public SkGLContextHelper { + +public: + SkDebugGLContext() {}; + + virtual void makeCurrent() const SK_OVERRIDE {}; + +protected: + virtual const GrGLInterface* createGLContext() SK_OVERRIDE; + + virtual void destroyGLContext() SK_OVERRIDE {}; +}; + +#endif diff --git a/gpu/gl/SkGLContextHelper.h b/gpu/gl/SkGLContextHelper.h new file mode 100644 index 0000000..386a695 --- /dev/null +++ b/gpu/gl/SkGLContextHelper.h @@ -0,0 +1,77 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkGLContextHelper_DEFINED +#define SkGLContextHelper_DEFINED + +#include "GrGLExtensions.h" +#include "GrGLInterface.h" + +/** + * Create an offscreen opengl context with an RGBA8 / 8bit stencil FBO. + * Provides a GrGLInterface struct of function pointers for the context. + */ + +class SkGLContextHelper : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkGLContextHelper) + + SkGLContextHelper(); + virtual ~SkGLContextHelper(); + + /** + * Initializes the context and makes it current. + */ + bool init(const int width, const int height); + + int getFBOID() const { return fFBO; } + + const GrGLInterface* gl() const { return fGL; } + + virtual void makeCurrent() const = 0; + + bool hasExtension(const char* extensionName) const { + GrAssert(NULL != fGL); + return fExtensions.has(extensionName); + } + +protected: + /** + * Subclass implements this to make a GL context. The returned GrGLInterface + * should be populated with functions compatible with the context. The + * format and size of backbuffers does not matter since an FBO will be + * created. + */ + virtual const GrGLInterface* createGLContext() = 0; + + /** + * Subclass should destroy the underlying GL context. + */ + virtual void destroyGLContext() = 0; + +private: + GrGLExtensions fExtensions; + GrGLuint fFBO; + GrGLuint fColorBufferID; + GrGLuint fDepthStencilBufferID; + const GrGLInterface* fGL; + + typedef SkRefCnt INHERITED; +}; + +/** + * Helper macros for using the GL context through the GrGLInterface. Example: + * SK_GL(glCtx, GenTextures(1, &texID)); + */ +#define SK_GL(ctx, X) (ctx).gl()->f ## X; \ + SkASSERT(GR_GL_NO_ERROR == (ctx).gl()->fGetError()) +#define SK_GL_RET(ctx, RET, X) (RET) = (ctx).gl()->f ## X; \ + SkASSERT(GR_GL_NO_ERROR == (ctx).gl()->fGetError()) +#define SK_GL_NOERRCHECK(ctx, X) (ctx).gl()->f ## X +#define SK_GL_RET_NOERRCHECK(ctx, RET, X) (RET) = (ctx).gl()->f ## X + +#endif diff --git a/gpu/gl/SkMesaGLContext.h b/gpu/gl/SkMesaGLContext.h new file mode 100644 index 0000000..6470d2e --- /dev/null +++ b/gpu/gl/SkMesaGLContext.h @@ -0,0 +1,50 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkMesaGLContext_DEFINED +#define SkMesaGLContext_DEFINED + +#include "SkGLContextHelper.h" + +#if SK_MESA + +class SkMesaGLContext : public SkGLContextHelper { +private: + typedef intptr_t Context; + +public: + SkMesaGLContext(); + + virtual ~SkMesaGLContext(); + + virtual void makeCurrent() const SK_OVERRIDE; + + class AutoContextRestore { + public: + AutoContextRestore(); + ~AutoContextRestore(); + + private: + Context fOldContext; + GrGLint fOldWidth; + GrGLint fOldHeight; + GrGLint fOldFormat; + void* fOldImage; + }; + +protected: + virtual const GrGLInterface* createGLContext() SK_OVERRIDE; + virtual void destroyGLContext() SK_OVERRIDE; + +private: + Context fContext; + GrGLubyte *fImage; +}; + +#endif + +#endif diff --git a/gpu/gl/SkNativeGLContext.h b/gpu/gl/SkNativeGLContext.h new file mode 100644 index 0000000..27a8f09 --- /dev/null +++ b/gpu/gl/SkNativeGLContext.h @@ -0,0 +1,85 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkNativeGLContext_DEFINED +#define SkNativeGLContext_DEFINED + +#include "SkGLContextHelper.h" + +#if defined(SK_BUILD_FOR_MAC) + #include <OpenGL/OpenGL.h> +#elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_NACL) + #include <GLES2/gl2.h> + #include <EGL/egl.h> +#elif defined(SK_BUILD_FOR_UNIX) + #include <X11/Xlib.h> + #include <GL/glx.h> +#elif defined(SK_BUILD_FOR_WIN32) + #include <Windows.h> + #include <GL/GL.h> +#endif + +class SkNativeGLContext : public SkGLContextHelper { +public: + SkNativeGLContext(); + + virtual ~SkNativeGLContext(); + + virtual void makeCurrent() const SK_OVERRIDE; + + class AutoContextRestore { + public: + AutoContextRestore(); + ~AutoContextRestore(); + + private: + #if defined(SK_BUILD_FOR_MAC) + CGLContextObj fOldCGLContext; + #elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_NACL) + EGLContext fOldEGLContext; + EGLDisplay fOldDisplay; + EGLSurface fOldSurface; + #elif defined(SK_BUILD_FOR_UNIX) + GLXContext fOldGLXContext; + Display* fOldDisplay; + GLXDrawable fOldDrawable; + #elif defined(SK_BUILD_FOR_WIN32) + HDC fOldHDC; + HGLRC fOldHGLRC; + + #elif defined(SK_BUILD_FOR_IOS) + void* fEAGLContext; + #endif + }; + +protected: + virtual const GrGLInterface* createGLContext() SK_OVERRIDE; + virtual void destroyGLContext() SK_OVERRIDE; + +private: +#if defined(SK_BUILD_FOR_MAC) + CGLContextObj fContext; +#elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_NACL) + EGLContext fContext; + EGLDisplay fDisplay; + EGLSurface fSurface; +#elif defined(SK_BUILD_FOR_UNIX) + GLXContext fContext; + Display* fDisplay; + Pixmap fPixmap; + GLXPixmap fGlxPixmap; +#elif defined(SK_BUILD_FOR_WIN32) + HWND fWindow; + HDC fDeviceContext; + HGLRC fGlRenderContext; + static ATOM gWC; +#elif defined(SK_BUILD_FOR_IOS) + void* fEAGLContext; +#endif +}; + +#endif diff --git a/gpu/gl/SkNullGLContext.h b/gpu/gl/SkNullGLContext.h new file mode 100644 index 0000000..4f2639c --- /dev/null +++ b/gpu/gl/SkNullGLContext.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkNullGLContext_DEFINED +#define SkNullGLContext_DEFINED + +#include "SkGLContextHelper.h" + +class SkNullGLContext : public SkGLContextHelper { + +public: + SkNullGLContext() {}; + + virtual void makeCurrent() const SK_OVERRIDE {}; + +protected: + virtual const GrGLInterface* createGLContext() SK_OVERRIDE; + + virtual void destroyGLContext() SK_OVERRIDE {}; +}; + +#endif diff --git a/images/SkForceLinking.h b/images/SkForceLinking.h new file mode 100644 index 0000000..39901f6 --- /dev/null +++ b/images/SkForceLinking.h @@ -0,0 +1,20 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * This function's sole purpose is to trick the linker into not discarding + * SkImageDecoder subclasses just because we do not directly call them. + * This is necessary in applications that will create image decoders from + * a stream. + * Call this function with an expression that evaluates to false to ensure + * that the linker includes the subclasses. + * Passing true will result in leaked objects. + */ +int SkForceLinking(bool doNotPassTrue); + +#define __SK_FORCE_IMAGE_DECODER_LINKING \ +static int linking_forced = SkForceLinking(false) diff --git a/images/SkImageRef.h b/images/SkImageRef.h new file mode 100644 index 0000000..bca4305 --- /dev/null +++ b/images/SkImageRef.h @@ -0,0 +1,104 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkImageRef_DEFINED +#define SkImageRef_DEFINED + +#include "SkPixelRef.h" +#include "SkBitmap.h" +#include "SkImageDecoder.h" +#include "SkString.h" + +class SkImageRefPool; +class SkStream; + +// define this to enable dumping whenever we add/remove/purge an imageref +//#define DUMP_IMAGEREF_LIFECYCLE + +class SkImageRef : public SkPixelRef { +public: + /** Create a new imageref from a stream. NOTE: the stream is not copied, but + since it may be accessed from another thread, the caller must ensure + that this imageref is the only owner of the stream. i.e. - sole + ownership of the stream object is transferred to this imageref object. + + @param stream The stream containing the encoded image data. This may be + retained (by calling ref()), so the caller should not + explicitly delete it. + @param config The preferred config of the decoded bitmap. + @param sampleSize Requested sampleSize for decoding. Defaults to 1. + */ + SkImageRef(SkStream*, SkBitmap::Config config, int sampleSize = 1, SkBaseMutex* mutex = NULL); + virtual ~SkImageRef(); + + /** this value is passed onto the decoder. Default is true + */ + void setDitherImage(bool dither) { fDoDither = dither; } + + /** Return true if the image can be decoded. If so, and bitmap is non-null, + call its setConfig() with the corresponding values, but explicitly will + not set its pixels or colortable. Use SkPixelRef::lockPixels() for that. + + If there has been an error decoding the bitmap, this will return false + and ignore the bitmap parameter. + */ + bool getInfo(SkBitmap* bm); + + /** Return true if the image can be decoded and is opaque. Calling this + method will decode and set the pixels in the specified bitmap and + sets the isOpaque flag. + */ + bool isOpaque(SkBitmap* bm); + + SkImageDecoderFactory* getDecoderFactory() const { return fFactory; } + // returns the factory parameter + SkImageDecoderFactory* setDecoderFactory(SkImageDecoderFactory*); + +protected: + /** Override if you want to install a custom allocator. + When this is called we will have already acquired the mutex! + */ + virtual bool onDecode(SkImageDecoder* codec, SkStream*, SkBitmap*, + SkBitmap::Config, SkImageDecoder::Mode); + + /* Overrides from SkPixelRef + When these are called, we will have already acquired the mutex! + */ + + virtual void* onLockPixels(SkColorTable**); + // override this in your subclass to clean up when we're unlocking pixels + virtual void onUnlockPixels() {} + + SkImageRef(SkFlattenableReadBuffer&, SkBaseMutex* mutex = NULL); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + + SkBitmap fBitmap; + +private: + SkStream* setStream(SkStream*); + // called with mutex already held. returns true if the bitmap is in the + // requested state (or further, i.e. has pixels) + bool prepareBitmap(SkImageDecoder::Mode); + + SkImageDecoderFactory* fFactory; // may be null + SkStream* fStream; + SkBitmap::Config fConfig; + int fSampleSize; + bool fDoDither; + bool fErrorInDecoding; + + friend class SkImageRefPool; + + SkImageRef* fPrev, *fNext; + size_t ramUsed() const; + + typedef SkPixelRef INHERITED; +}; + +#endif diff --git a/images/SkImageRef_GlobalPool.h b/images/SkImageRef_GlobalPool.h new file mode 100644 index 0000000..914b0eb --- /dev/null +++ b/images/SkImageRef_GlobalPool.h @@ -0,0 +1,61 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkImageRef_GlobalPool_DEFINED +#define SkImageRef_GlobalPool_DEFINED + +#include "SkImageRef.h" + +class SkImageRef_GlobalPool : public SkImageRef { +public: + // if pool is null, use the global pool + SkImageRef_GlobalPool(SkStream*, SkBitmap::Config, int sampleSize = 1); + virtual ~SkImageRef_GlobalPool(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageRef_GlobalPool) + + // API to control the global pool + + /** Return the amount specified as the budget for the cache (in bytes). + */ + static size_t GetRAMBudget(); + + /** Set a new budget value for the cache. + */ + static void SetRAMBudget(size_t); + + /** Return how much ram is currently in use by the global cache. + */ + static size_t GetRAMUsed(); + + /** Free up (approximately) enough such that the amount used by the cache + is <= the specified amount. Since some images may be "in use", the + amount actually freed may not always result in a ram usage value <= + to the requested amount. In addition, because of the + chunky nature of the cache, the resulting usage may be < the requested + amount. + */ + static void SetRAMUsed(size_t usageInBytes); + + static void DumpPool(); + +protected: + virtual bool onDecode(SkImageDecoder* codec, SkStream* stream, + SkBitmap* bitmap, SkBitmap::Config config, + SkImageDecoder::Mode mode); + + virtual void onUnlockPixels(); + + SkImageRef_GlobalPool(SkFlattenableReadBuffer&); + +private: + typedef SkImageRef INHERITED; +}; + +#endif diff --git a/images/SkImages.h b/images/SkImages.h new file mode 100644 index 0000000..abe10da --- /dev/null +++ b/images/SkImages.h @@ -0,0 +1,14 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +class SkImages { +public: + /** + * Initializes flattenables in the images project. + */ + static void InitializeFlattenables(); +}; diff --git a/images/SkMovie.h b/images/SkMovie.h new file mode 100644 index 0000000..f32d609 --- /dev/null +++ b/images/SkMovie.h @@ -0,0 +1,80 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkMovie_DEFINED +#define SkMovie_DEFINED + +#include "SkRefCnt.h" +#include "SkCanvas.h" + +class SkStream; + +class SkMovie : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkMovie) + + /** Try to create a movie from the stream. If the stream format is not + supported, return NULL. + */ + static SkMovie* DecodeStream(SkStream*); + /** Try to create a movie from the specified file path. If the file is not + found, or the format is not supported, return NULL. If a movie is + returned, the stream may be retained by the movie (via ref()) until + the movie is finished with it (by calling unref()). + */ + static SkMovie* DecodeFile(const char path[]); + /** Try to create a movie from the specified memory. + If the format is not supported, return NULL. If a movie is returned, + the data will have been read or copied, and so the caller may free + it. + */ + static SkMovie* DecodeMemory(const void* data, size_t length); + + SkMSec duration(); + int width(); + int height(); + int isOpaque(); + + /** Specify the time code (between 0...duration) to sample a bitmap + from the movie. Returns true if this time code generated a different + bitmap/frame from the previous state (i.e. true means you need to + redraw). + */ + bool setTime(SkMSec); + + // return the right bitmap for the current time code + const SkBitmap& bitmap(); + +protected: + struct Info { + SkMSec fDuration; + int fWidth; + int fHeight; + bool fIsOpaque; + }; + + virtual bool onGetInfo(Info*) = 0; + virtual bool onSetTime(SkMSec) = 0; + virtual bool onGetBitmap(SkBitmap*) = 0; + + // visible for subclasses + SkMovie(); + +private: + Info fInfo; + SkMSec fCurrTime; + SkBitmap fBitmap; + bool fNeedBitmap; + + void ensureInfo(); + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/images/SkPageFlipper.h b/images/SkPageFlipper.h new file mode 100644 index 0000000..7779c30 --- /dev/null +++ b/images/SkPageFlipper.h @@ -0,0 +1,62 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPageFlipper_DEFINED +#define SkPageFlipper_DEFINED + +#include "SkRegion.h" + +/** SkPageFlipper manages alternating inval/dirty regions for a rectangular area + (like a bitmap). You call inval() to accumulate inval areas, and then when + you're ready to "flip" pages (i.e. draw into the one you've been + invalidating) you call update, which swaps the inval regions, and returns + two things to you: 1) the final inval region to be drawn into, and 2) the + region of pixels that should be copied from the "front" page onto the one + you're about to draw into. This copyBits region will be disjoint from the + inval region, so both need to be handled. + */ +class SkPageFlipper { +public: + SkPageFlipper(); + SkPageFlipper(int width, int height); + + int width() const { return fWidth; } + int height() const { return fHeight; } + + void resize(int width, int height); + + bool isDirty() const { return !fDirty1->isEmpty(); } + const SkRegion& dirtyRgn() const { return *fDirty1; } + + void inval(); + void inval(const SkIRect&); + void inval(const SkRegion&); + void inval(const SkRect&, bool antialias); + + /** When you're ready to write to the back page, call update. The returned + region is the invalidate are that needs to be drawn to. The copyBits + region (provided by the caller) is the area that should be copied from + the front page to the back page (will not intersect with the returned + inval region. + + Once this is called, the two internal regions are swapped, so the *new* + back inval region is ready to receive new inval calls. + */ + const SkRegion& update(SkRegion* copyBits); + +private: + SkRegion* fDirty0; + SkRegion* fDirty1; + SkRegion fDirty0Storage; + SkRegion fDirty1Storage; + int fWidth; + int fHeight; +}; + +#endif diff --git a/lazy/SkBitmapFactory.h b/lazy/SkBitmapFactory.h new file mode 100644 index 0000000..e967a91 --- /dev/null +++ b/lazy/SkBitmapFactory.h @@ -0,0 +1,99 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkBitmapFactory_DEFINED +#define SkBitmapFactory_DEFINED + +#include "SkImage.h" +#include "SkTypes.h" + +class SkBitmap; +class SkData; +class SkImageCache; + +/** + * Factory for creating a bitmap from encoded data. + */ +class SkBitmapFactory { + +public: + /** + * Struct containing information about a pixel destination. + */ + struct Target { + /** + * Pre-allocated memory. + */ + void* fAddr; + + /** + * Rowbytes of the allocated memory. + */ + size_t fRowBytes; + }; + + /** + * Signature for a function to decode an image from encoded data. + */ + typedef bool (*DecodeProc)(const void* data, size_t length, SkImage::Info*, const Target*); + + /** + * Create a bitmap factory which uses DecodeProc for decoding. + * @param DecodeProc Must not be NULL. + */ + SkBitmapFactory(DecodeProc); + + ~SkBitmapFactory(); + + /** + * Set an image cache to use on pixelrefs provided by installPixelRef. Mutually exclusive + * with fCacheSelector. + */ + void setImageCache(SkImageCache* cache); + + /** + * Sets up an SkBitmap from encoded data. On success, the SkBitmap will have its Config, + * width, height, rowBytes and pixelref set. If fImageCache is non-NULL, or if fCacheSelector + * is set and returns non-NULL, the pixelref will lazily decode, and that SkImageCache will + * handle the pixel memory. Otherwise installPixelRef will do an immediate decode. + * @param SkData Encoded data. + * @param SkBitmap to install the pixel ref on. + * @return bool Whether or not a pixel ref was successfully installed. + */ + bool installPixelRef(SkData*, SkBitmap*); + + /** + * An object for selecting an SkImageCache to use based on an SkImage::Info. + */ + class CacheSelector : public SkRefCnt { + + public: + SK_DECLARE_INST_COUNT(CacheSelector) + /** + * Return an SkImageCache to use based on the provided SkImage::Info. If the caller decides + * to hang on to the result, it will call ref, so the implementation should not add a ref + * as a result of this call. + */ + virtual SkImageCache* selectCache(const SkImage::Info&) = 0; + + private: + typedef SkRefCnt INHERITED; + }; + + /** + * Set the function to be used to select which SkImageCache to use. Mutually exclusive with + * fImageCache. + */ + void setCacheSelector(CacheSelector*); + +private: + DecodeProc fDecodeProc; + SkImageCache* fImageCache; + CacheSelector* fCacheSelector; +}; + +#endif // SkBitmapFactory_DEFINED diff --git a/lazy/SkImageCache.h b/lazy/SkImageCache.h new file mode 100644 index 0000000..6d30ae7 --- /dev/null +++ b/lazy/SkImageCache.h @@ -0,0 +1,132 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageCache_DEFINED +#define SkImageCache_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +/** + * Interface for a cache that manages pixel memory. + */ +class SkImageCache : public SkRefCnt { + +public: + SK_DECLARE_INST_COUNT(SkImageCache) + + typedef intptr_t ID; + + /** + * Allocate memory whose lifetime is managed by the cache. On success, MUST be balanced with a + * call to releaseCache and a call to throwAwayCache. + * @param bytes Number of bytes needed. + * @param ID Output parameter which must not be NULL. On success, ID will be set to a value + * associated with that memory which can be used as a parameter to the other functions + * in SkImageCache. On failure, ID is unchanged. + * @return Pointer to the newly allocated memory, or NULL. This memory is safe to use until + * releaseCache is called with ID. + */ + virtual void* allocAndPinCache(size_t bytes, ID*) = 0; + + /** + * Output parameter for pinCache, stating whether the memory still contains the data it held + * when releaseCache was last called for the same ID. + */ + enum DataStatus { + /** + * The data has been purged, and therefore needs to be rewritten to the returned memory. + */ + kUninitialized_DataStatus, + + /** + * The memory still contains the data it held when releaseCache was last called with the + * same ID. + */ + kRetained_DataStatus, + }; + + /** + * Re-request the memory associated with ID and pin it so that it will not be reclaimed until + * the next call to releaseCache with the same ID. + * @param ID Unique ID for the memory block. + * @param status Output parameter which must not be NULL. On success (i.e. the return value is + * not NULL), status will be set to one of two states representing the cached memory. If + * status is set to kRetained_DataStatus, the memory contains the same data it did + * before releaseCache was called with this ID. If status is set to + * kUninitialized_DataStatus, the memory is still pinned, but the previous data is no + * longer available. If the return value is NULL, status is unchanged. + * @return Pointer: If non-NULL, points to the previously allocated memory, in which case + * this call must be balanced with a call to releaseCache. If NULL, the memory + * has been reclaimed, and throwAwayCache MUST NOT be called. + */ + virtual void* pinCache(ID, DataStatus* status) = 0; + + /** + * Inform the cache that it is safe to free the block of memory corresponding to ID. After + * calling this function, the pointer returned by allocAndPinCache or pinCache must not be + * used again. In order to access the same memory after this, pinCache must be called with + * the same ID. + * @param ID Unique ID for the memory block which is now safe to age out of the cache. + */ + virtual void releaseCache(ID) = 0; + + /** + * Inform the cache that the block of memory associated with ID will not be asked for again. + * After this call, ID is no longer valid. Must not be called while the associated memory is + * pinned. Must be called to balance a successful allocAndPinCache. + */ + virtual void throwAwayCache(ID) = 0; + + /** + * ID which does not correspond to any valid cache. + */ + static const ID UNINITIALIZED_ID = 0; + +#ifdef SK_DEBUG + /** + * Debug only status of a memory block. + */ + enum MemoryStatus { + /** + * It is safe to use the pointer returned by the most recent of allocAndPinCache(ID) or + * pinCache(ID) with the same ID. + */ + kPinned_MemoryStatus, + + /** + * The pointer returned by the most recent call to allocAndPinCache(ID) or pinCache(ID) has + * since been released by releaseCache(ID). In order to reuse it, pinCache(ID) must be + * called again. Note that after calling releaseCache(ID), the status of that particular + * ID may not be kUnpinned_MemoryStatus, depending on the implementation, but it will not + * be kPinned_MemoryStatus. + */ + kUnpinned_MemoryStatus, + + /** + * The memory associated with ID has been thrown away. No calls should be made using the + * same ID. + */ + kFreed_MemoryStatus, + }; + + /** + * Debug only function to get the status of a particular block of memory. Safe to call after + * throwAwayCache has been called with this ID. + */ + virtual MemoryStatus getMemoryStatus(intptr_t ID) const = 0; + + /** + * Debug only function to clear all unpinned caches. + */ + virtual void purgeAllUnpinnedCaches() = 0; +#endif + +private: + typedef SkRefCnt INHERITED; +}; +#endif // SkImageCache_DEFINED diff --git a/lazy/SkLruImageCache.h b/lazy/SkLruImageCache.h new file mode 100644 index 0000000..5170a05 --- /dev/null +++ b/lazy/SkLruImageCache.h @@ -0,0 +1,91 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLruImageCache_DEFINED +#define SkLruImageCache_DEFINED + +#include "SkImageCache.h" +#include "SkThread.h" +#include "SkTInternalLList.h" + +class CachedPixels; + +/** + * SkImageCache implementation that uses an LRU cache to age out old images. + */ +class SkLruImageCache : public SkImageCache { + +public: + SK_DECLARE_INST_COUNT(SkLruImageCache) + + SkLruImageCache(size_t budget); + + virtual ~SkLruImageCache(); + +#ifdef SK_DEBUG + virtual MemoryStatus getMemoryStatus(ID) const SK_OVERRIDE; + virtual void purgeAllUnpinnedCaches() SK_OVERRIDE; +#endif + + /** + * Set the byte limit on cached pixels. If more bytes are used than this, the cache will free + * unpinned memory until under the new limit or until all unpinned memory is freed. This will + * never free pinned memory, so the cache can potentially remain over the limit. The limit is + * enforced each time memory is allocated or released. + * 0 is a special flag for an infinite budget. + * @return size_t The previous limit. + */ + size_t setImageCacheLimit(size_t newLimit); + + /** + * Return the number of bytes of memory currently in use by the cache. Can include memory that + * is no longer pinned, but has not been freed. + */ + size_t getImageCacheUsed() const { return fRamUsed; } + + virtual void* allocAndPinCache(size_t bytes, ID*) SK_OVERRIDE; + virtual void* pinCache(ID, SkImageCache::DataStatus*) SK_OVERRIDE; + virtual void releaseCache(ID) SK_OVERRIDE; + virtual void throwAwayCache(ID) SK_OVERRIDE; + +private: + // Linked list of recently used. Head is the most recently used, and tail is the least. + SkTInternalLList<CachedPixels> fLRU; + typedef SkTInternalLList<CachedPixels>::Iter Iter; + +#ifdef SK_DEBUG + // fMutex is mutable so that getMemoryStatus can be const + mutable +#endif + SkMutex fMutex; + size_t fRamBudget; + size_t fRamUsed; + + /** + * Find the CachedPixels represented by ID, or NULL if not in the cache. Mutex must be locked + * before calling. + */ + CachedPixels* findByID(ID) const; + + /** + * If over budget, throw away pixels which are not currently in use until below budget or there + * are no more pixels eligible to be thrown away. Mutex must be locked before calling. + */ + void purgeIfNeeded(); + + /** + * Purge until below limit. Mutex must be locked before calling. + */ + void purgeTilAtOrBelow(size_t limit); + + /** + * Remove a set of CachedPixels. Mutex must be locked before calling. + */ + void removePixels(CachedPixels*); +}; + +#endif // SkLruImageCache_DEFINED diff --git a/lazy/SkPurgeableImageCache.h b/lazy/SkPurgeableImageCache.h new file mode 100644 index 0000000..24525b0 --- /dev/null +++ b/lazy/SkPurgeableImageCache.h @@ -0,0 +1,47 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPurgeableImageCache_DEFINED +#define SkPurgeableImageCache_DEFINED + +#include "SkImageCache.h" + +#ifdef SK_DEBUG + #include "SkTDArray.h" +#endif + +/** + * Implementation for SkImageCache that uses system defined purgeable memory. + */ +class SkPurgeableImageCache : public SkImageCache { + +public: + SK_DECLARE_INST_COUNT(SkPurgeableImageCache) + + static SkImageCache* Create(); + + virtual void* allocAndPinCache(size_t bytes, ID*) SK_OVERRIDE; + virtual void* pinCache(ID, SkImageCache::DataStatus*) SK_OVERRIDE; + virtual void releaseCache(ID) SK_OVERRIDE; + virtual void throwAwayCache(ID) SK_OVERRIDE; + +#ifdef SK_DEBUG + virtual MemoryStatus getMemoryStatus(ID) const SK_OVERRIDE; + virtual void purgeAllUnpinnedCaches() SK_OVERRIDE; + virtual ~SkPurgeableImageCache(); +#endif + +private: + SkPurgeableImageCache(); + +#ifdef SK_DEBUG + SkTDArray<ID> fRecs; + int findRec(ID) const; +#endif + void removeRec(ID); +}; +#endif // SkPurgeableImageCache_DEFINED diff --git a/pathops/SkPathOps.h b/pathops/SkPathOps.h new file mode 100644 index 0000000..a98f4ea --- /dev/null +++ b/pathops/SkPathOps.h @@ -0,0 +1,57 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkPathOps_DEFINED +#define SkPathOps_DEFINED + +#include "SkPreConfig.h" + +class SkPath; + +// FIXME: move everything below into the SkPath class +/** + * The logical operations that can be performed when combining two paths. + */ +enum SkPathOp { + kDifference_PathOp, //!< subtract the op path from the first path + kIntersect_PathOp, //!< intersect the two paths + kUnion_PathOp, //!< union (inclusive-or) the two paths + kXOR_PathOp, //!< exclusive-or the two paths + kReverseDifference_PathOp, //!< subtract the first path from the op path +}; + +/** Set this path to the result of applying the Op to this path and the + specified path: this = (this op operand). + The resulting path will be constructed from non-overlapping contours. + The curve order is reduced where possible so that cubics may be turned + into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param one The first operand (for difference, the minuend) + @param two The second operand (for difference, the subtrahend) + @param result The product of the operands. The result may be one of the + inputs. + @return True if operation succeeded. + */ +bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result); + +/** Set this path to a set of non-overlapping contours that describe the + same area as the original path. + The curve order is reduced where possible so that cubics may + be turned into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param path The path to simplify. + @param result The simplified path. The result may be the input. + @return True if simplification succeeded. + */ +bool SK_API Simplify(const SkPath& path, SkPath* result); + +#endif diff --git a/pdf/SkPDFDevice.h b/pdf/SkPDFDevice.h new file mode 100644 index 0000000..207b2b2 --- /dev/null +++ b/pdf/SkPDFDevice.h @@ -0,0 +1,315 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFDevice_DEFINED +#define SkPDFDevice_DEFINED + +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkTDArray.h" +#include "SkTScopedPtr.h" + +class SkPDFArray; +class SkPDFDevice; +class SkPDFDict; +class SkPDFFont; +class SkPDFFormXObject; +class SkPDFGlyphSetMap; +class SkPDFGraphicState; +class SkPDFObject; +class SkPDFResourceDict; +class SkPDFShader; +class SkPDFStream; +template <typename T> class SkTSet; + +// Private classes. +struct ContentEntry; +struct GraphicStateEntry; +struct NamedDestination; + +typedef bool (*EncodeToDCTStream)(SkWStream* stream, const SkBitmap& bitmap, const SkIRect& rect); + +/** \class SkPDFDevice + + The drawing context for the PDF backend. +*/ +class SkPDFDevice : public SkDevice { +public: + /** Create a PDF drawing context with the given width and height. + * 72 points/in means letter paper is 612x792. + * @param pageSize Page size in points. + * @param contentSize The content size of the page in points. This will be + * combined with the initial transform to determine the drawing area + * (as reported by the width and height methods). Anything outside + * of the drawing area will be clipped. + * @param initialTransform The initial transform to apply to the page. + * This may be useful to, for example, move the origin in and + * over a bit to account for a margin, scale the canvas, + * or apply a rotation. Note1: the SkPDFDevice also applies + * a scale+translate transform to move the origin from the + * bottom left (PDF default) to the top left. Note2: drawDevice + * (used by layer restore) draws the device after this initial + * transform is applied, so the PDF device does an + * inverse scale+translate to accommodate the one that SkPDFDevice + * always does. + */ + // TODO(vandebo): The sizes should be SkSize and not SkISize. + SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, + const SkMatrix& initialTransform); + SK_API virtual ~SkPDFDevice(); + + virtual uint32_t getDeviceCapabilities() SK_OVERRIDE; + + virtual void clear(SkColor color) SK_OVERRIDE; + + /** 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) SK_OVERRIDE; + virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, + size_t count, const SkPoint[], + const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint); + virtual void drawPath(const SkDraw&, const SkPath& origpath, + const SkPaint& paint, const SkMatrix* prePathMatrix, + bool pathIsMutable) SK_OVERRIDE; + virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, + const SkRect* src, const SkRect& dst, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE; + virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawText(const SkDraw&, const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE; + virtual void drawPosText(const SkDraw&, const void* text, size_t len, + const SkScalar pos[], SkScalar constY, + int scalarsPerPos, const SkPaint&) SK_OVERRIDE; + virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + 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) SK_OVERRIDE; + virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&) SK_OVERRIDE; + + virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE; + virtual void onDetachFromCanvas() SK_OVERRIDE; + + enum DrawingArea { + kContent_DrawingArea, // Drawing area for the page content. + kMargin_DrawingArea, // Drawing area for the margin content. + }; + + /** Sets the drawing area for the device. Subsequent draw calls are directed + * to the specific drawing area (margin or content). The default drawing + * area is the content drawing area. + * + * Currently if margin content is drawn and then a complex (for PDF) xfer + * mode is used, like SrcIn, Clear, etc, the margin content will get + * clipped. A simple way to avoid the bug is to always draw the margin + * content last. + */ + SK_API void setDrawingArea(DrawingArea drawingArea); + + /** Sets the DCTEncoder for images. + * @param encoder The encoder to encode a bitmap as JPEG (DCT). + * Result of encodings are cached, if the encoder changes the + * behaivor dynamically and an image is added to a second catalog, + * we will likely use the result of the first encoding call. + * By returning false from the encoder function, the encoder result + * is not used. + * Callers might not want to encode small images, as the time spent + * encoding and decoding might not be worth the space savings, + * if any at all. + */ + void setDCTEncoder(EncodeToDCTStream encoder) { + fEncoder = encoder; + } + + // PDF specific methods. + + /** Returns the resource dictionary for this device. + */ + SK_API SkPDFResourceDict* getResourceDict(); + + /** Get the fonts used on this device. + */ + SK_API const SkTDArray<SkPDFFont*>& getFontResources() const; + + /** Add our named destinations to the supplied dictionary. + * @param dict Dictionary to add destinations to. + * @param page The PDF object representing the page for this device. + */ + void appendDestinations(SkPDFDict* dict, SkPDFObject* page); + + /** Returns a copy of the media box for this device. The caller is required + * to unref() this when it is finished. + */ + SK_API SkPDFArray* copyMediaBox() const; + + /** Get the annotations from this page, or NULL if there are none. + */ + SK_API SkPDFArray* getAnnotations() const { return fAnnotations; } + + /** Returns a SkStream with the page contents. The caller is responsible + for a reference to the returned value. + DEPRECATED: use copyContentToData() + */ + SK_API SkStream* content() const; + + /** Returns a SkStream with the page contents. The caller is responsible + * for calling data->unref() when it is finished. + */ + SK_API SkData* copyContentToData() const; + + SK_API const SkMatrix& initialTransform() const { + return fInitialTransform; + } + + /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font + * that shows on this device. + */ + const SkPDFGlyphSetMap& getFontGlyphUsage() const { + return *(fFontGlyphUsage.get()); + } + +protected: + virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y, + SkCanvas::Config8888) SK_OVERRIDE; + + virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE; + +private: + // TODO(vandebo): push most of SkPDFDevice's state into a core object in + // order to get the right access levels without using friend. + friend class ScopedContentEntry; + + SkISize fPageSize; + SkISize fContentSize; + SkMatrix fInitialTransform; + SkClipStack fExistingClipStack; + SkRegion fExistingClipRegion; + SkPDFArray* fAnnotations; + SkPDFResourceDict* fResourceDict; + SkTDArray<NamedDestination*> fNamedDestinations; + + SkTDArray<SkPDFGraphicState*> fGraphicStateResources; + SkTDArray<SkPDFObject*> fXObjectResources; + SkTDArray<SkPDFFont*> fFontResources; + SkTDArray<SkPDFObject*> fShaderResources; + + SkTScopedPtr<ContentEntry> fContentEntries; + ContentEntry* fLastContentEntry; + SkTScopedPtr<ContentEntry> fMarginContentEntries; + ContentEntry* fLastMarginContentEntry; + DrawingArea fDrawingArea; + + const SkClipStack* fClipStack; + + // Accessor and setter functions based on the current DrawingArea. + SkTScopedPtr<ContentEntry>* getContentEntries(); + ContentEntry* getLastContentEntry(); + void setLastContentEntry(ContentEntry* contentEntry); + + // Glyph ids used for each font on this device. + SkTScopedPtr<SkPDFGlyphSetMap> fFontGlyphUsage; + + EncodeToDCTStream fEncoder; + + SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack, + const SkRegion& existingClipRegion); + + // override from SkDevice + virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config, + int width, int height, + bool isOpaque, + Usage usage) SK_OVERRIDE; + + void init(); + void cleanUp(bool clearFontUsage); + SkPDFFormXObject* createFormXObjectFromDevice(); + + // Clear the passed clip from all existing content entries. + void clearClipFromContent(const SkClipStack* clipStack, + const SkRegion& clipRegion); + void drawFormXObjectWithClip(SkPDFFormXObject* form, + const SkClipStack* clipStack, + const SkRegion& clipRegion, + bool invertClip); + + // If the paint or clip is such that we shouldn't draw anything, this + // returns NULL and does not create a content entry. + // setUpContentEntry and finishContentEntry can be used directly, but + // the preferred method is to use the ScopedContentEntry helper class. + ContentEntry* setUpContentEntry(const SkClipStack* clipStack, + const SkRegion& clipRegion, + const SkMatrix& matrix, + const SkPaint& paint, + bool hasText, + SkPDFFormXObject** dst); + void finishContentEntry(SkXfermode::Mode xfermode, + SkPDFFormXObject* dst); + bool isContentEmpty(); + + void populateGraphicStateEntryFromPaint(const SkMatrix& matrix, + const SkClipStack& clipStack, + const SkRegion& clipRegion, + const SkPaint& paint, + bool hasText, + GraphicStateEntry* entry); + int addGraphicStateResource(SkPDFGraphicState* gs); + + void updateFont(const SkPaint& paint, uint16_t glyphID, + ContentEntry* contentEntry); + int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID); + + void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry); + void internalDrawBitmap(const SkMatrix& matrix, + const SkClipStack* clipStack, + const SkRegion& clipRegion, + const SkBitmap& bitmap, + const SkIRect* srcRect, + const SkPaint& paint); + + /** Helper method for copyContentToData. It is responsible for copying the + * list of content entries |entry| to |data|. + */ + void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const; + +#ifdef SK_PDF_USE_PATHOPS + bool handleInversePath(const SkDraw& d, const SkPath& origPath, + const SkPaint& paint, bool pathIsMutable); +#endif + bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, + const SkPaint& paint); + bool handlePointAnnotation(const SkPoint* points, size_t count, + const SkMatrix& matrix, const SkPaint& paint); + SkPDFDict* createLinkAnnotation(const SkRect& r, const SkMatrix& matrix); + void handleLinkToURL(SkData* urlData, const SkRect& r, + const SkMatrix& matrix); + void handleLinkToNamedDest(SkData* nameData, const SkRect& r, + const SkMatrix& matrix); + void defineNamedDestination(SkData* nameData, const SkPoint& point, + const SkMatrix& matrix); + + typedef SkDevice INHERITED; +}; + +#endif diff --git a/pdf/SkPDFDocument.h b/pdf/SkPDFDocument.h new file mode 100644 index 0000000..31c6f9b --- /dev/null +++ b/pdf/SkPDFDocument.h @@ -0,0 +1,105 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFDocument_DEFINED +#define SkPDFDocument_DEFINED + +#include "SkAdvancedTypefaceMetrics.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" +#include "SkTScopedPtr.h" + +class SkPDFCatalog; +class SkPDFDevice; +class SkPDFDict; +class SkPDFPage; +class SkPDFObject; +class SkWStream; +template <typename T> class SkTSet; + +/** \class SkPDFDocument + + A SkPDFDocument assembles pages together and generates the final PDF file. +*/ +class SkPDFDocument { +public: + enum Flags { + kNoCompression_Flags = 0x01, //!< DEPRECATED. + kFavorSpeedOverSize_Flags = 0x01, //!< Don't compress the stream, but + // if it is already compressed return + // the compressed stream. + kNoLinks_Flags = 0x02, //!< do not honor link annotations. + + kDraftMode_Flags = 0x01, + }; + /** Create a PDF document. + */ + explicit SK_API SkPDFDocument(Flags flags = (Flags)0); + SK_API ~SkPDFDocument(); + + /** Output the PDF to the passed stream. It is an error to call this (it + * will return false and not modify stream) if no pages have been added + * or there are pages missing (i.e. page 1 and 3 have been added, but not + * page 2). + * + * @param stream The writable output stream to send the PDF to. + */ + SK_API bool emitPDF(SkWStream* stream); + + /** Sets the specific page to the passed PDF device. If the specified + * page is already set, this overrides it. Returns true if successful. + * Will fail if the document has already been emitted. + * + * @param pageNumber The position to add the passed device (1 based). + * @param pdfDevice The page to add to this document. + */ + SK_API bool setPage(int pageNumber, SkPDFDevice* pdfDevice); + + /** Append the passed pdf device to the document as a new page. Returns + * true if successful. Will fail if the document has already been emitted. + * + * @param pdfDevice The page to add to this document. + */ + SK_API bool appendPage(SkPDFDevice* pdfDevice); + + /** Get the count of unique font types used in the document. + */ + SK_API void getCountOfFontTypes( + int counts[SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1]) const; + +private: + SkTScopedPtr<SkPDFCatalog> fCatalog; + int64_t fXRefFileOffset; + + SkTDArray<SkPDFPage*> fPages; + SkTDArray<SkPDFDict*> fPageTree; + SkPDFDict* fDocCatalog; + SkTSet<SkPDFObject*>* fFirstPageResources; + SkTSet<SkPDFObject*>* fOtherPageResources; + SkTDArray<SkPDFObject*> fSubstitutes; + + SkPDFDict* fTrailerDict; + + /** Output the PDF header to the passed stream. + * @param stream The writable output stream to send the header to. + */ + void emitHeader(SkWStream* stream); + + /** Get the size of the header. + */ + size_t headerSize(); + + /** Output the PDF footer to the passed stream. + * @param stream The writable output stream to send the footer to. + * @param objCount The number of objects in the PDF. + */ + void emitFooter(SkWStream* stream, int64_t objCount); +}; + +#endif diff --git a/pipe/SkGPipe.h b/pipe/SkGPipe.h new file mode 100644 index 0000000..879ab04 --- /dev/null +++ b/pipe/SkGPipe.h @@ -0,0 +1,168 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkGPipe_DEFINED +#define SkGPipe_DEFINED + +#include "SkFlattenable.h" +#include "SkPicture.h" +#include "SkWriter32.h" + +class SkCanvas; + +// XLib.h might have defined Status already (ugh) +#ifdef Status + #undef Status +#endif + +class SkGPipeReader { +public: + SkGPipeReader(); + SkGPipeReader(SkCanvas* target); + ~SkGPipeReader(); + + enum Status { + kDone_Status, //!< no more data expected from reader + kEOF_Status, //!< need more data from reader + kError_Status, //!< encountered error + kReadAtom_Status//!< finished reading an atom + }; + + enum PlaybackFlags { + kReadAtom_PlaybackFlag = 0x1, //!< playback a single command from the stream + kSilent_PlaybackFlag = 0x2, //!< playback without drawing + }; + + void setCanvas(SkCanvas*); + + /** + * Set a function for decoding bitmaps that have encoded data. + */ + void setBitmapDecoder(SkPicture::InstallPixelRefProc proc) { fProc = proc; } + + // data must be 4-byte aligned + // length must be a multiple of 4 + Status playback(const void* data, size_t length, uint32_t playbackFlags = 0, + size_t* bytesRead = NULL); +private: + SkCanvas* fCanvas; + class SkGPipeState* fState; + SkPicture::InstallPixelRefProc fProc; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkGPipeCanvas; + +class SkGPipeController { +public: + SkGPipeController() : fCanvas(NULL) {} + virtual ~SkGPipeController(); + + /** + * Called periodically by the writer, to get a working buffer of RAM to + * write into. The actual size of the block is also returned, and must be + * actual >= minRequest. If NULL is returned, then actual is ignored and + * writing will stop. + * + * The returned block must be 4-byte aligned, and actual must be a + * multiple of 4. + * minRequest will always be a multiple of 4. + */ + virtual void* requestBlock(size_t minRequest, size_t* actual) = 0; + + /** + * This is called each time some atomic portion of the data has been + * written to the block (most recently returned by requestBlock()). + * If bytes == 0, then the writer has finished. + * + * bytes will always be a multiple of 4. + */ + virtual void notifyWritten(size_t bytes) = 0; + virtual int numberOfReaders() const { return 1; } + +private: + friend class SkGPipeWriter; + void setCanvas(SkGPipeCanvas*); + + SkGPipeCanvas* fCanvas; +}; + +class SkGPipeWriter { +public: + SkGPipeWriter(); + ~SkGPipeWriter(); + + bool isRecording() const { return NULL != fCanvas; } + + enum Flags { + /** + * Tells the writer that the reader will be in a different process, so + * (for example) we cannot put function pointers in the stream. + */ + kCrossProcess_Flag = 1 << 0, + + /** + * Only meaningful if kCrossProcess_Flag is set. Tells the writer that + * in spite of being cross process, it will have shared address space + * with the reader, so the two can share large objects (like SkBitmaps). + */ + kSharedAddressSpace_Flag = 1 << 1, + + /** + * Tells the writer that there will be multiple threads reading the stream + * simultaneously. + */ + kSimultaneousReaders_Flag = 1 << 2, + }; + + SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0, + uint32_t width = kDefaultRecordingCanvasSize, + uint32_t height = kDefaultRecordingCanvasSize); + + // called in destructor, but can be called sooner once you know there + // should be no more drawing calls made into the recording canvas. + void endRecording(); + + /** + * Tells the writer to commit all recorded draw commands to the + * controller immediately. + * @param detachCurrentBlock Set to true to request that the next draw + * command be recorded in a new block. + */ + void flushRecording(bool detachCurrentBlock); + + /** + * Return the amount of bytes being used for recording. Note that this + * does not include the amount of storage written to the stream, which is + * controlled by the SkGPipeController. + * Currently only returns the amount used for SkBitmaps, since they are + * potentially unbounded (if the client is not calling playback). + */ + size_t storageAllocatedForRecording() const; + + /** + * Attempt to reduce the storage allocated for recording by evicting + * cache resources. + * @param bytesToFree minimum number of bytes that should be attempted to + * be freed. + * @return number of bytes actually freed. + */ + size_t freeMemoryIfPossible(size_t bytesToFree); + +private: + enum { + kDefaultRecordingCanvasSize = 32767, + }; + + SkGPipeCanvas* fCanvas; + SkWriter32 fWriter; +}; + +#endif diff --git a/ports/SkFontConfigInterface.h b/ports/SkFontConfigInterface.h new file mode 100644 index 0000000..661c3be --- /dev/null +++ b/ports/SkFontConfigInterface.h @@ -0,0 +1,111 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontConfigInterface_DEFINED +#define SkFontConfigInterface_DEFINED + +#include "SkDataTable.h" +#include "SkFontStyle.h" +#include "SkRefCnt.h" +#include "SkTArray.h" +#include "SkTypeface.h" + +/** + * \class SkFontConfigInterface + * + * Provides SkFontHost clients with access to fontconfig services. They will + * access the global instance found in RefGlobal(). + */ +class SK_API SkFontConfigInterface : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkFontConfigInterface) + + /** + * Returns the global SkFontConfigInterface instance, and if it is not + * NULL, calls ref() on it. The caller must balance this with a call to + * unref(). + */ + static SkFontConfigInterface* RefGlobal(); + + /** + * Replace the current global instance with the specified one, safely + * ref'ing the new instance, and unref'ing the previous. Returns its + * parameter (the new global instance). + */ + static SkFontConfigInterface* SetGlobal(SkFontConfigInterface*); + + /** + * This should be treated as private to the impl of SkFontConfigInterface. + * Callers should not change or expect any particular values. It is meant + * to be a union of possible storage types to aid the impl. + */ + struct FontIdentity { + FontIdentity() : fID(0), fTTCIndex(0) {} + + bool operator==(const FontIdentity& other) const { + return fID == other.fID && + fTTCIndex == other.fTTCIndex && + fString == other.fString; + } + bool operator!=(const FontIdentity& other) const { + return !(*this == other); + } + + uint32_t fID; + int32_t fTTCIndex; + SkString fString; + SkFontStyle fStyle; + + // If buffer is NULL, just return the number of bytes that would have + // been written. Will pad contents to a multiple of 4. + size_t writeToMemory(void* buffer = NULL) const; + + // Recreate from a flattened buffer, returning the number of bytes read. + size_t readFromMemory(const void* buffer, size_t length); + }; + + /** + * Given a familyName and style, find the best match. + * + * If a match is found, return true and set its outFontIdentifier. + * If outFamilyName is not null, assign the found familyName to it + * (which may differ from the requested familyName). + * If outStyle is not null, assign the found style to it + * (which may differ from the requested style). + * + * If a match is not found, return false, and ignore all out parameters. + */ + virtual bool matchFamilyName(const char familyName[], + SkTypeface::Style requested, + FontIdentity* outFontIdentifier, + SkString* outFamilyName, + SkTypeface::Style* outStyle) = 0; + + /** + * Given a FontRef, open a stream to access its data, or return null + * if the FontRef's data is not available. The caller is responsible for + * calling stream->unref() when it is done accessing the data. + */ + virtual SkStream* openStream(const FontIdentity&) = 0; + + /** + * Return a singleton instance of a direct subclass that calls into + * libfontconfig. This does not affect the refcnt of the returned instance. + */ + static SkFontConfigInterface* GetSingletonDirectInterface(); + + // New APIS, which have default impls for now (which do nothing) + + virtual SkDataTable* getFamilyNames() { return SkDataTable::NewEmpty(); } + virtual bool matchFamilySet(const char inFamilyName[], + SkString* outFamilyName, + SkTArray<FontIdentity>*) { + return false; + } +}; + +#endif diff --git a/ports/SkFontMgr.h b/ports/SkFontMgr.h new file mode 100644 index 0000000..d243825 --- /dev/null +++ b/ports/SkFontMgr.h @@ -0,0 +1,112 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_DEFINED +#define SkFontMgr_DEFINED + +#include "SkRefCnt.h" +#include "SkFontStyle.h" + +class SkData; +class SkStream; +class SkString; +class SkTypeface; + +class SK_API SkFontStyleSet : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkFontStyleSet) + + virtual int count() = 0; + virtual void getStyle(int index, SkFontStyle*, SkString* style) = 0; + virtual SkTypeface* createTypeface(int index) = 0; + virtual SkTypeface* matchStyle(const SkFontStyle& pattern) = 0; + + static SkFontStyleSet* CreateEmpty(); + +private: + typedef SkRefCnt INHERITED; +}; + +class SkTypeface; + +class SK_API SkFontMgr : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkFontMgr) + + int countFamilies(); + void getFamilyName(int index, SkString* familyName); + SkFontStyleSet* createStyleSet(int index); + + SkFontStyleSet* matchFamily(const char familyName[]); + + /** + * Find the closest matching typeface to the specified familyName and style + * and return a ref to it. The caller must call unref() on the returned + * object. Will never return NULL, as it will return the default font if + * no matching font is found. + */ + SkTypeface* matchFamilyStyle(const char familyName[], const SkFontStyle&); + + SkTypeface* matchFaceStyle(const SkTypeface*, const SkFontStyle&); + + /** + * Create a typeface for the specified data and TTC index (pass 0 for none) + * or NULL if the data is not recognized. The caller must call unref() on + * the returned object if it is not null. + */ + SkTypeface* createFromData(SkData*, int ttcIndex = 0); + + /** + * Create a typeface for the specified stream and TTC index + * (pass 0 for none) or NULL if the stream is not recognized. The caller + * must call unref() on the returned object if it is not null. + */ + SkTypeface* createFromStream(SkStream*, int ttcIndex = 0); + + /** + * Create a typeface for the specified fileName and TTC index + * (pass 0 for none) or NULL if the file is not found, or its contents are + * not recognized. The caller must call unref() on the returned object + * if it is not null. + */ + SkTypeface* createFromFile(const char path[], int ttcIndex = 0); + + SkTypeface* legacyCreateTypeface(const char familyName[], + unsigned typefaceStyleBits); + + /** + * Return a ref to the default fontmgr. The caller must call unref() on + * the returned object. + */ + static SkFontMgr* RefDefault(); + +protected: + virtual int onCountFamilies() = 0; + virtual void onGetFamilyName(int index, SkString* familyName) = 0; + virtual SkFontStyleSet* onCreateStyleSet(int index) = 0; + + virtual SkFontStyleSet* onMatchFamily(const char familyName[]) = 0; + + virtual SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle&) = 0; + virtual SkTypeface* onMatchFaceStyle(const SkTypeface*, + const SkFontStyle&) = 0; + + virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) = 0; + virtual SkTypeface* onCreateFromStream(SkStream*, int ttcIndex) = 0; + virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) = 0; + + // TODO: make this pure-virtual once all ports know about it + virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], + unsigned styleBits); +private: + static SkFontMgr* Factory(); // implemented by porting layer + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/ports/SkFontStyle.h b/ports/SkFontStyle.h new file mode 100644 index 0000000..9d9a912 --- /dev/null +++ b/ports/SkFontStyle.h @@ -0,0 +1,70 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontStyle_DEFINED +#define SkFontStyle_DEFINED + +#include "SkTypes.h" + +class SK_API SkFontStyle { +public: + enum Weight { + kThin_Weight = 100, + kExtraLight_Weight = 200, + kLight_Weight = 300, + kNormal_Weight = 400, + kMedium_Weight = 500, + kSemiBold_Weight = 600, + kBold_Weight = 700, + kExtraBold_Weight = 800, + kBlack_Weight = 900 + }; + + enum Width { + kUltraCondensed_Width = 1, + kExtraCondensed_Width = 2, + kCondensed_Width = 3, + kSemiCondensed_Width = 4, + kNormal_Width = 5, + kSemiExpanded_Width = 6, + kExpanded_Width = 7, + kExtraExpanded_Width = 8, + kUltaExpanded_Width = 9 + }; + + enum Slant { + kUpright_Slant, + kItalic_Slant, + }; + + SkFontStyle(); + SkFontStyle(int weight, int width, Slant); + + bool operator==(const SkFontStyle& rhs) const { + return fUnion.fU32 == rhs.fUnion.fU32; + } + + int weight() const { return fUnion.fR.fWeight; } + int width() const { return fUnion.fR.fWidth; } + Slant slant() const { return (Slant)fUnion.fR.fSlant; } + + bool isItalic() const { + return kItalic_Slant == fUnion.fR.fSlant; + } + +private: + union { + struct { + uint16_t fWeight; // 100 .. 900 + uint8_t fWidth; // 1 .. 9 + uint8_t fSlant; // 0 .. 2 + } fR; + uint32_t fU32; + } fUnion; +}; + +#endif diff --git a/ports/SkHarfBuzzFont.h b/ports/SkHarfBuzzFont.h new file mode 100644 index 0000000..22749af --- /dev/null +++ b/ports/SkHarfBuzzFont.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkHarfBuzzFont_DEFINED +#define SkHarfBuzzFont_DEFINED + +extern "C" { +#include "harfbuzz-shaper.h" +//#include "harfbuzz-unicode.h" +} + +#include "SkTypes.h" + +class SkPaint; +class SkTypeface; + +class SkHarfBuzzFont { +public: + /** The subclass returns the typeface for this font, or NULL + */ + virtual SkTypeface* getTypeface() const = 0; + /** The subclass sets the text related attributes of the paint. + e.g. textSize, typeface, textSkewX, etc. + All of the attributes that could effect how the text is measured. + Color information (e.g. color, xfermode, shader, etc.) are not required. + */ + virtual void setupPaint(SkPaint*) const = 0; + + /** Implementation of HB_GetFontTableFunc, using SkHarfBuzzFont* as + the first parameter. + */ + static HB_Error GetFontTableFunc(void* skharfbuzzfont, const HB_Tag tag, + HB_Byte* buffer, HB_UInt* len); + + static const HB_FontClass& GetFontClass(); +}; + +#endif diff --git a/ports/SkTypeface_android.h b/ports/SkTypeface_android.h new file mode 100644 index 0000000..655670f --- /dev/null +++ b/ports/SkTypeface_android.h @@ -0,0 +1,72 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTypeface_android_DEFINED +#define SkTypeface_android_DEFINED + +#include "SkTypeface.h" + +#ifdef SK_BUILD_FOR_ANDROID + +class SkPaintOptionsAndroid; + +/** + * Get the family name of the font in the fallback font list containing + * the specified character. if no font is found, returns false. + */ +SK_API bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name); + +/** + * For test only. + * Load font config from given xml files, instead of those from Android system. + */ +SK_API void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, + const char* fontsdir); + +/** + * Given a "current" fontID, return a ref to the next logical typeface + * when searching fonts for a given unicode value. Typically the caller + * will query a given font, and if a unicode value is not supported, they + * will call this, and if 0 is not returned, will search that font, and so + * on. This process must be finite, and when the fonthost sees a + * font with no logical successor, it must return NULL. + * + * The original fontID is also provided. This is the initial font that was + * stored in the typeface of the caller. It is provided as an aid to choose + * the best next logical font. e.g. If the original font was bold or serif, + * but the 2nd in the logical chain was plain, then a subsequent call to + * get the 3rd can still inspect the original, and try to match its + * stylistic attributes. + */ +SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, + const SkPaintOptionsAndroid& options); + +#endif // #ifdef SK_BUILD_FOR_ANDROID +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + +#include "SkPaintOptionsAndroid.h" +#include "../harfbuzz/src/harfbuzz-shaper.h" +#include "../harfbuzz_ng/src/hb.h" + +/** + * Return a new typeface for a fallback script. If the script is + * not valid, or can not map to a font, returns null. + * @param script The harfbuzz script id. + * @param style The font style, for example bold + * @param elegant true if we want the web friendly elegant version of the font + * @return reference to the matching typeface. Caller must call + * unref() when they are done. + */ +SK_API SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style, + SkPaintOptionsAndroid::FontVariant fontVariant = SkPaintOptionsAndroid::kDefault_Variant); + +SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, + SkPaintOptionsAndroid::FontVariant fontVariant = SkPaintOptionsAndroid::kDefault_Variant); + +#endif // #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK +#endif // #ifndef SkTypeface_android_DEFINED diff --git a/ports/SkTypeface_mac.h b/ports/SkTypeface_mac.h new file mode 100644 index 0000000..0166ee5 --- /dev/null +++ b/ports/SkTypeface_mac.h @@ -0,0 +1,29 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkTypeface_mac_DEFINED +#define SkTypeface_mac_DEFINED + +#include "SkTypeface.h" +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#endif +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified CTFontRef. The caller must call + * unref() when it is finished. + */ +SK_API extern SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef); + +#endif diff --git a/ports/SkTypeface_win.h b/ports/SkTypeface_win.h new file mode 100644 index 0000000..fea5f47 --- /dev/null +++ b/ports/SkTypeface_win.h @@ -0,0 +1,39 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef SkTypeface_win_DEFINED +#define SkTypeface_win_DEFINED + +#include "SkTypeface.h" + +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified logfont. The caller is responsible + * for calling unref() when it is finished. + */ +SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&); + +/** + * Copy the LOGFONT associated with this typeface into the lf parameter. Note + * that the lfHeight will need to be set afterwards, since the typeface does + * not track this (the paint does). + * typeface may be NULL, in which case we return the logfont for the default font. + */ +SK_API void SkLOGFONTFromTypeface(const SkTypeface* typeface, LOGFONT* lf); + +/** + * Set an optional callback to ensure that the data behind a LOGFONT is loaded. + * This will get called if Skia tries to access the data but hits a failure. + * Normally this is null, and is only required if the font data needs to be + * remotely (re)loaded. + */ +SK_API void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*)(const LOGFONT&)); + +#endif diff --git a/svg/SkSVGAttribute.h b/svg/SkSVGAttribute.h new file mode 100644 index 0000000..940ca5a --- /dev/null +++ b/svg/SkSVGAttribute.h @@ -0,0 +1,42 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSVGAttribute_DEFINED +#define SkSVGAttribute_DEFINED + +#include "SkTypes.h" + +struct SkSVGAttribute { + const char* fName; +#ifdef SK_DEBUG + size_t fOffset; +#endif +}; + +#ifndef SK_OFFSETOF +#define SK_OFFSETOF(a, b) (((size_t) (&(((a*) 1)->b)))-1) +#endif + +#ifdef SK_DEBUG +#define SVG_ATTRIBUTE(attr) { #attr, SK_OFFSETOF(BASE_CLASS, f_##attr) } +#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr, SK_OFFSETOF(BASE_CLASS, cAttr) } +#else +#define SVG_ATTRIBUTE(attr) { #attr } +#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr } +#endif + +#define SVG_ADD_ATTRIBUTE(attr) \ + if (f_##attr.size() > 0) \ + parser._addAttributeLen(#attr, f_##attr.c_str(), f_##attr.size()) + +#define SVG_ADD_ATTRIBUTE_ALIAS(attr, alias) \ + if (f_##alias.size() > 0) \ + parser._addAttributeLen(#attr, f_##alias.c_str(), f_##alias.size()) + +#endif // SkSVGAttribute_DEFINED diff --git a/svg/SkSVGBase.h b/svg/SkSVGBase.h new file mode 100644 index 0000000..6bfc39d --- /dev/null +++ b/svg/SkSVGBase.h @@ -0,0 +1,25 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSVGBase_DEFINED +#define SkSVGBase_DEFINED + +#include "SkSVGAttribute.h" + +class SkSVGParser; + +class SkSVGBase { +public: + virtual ~SkSVGBase(); + virtual void addAttribute(SkSVGParser& parser, int attrIndex, + const char* attrValue, size_t attrLength); + virtual int getAttributes(const SkSVGAttribute** attrPtr) = 0; +}; + +#endif // SkSVGBase_DEFINEDes(const SkSVGAttribute** attrPtr) = 0; diff --git a/svg/SkSVGPaintState.h b/svg/SkSVGPaintState.h new file mode 100644 index 0000000..211e9cf --- /dev/null +++ b/svg/SkSVGPaintState.h @@ -0,0 +1,89 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSVGPaintState_DEFINED +#define SkSVGPaintState_DEFINED + +#include "SkSVGBase.h" +#include "SkString.h" + +class SkSVGPaint : public SkSVGBase { +public: + enum Field { + kInitial = -1, + kClipPath, + kClipRule, + kEnableBackground, + kFill, + kFillRule, + kFilter, + kFontFamily, + kFontSize, + kLetterSpacing, + kMask, + kOpacity, + kStopColor, + kStopOpacity, + kStroke, + kStroke_Dasharray, + kStroke_Linecap, + kStroke_Linejoin, + kStroke_Miterlimit, + kStroke_Width, + kStyle, + kTransform, + kTerminal + }; + + SkSVGPaint(); + virtual void addAttribute(SkSVGParser& parser, int attrIndex, + const char* attrValue, size_t attrLength); + bool flush(SkSVGParser& , bool isFlushable, bool isDef); + virtual int getAttributes(const SkSVGAttribute** attrPtr); + static void Push(SkSVGPaint** head, SkSVGPaint* add); + static void Pop(SkSVGPaint** head); + SkString* operator[](int index); + SkString fInitial; + SkString f_clipPath; + SkString f_clipRule; + SkString f_enableBackground; + SkString f_fill; + SkString f_fillRule; + SkString f_filter; + SkString f_fontFamily; + SkString f_fontSize; + SkString f_letterSpacing; + SkString f_mask; + SkString f_opacity; + SkString f_stopColor; + SkString f_stopOpacity; + SkString f_stroke; + SkString f_strokeDasharray; + SkString f_strokeLinecap; + SkString f_strokeLinejoin; + SkString f_strokeMiterlimit; + SkString f_strokeWidth; + SkString f_style; // unused, but allows array access to the rest + SkString f_transform; +#ifdef SK_DEBUG + SkString fTerminal; +#endif + SkString fTransformID; + static SkSVGAttribute gAttributes[]; + static const int kAttributesSize; +private: + void setSave(SkSVGParser& ); + bool writeChangedAttributes(SkSVGParser& , SkSVGPaint& , bool* changed); + bool writeChangedElements(SkSVGParser& , SkSVGPaint& , bool* changed); + SkSVGPaint* fNext; + friend class SkSVGParser; + typedef SkSVGPaint BASE_CLASS; +}; + +#endif // SkSVGPaintState_DEFINED diff --git a/svg/SkSVGParser.h b/svg/SkSVGParser.h new file mode 100644 index 0000000..c2f9112 --- /dev/null +++ b/svg/SkSVGParser.h @@ -0,0 +1,74 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSVGParser_DEFINED +#define SkSVGParser_DEFINED + +#include "SkMatrix.h" +#include "SkTDict.h" +#include "SkTDStack.h" +#include "SkSVGPaintState.h" +#include "SkSVGTypes.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkXMLParser.h" +#include "SkXMLWriter.h" + +class SkSVGBase; +class SkSVGElement; + +class SkSVGParser : public SkXMLParser { +public: + SkSVGParser(SkXMLParserError* err = NULL); + virtual ~SkSVGParser(); + void _addAttribute(const char* attrName, const char* attrValue) { + fXMLWriter.addAttribute(attrName, attrValue); } + void _addAttribute(const char* attrName, SkString& attrValue) { + fXMLWriter.addAttribute(attrName, attrValue.c_str()); } + void _addAttributeLen(const char* attrName, const char* attrValue, size_t len) { + fXMLWriter.addAttributeLen(attrName, attrValue, len); } + void _endElement() { fXMLWriter.endElement(); } + int findAttribute(SkSVGBase* , const char* attrValue, size_t len, bool isPaint); +// const char* getFinal(); + SkTDict<SkSVGElement*>& getIDs() { return fIDs; } + SkString& getPaintLast(SkSVGPaint::Field field); + void _startElement(const char name[]) { fXMLWriter.startElement(name); } + void translate(SkSVGElement*, bool isDef); + void translateMatrix(SkString& , SkString* id); + static void ConvertToArray(SkString& vals); +protected: + virtual bool onAddAttribute(const char name[], const char value[]); + bool onAddAttributeLen(const char name[], const char value[], size_t len); + virtual bool onEndElement(const char elem[]); + virtual bool onStartElement(const char elem[]); + bool onStartElementLen(const char elem[], size_t len); + virtual bool onText(const char text[], int len); +private: + bool isStrokeAndFill(SkSVGPaint** stroke, SkSVGPaint** fill); + static SkSVGElement* CreateElement(SkSVGTypes type, SkSVGElement* parent); + static void Delete(SkTDArray<SkSVGElement*>& fChildren); + static SkSVGTypes GetType(const char name[], size_t len); + SkSVGPaint* fHead; + SkSVGPaint fEmptyPaint; + SkSVGPaint fLastFlush; + SkString fLastColor; + SkMatrix fLastTransform; + SkTDArray<SkSVGElement*> fChildren; + SkTDict<SkSVGElement*> fIDs; + SkTDArray<SkSVGElement*> fParents; + SkDynamicMemoryWStream fStream; + SkXMLStreamWriter fXMLWriter; + SkSVGElement* fCurrElement; + SkBool8 fInSVG; + SkBool8 fSuppressPaint; + friend class SkSVGPaint; + friend class SkSVGGradient; +}; + +#endif // SkSVGParser_DEFINED diff --git a/svg/SkSVGTypes.h b/svg/SkSVGTypes.h new file mode 100644 index 0000000..b13bc6e --- /dev/null +++ b/svg/SkSVGTypes.h @@ -0,0 +1,40 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSVGTypes_DEFINED +#define SkSVGTypes_DEFINED + +enum SkSVGTypes { + SkSVGType_Circle, + SkSVGType_ClipPath, + SkSVGType_Defs, + SkSVGType_Ellipse, + SkSVGType_FeColorMatrix, + SkSVGType_Filter, + SkSVGType_G, + SkSVGType_Image, + SkSVGType_Line, + SkSVGType_LinearGradient, + SkSVGType_Mask, + SkSVGType_Metadata, + SkSVGType_Path, + SkSVGType_Polygon, + SkSVGType_Polyline, + SkSVGType_RadialGradient, + SkSVGType_Rect, + SkSVGType_SVG, + SkSVGType_Stop, + SkSVGType_Symbol, + SkSVGType_Text, + SkSVGType_Tspan, + SkSVGType_Unknown, + SkSVGType_Use +}; + +#endif // SkSVGTypes_DEFINED diff --git a/text/SkTextLayout.h b/text/SkTextLayout.h new file mode 100644 index 0000000..718acdb --- /dev/null +++ b/text/SkTextLayout.h @@ -0,0 +1,60 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkTextLayout_DEFINED +#define SkTextLayout_DEFINED + +#include "SkPaint.h" +#include "SkRefCnt.h" + +class SkTextStyle : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkTextStyle) + + SkTextStyle(); + SkTextStyle(const SkTextStyle&); + explicit SkTextStyle(const SkPaint&); + virtual ~SkTextStyle(); + + const SkPaint& paint() const { return fPaint; } + SkPaint& paint() { return fPaint; } + + // todo: bidi-override, language + +private: + SkPaint fPaint; + + typedef SkRefCnt INHERITED; +}; + +class SkTextLayout { +public: + SkTextLayout(); + ~SkTextLayout(); + + void setText(const char text[], size_t length); + void setBounds(const SkRect& bounds); + + SkTextStyle* getDefaultStyle() const { return fDefaultStyle; } + SkTextStyle* setDefaultStyle(SkTextStyle*); + +// SkTextStyle* setStyle(SkTextStyle*, size_t offset, size_t length); + + void draw(SkCanvas* canvas); + +private: + SkTDArray<char> fText; + SkTextStyle* fDefaultStyle; + SkRect fBounds; + + // cache + struct Line; + struct GlyphRun; + SkTDArray<Line*> fLines; +}; + +#endif diff --git a/utils/SkBoundaryPatch.h b/utils/SkBoundaryPatch.h new file mode 100644 index 0000000..cf001d5 --- /dev/null +++ b/utils/SkBoundaryPatch.h @@ -0,0 +1,66 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBoundaryPatch_DEFINED +#define SkBoundaryPatch_DEFINED + +#include "SkPoint.h" +#include "SkRefCnt.h" + +class SkBoundary : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkBoundary) + + // These must be 0, 1, 2, 3 for efficiency in the subclass implementations + enum Edge { + kTop = 0, + kRight = 1, + kBottom = 2, + kLeft = 3 + }; + // Edge index goes clockwise around the boundary, beginning at the "top" + virtual SkPoint eval(Edge, SkScalar unitInterval) = 0; + +private: + typedef SkRefCnt INHERITED; +}; + +class SkBoundaryPatch { +public: + SkBoundaryPatch(); + ~SkBoundaryPatch(); + + SkBoundary* getBoundary() const { return fBoundary; } + SkBoundary* setBoundary(SkBoundary*); + + SkPoint eval(SkScalar unitU, SkScalar unitV); + bool evalPatch(SkPoint verts[], int rows, int cols); + +private: + SkBoundary* fBoundary; +}; + +//////////////////////////////////////////////////////////////////////// + +class SkLineBoundary : public SkBoundary { +public: + SkPoint fPts[4]; + + // override + virtual SkPoint eval(Edge, SkScalar); +}; + +class SkCubicBoundary : public SkBoundary { +public: + // the caller sets the first 12 entries. The 13th is used by the impl. + SkPoint fPts[13]; + + // override + virtual SkPoint eval(Edge, SkScalar); +}; + +#endif diff --git a/utils/SkCamera.h b/utils/SkCamera.h new file mode 100644 index 0000000..eafacbc --- /dev/null +++ b/utils/SkCamera.h @@ -0,0 +1,175 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + + +// Inspired by Rob Johnson's most excellent QuickDraw GX sample code + +#ifndef SkCamera_DEFINED +#define SkCamera_DEFINED + +#include "Sk64.h" +#include "SkMatrix.h" + +class SkCanvas; + +#ifdef SK_SCALAR_IS_FIXED + typedef SkFract SkUnitScalar; + #define SK_UnitScalar1 SK_Fract1 + #define SkUnitScalarMul(a, b) SkFractMul(a, b) + #define SkUnitScalarDiv(a, b) SkFractDiv(a, b) +#else + typedef float SkUnitScalar; + #define SK_UnitScalar1 SK_Scalar1 + #define SkUnitScalarMul(a, b) SkScalarMul(a, b) + #define SkUnitScalarDiv(a, b) SkScalarDiv(a, b) +#endif + +struct SkUnit3D { + SkUnitScalar fX, fY, fZ; + + void set(SkUnitScalar x, SkUnitScalar y, SkUnitScalar z) + { + fX = x; fY = y; fZ = z; + } + static SkUnitScalar Dot(const SkUnit3D&, const SkUnit3D&); + static void Cross(const SkUnit3D&, const SkUnit3D&, SkUnit3D* cross); +}; + +struct SkPoint3D { + SkScalar fX, fY, fZ; + + void set(SkScalar x, SkScalar y, SkScalar z) + { + fX = x; fY = y; fZ = z; + } + SkScalar normalize(SkUnit3D*) const; +}; +typedef SkPoint3D SkVector3D; + +struct SkMatrix3D { + SkScalar fMat[3][4]; + + void reset(); + + void setRow(int row, SkScalar a, SkScalar b, SkScalar c, SkScalar d = 0) + { + SkASSERT((unsigned)row < 3); + fMat[row][0] = a; + fMat[row][1] = b; + fMat[row][2] = c; + fMat[row][3] = d; + } + + void setRotateX(SkScalar deg); + void setRotateY(SkScalar deg); + void setRotateZ(SkScalar deg); + void setTranslate(SkScalar x, SkScalar y, SkScalar z); + + void preRotateX(SkScalar deg); + void preRotateY(SkScalar deg); + void preRotateZ(SkScalar deg); + void preTranslate(SkScalar x, SkScalar y, SkScalar z); + + void setConcat(const SkMatrix3D& a, const SkMatrix3D& b); + void mapPoint(const SkPoint3D& src, SkPoint3D* dst) const; + void mapVector(const SkVector3D& src, SkVector3D* dst) const; + + void mapPoint(SkPoint3D* v) const + { + this->mapPoint(*v, v); + } + void mapVector(SkVector3D* v) const + { + this->mapVector(*v, v); + } +}; + +class SkPatch3D { +public: + SkPatch3D(); + + void reset(); + void transform(const SkMatrix3D&, SkPatch3D* dst = NULL) const; + + // dot a unit vector with the patch's normal + SkScalar dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const; + SkScalar dotWith(const SkVector3D& v) const + { + return this->dotWith(v.fX, v.fY, v.fZ); + } + + // deprecated, but still here for animator (for now) + void rotate(SkScalar x, SkScalar y, SkScalar z) {} + void rotateDegrees(SkScalar x, SkScalar y, SkScalar z) {} + +private: +public: // make public for SkDraw3D for now + SkVector3D fU, fV; + SkPoint3D fOrigin; + + friend class SkCamera3D; +}; + +class SkCamera3D { +public: + SkCamera3D(); + + void reset(); + void update(); + void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const; + + SkPoint3D fLocation; + SkPoint3D fAxis; + SkPoint3D fZenith; + SkPoint3D fObserver; + +private: + mutable SkMatrix fOrientation; + mutable bool fNeedToUpdate; + + void doUpdate() const; +}; + +class Sk3DView : SkNoncopyable { +public: + Sk3DView(); + ~Sk3DView(); + + void save(); + void restore(); + + void translate(SkScalar x, SkScalar y, SkScalar z); + void rotateX(SkScalar deg); + void rotateY(SkScalar deg); + void rotateZ(SkScalar deg); + +#ifdef SK_BUILD_FOR_ANDROID + void setCameraLocation(SkScalar x, SkScalar y, SkScalar z); + SkScalar getCameraLocationX(); + SkScalar getCameraLocationY(); + SkScalar getCameraLocationZ(); +#endif + + void getMatrix(SkMatrix*) const; + void applyToCanvas(SkCanvas*) const; + + SkScalar dotWithNormal(SkScalar dx, SkScalar dy, SkScalar dz) const; + +private: + struct Rec { + Rec* fNext; + SkMatrix3D fMatrix; + }; + Rec* fRec; + Rec fInitialRec; + SkCamera3D fCamera; +}; + +#endif diff --git a/utils/SkCanvasStateUtils.h b/utils/SkCanvasStateUtils.h new file mode 100644 index 0000000..f8266c9 --- /dev/null +++ b/utils/SkCanvasStateUtils.h @@ -0,0 +1,76 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCanvasStateUtils_DEFINED +#define SkCanvasStateUtils_DEFINED + +#include "SkCanvas.h" + +class SkCanvasState; + +/** + * A set of functions that are useful for copying an SkCanvas across a library + * boundary where the Skia libraries on either side of the boundary may not be + * version identical. The expected usage is outline below... + * + * Lib Boundary + * CaptureCanvasState(...) ||| + * SkCanvas --> SkCanvasState ||| + * ||| CreateFromCanvasState(...) + * ||| SkCanvasState --> SkCanvas` + * ||| Draw into SkCanvas` + * ||| Unref SkCanvas` + * ReleaseCanvasState(...) ||| + * + */ +namespace SkCanvasStateUtils { + /** + * Captures the current state of the canvas into an opaque ptr that is safe + * to pass between different instances of Skia (which may or may not be the + * same version). The function will return NULL in the event that one of the + * following conditions are true. + * 1) the canvas device type is not supported (currently only raster is supported) + * 2) the canvas clip type is not supported (currently only non-AA clips are supported) + * + * It is recommended that the original canvas also not be used until all + * canvases that have been created using its captured state have been dereferenced. + * + * Finally, it is important to note that any draw filters attached to the + * canvas are NOT currently captured. + * + * @param canvas The canvas you wish to capture the current state of. + * @return NULL or an opaque ptr that can be passed to CreateFromCanvasState + * to reconstruct the canvas. The caller is responsible for calling + * ReleaseCanvasState to free the memory associated with this state. + */ + SK_API SkCanvasState* CaptureCanvasState(SkCanvas* canvas); + + /** + * Create a new SkCanvas from the captured state of another SkCanvas. The + * function will return NULL in the event that one of the + * following conditions are true. + * 1) the captured state is in an unrecognized format + * 2) the captured canvas device type is not supported + * + * @param canvas The canvas you wish to capture the current state of. + * @return NULL or an SkCanvas* whose devices and matrix/clip state are + * identical to the captured canvas. The caller is responsible for + * calling unref on the SkCanvas. + */ + SK_API SkCanvas* CreateFromCanvasState(const SkCanvasState* state); + + /** + * Free the memory associated with the captured canvas state. The state + * should not be released until all SkCanvas objects created using that + * state have been dereferenced. + * + * @param state The captured state you wish to dispose of. + */ + SK_API void ReleaseCanvasState(SkCanvasState* state); +}; + +#endif diff --git a/utils/SkCondVar.h b/utils/SkCondVar.h new file mode 100644 index 0000000..15f16e6 --- /dev/null +++ b/utils/SkCondVar.h @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCondVar_DEFINED +#define SkCondVar_DEFINED + +#ifdef SK_USE_POSIX_THREADS +#include <pthread.h> +#elif defined(SK_BUILD_FOR_WIN32) +#include <Windows.h> +#endif + +/** + * Condition variable for blocking access to shared data from other threads and + * controlling which threads are awake. + * + * Currently only supported on platforms with posix threads and Windows Vista and + * above. + */ +class SkCondVar { +public: + SkCondVar(); + ~SkCondVar(); + + /** + * Lock a mutex. Must be done before calling the other functions on this object. + */ + void lock(); + + /** + * Unlock the mutex. + */ + void unlock(); + + /** + * Pause the calling thread. Will be awoken when signal() or broadcast() is called. + * Must be called while lock() is held (but gives it up while waiting). Once awoken, + * the calling thread will hold the lock once again. + */ + void wait(); + + /** + * Wake one thread waiting on this condition. Must be called while lock() + * is held. + */ + void signal(); + + /** + * Wake all threads waiting on this condition. Must be called while lock() + * is held. + */ + void broadcast(); + +private: +#ifdef SK_USE_POSIX_THREADS + pthread_mutex_t fMutex; + pthread_cond_t fCond; +#elif defined(SK_BUILD_FOR_WIN32) + CRITICAL_SECTION fCriticalSection; + CONDITION_VARIABLE fCondition; +#endif +}; + +#endif diff --git a/utils/SkCountdown.h b/utils/SkCountdown.h new file mode 100644 index 0000000..6bcec7d --- /dev/null +++ b/utils/SkCountdown.h @@ -0,0 +1,36 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCountdown_DEFINED +#define SkCountdown_DEFINED + +#include "SkCondVar.h" +#include "SkRunnable.h" +#include "SkTypes.h" + +class SkCountdown : public SkRunnable { +public: + explicit SkCountdown(int32_t count); + + /** + * Resets the countdown to the count provided. + */ + void reset(int32_t count); + + virtual void run() SK_OVERRIDE; + + /** + * Blocks until run() has been called count times. + */ + void wait(); + +private: + SkCondVar fReady; + int32_t fCount; +}; + +#endif diff --git a/utils/SkCubicInterval.h b/utils/SkCubicInterval.h new file mode 100644 index 0000000..64d63cf --- /dev/null +++ b/utils/SkCubicInterval.h @@ -0,0 +1,22 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkCubicInterval_DEFINED +#define SkCubicInterval_DEFINED + +#include "SkPoint.h" + +SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1, + SkScalar x2, SkScalar y2, + SkScalar unitX); + +static inline SkScalar SkEvalCubicInterval(const SkPoint pts[2], SkScalar x) { + return SkEvalCubicInterval(pts[0].fX, pts[0].fY, + pts[1].fX, pts[1].fY, x); +} + +#endif diff --git a/utils/SkCullPoints.h b/utils/SkCullPoints.h new file mode 100644 index 0000000..fafa0fc --- /dev/null +++ b/utils/SkCullPoints.h @@ -0,0 +1,71 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkCullPoints_DEFINED +#define SkCullPoints_DEFINED + +#include "SkRect.h" + +class SkCullPoints { +public: + SkCullPoints(); + SkCullPoints(const SkIRect& r); + + void reset(const SkIRect& r); + + /** Start a contour at (x,y). Follow this with call(s) to lineTo(...) + */ + void moveTo(int x, int y); + + enum LineToResult { + kNo_Result, //!< line segment was completely clipped out + kLineTo_Result, //!< path.lineTo(pts[1]); + kMoveToLineTo_Result //!< path.moveTo(pts[0]); path.lineTo(pts[1]); + }; + /** Connect a line to the previous call to lineTo (or moveTo). + */ + LineToResult lineTo(int x, int y, SkIPoint pts[2]); + +private: + SkIRect fR; // the caller's rectangle + SkIPoint fAsQuad[4]; // cache of fR as 4 points + SkIPoint fPrevPt; // private state + LineToResult fPrevResult; // private state + + bool sect_test(int x0, int y0, int x1, int y1) const; +}; + +///////////////////////////////////////////////////////////////////////////////// + +class SkPath; + +/** \class SkCullPointsPath + + Similar to SkCullPoints, but this class handles the return values + from lineTo, and automatically builds a SkPath with the result(s). +*/ +class SkCullPointsPath { +public: + SkCullPointsPath(); + SkCullPointsPath(const SkIRect& r, SkPath* dst); + + void reset(const SkIRect& r, SkPath* dst); + + void moveTo(int x, int y); + void lineTo(int x, int y); + +private: + SkCullPoints fCP; + SkPath* fPath; +}; + +bool SkHitTestPath(const SkPath&, SkRect& target, bool hires); +bool SkHitTestPath(const SkPath&, SkScalar x, SkScalar y, bool hires); + +#endif diff --git a/utils/SkDebugUtils.h b/utils/SkDebugUtils.h new file mode 100644 index 0000000..2fa6d41 --- /dev/null +++ b/utils/SkDebugUtils.h @@ -0,0 +1,94 @@ + +/* + * Copyright 2013 Google, Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDebugUtils_DEFINED +#define SkDebugUtils_DEFINED + +#include "SkTypes.h" + +// These functions dump 0, 1, and 2d arrays of data in a format that's +// compatible with Mathematica for quick visualization + + +template<class T> +inline void SkDebugDumpMathematica( const T val ) { + SkDEBUGFAIL("Need to specialize SkDebugDumpMathematica for your type, sorry."); +} + +template<class T> +inline void SkDebugDumpMathematica(const char *name, const T *array, int size) { + SkDebugf(name); + SkDebugf(" = {"); + for (int i=0 ; i < size ; i++) { + SkDebugDumpMathematica<T>(array[i]); + if (i != size-1) SkDebugf(", "); + } + SkDebugf("};\n"); +} + +template<class T> +inline void SkDebugDumpMathematica(const char *name, const T *array, int width, int height) { + SkDebugf(name); + SkDebugf(" = {\n"); + for (int i=0 ; i < height ; i++) { + SkDebugf(" {"); + for (int j = 0 ; j < width ; j++) { + SkDebugDumpMathematica<T>(array[i*width + j]); + if (j != width-1) { + SkDebugf(", "); + } + } + SkDebugf("}"); + if (i != height-1) { + SkDebugf(", \n"); + } + } + SkDebugf("\n};\n"); +} + +template<class T> +inline void SkDebugDumpMathematica( const char *name, const T val ) { + SkDebugf(name); + SkDebugf(" = "); + SkDebugDumpMathematica<T>(val); + SkDebugf(";\n"); +} + +template<> +inline void SkDebugDumpMathematica<uint8_t>( const uint8_t val ) { + SkDebugf("%u", val); +} + +template<> +inline void SkDebugDumpMathematica<unsigned int>( const unsigned int val ) { + SkDebugf("%u", val); +} + +template<> +inline void SkDebugDumpMathematica<int>( const int val ) { + SkDebugf("%d", val); +} + +template<> +inline void SkDebugDumpMathematica<size_t>( const size_t val ) { + SkDebugf("%u", val); +} + +template<> +void SkDebugDumpMathematica<const char *>( const char * val ) { + SkDebugf("%s", val); +} + +template<> +inline void SkDebugDumpMathematica<float>( float val ) { + SkDebugf("%f", val); +} + + +#endif diff --git a/utils/SkDeferredCanvas.h b/utils/SkDeferredCanvas.h new file mode 100644 index 0000000..77229a7 --- /dev/null +++ b/utils/SkDeferredCanvas.h @@ -0,0 +1,256 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDeferredCanvas_DEFINED +#define SkDeferredCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkPixelRef.h" + +class DeferredDevice; +class SkImage; +class SkSurface; + +/** \class SkDeferredCanvas + Subclass of SkCanvas that encapsulates an SkPicture or SkGPipe for deferred + drawing. The main difference between this class and SkPictureRecord (the + canvas provided by SkPicture) is that this is a full drop-in replacement + for SkCanvas, while SkPictureRecord only supports draw operations. + SkDeferredCanvas will transparently trigger the flushing of deferred + draw operations when an attempt is made to access the pixel data. +*/ +class SK_API SkDeferredCanvas : public SkCanvas { +public: + class NotificationClient; + + /** Construct a canvas with the specified surface to draw into. + This factory must be used for newImageSnapshot to work. + @param surface Specifies a surface for the canvas to draw into. + */ + static SkDeferredCanvas* Create(SkSurface* surface); + + static SkDeferredCanvas* Create(SkDevice* device); + + virtual ~SkDeferredCanvas(); + + /** + * Specify the surface to be used by this canvas. Calling setSurface will + * release the previously set surface or device. Takes a reference on the + * surface. + * + * @param surface The surface that the canvas will raw into + * @return The surface argument, for convenience. + */ + SkSurface* setSurface(SkSurface* surface); + + /** + * Specify a NotificationClient to be used by this canvas. Calling + * setNotificationClient will release the previously set + * NotificationClient, if any. SkDeferredCanvas does not take ownership + * of the notification client. Therefore user code is resposible + * for its destruction. The notification client must be unregistered + * by calling setNotificationClient(NULL) if it is destroyed before + * this canvas. + * Note: Must be called after the device is set with setDevice. + * + * @param notificationClient interface for dispatching notifications + * @return The notificationClient argument, for convenience. + */ + NotificationClient* setNotificationClient(NotificationClient* notificationClient); + + /** + * Enable or disable deferred drawing. When deferral is disabled, + * pending draw operations are immediately flushed and from then on, + * the SkDeferredCanvas behaves just like a regular SkCanvas. + * This method must not be called while the save/restore stack is in use. + * @param deferred true/false + */ + void setDeferredDrawing(bool deferred); + + /** + * Returns true if deferred drawing is currenlty enabled. + */ + bool isDeferredDrawing() const; + + /** + * Returns true if the canvas contains a fresh frame. A frame is + * considered fresh when its content do not depend on the contents + * of the previous frame. For example, if a canvas is cleared before + * drawing each frame, the frames will all be considered fresh. + * A frame is defined as the graphics image produced by as a result + * of all the canvas draws operation executed between two successive + * calls to isFreshFrame. The result of isFreshFrame is computed + * conservatively, so it may report false negatives. + */ + bool isFreshFrame() const; + + /** + * Returns true if the canvas has recorded draw commands that have + * not yet been played back. + */ + bool hasPendingCommands() const; + + /** + * Flushes pending draw commands, if any, and returns an image of the + * current state of the surface pixels up to this point. Subsequent + * changes to the surface (by drawing into its canvas) will not be + * reflected in this image. Will return NULL if the deferred canvas + * was not constructed from an SkSurface. + */ + SkImage* newImageSnapshot(); + + /** + * Specify the maximum number of bytes to be allocated for the purpose + * of recording draw commands to this canvas. The default limit, is + * 64MB. + * @param maxStorage The maximum number of bytes to be allocated. + */ + void setMaxRecordingStorage(size_t maxStorage); + + /** + * Returns the number of bytes currently allocated for the purpose of + * recording draw commands. + */ + size_t storageAllocatedForRecording() const; + + /** + * Attempt to reduce the storage allocated for recording by evicting + * cache resources. + * @param bytesToFree minimum number of bytes that should be attempted to + * be freed. + * @return number of bytes actually freed. + */ + size_t freeMemoryIfPossible(size_t bytesToFree); + + /** + * Specifies the maximum size (in bytes) allowed for a given image to be + * rendered using the deferred canvas. + */ + void setBitmapSizeThreshold(size_t sizeThreshold); + + /** + * Executes all pending commands without drawing + */ + void silentFlush(); + + // Overrides of the SkCanvas interface + virtual int save(SaveFlags flags) SK_OVERRIDE; + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags flags) SK_OVERRIDE; + virtual void restore() SK_OVERRIDE; + virtual bool isDrawingToLayer() const SK_OVERRIDE; + virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE; + virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool rotate(SkScalar degrees) SK_OVERRIDE; + virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE; + virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE; + virtual bool clipRect(const SkRect& rect, SkRegion::Op op, + bool doAntiAlias) SK_OVERRIDE; + virtual bool clipRRect(const SkRRect& rect, SkRegion::Op op, + bool doAntiAlias) SK_OVERRIDE; + virtual bool clipPath(const SkPath& path, SkRegion::Op op, + bool doAntiAlias) SK_OVERRIDE; + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op op) SK_OVERRIDE; + virtual void clear(SkColor) SK_OVERRIDE; + virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) SK_OVERRIDE; + virtual void drawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPath(const SkPath& path, const SkPaint& paint) + SK_OVERRIDE; + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, + SkScalar top, const SkPaint* paint) + SK_OVERRIDE; + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint) + SK_OVERRIDE; + + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) + SK_OVERRIDE; + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) + SK_OVERRIDE; + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawPicture(SkPicture& picture) SK_OVERRIDE; + 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) SK_OVERRIDE; + virtual SkBounder* setBounder(SkBounder* bounder) SK_OVERRIDE; + virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE; + +public: + class NotificationClient { + public: + virtual ~NotificationClient() {} + + /** + * Called before executing one or several draw commands, which means + * once per flush when deferred rendering is enabled. + */ + virtual void prepareForDraw() {} + + /** + * Called after a recording a draw command if additional memory + * had to be allocated for recording. + * @param newAllocatedStorage same value as would be returned by + * storageAllocatedForRecording(), for convenience. + */ + virtual void storageAllocatedForRecordingChanged( + size_t newAllocatedStorage) {} + + /** + * Called after pending draw commands have been flushed + */ + virtual void flushedDrawCommands() {} + + /** + * Called after pending draw commands have been skipped, meaning + * that they were optimized-out because the canvas is cleared + * or completely overwritten by the command currently being recorded. + */ + virtual void skippedPendingDrawCommands() {} + }; + +protected: + virtual SkCanvas* canvasForDrawIter(); + DeferredDevice* getDeferredDevice() const; + +private: + SkDeferredCanvas(DeferredDevice*); + + void recordedDrawCommand(); + SkCanvas* drawingCanvas() const; + SkCanvas* immediateCanvas() const; + bool isFullFrame(const SkRect*, const SkPaint*) const; + void validate() const; + void init(); + bool fDeferredDrawing; + + friend class SkDeferredCanvasTester; // for unit testing + typedef SkCanvas INHERITED; +}; + + +#endif diff --git a/utils/SkDumpCanvas.h b/utils/SkDumpCanvas.h new file mode 100644 index 0000000..cdb1f19 --- /dev/null +++ b/utils/SkDumpCanvas.h @@ -0,0 +1,168 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkDumpCanvas_DEFINED +#define SkDumpCanvas_DEFINED + +#include "SkCanvas.h" + +#ifdef SK_DEVELOPER + +/** This class overrides all the draw methods on SkCanvas, and formats them + as text, and then sends that to a Dumper helper object. + + Typical use might be to dump a display list to a log file to see what is + being drawn. + */ +class SkDumpCanvas : public SkCanvas { +public: + class Dumper; + + explicit SkDumpCanvas(Dumper* = 0); + virtual ~SkDumpCanvas(); + + enum Verb { + kNULL_Verb, + + kSave_Verb, + kRestore_Verb, + + kMatrix_Verb, + + kClip_Verb, + + kDrawPaint_Verb, + kDrawPoints_Verb, + kDrawOval_Verb, + kDrawRect_Verb, + kDrawRRect_Verb, + kDrawPath_Verb, + kDrawBitmap_Verb, + kDrawText_Verb, + kDrawPicture_Verb, + kDrawVertices_Verb, + kDrawData_Verb, + + kBeginCommentGroup_Verb, + kAddComment_Verb, + kEndCommentGroup_Verb + }; + + /** Subclasses of this are installed on the DumpCanvas, and then called for + each drawing command. + */ + class Dumper : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Dumper) + + virtual void dump(SkDumpCanvas*, SkDumpCanvas::Verb, const char str[], + const SkPaint*) = 0; + + private: + typedef SkRefCnt INHERITED; + }; + + Dumper* getDumper() const { return fDumper; } + void setDumper(Dumper*); + + int getNestLevel() const { return fNestLevel; } + + virtual int save(SaveFlags) SK_OVERRIDE; + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags) SK_OVERRIDE; + virtual void restore() SK_OVERRIDE; + + virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE; + virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool rotate(SkScalar degrees) SK_OVERRIDE; + virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE; + virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE; + + virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRRect(const SkRRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op) SK_OVERRIDE; + + virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) SK_OVERRIDE; + virtual void drawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE; + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint) SK_OVERRIDE; + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawPicture(SkPicture&) SK_OVERRIDE; + 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) SK_OVERRIDE; + virtual void drawData(const void*, size_t) SK_OVERRIDE; + virtual void beginCommentGroup(const char* description) SK_OVERRIDE; + virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE; + virtual void endCommentGroup() SK_OVERRIDE; + +private: + Dumper* fDumper; + int fNestLevel; // for nesting recursive elements like pictures + + void dump(Verb, const SkPaint*, const char format[], ...); + + typedef SkCanvas INHERITED; +}; + +/** Formats the draw commands, and send them to a function-pointer provided + by the caller. + */ +class SkFormatDumper : public SkDumpCanvas::Dumper { +public: + SkFormatDumper(void (*)(const char text[], void* refcon), void* refcon); + + // override from baseclass that does the formatting, and in turn calls + // the function pointer that was passed to the constructor + virtual void dump(SkDumpCanvas*, SkDumpCanvas::Verb, const char str[], + const SkPaint*) SK_OVERRIDE; + +private: + void (*fProc)(const char*, void*); + void* fRefcon; + + typedef SkDumpCanvas::Dumper INHERITED; +}; + +/** Subclass of Dumper that dumps the drawing command to SkDebugf + */ +class SkDebugfDumper : public SkFormatDumper { +public: + SkDebugfDumper(); + +private: + typedef SkFormatDumper INHERITED; +}; + +#endif + +#endif diff --git a/utils/SkInterpolator.h b/utils/SkInterpolator.h new file mode 100644 index 0000000..74789c8 --- /dev/null +++ b/utils/SkInterpolator.h @@ -0,0 +1,131 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkInterpolator_DEFINED +#define SkInterpolator_DEFINED + +#include "SkScalar.h" + +class SkInterpolatorBase : SkNoncopyable { +public: + enum Result { + kNormal_Result, + kFreezeStart_Result, + kFreezeEnd_Result + }; +protected: + SkInterpolatorBase(); + ~SkInterpolatorBase(); +public: + void reset(int elemCount, int frameCount); + + /** Return the start and end time for this interpolator. + If there are no key frames, return false. + @param startTime If not null, returns the time (in milliseconds) of the + first keyframe. If there are no keyframes, this param + is ignored (left unchanged). + @param endTime If not null, returns the time (in milliseconds) of the + last keyframe. If there are no keyframes, this parameter + is ignored (left unchanged). + @return True if there are key frames, or false if there are none. + */ + bool getDuration(SkMSec* startTime, SkMSec* endTime) const; + + + /** Set the whether the repeat is mirrored. + @param mirror If true, the odd repeats interpolate from the last key + frame and the first. + */ + void setMirror(bool mirror) { + fFlags = SkToU8((fFlags & ~kMirror) | (int)mirror); + } + + /** Set the repeat count. The repeat count may be fractional. + @param repeatCount Multiplies the total time by this scalar. + */ + void setRepeatCount(SkScalar repeatCount) { fRepeat = repeatCount; } + + /** Set the whether the repeat is mirrored. + @param reset If true, the odd repeats interpolate from the last key + frame and the first. + */ + void setReset(bool reset) { + fFlags = SkToU8((fFlags & ~kReset) | (int)reset); + } + + Result timeToT(SkMSec time, SkScalar* T, int* index, SkBool* exact) const; + +protected: + enum Flags { + kMirror = 1, + kReset = 2, + kHasBlend = 4 + }; + static SkScalar ComputeRelativeT(SkMSec time, SkMSec prevTime, + SkMSec nextTime, const SkScalar blend[4] = NULL); + int16_t fFrameCount; + uint8_t fElemCount; + uint8_t fFlags; + SkScalar fRepeat; + struct SkTimeCode { + SkMSec fTime; + SkScalar fBlend[4]; + }; + SkTimeCode* fTimes; // pointer into fStorage + void* fStorage; +#ifdef SK_DEBUG + SkTimeCode(* fTimesArray)[10]; +#endif +}; + +class SkInterpolator : public SkInterpolatorBase { +public: + SkInterpolator(); + SkInterpolator(int elemCount, int frameCount); + void reset(int elemCount, int frameCount); + + /** Add or replace a key frame, copying the values[] data into the + interpolator. + @param index The index of this frame (frames must be ordered by time) + @param time The millisecond time for this frame + @param values The array of values [elemCount] for this frame. The data + is copied into the interpolator. + @param blend A positive scalar specifying how to blend between this + and the next key frame. [0...1) is a cubic lag/log/lag + blend (slow to change at the beginning and end) + 1 is a linear blend (default) + */ + bool setKeyFrame(int index, SkMSec time, const SkScalar values[], + const SkScalar blend[4] = NULL); + + /** Return the computed values given the specified time. Return whether + those values are the result of pinning to either the first + (kFreezeStart) or last (kFreezeEnd), or from interpolated the two + nearest key values (kNormal). + @param time The time to sample (in milliseconds) + @param (may be null) where to write the computed values. + */ + Result timeToValues(SkMSec time, SkScalar values[] = NULL) const; + + SkDEBUGCODE(static void UnitTest();) +private: + SkScalar* fValues; // pointer into fStorage +#ifdef SK_DEBUG + SkScalar(* fScalarsArray)[10]; +#endif + typedef SkInterpolatorBase INHERITED; +}; + +/** Given all the parameters are [0...1], apply the cubic specified by (0,0) + (bx,by) (cx,cy) (1,1) to value, returning the answer, also [0...1]. +*/ +SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by, + SkScalar cx, SkScalar cy); + +#endif diff --git a/utils/SkJSON.h b/utils/SkJSON.h new file mode 100644 index 0000000..c601fa8 --- /dev/null +++ b/utils/SkJSON.h @@ -0,0 +1,285 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJSON_DEFINED +#define SkJSON_DEFINED + +#include "SkTypes.h" + +class SkStream; +class SkString; + +class SkJSON { +public: + enum Type { + kObject, + kArray, + kString, + kInt, + kFloat, + kBool, + }; + + class Array; + + class Object { + private: + struct Slot; + + public: + Object(); + Object(const Object&); + ~Object(); + + /** + * Create a new slot with the specified name and value. The name + * parameter is copied, but ownership of the Object parameter is + * transferred. The Object parameter may be null, but the name must + * not be null. + */ + void addObject(const char name[], Object* value); + + /** + * Create a new slot with the specified name and value. The name + * parameter is copied, but ownership of the Array parameter is + * transferred. The Array parameter may be null, but the name must + * not be null. + */ + void addArray(const char name[], Array* value); + + /** + * Create a new slot with the specified name and value. Both parameters + * are copied. The value parameter may be null, but the name must + * not be null. + */ + void addString(const char name[], const char value[]); + + /** + * Create a new slot with the specified name and value. The name + * parameter is copied, and must not be null. + */ + void addInt(const char name[], int32_t value); + + /** + * Create a new slot with the specified name and value. The name + * parameter is copied, and must not be null. + */ + void addFloat(const char name[], float value); + + /** + * Create a new slot with the specified name and value. The name + * parameter is copied, and must not be null. + */ + void addBool(const char name[], bool value); + + /** + * Return the number of slots/fields in this object. These can be + * iterated using Iter. + */ + int count() const; + + /** + * Returns true if a slot matching the name and Type is found. + */ + bool find(const char name[], Type) const; + bool findObject(const char name[], Object** = NULL) const; + bool findArray(const char name[], Array** = NULL) const; + bool findString(const char name[], SkString* = NULL) const; + bool findInt(const char name[], int32_t* = NULL) const; + bool findFloat(const char name[], float* = NULL) const; + bool findBool(const char name[], bool* = NULL) const; + + /** + * Finds the first slot matching the name and Type and removes it. + * Returns true if found, false if not. + */ + bool remove(const char name[], Type); + + void toDebugf() const; + + /** + * Iterator class which returns all of the fields/slots in an Object, + * in the order that they were added. + */ + class Iter { + public: + Iter(const Object&); + + /** + * Returns true when there are no more entries in the iterator. + * In this case, no other methods should be called. + */ + bool done() const; + + /** + * Moves the iterator to the next element. Should only be called + * if done() returns false. + */ + void next(); + + /** + * Returns the type of the current element. Should only be called + * if done() returns false. + */ + Type type() const; + + /** + * Returns the name of the current element. Should only be called + * if done() returns false. + */ + const char* name() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kObject. + */ + Object* objectValue() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kArray. + */ + Array* arrayValue() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kString. + */ + const char* stringValue() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kInt. + */ + int32_t intValue() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kFloat. + */ + float floatValue() const; + + /** + * Returns the type of the current element. Should only be called + * if done() returns false and type() returns kBool. + */ + bool boolValue() const; + + private: + Slot* fSlot; + }; + + private: + Slot* fHead; + Slot* fTail; + + const Slot* findSlot(const char name[], Type) const; + Slot* addSlot(Slot*); + void dumpLevel(int level) const; + + friend class Array; + }; + + class Array { + public: + /** + * Creates an array with the specified Type and element count. All + * entries are initialized to NULL/0/false. + */ + Array(Type, int count); + + /** + * Creates an array of ints, initialized by copying the specified + * values. + */ + Array(const int32_t values[], int count); + + /** + * Creates an array of floats, initialized by copying the specified + * values. + */ + Array(const float values[], int count); + + /** + * Creates an array of bools, initialized by copying the specified + * values. + */ + Array(const bool values[], int count); + + Array(const Array&); + ~Array(); + + int count() const { return fCount; } + Type type() const { return fType; } + + /** + * Replace the element at the specified index with the specified + * Object (which may be null). Ownership of the Object is transferred. + * Should only be called if the Array's type is kObject. + */ + void setObject(int index, Object*); + + /** + * Replace the element at the specified index with the specified + * Array (which may be null). Ownership of the Array is transferred. + * Should only be called if the Array's type is kArray. + */ + void setArray(int index, Array*); + + /** + * Replace the element at the specified index with a copy of the + * specified string (which may be null). Should only be called if the + * Array's type is kString. + */ + void setString(int index, const char str[]); + + Object* const* objects() const { + SkASSERT(kObject == fType); + return fArray.fObjects; + } + Array* const* arrays() const { + SkASSERT(kObject == fType); + return fArray.fArrays; + } + const char* const* strings() const { + SkASSERT(kString == fType); + return fArray.fStrings; + } + int32_t* ints() const { + SkASSERT(kInt == fType); + return fArray.fInts; + } + float* floats() const { + SkASSERT(kFloat == fType); + return fArray.fFloats; + } + bool* bools() const { + SkASSERT(kBool == fType); + return fArray.fBools; + } + + private: + int fCount; + Type fType; + union { + void* fVoids; + Object** fObjects; + Array** fArrays; + char** fStrings; + int32_t* fInts; + float* fFloats; + bool* fBools; + } fArray; + + void init(Type, int count, const void* src); + void dumpLevel(int level) const; + + friend class Object; + }; +}; + +#endif diff --git a/utils/SkLayer.h b/utils/SkLayer.h new file mode 100644 index 0000000..70fa01b --- /dev/null +++ b/utils/SkLayer.h @@ -0,0 +1,130 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkLayer_DEFINED +#define SkLayer_DEFINED + +#include "SkRefCnt.h" +#include "SkTDArray.h" +#include "SkColor.h" +#include "SkMatrix.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkSize.h" + +class SkCanvas; + +class SkLayer : public SkRefCnt { + +public: + SK_DECLARE_INST_COUNT(SkLayer) + + SkLayer(); + SkLayer(const SkLayer&); + virtual ~SkLayer(); + + bool isInheritFromRootTransform() const; + SkScalar getOpacity() const { return m_opacity; } + const SkSize& getSize() const { return m_size; } + const SkPoint& getPosition() const { return m_position; } + const SkPoint& getAnchorPoint() const { return m_anchorPoint; } + const SkMatrix& getMatrix() const { return fMatrix; } + const SkMatrix& getChildrenMatrix() const { return fChildrenMatrix; } + + SkScalar getWidth() const { return m_size.width(); } + SkScalar getHeight() const { return m_size.height(); } + + void setInheritFromRootTransform(bool); + void setOpacity(SkScalar opacity) { m_opacity = opacity; } + void setSize(SkScalar w, SkScalar h) { m_size.set(w, h); } + void setPosition(SkScalar x, SkScalar y) { m_position.set(x, y); } + void setAnchorPoint(SkScalar x, SkScalar y) { m_anchorPoint.set(x, y); } + void setMatrix(const SkMatrix&); + void setChildrenMatrix(const SkMatrix&); + + // children + + /** Return the number of layers in our child list. + */ + int countChildren() const; + + /** Return the child at the specified index (starting at 0). This does not + affect the reference count of the child. + */ + SkLayer* getChild(int index) const; + + /** Add this layer to our child list at the end (top-most), and ref() it. + If it was already in another hierarchy, remove it from that list. + Return the new child. + */ + SkLayer* addChild(SkLayer* child); + + /** Remove this layer from its parent's list (or do nothing if it has no + parent.) If it had a parent, then unref() is called. + */ + void detachFromParent(); + + /** Remove, and unref(), all of the layers in our child list. + */ + void removeChildren(); + + /** Return our parent layer, or NULL if we have none. + */ + SkLayer* getParent() const { return fParent; } + + /** Return the root layer in this hiearchy. If this layer is the root + (i.e. has no parent), then this returns itself. + */ + SkLayer* getRootLayer() const; + + // coordinate system transformations + + /** Return, in matrix, the matix transfomations that are applied locally + when this layer draws (i.e. its position and matrix/anchorPoint). + This does not include the childrenMatrix, since that is only applied + after this layer draws (but before its children draw). + */ + void getLocalTransform(SkMatrix* matrix) const; + + /** Return, in matrix, the concatenation of transforms that are applied + from this layer's root parent to the layer itself. + This is the matrix that is applied to the layer during drawing. + */ + void localToGlobal(SkMatrix* matrix) const; + + // paint method + + void draw(SkCanvas*, SkScalar opacity); + void draw(SkCanvas* canvas) { + this->draw(canvas, SK_Scalar1); + } + +protected: + virtual void onDraw(SkCanvas*, SkScalar opacity); + +private: + enum Flags { + kInheritFromRootTransform_Flag = 0x01 + }; + + SkLayer* fParent; + SkScalar m_opacity; + SkSize m_size; + SkPoint m_position; + SkPoint m_anchorPoint; + SkMatrix fMatrix; + SkMatrix fChildrenMatrix; + uint32_t fFlags; + + SkTDArray<SkLayer*> m_children; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/utils/SkLua.h b/utils/SkLua.h new file mode 100644 index 0000000..c609746 --- /dev/null +++ b/utils/SkLua.h @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLua_DEFINED +#define SkLua_DEFINED + +#include "SkColor.h" +#include "SkScalar.h" +#include "SkString.h" + +struct lua_State; + +class SkCanvas; +class SkMatrix; +class SkPaint; +class SkPath; +struct SkRect; +class SkRRect; + +#define SkScalarToLua(x) SkScalarToDouble(x) +#define SkLuaToScalar(x) SkDoubleToScalar(x) + +class SkLua { +public: + static void Load(lua_State*); + + SkLua(const char termCode[] = NULL); // creates a new L, will close it + SkLua(lua_State*); // uses L, will not close it + ~SkLua(); + + lua_State* get() const { return fL; } + lua_State* operator*() const { return fL; } + lua_State* operator->() const { return fL; } + + bool runCode(const char code[]); + bool runCode(const void* code, size_t size); + + void pushBool(bool, const char tableKey[] = NULL); + void pushString(const char[], const char tableKey[] = NULL); + void pushString(const char[], size_t len, const char tableKey[] = NULL); + void pushString(const SkString&, const char tableKey[] = NULL); + void pushArrayU16(const uint16_t[], int count, const char tableKey[] = NULL); + void pushColor(SkColor, const char tableKey[] = NULL); + void pushU32(uint32_t, const char tableKey[] = NULL); + void pushScalar(SkScalar, const char tableKey[] = NULL); + void pushRect(const SkRect&, const char tableKey[] = NULL); + void pushRRect(const SkRRect&, const char tableKey[] = NULL); + void pushMatrix(const SkMatrix&, const char tableKey[] = NULL); + void pushPaint(const SkPaint&, const char tableKey[] = NULL); + void pushPath(const SkPath&, const char tableKey[] = NULL); + void pushCanvas(SkCanvas*, const char tableKey[] = NULL); + +private: + lua_State* fL; + SkString fTermCode; + bool fWeOwnL; +}; + +#endif diff --git a/utils/SkLuaCanvas.h b/utils/SkLuaCanvas.h new file mode 100644 index 0000000..e41e58c --- /dev/null +++ b/utils/SkLuaCanvas.h @@ -0,0 +1,83 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLuaCanvas_DEFINED +#define SkLuaCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkString.h" + +struct lua_State; + +class SkLuaCanvas : public SkCanvas { +public: + void pushThis(); + + SkLuaCanvas(int width, int height, lua_State*, const char function[]); + virtual ~SkLuaCanvas(); + + virtual int save(SaveFlags flags) SK_OVERRIDE; + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags flags) SK_OVERRIDE; + virtual void restore() SK_OVERRIDE; + + virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE; + virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool rotate(SkScalar degrees) SK_OVERRIDE; + virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE; + virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE; + + virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRRect(const SkRRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op) SK_OVERRIDE; + + virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) SK_OVERRIDE; + virtual void drawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE; + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint) SK_OVERRIDE; + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) SK_OVERRIDE; + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawPicture(SkPicture&) SK_OVERRIDE; + 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) SK_OVERRIDE; + virtual void drawData(const void* data, size_t length) SK_OVERRIDE; + +private: + lua_State* fL; + SkString fFunc; + + void sendverb(const char verb[]); + + typedef SkCanvas INHERITED; +}; + +#endif diff --git a/utils/SkMatrix44.h b/utils/SkMatrix44.h new file mode 100644 index 0000000..9d9b6e0 --- /dev/null +++ b/utils/SkMatrix44.h @@ -0,0 +1,405 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMatrix44_DEFINED +#define SkMatrix44_DEFINED + +#include "SkMatrix.h" +#include "SkScalar.h" + +#ifdef SK_MSCALAR_IS_DOUBLE +#ifdef SK_MSCALAR_IS_FLOAT + #error "can't define MSCALAR both as DOUBLE and FLOAT" +#endif + typedef double SkMScalar; + + static inline double SkFloatToMScalar(float x) { + return static_cast<double>(x); + } + static inline float SkMScalarToFloat(double x) { + return static_cast<float>(x); + } + static inline double SkDoubleToMScalar(double x) { + return x; + } + static inline double SkMScalarToDouble(double x) { + return x; + } + static const SkMScalar SK_MScalarPI = 3.141592653589793; +#elif defined SK_MSCALAR_IS_FLOAT +#ifdef SK_MSCALAR_IS_DOUBLE + #error "can't define MSCALAR both as DOUBLE and FLOAT" +#endif + typedef float SkMScalar; + + static inline float SkFloatToMScalar(float x) { + return x; + } + static inline float SkMScalarToFloat(float x) { + return x; + } + static inline float SkDoubleToMScalar(double x) { + return static_cast<float>(x); + } + static inline double SkMScalarToDouble(float x) { + return static_cast<double>(x); + } + static const SkMScalar SK_MScalarPI = 3.14159265f; +#endif + +#define SkMScalarToScalar SkMScalarToFloat +#define SkScalarToMScalar SkFloatToMScalar + +static const SkMScalar SK_MScalar1 = 1; + +/////////////////////////////////////////////////////////////////////////////// + +struct SkVector4 { + SkScalar fData[4]; + + SkVector4() { + this->set(0, 0, 0, 1); + } + SkVector4(const SkVector4& src) { + memcpy(fData, src.fData, sizeof(fData)); + } + SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { + fData[0] = x; + fData[1] = y; + fData[2] = z; + fData[3] = w; + } + + SkVector4& operator=(const SkVector4& src) { + memcpy(fData, src.fData, sizeof(fData)); + return *this; + } + + bool operator==(const SkVector4& v) { + return fData[0] == v.fData[0] && fData[1] == v.fData[1] && + fData[2] == v.fData[2] && fData[3] == v.fData[3]; + } + bool operator!=(const SkVector4& v) { + return !(*this == v); + } + bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { + return fData[0] == x && fData[1] == y && + fData[2] == z && fData[3] == w; + } + + void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { + fData[0] = x; + fData[1] = y; + fData[2] = z; + fData[3] = w; + } +}; + +class SK_API SkMatrix44 { +public: + + enum Uninitialized_Constructor { + kUninitialized_Constructor + }; + enum Identity_Constructor { + kIdentity_Constructor + }; + + SkMatrix44(Uninitialized_Constructor) { } + SkMatrix44(Identity_Constructor) { this->setIdentity(); } + + // DEPRECATED: use the constructors that take an enum + SkMatrix44() { this->setIdentity(); } + + SkMatrix44(const SkMatrix44& src) { + memcpy(fMat, src.fMat, sizeof(fMat)); + fTypeMask = src.fTypeMask; + } + + SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) { + this->setConcat(a, b); + } + + SkMatrix44& operator=(const SkMatrix44& src) { + if (&src != this) { + memcpy(fMat, src.fMat, sizeof(fMat)); + fTypeMask = src.fTypeMask; + } + return *this; + } + + bool operator==(const SkMatrix44& other) const; + bool operator!=(const SkMatrix44& other) const { + return !(other == *this); + } + + SkMatrix44(const SkMatrix&); + SkMatrix44& operator=(const SkMatrix& src); + operator SkMatrix() const; + + /** + * Return a reference to a const identity matrix + */ + static const SkMatrix44& I(); + + enum TypeMask { + kIdentity_Mask = 0, + kTranslate_Mask = 0x01, //!< set if the matrix has translation + kScale_Mask = 0x02, //!< set if the matrix has any scale != 1 + kAffine_Mask = 0x04, //!< set if the matrix skews or rotates + kPerspective_Mask = 0x08 //!< set if the matrix is in perspective + }; + + /** + * Returns a bitfield describing the transformations the matrix may + * perform. The bitfield is computed conservatively, so it may include + * false positives. For example, when kPerspective_Mask is true, all + * other bits may be set to true even in the case of a pure perspective + * transform. + */ + inline TypeMask getType() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + SkASSERT(!(fTypeMask & kUnknown_Mask)); + return (TypeMask)fTypeMask; + } + + /** + * Return true if the matrix is identity. + */ + inline bool isIdentity() const { + return kIdentity_Mask == this->getType(); + } + + /** + * Return true if the matrix contains translate or is identity. + */ + inline bool isTranslate() const { + return !(this->getType() & ~kTranslate_Mask); + } + + /** + * Return true if the matrix only contains scale or translate or is identity. + */ + inline bool isScaleTranslate() const { + return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); + } + + void setIdentity(); + inline void reset() { this->setIdentity();} + + /** + * get a value from the matrix. The row,col parameters work as follows: + * (0, 0) scale-x + * (0, 3) translate-x + * (3, 0) perspective-x + */ + inline SkMScalar get(int row, int col) const { + SkASSERT((unsigned)row <= 3); + SkASSERT((unsigned)col <= 3); + return fMat[col][row]; + } + + /** + * set a value in the matrix. The row,col parameters work as follows: + * (0, 0) scale-x + * (0, 3) translate-x + * (3, 0) perspective-x + */ + inline void set(int row, int col, SkMScalar value) { + SkASSERT((unsigned)row <= 3); + SkASSERT((unsigned)col <= 3); + fMat[col][row] = value; + this->dirtyTypeMask(); + } + + inline double getDouble(int row, int col) const { + return SkMScalarToDouble(this->get(row, col)); + } + inline void setDouble(int row, int col, double value) { + this->set(row, col, SkDoubleToMScalar(value)); + } + + /** These methods allow one to efficiently read matrix entries into an + * array. The given array must have room for exactly 16 entries. Whenever + * possible, they will try to use memcpy rather than an entry-by-entry + * copy. + */ + void asColMajorf(float[]) const; + void asColMajord(double[]) const; + void asRowMajorf(float[]) const; + void asRowMajord(double[]) const; + + /** These methods allow one to efficiently set all matrix entries from an + * array. The given array must have room for exactly 16 entries. Whenever + * possible, they will try to use memcpy rather than an entry-by-entry + * copy. + */ + void setColMajorf(const float[]); + void setColMajord(const double[]); + void setRowMajorf(const float[]); + void setRowMajord(const double[]); + +#ifdef SK_MSCALAR_IS_FLOAT + void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); } + void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); } +#else + void setColMajor(const SkMScalar data[]) { this->setColMajord(data); } + void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); } +#endif + + void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, + SkMScalar m10, SkMScalar m11, SkMScalar m12, + SkMScalar m20, SkMScalar m21, SkMScalar m22); + + void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); + void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); + void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); + + void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); + void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); + void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); + + inline void setScale(SkMScalar scale) { + this->setScale(scale, scale, scale); + } + inline void preScale(SkMScalar scale) { + this->preScale(scale, scale, scale); + } + inline void postScale(SkMScalar scale) { + this->postScale(scale, scale, scale); + } + + void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z, + SkMScalar degrees) { + this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180); + } + + /** Rotate about the vector [x,y,z]. If that vector is not unit-length, + it will be automatically resized. + */ + void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z, + SkMScalar radians); + /** Rotate about the vector [x,y,z]. Does not check the length of the + vector, assuming it is unit-length. + */ + void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z, + SkMScalar radians); + + void setConcat(const SkMatrix44& a, const SkMatrix44& b); + inline void preConcat(const SkMatrix44& m) { + this->setConcat(*this, m); + } + inline void postConcat(const SkMatrix44& m) { + this->setConcat(m, *this); + } + + friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) { + return SkMatrix44(a, b); + } + + /** If this is invertible, return that in inverse and return true. If it is + not invertible, return false and ignore the inverse parameter. + */ + bool invert(SkMatrix44* inverse) const; + + /** Transpose this matrix in place. */ + void transpose(); + + /** Apply the matrix to the src vector, returning the new vector in dst. + It is legal for src and dst to point to the same memory. + */ + void mapScalars(const SkScalar src[4], SkScalar dst[4]) const; + inline void mapScalars(SkScalar vec[4]) const { + this->mapScalars(vec, vec); + } + + // DEPRECATED: call mapScalars() + void map(const SkScalar src[4], SkScalar dst[4]) const { + this->mapScalars(src, dst); + } + // DEPRECATED: call mapScalars() + void map(SkScalar vec[4]) const { + this->mapScalars(vec, vec); + } + +#ifdef SK_MSCALAR_IS_DOUBLE + void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const; +#elif defined SK_MSCALAR_IS_FLOAT + inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const { + this->mapScalars(src, dst); + } +#endif + inline void mapMScalars(SkMScalar vec[4]) const { + this->mapMScalars(vec, vec); + } + + friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) { + SkVector4 dst; + m.map(src.fData, dst.fData); + return dst; + } + + /** + * map an array of [x, y, 0, 1] through the matrix, returning an array + * of [x', y', z', w']. + * + * @param src2 array of [x, y] pairs, with implied z=0 and w=1 + * @param count number of [x, y] pairs in src2 + * @param dst4 array of [x', y', z', w'] quads as the output. + */ + void map2(const float src2[], int count, float dst4[]) const; + void map2(const double src2[], int count, double dst4[]) const; + + void dump() const; + + double determinant() const; + +private: + SkMScalar fMat[4][4]; + mutable unsigned fTypeMask; + + enum { + kUnknown_Mask = 0x80, + + kAllPublic_Masks = 0xF + }; + + SkMScalar transX() const { return fMat[3][0]; } + SkMScalar transY() const { return fMat[3][1]; } + SkMScalar transZ() const { return fMat[3][2]; } + + SkMScalar scaleX() const { return fMat[0][0]; } + SkMScalar scaleY() const { return fMat[1][1]; } + SkMScalar scaleZ() const { return fMat[2][2]; } + + SkMScalar perspX() const { return fMat[0][3]; } + SkMScalar perspY() const { return fMat[1][3]; } + SkMScalar perspZ() const { return fMat[2][3]; } + + int computeTypeMask() const; + + inline void dirtyTypeMask() { + fTypeMask = kUnknown_Mask; + } + + inline void setTypeMask(int mask) { + SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask)); + fTypeMask = mask; + } + + /** + * Does not take the time to 'compute' the typemask. Only returns true if + * we already know that this matrix is identity. + */ + inline bool isTriviallyIdentity() const { + return 0 == fTypeMask; + } +}; + +#endif diff --git a/utils/SkMeshUtils.h b/utils/SkMeshUtils.h new file mode 100644 index 0000000..564df67 --- /dev/null +++ b/utils/SkMeshUtils.h @@ -0,0 +1,50 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkMeshUtils_DEFINED +#define SkMeshUtils_DEFINED + +#include "SkPoint.h" +#include "SkColor.h" + +class SkBitmap; +class SkCanvas; +class SkPaint; + +class SkMeshIndices { +public: + SkMeshIndices(); + ~SkMeshIndices(); + + bool init(int texW, int texH, int rows, int cols) { + return this->init(NULL, NULL, texW, texH, rows, cols); + } + + bool init(SkPoint tex[], uint16_t indices[], + int texW, int texH, int rows, int cols); + + size_t indexCount() const { return fIndexCount; } + const uint16_t* indices() const { return fIndices; } + + size_t texCount() const { return fTexCount; } + const SkPoint* tex() const { return fTex; } + +private: + size_t fIndexCount, fTexCount; + SkPoint* fTex; + uint16_t* fIndices; + void* fStorage; // may be null +}; + +class SkMeshUtils { +public: + static void Draw(SkCanvas*, const SkBitmap&, int rows, int cols, + const SkPoint verts[], const SkColor colors[], + const SkPaint& paint); +}; + +#endif diff --git a/utils/SkNWayCanvas.h b/utils/SkNWayCanvas.h new file mode 100644 index 0000000..de78f8a --- /dev/null +++ b/utils/SkNWayCanvas.h @@ -0,0 +1,91 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNWayCanvas_DEFINED +#define SkNWayCanvas_DEFINED + +#include "SkCanvas.h" + +class SK_API SkNWayCanvas : public SkCanvas { +public: + SkNWayCanvas(int width, int height); + virtual ~SkNWayCanvas(); + + virtual void addCanvas(SkCanvas*); + virtual void removeCanvas(SkCanvas*); + virtual void removeAll(); + + /////////////////////////////////////////////////////////////////////////// + // These are forwarded to the N canvases we're referencing + + virtual int save(SaveFlags) SK_OVERRIDE; + virtual int saveLayer(const SkRect* bounds, const SkPaint*, + SaveFlags) SK_OVERRIDE; + virtual void restore() SK_OVERRIDE; + virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE; + virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool rotate(SkScalar degrees) SK_OVERRIDE; + virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE; + virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE; + virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRRect(const SkRRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op) SK_OVERRIDE; + + virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint&) SK_OVERRIDE; + virtual void drawOval(const SkRect&, const SkPaint&) SK_OVERRIDE; + virtual void drawRect(const SkRect&, const SkPaint&) SK_OVERRIDE; + virtual void drawRRect(const SkRRect&, const SkPaint&) SK_OVERRIDE; + virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE; + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint*) SK_OVERRIDE; + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint*) SK_OVERRIDE; + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint*) SK_OVERRIDE; + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint*) SK_OVERRIDE; + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint&) SK_OVERRIDE; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint&) SK_OVERRIDE; + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint&) SK_OVERRIDE; + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint&) SK_OVERRIDE; + virtual void drawPicture(SkPicture&) SK_OVERRIDE; + 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&) SK_OVERRIDE; + + virtual SkBounder* setBounder(SkBounder*) SK_OVERRIDE; + virtual SkDrawFilter* setDrawFilter(SkDrawFilter*) SK_OVERRIDE; + + virtual void beginCommentGroup(const char* description) SK_OVERRIDE; + virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE; + virtual void endCommentGroup() SK_OVERRIDE; + +protected: + SkTDArray<SkCanvas*> fList; + + class Iter; + +private: + typedef SkCanvas INHERITED; +}; + + +#endif diff --git a/utils/SkNinePatch.h b/utils/SkNinePatch.h new file mode 100644 index 0000000..4d8788b --- /dev/null +++ b/utils/SkNinePatch.h @@ -0,0 +1,33 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkNinePatch_DEFINED +#define SkNinePatch_DEFINED + +#include "SkRect.h" +#include "SkRegion.h" + +class SkBitmap; +class SkCanvas; +class SkPaint; + +class SkNinePatch { +public: + static void DrawNine(SkCanvas* canvas, const SkRect& dst, + const SkBitmap& bitmap, const SkIRect& margins, + const SkPaint* paint = NULL); + + static void DrawMesh(SkCanvas* canvas, const SkRect& dst, + const SkBitmap& bitmap, + const int32_t xDivs[], int numXDivs, + const int32_t yDivs[], int numYDivs, + const SkPaint* paint = NULL); +}; + +#endif diff --git a/utils/SkNullCanvas.h b/utils/SkNullCanvas.h new file mode 100644 index 0000000..99a26da --- /dev/null +++ b/utils/SkNullCanvas.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkNullCanvas_DEFINED +#define SkNullCanvas_DEFINED + +#include "SkBitmap.h" + +class SkCanvas; + +/** + * Creates a canvas that draws nothing. This is useful for performance testing. + */ +SK_API SkCanvas* SkCreateNullCanvas(); + +#endif diff --git a/utils/SkParse.h b/utils/SkParse.h new file mode 100644 index 0000000..c5aac7d --- /dev/null +++ b/utils/SkParse.h @@ -0,0 +1,36 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkParse_DEFINED +#define SkParse_DEFINED + +#include "SkColor.h" + +class SkParse { +public: + static int Count(const char str[]); // number of scalars or int values + static int Count(const char str[], char separator); + static const char* FindColor(const char str[], SkColor* value); + static const char* FindHex(const char str[], uint32_t* value); + static const char* FindMSec(const char str[], SkMSec* value); + static const char* FindNamedColor(const char str[], size_t len, SkColor* color); + static const char* FindS32(const char str[], int32_t* value); + static const char* FindScalar(const char str[], SkScalar* value); + static const char* FindScalars(const char str[], SkScalar value[], int count); + + static bool FindBool(const char str[], bool* value); + // return the index of str in list[], or -1 if not found + static int FindList(const char str[], const char list[]); +#ifdef SK_SUPPORT_UNITTEST + static void TestColor(); + static void UnitTest(); +#endif +}; + +#endif diff --git a/utils/SkParsePaint.h b/utils/SkParsePaint.h new file mode 100644 index 0000000..066292f --- /dev/null +++ b/utils/SkParsePaint.h @@ -0,0 +1,26 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkParsePaint_DEFINED +#define SkParsePaint_DEFINED + +#include "SkPaint.h" +#include "SkDOM.h" + +/** "color" color + "opacity" scalar [0..1] + "stroke-width" scalar (0...inf) + "text-size" scalar (0..inf) + "is-stroke" bool + "is-antialias" bool + "is-lineartext" bool +*/ +void SkPaint_Inflate(SkPaint*, const SkDOM&, const SkDOM::Node*); + +#endif diff --git a/utils/SkParsePath.h b/utils/SkParsePath.h new file mode 100644 index 0000000..c52b3c0 --- /dev/null +++ b/utils/SkParsePath.h @@ -0,0 +1,23 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkParsePath_DEFINED +#define SkParsePath_DEFINED + +#include "SkPath.h" + +class SkString; + +class SkParsePath { +public: + static bool FromSVGString(const char str[], SkPath*); + static void ToSVGString(const SkPath&, SkString*); +}; + +#endif diff --git a/utils/SkPathUtils.h b/utils/SkPathUtils.h new file mode 100644 index 0000000..a27cbb8 --- /dev/null +++ b/utils/SkPathUtils.h @@ -0,0 +1,40 @@ +/* + * CAUTION: EXPERIMENTAL CODE + * + * This code is not to be used and will not be supported + * if it fails on you. DO NOT USE! + * + */ + +#ifndef SkPathUtils_DEFINED +#define SkPathUtils_DEFINED + +#include "SkPath.h" + +/* + * The following methods return the boundary path given a 1-bit bitmap, specified + * by width/height and stride. The bits are interpreted as 1 being "in" the path, + * and 0 being "out". The bits are interpreted as MSB on the left, and LSB on the right. + */ + +class SK_API SkPathUtils { +public: + /** + This variation iterates the binary data sequentially (as in scanline fashion) + and will add each run of 1's to the path as a rectangular path. Upon parsing + all binary data the path is simplified using the PathOps::Simplify() method. + */ + static void BitsToPath_Path(SkPath* path, const char* bitmap, + int w, int h, int rowBytes); + + /** + This variation utilizes the SkRegion class to generate paths, adding + each run of 1's to the SkRegion as an SkIRect. Upon parsing the entirety + of the binary the SkRegion is converted to a Path via getBoundaryPath(). + */ + static void BitsToPath_Region(SkPath* path, const char* bitmap, + int w, int h, int rowBytes); + +}; + +#endif diff --git a/utils/SkPictureUtils.h b/utils/SkPictureUtils.h new file mode 100644 index 0000000..5e6b051 --- /dev/null +++ b/utils/SkPictureUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPictureUtils_DEFINED +#define SkPictureUtils_DEFINED + +#include "SkPicture.h" + +class SkData; +struct SkRect; + +class SK_API SkPictureUtils { +public: + /** + * Given a rectangular visible "window" into the picture, return an array + * of SkPixelRefs that might intersect that area. To keep the call fast, + * the returned list is not guaranteed to be exact, so it may miss some, + * and it may return false positives. + * + * The pixelrefs returned in the SkData are already owned by the picture, + * so the returned pointers are only valid while the picture is in scope + * and remains unchanged. + */ + static SkData* GatherPixelRefs(SkPicture* pict, const SkRect& area); +}; + +#endif diff --git a/utils/SkProxyCanvas.h b/utils/SkProxyCanvas.h new file mode 100644 index 0000000..4091636 --- /dev/null +++ b/utils/SkProxyCanvas.h @@ -0,0 +1,93 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkProxyCanvas_DEFINED +#define SkProxyCanvas_DEFINED + +#include "SkCanvas.h" + +/** This class overrides all virtual methods on SkCanvas, and redirects them + to a "proxy", another SkCanvas instance. It can be the basis for + intercepting (and possibly modifying) calls to a canvas. + + There must be a proxy installed before the proxycanvas can be used (i.e. + before its virtual methods can be called). + */ +class SK_API SkProxyCanvas : public SkCanvas { +public: + SkProxyCanvas() : fProxy(NULL) {} + SkProxyCanvas(SkCanvas* proxy); + virtual ~SkProxyCanvas(); + + SkCanvas* getProxy() const { return fProxy; } + void setProxy(SkCanvas* proxy); + + virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) SK_OVERRIDE; + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags flags = kARGB_ClipLayer_SaveFlag) SK_OVERRIDE; + virtual void restore() SK_OVERRIDE; + + virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE; + virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool rotate(SkScalar degrees) SK_OVERRIDE; + virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE; + virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE; + virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE; + + virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRRect(const SkRRect&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE; + virtual bool clipRegion(const SkRegion& deviceRgn, + SkRegion::Op op = SkRegion::kIntersect_Op) SK_OVERRIDE; + + virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) SK_OVERRIDE; + virtual void drawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRect(const SkRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE; + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint = NULL) SK_OVERRIDE; + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE; + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint = NULL) SK_OVERRIDE; + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint = NULL) SK_OVERRIDE; + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) SK_OVERRIDE; + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) SK_OVERRIDE; + virtual void drawPicture(SkPicture&) SK_OVERRIDE; + 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) SK_OVERRIDE; + virtual void drawData(const void* data, size_t length) SK_OVERRIDE; + + virtual void beginCommentGroup(const char* description) SK_OVERRIDE; + virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE; + virtual void endCommentGroup() SK_OVERRIDE; + + virtual SkBounder* setBounder(SkBounder* bounder) SK_OVERRIDE; + virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE; + +private: + SkCanvas* fProxy; + + typedef SkCanvas INHERITED; +}; + +#endif diff --git a/utils/SkRTConf.h b/utils/SkRTConf.h new file mode 100644 index 0000000..ea6e99e --- /dev/null +++ b/utils/SkRTConf.h @@ -0,0 +1,172 @@ +/* + * Copyright 2013 Google, Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkRTConf_DEFINED +#define SkRTConf_DEFINED + +#include "SkString.h" +#include "SkStream.h" + +#include "SkTDict.h" +#include "SkTArray.h" + +/** \class SkRTConfBase + Non-templated base class for the runtime configs +*/ + +class SkRTConfBase { +public: + SkRTConfBase(const char *name) : fName(name) {} + virtual ~SkRTConfBase() {} + virtual const char *getName() const { return fName.c_str(); } + virtual bool isDefault() const = 0; + virtual void print(SkWStream *o) const = 0; + virtual bool equals(const SkRTConfBase *conf) const = 0; +protected: + SkString fName; +}; + +/** \class SkRTConf + A class to provide runtime configurability. +*/ +template<typename T> class SkRTConf: public SkRTConfBase { +public: + SkRTConf(const char *name, const T &defaultValue, const char *description); + operator const T&() const { return fValue; } + void print(SkWStream *o) const; + bool equals(const SkRTConfBase *conf) const; + bool isDefault() const { return fDefault == fValue; } + void set(const T& value) { fValue = value; } +protected: + void doPrint(char *s) const; + + T fValue; + T fDefault; + SkString fDescription; +}; + +#ifdef SK_DEVELOPER +#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf<confType> varName(confName, defaultValue, description) +#define SK_CONF_SET(confname, value) skRTConfRegistry().set(confname, value) +#else +#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue +#define SK_CONF_SET(confname, value) (void) confname, (void) value +#endif + +/** \class SkRTConfRegistry + A class that maintains a systemwide registry of all runtime configuration + parameters. Mainly used for printing them out and handling multiply-defined + knobs. +*/ + +class SkRTConfRegistry { +public: + SkRTConfRegistry(); + void printAll(const char *fname = NULL) const; + void printNonDefault(const char *fname = NULL) const; + const char *configFileLocation() const; + void possiblyDumpFile() const; + void validate() const; + template <typename T> void set(const char *confname, T value); +private: + template<typename T> friend class SkRTConf; + + void registerConf(SkRTConfBase *conf); + template <typename T> bool parse(const char *name, T* value); + + SkTDArray<SkString *> fConfigFileKeys, fConfigFileValues; + typedef SkTDict< SkTDArray<SkRTConfBase *> * > ConfMap; + ConfMap fConfs; +}; + +// our singleton registry + +SkRTConfRegistry &skRTConfRegistry(); + +template<typename T> +SkRTConf<T>::SkRTConf(const char *name, const T &defaultValue, const char *description) + : SkRTConfBase(name) + , fValue(defaultValue) + , fDefault(defaultValue) + , fDescription(description) { + + T value; + if (skRTConfRegistry().parse(fName.c_str(), &value)) { + fValue = value; + } + skRTConfRegistry().registerConf(this); +} + +template<typename T> +void SkRTConf<T>::print(SkWStream *o) const { + char outline[200]; // should be ok because we specify a max. width for everything here. + + sprintf(outline, "%-30.30s", getName()); + doPrint(&(outline[30])); + sprintf(&(outline[60]), " %.128s", fDescription.c_str()); + if (' ' == outline[strlen(outline)-1]) { + for (int i = strlen(outline)-1 ; ' ' == outline[i] ; i--) { + outline[i] = '\0'; + } + } + o->writeText(outline); +} + +template<typename T> +void SkRTConf<T>::doPrint(char *s) const { + sprintf(s, "%-30.30s", "How do I print myself??"); +} + +template<> inline void SkRTConf<bool>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false"); + sprintf(s, "%-30.30s", tmp); +} + +template<> inline void SkRTConf<int>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%d # [%d]", fValue, fDefault); + sprintf(s, "%-30.30s", tmp); +} + +template<> inline void SkRTConf<unsigned int>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%u # [%u]", fValue, fDefault); + sprintf(s, "%-30.30s", tmp); +} + +template<> inline void SkRTConf<float>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); + sprintf(s, "%-30.30s", tmp); +} + +template<> inline void SkRTConf<double>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); + sprintf(s, "%-30.30s", tmp); +} + +template<> inline void SkRTConf<const char *>::doPrint(char *s) const { + char tmp[30]; + sprintf(tmp, "%s # [%s]", fValue, fDefault); + sprintf(s, "%-30.30s", tmp); +} + +template<typename T> +bool SkRTConf<T>::equals(const SkRTConfBase *conf) const { + // static_cast here is okay because there's only one kind of child class. + const SkRTConf<T> *child_pointer = static_cast<const SkRTConf<T> *>(conf); + return child_pointer && + fName == child_pointer->fName && + fDescription == child_pointer->fDescription && + fValue == child_pointer->fValue && + fDefault == child_pointer->fDefault; +} + +#endif diff --git a/utils/SkRandom.h b/utils/SkRandom.h new file mode 100644 index 0000000..3e2ef20 --- /dev/null +++ b/utils/SkRandom.h @@ -0,0 +1,323 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#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; } + + /** + * Returns value [0...1) as a float + */ + float nextF() { + // const is 1 / (2^32 - 1) + return (float)(this->nextU() * 2.32830644e-10); + } + + /** + * Returns value [min...max) as a float + */ + float nextRangeF(float min, float max) { + return min + this->nextF() * (max - min); + } + + /** 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); + uint32_t range = max - min + 1; + if (0 == range) { + return this->nextU(); + } else { + return min + this->nextU() % range; + } + } + + /** Return the next pseudo random unsigned number, mapped to lie within + [0, count). + */ + uint32_t nextULessThan(uint32_t count) { + SkASSERT(count > 0); + return this->nextRangeU(0, count - 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 [min..max). + */ + SkScalar nextRangeScalar(SkScalar min, SkScalar max) { + return SkScalarMul(this->nextUScalar1(), (max - min)) + min; + } + + /** 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 bool. + */ + bool nextBool() { return this->nextU() >= 0x80000000; } + + /** A biased version of nextBool(). + */ + bool nextBiasedBool(SkScalar fractionTrue) { + SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1); + return this->nextUScalar1() <= fractionTrue; + } + + /** Return the next pseudo random number as a signed 64bit value. + */ + void next64(Sk64* a) { + SkASSERT(a); + a->set(this->nextS(), this->nextU()); + } + + /** + * Return the current seed. This allows the caller to later reset to the + * same seed (using setSeed) so it can generate the same sequence. + */ + int32_t getSeed() const { return fSeed; } + + /** 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; +}; + +/** \class SkMWCRandom + + Utility class that implements pseudo random 32bit numbers using Marsaglia's + multiply-with-carry "mother of all" algorithm. Unlike rand(), this class holds + its own state, so that multiple instances can be used with no side-effects. + + Has a large period and all bits are well-randomized. + */ +class SkMWCRandom { +public: + SkMWCRandom() { init(0); } + SkMWCRandom(uint32_t seed) { init(seed); } + SkMWCRandom(const SkMWCRandom& rand) : fK(rand.fK), fJ(rand.fJ) {} + + SkMWCRandom& operator=(const SkMWCRandom& rand) { + fK = rand.fK; + fJ = rand.fJ; + + return *this; + } + + /** Return the next pseudo random number as an unsigned 32bit value. + */ + uint32_t nextU() { + fK = kKMul*(fK & 0xffff) + (fK >> 16); + fJ = kJMul*(fJ & 0xffff) + (fJ >> 16); + return (((fK << 16) | (fK >> 16)) + fJ); + } + + /** 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; } + + /** + * Returns value [0...1) as an IEEE float + */ + float nextF() { + unsigned int floatint = 0x3f800000 | (this->nextU() >> 9); + float f = SkBits2Float(floatint) - 1.0f; + return f; + } + + /** + * Returns value [min...max) as a float + */ + float nextRangeF(float min, float max) { + return min + this->nextF() * (max - min); + } + + /** 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); + uint32_t range = max - min + 1; + if (0 == range) { + return this->nextU(); + } else { + return min + this->nextU() % range; + } + } + + /** Return the next pseudo random unsigned number, mapped to lie within + [0, count). + */ + uint32_t nextULessThan(uint32_t count) { + SkASSERT(count > 0); + return this->nextRangeU(0, count - 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 [min..max). + */ + SkScalar nextRangeScalar(SkScalar min, SkScalar max) { + return SkScalarMul(this->nextUScalar1(), (max - min)) + min; + } + + /** 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 bool. + */ + bool nextBool() { return this->nextU() >= 0x80000000; } + + /** A biased version of nextBool(). + */ + bool nextBiasedBool(SkScalar fractionTrue) { + SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1); + return this->nextUScalar1() <= fractionTrue; + } + + /** Return the next pseudo random number as a signed 64bit value. + */ + void next64(Sk64* a) { + SkASSERT(a); + a->set(this->nextS(), this->nextU()); + } + + /** Reset the random object. + */ + void setSeed(uint32_t seed) { init(seed); } + +private: + // Initialize state variables with LCG. + // We must ensure that both J and K are non-zero, otherwise the + // multiply-with-carry step will forevermore return zero. + void init(uint32_t seed) { + fK = NextLCG(seed); + if (0 == fK) { + fK = NextLCG(fK); + } + fJ = NextLCG(fK); + if (0 == fJ) { + fJ = NextLCG(fJ); + } + SkASSERT(0 != fK && 0 != fJ); + } + static uint32_t NextLCG(uint32_t seed) { return kMul*seed + kAdd; } + + // See "Numerical Recipes in C", 1992 page 284 for these constants + // For the LCG that sets the initial state from a seed + enum { + kMul = 1664525, + kAdd = 1013904223 + }; + // Constants for the multiply-with-carry steps + enum { + kKMul = 30345, + kJMul = 18000, + }; + + uint32_t fK; + uint32_t fJ; +}; + +#endif diff --git a/utils/SkRunnable.h b/utils/SkRunnable.h new file mode 100644 index 0000000..84e4375 --- /dev/null +++ b/utils/SkRunnable.h @@ -0,0 +1,17 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRunnable_DEFINED +#define SkRunnable_DEFINED + +class SkRunnable { +public: + virtual ~SkRunnable() {}; + virtual void run() = 0; +}; + +#endif diff --git a/utils/SkThreadPool.h b/utils/SkThreadPool.h new file mode 100644 index 0000000..3c86158 --- /dev/null +++ b/utils/SkThreadPool.h @@ -0,0 +1,51 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadPool_DEFINED +#define SkThreadPool_DEFINED + +#include "SkCondVar.h" +#include "SkTDArray.h" +#include "SkTInternalLList.h" + +class SkRunnable; +class SkThread; + +class SkThreadPool { + +public: + /** + * Create a threadpool with count threads, or one thread per core if kThreadPerCore. + */ + static const int kThreadPerCore = -1; + explicit SkThreadPool(int count); + ~SkThreadPool(); + + /** + * Queues up an SkRunnable to run when a thread is available, or immediately if + * count is 0. NULL is a safe no-op. Does not take ownership. + */ + void add(SkRunnable*); + + private: + struct LinkedRunnable { + // Unowned pointer. + SkRunnable* fRunnable; + + private: + SK_DECLARE_INTERNAL_LLIST_INTERFACE(LinkedRunnable); + }; + + SkTInternalLList<LinkedRunnable> fQueue; + SkCondVar fReady; + SkTDArray<SkThread*> fThreads; + bool fDone; + + static void Loop(void*); // Static because we pass in this. +}; + +#endif diff --git a/utils/SkUnitMappers.h b/utils/SkUnitMappers.h new file mode 100644 index 0000000..64aab5d --- /dev/null +++ b/utils/SkUnitMappers.h @@ -0,0 +1,55 @@ + +/* + * Copyright 2008 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkUnitMappers_DEFINED +#define SkUnitMappers_DEFINED + +#include "SkUnitMapper.h" + +/** This discretizes the range [0...1) into N discret values. +*/ +class SkDiscreteMapper : public SkUnitMapper { +public: + SkDiscreteMapper(int segments); + // override from SkUnitMapper + virtual uint16_t mapUnit16(uint16_t x); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiscreteMapper) + +protected: + SkDiscreteMapper(SkFlattenableReadBuffer& ); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + int fSegments; + SkFract fScale; // computed from fSegments + + typedef SkUnitMapper INHERITED; +}; + +/** This returns cos(x), to simulate lighting a sphere, where 0 maps to the + center of the sphere, and 1 maps to the edge. +*/ +class SkCosineMapper : public SkUnitMapper { +public: + SkCosineMapper() {} + // override from SkUnitMapper + virtual uint16_t mapUnit16(uint16_t x); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkCosineMapper) + +protected: + SkCosineMapper(SkFlattenableReadBuffer&); + +private: + + typedef SkUnitMapper INHERITED; +}; + +#endif diff --git a/utils/SkWGL.h b/utils/SkWGL.h new file mode 100644 index 0000000..3d94174 --- /dev/null +++ b/utils/SkWGL.h @@ -0,0 +1,117 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkRefCnt.h" + +#ifndef SkWGL_DEFINED +#define SkWGL_DEFINED + +/** + * Working with WGL extensions can be a pain. Among the reasons is that You must + * have a GL context to get the proc addresses, but you want to use the procs to + * create a context in the first place. So you have to create a dummy GL ctx to + * get the proc addresses. + * + * This file helps by providing SkCreateWGLInterface(). It returns a struct of + * function pointers that it initializes. It also has a helper function to query + * for WGL extensions. It handles the fact that wglGetExtensionsString is itself + * an extension. + */ + +#if !defined(WIN32_LEAN_AND_MEAN) + #define WIN32_LEAN_AND_MEAN + #define SK_LOCAL_LEAN_AND_MEAN +#endif +#include <Windows.h> +#if defined(SK_LOCAL_LEAN_AND_MEAN) + #undef WIN32_LEAN_AND_MEAN + #undef SK_LOCAL_LEAN_AND_MEAN +#endif + +#define SK_WGL_DRAW_TO_WINDOW 0x2001 +#define SK_WGL_ACCELERATION 0x2003 +#define SK_WGL_SUPPORT_OPENGL 0x2010 +#define SK_WGL_DOUBLE_BUFFER 0x2011 +#define SK_WGL_COLOR_BITS 0x2014 +#define SK_WGL_ALPHA_BITS 0x201B +#define SK_WGL_STENCIL_BITS 0x2023 +#define SK_WGL_FULL_ACCELERATION 0x2027 +#define SK_WGL_SAMPLE_BUFFERS 0x2041 +#define SK_WGL_SAMPLES 0x2042 +#define SK_WGL_COVERAGE_SAMPLES 0x2042 /* same as SAMPLES */ +#define SK_WGL_COLOR_SAMPLES 0x20B9 +#define SK_WGL_CONTEXT_MAJOR_VERSION 0x2091 +#define SK_WGL_CONTEXT_MINOR_VERSION 0x2092 +#define SK_WGL_CONTEXT_LAYER_PLANE 0x2093 +#define SK_WGL_CONTEXT_FLAGS 0x2094 +#define SK_WGL_CONTEXT_PROFILE_MASK 0x9126 +#define SK_WGL_CONTEXT_DEBUG_BIT 0x0001 +#define SK_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT 0x0002 +#define SK_WGL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define SK_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define SK_WGL_CONTEXT_ES2_PROFILE_BIT 0x00000004 +#define SK_ERROR_INVALID_VERSION 0x2095 +#define SK_ERROR_INVALID_PROFILE 0x2096 + +class SkWGLExtensions { +public: + SkWGLExtensions(); + /** + * Determines if an extensions is available for a given DC. + * WGL_extensions_string is considered a prerequisite for all other + * extensions. It is necessary to check this before calling other class + * functions. + */ + bool hasExtension(HDC dc, const char* ext) const; + + const char* getExtensionsString(HDC hdc) const; + BOOL choosePixelFormat(HDC hdc, const int*, const FLOAT*, UINT, int*, UINT*) const; + BOOL getPixelFormatAttribiv(HDC, int, int, UINT, const int*, int*) const; + BOOL getPixelFormatAttribfv(HDC hdc, int, int, UINT, const int*, FLOAT*) const; + HGLRC createContextAttribs(HDC, HGLRC, const int *) const; + + /** + * WGL doesn't have precise rules for the ordering of formats returned + * by wglChoosePixelFormat. This function helps choose among the set of + * formats returned by wglChoosePixelFormat. The rules in decreasing + * priority are: + * * Choose formats with the smallest sample count that is >= + * desiredSampleCount (or the largest sample count if all formats have + * fewer samples than desiredSampleCount.) + * * Choose formats with the fewest color samples when coverage sampling + * is available. + * * If the above rules leave multiple formats, choose the one that + * appears first in the formats array parameter. + */ + int selectFormat(const int formats[], + int formatCount, + HDC dc, + int desiredSampleCount); +private: + typedef const char* (WINAPI *GetExtensionsStringProc)(HDC hdc); + typedef BOOL (WINAPI *ChoosePixelFormatProc)(HDC hdc, const int *, const FLOAT *, UINT, int *, UINT *); + typedef BOOL (WINAPI *GetPixelFormatAttribivProc)(HDC, int, int, UINT, const int*, int*); + typedef BOOL (WINAPI *GetPixelFormatAttribfvProc)(HDC hdc, int, int, UINT, const int*, FLOAT*); + typedef HGLRC (WINAPI *CreateContextAttribsProc)(HDC hDC, HGLRC, const int *); + + GetExtensionsStringProc fGetExtensionsString; + ChoosePixelFormatProc fChoosePixelFormat; + GetPixelFormatAttribfvProc fGetPixelFormatAttribfv; + GetPixelFormatAttribivProc fGetPixelFormatAttribiv; + CreateContextAttribsProc fCreateContextAttribs; +}; + +/** + * Helper to create an OpenGL context for a DC using WGL. Configs with a sample count >= to + * msaaSampleCount are preferred but if none is available then a context with a lower sample count + * (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be + * created then a compatible profile context will be created. + */ +HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile); + +#endif diff --git a/utils/ios/SkStream_NSData.h b/utils/ios/SkStream_NSData.h new file mode 100755 index 0000000..8e6f064 --- /dev/null +++ b/utils/ios/SkStream_NSData.h @@ -0,0 +1,41 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkStream_NSData_DEFINED +#define SkStream_NSData_DEFINED + +#import <UIKit/UIKit.h> +#include "SkStream.h" + +/** Returns an NSData with a copy of the stream's data. The caller must call + retain if it intends to keep the data object beyond the current stack-frame + (i.e. internally we're calling [NSData dataWithBytes...] + */ +NSData* NSData_dataWithStream(SkStream* stream); + +/** Returns an NSData from the named resource (from main bundle). + The caller must call retain if it intends to keep the data object beyond + the current stack-frame + (i.e. internally we're calling [NSData dataWithContentsOfMappedFile...] + */ +NSData* NSData_dataFromResource(const char name[], const char suffix[]); + +/** Wrap a stream around NSData. + */ +class SkStream_NSData : public SkMemoryStream { +public: + SkStream_NSData(NSData* data); + virtual ~SkStream_NSData(); + + static SkStream_NSData* CreateFromResource(const char name[], + const char suffix[]); + +private: + NSData* fNSData; +}; + +#endif diff --git a/utils/mac/SkCGUtils.h b/utils/mac/SkCGUtils.h new file mode 100644 index 0000000..54c858c --- /dev/null +++ b/utils/mac/SkCGUtils.h @@ -0,0 +1,67 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkCGUtils_DEFINED +#define SkCGUtils_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_MAC +#include <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreGraphics/CoreGraphics.h> +#endif + +class SkBitmap; +class SkData; +class SkStream; + +/** + * Create an imageref from the specified bitmap using the specified colorspace. + * If space is NULL, then CGColorSpaceCreateDeviceRGB() is used. + */ +SK_API CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, + CGColorSpaceRef space); + +/** + * Create an imageref from the specified bitmap using the colorspace returned + * by CGColorSpaceCreateDeviceRGB() + */ +static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) { + return SkCreateCGImageRefWithColorspace(bm, NULL); +} + +/** + * Draw the bitmap into the specified CG context. The bitmap will be converted + * to a CGImage using the generic RGB colorspace. (x,y) specifies the position + * of the top-left corner of the bitmap. The bitmap is converted using the + * colorspace returned by CGColorSpaceCreateDeviceRGB() + */ +void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y); + +bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output); + +/** + * Return a provider that wraps the specified stream. It will become an + * owner of the stream, so the caller must still manage its ownership. + * + * To hand-off ownership of the stream to the provider, the caller must do + * something like the following: + * + * SkStream* stream = new ...; + * CGDataProviderRef provider = SkStreamToDataProvider(stream); + * stream->unref(); + * + * Now when the provider is finally deleted, it will delete the stream. + */ +CGDataProviderRef SkCreateDataProviderFromStream(SkStream*); + +CGDataProviderRef SkCreateDataProviderFromData(SkData*); + +#endif diff --git a/utils/win/SkAutoCoInitialize.h b/utils/win/SkAutoCoInitialize.h new file mode 100644 index 0000000..709fa6b --- /dev/null +++ b/utils/win/SkAutoCoInitialize.h @@ -0,0 +1,30 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkAutoCo_DEFINED +#define SkAutoCo_DEFINED + +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include "SkTemplates.h" + +/** + * An instance of this class initializes COM on creation + * and closes the COM library on destruction. + */ +class SkAutoCoInitialize : SkNoncopyable { +private: + HRESULT fHR; +public: + SkAutoCoInitialize(); + ~SkAutoCoInitialize(); + bool succeeded(); +}; + +#endif diff --git a/utils/win/SkHRESULT.h b/utils/win/SkHRESULT.h new file mode 100644 index 0000000..9738f74 --- /dev/null +++ b/utils/win/SkHRESULT.h @@ -0,0 +1,54 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkHRESULT_DEFINED +#define SkHRESULT_DEFINED + +#include "SkTypes.h" + +void SkTraceHR(const char* file, unsigned long line, + HRESULT hr, const char* msg); + +#ifdef SK_DEBUG +#define SK_TRACEHR(_hr, _msg) SkTraceHR(__FILE__, __LINE__, _hr, _msg) +#else +#define SK_TRACEHR(_hr, _msg) _hr +#endif + +#define HR_GENERAL(_ex, _msg, _ret) {\ + HRESULT _hr = _ex;\ + if (FAILED(_hr)) {\ + SK_TRACEHR(_hr, _msg);\ + return _ret;\ + }\ +} + +//@{ +/** +These macros are for reporting HRESULT errors. +The expression will be evaluated. +If the resulting HRESULT SUCCEEDED then execution will continue normally. +If the HRESULT FAILED then the macro will return from the current function. +In variants ending with 'M' the given message will be traced when FAILED. +The HR variants will return the HRESULT when FAILED. +The HRB variants will return false when FAILED. +The HRN variants will return NULL when FAILED. +The HRV variants will simply return when FAILED. +*/ +#define HR(ex) HR_GENERAL(ex, NULL, _hr) +#define HRM(ex, msg) HR_GENERAL(ex, msg, _hr) + +#define HRB(ex) HR_GENERAL(ex, NULL, false) +#define HRBM(ex, msg) HR_GENERAL(ex, msg, false) + +#define HRN(ex) HR_GENERAL(ex, NULL, NULL) +#define HRNM(ex, msg) HR_GENERAL(ex, msg, NULL) + +#define HRV(ex) HR_GENERAL(ex, NULL, ) +#define HRVM(ex, msg) HR_GENERAL(ex, msg, ) +//@} +#endif diff --git a/utils/win/SkIStream.h b/utils/win/SkIStream.h new file mode 100644 index 0000000..e4e045c --- /dev/null +++ b/utils/win/SkIStream.h @@ -0,0 +1,131 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkIStream_DEFINED +#define SkIStream_DEFINED + +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <ole2.h> + +class SkStream; +class SkWStream; + +/** + * A bare IStream implementation which properly reference counts + * but returns E_NOTIMPL for all ISequentialStream and IStream methods. + */ +class SkBaseIStream : public IStream { +private: + LONG _refcount; + +protected: + explicit SkBaseIStream(); + virtual ~SkBaseIStream(); + +public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid + , void ** ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // ISequentialStream Interface +public: + virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead); + + virtual HRESULT STDMETHODCALLTYPE Write(void const* pv + , ULONG cb + , ULONG* pcbWritten); + + // IStream Interface +public: + virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER); + + virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream* + , ULARGE_INTEGER + , ULARGE_INTEGER* + , ULARGE_INTEGER*); + + virtual HRESULT STDMETHODCALLTYPE Commit(DWORD); + + virtual HRESULT STDMETHODCALLTYPE Revert(void); + + virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER + , ULARGE_INTEGER + , DWORD); + + virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER + , ULARGE_INTEGER + , DWORD); + + virtual HRESULT STDMETHODCALLTYPE Clone(IStream **); + + virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove + , DWORD dwOrigin + , ULARGE_INTEGER* lpNewFilePointer); + + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg + , DWORD grfStatFlag); +}; + +/** + * A minimal read-only IStream implementation which wraps an SkIStream. + */ +class SkIStream : public SkBaseIStream { +private: + SkStream *fSkStream; + bool fUnrefOnRelease; + ULARGE_INTEGER fLocation; + + SkIStream(SkStream* stream, bool unrefOnRelease); + virtual ~SkIStream(); + +public: + HRESULT static CreateFromSkStream(SkStream* stream + , bool unrefOnRelease + , IStream ** ppStream); + + virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead); + + virtual HRESULT STDMETHODCALLTYPE Write(void const* pv + , ULONG cb + , ULONG* pcbWritten); + + virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove + , DWORD dwOrigin + , ULARGE_INTEGER* lpNewFilePointer); + + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg + , DWORD grfStatFlag); +}; + +/** + * A minimal write-only IStream implementation which wraps an SkWIStream. + */ +class SkWIStream : public SkBaseIStream { +private: + SkWStream *fSkWStream; + + SkWIStream(SkWStream* stream); + virtual ~SkWIStream(); + +public: + HRESULT static CreateFromSkWStream(SkWStream* stream, IStream ** ppStream); + + virtual HRESULT STDMETHODCALLTYPE Write(void const* pv + , ULONG cb + , ULONG* pcbWritten); + + virtual HRESULT STDMETHODCALLTYPE Commit(DWORD); + + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg + , DWORD grfStatFlag); +}; + +#endif diff --git a/utils/win/SkTScopedComPtr.h b/utils/win/SkTScopedComPtr.h new file mode 100644 index 0000000..8f3c22a --- /dev/null +++ b/utils/win/SkTScopedComPtr.h @@ -0,0 +1,76 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSkTScopedPtr_DEFINED +#define SkSkTScopedPtr_DEFINED + +#include "SkTypes.h" +#include "SkTemplates.h" + +template<typename T> +class SkBlockComRef : public T { +private: + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; +}; + +template<typename T> T* SkRefComPtr(T* ptr) { + ptr->AddRef(); + return ptr; +} + +template<typename T> T* SkSafeRefComPtr(T* ptr) { + if (ptr) { + ptr->AddRef(); + } + return ptr; +} + +template<typename T> +class SkTScopedComPtr : SkNoncopyable { +private: + T *fPtr; + +public: + explicit SkTScopedComPtr(T *ptr = NULL) : fPtr(ptr) { } + ~SkTScopedComPtr() { + this->reset(); + } + T &operator*() const { SkASSERT(fPtr != NULL); return *fPtr; } + SkBlockComRef<T> *operator->() const { + return static_cast<SkBlockComRef<T>*>(fPtr); + } + /** + * Returns the address of the underlying pointer. + * This is dangerous -- it breaks encapsulation and the reference escapes. + * Must only be used on instances currently pointing to NULL, + * and only to initialize the instance. + */ + T **operator&() { SkASSERT(fPtr == NULL); return &fPtr; } + T *get() const { return fPtr; } + void reset() { + if (NULL != this->fPtr) { + this->fPtr->Release(); + this->fPtr = NULL; + } + } + + void swap(SkTScopedComPtr<T>& that) { + T* temp = this->fPtr; + this->fPtr = that.fPtr; + that.fPtr = temp; + } + + T* release() { + T* temp = this->fPtr; + this->fPtr = NULL; + return temp; + } +}; + +#endif diff --git a/views/SkApplication.h b/views/SkApplication.h new file mode 100644 index 0000000..8369f68 --- /dev/null +++ b/views/SkApplication.h @@ -0,0 +1,19 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkApplication_DEFINED +#define SkApplication_DEFINED + +class SkOSWindow; + +extern SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv); +extern void application_init(); +extern void application_term(); + +#endif // SkApplication_DEFINED diff --git a/views/SkBGViewArtist.h b/views/SkBGViewArtist.h new file mode 100644 index 0000000..33054c8 --- /dev/null +++ b/views/SkBGViewArtist.h @@ -0,0 +1,33 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBGViewArtist_DEFINED +#define SkBGViewArtist_DEFINED + +#include "SkView.h" +#include "SkPaint.h" + +class SkBGViewArtist : public SkView::Artist { +public: + SkBGViewArtist(SkColor c = SK_ColorWHITE); + virtual ~SkBGViewArtist(); + + const SkPaint& paint() const { return fPaint; } + SkPaint& paint() { return fPaint; } + +protected: + // overrides + virtual void onDraw(SkView*, SkCanvas*); + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + +private: + SkPaint fPaint; +}; + +#endif diff --git a/views/SkEvent.h b/views/SkEvent.h new file mode 100644 index 0000000..f4df448 --- /dev/null +++ b/views/SkEvent.h @@ -0,0 +1,284 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEvent_DEFINED +#define SkEvent_DEFINED + +#include "SkDOM.h" +#include "SkMetaData.h" +#include "SkString.h" + +/** Unique 32bit id used to identify an instance of SkEventSink. When events are + posted, they are posted to a specific sinkID. When it is time to dispatch the + event, the sinkID is used to find the specific SkEventSink object. If it is found, + its doEvent() method is called with the event. +*/ +typedef uint32_t SkEventSinkID; + +/** + * \class SkEvent + * + * When an event is dispatched from the event queue, it is either sent to + * the eventsink matching the target ID (if not 0), or the target proc is + * called (if not NULL). + */ +class SkEvent { +public: + /** + * Function pointer that takes an event, returns true if it "handled" it. + */ + typedef bool (*Proc)(const SkEvent& evt); + + SkEvent(); + explicit SkEvent(const SkString& type, SkEventSinkID = 0); + explicit SkEvent(const char type[], SkEventSinkID = 0); + SkEvent(const SkEvent& src); + ~SkEvent(); + + /** Copy the event's type into the specified SkString parameter */ + void getType(SkString* str) const; + + /** Returns true if the event's type matches exactly the specified type (case sensitive) */ + bool isType(const SkString& str) const; + + /** Returns true if the event's type matches exactly the specified type (case sensitive) */ + bool isType(const char type[], size_t len = 0) const; + + /** + * Set the event's type to the specified string. + */ + void setType(const SkString&); + + /** + * Set the event's type to the specified string. + */ + void setType(const char type[], size_t len = 0); + + /** + * Return the target ID, or 0 if there is none. + * + * When an event is dispatched from the event queue, it is either sent to + * the eventsink matching the targetID (if not 0), or the target proc is + * called (if not NULL). + */ + SkEventSinkID getTargetID() const { return fTargetID; } + + /** + * Set the target ID for this event. 0 means none. Calling this will + * automatically clear the targetProc to null. + * + * When an event is dispatched from the event queue, it is either sent to + * the eventsink matching the targetID (if not 0), or the target proc is + * called (if not NULL). + */ + SkEvent* setTargetID(SkEventSinkID targetID) { + fTargetProc = NULL; + fTargetID = targetID; + return this; + } + + /** + * Return the target proc, or NULL if it has none. + * + * When an event is dispatched from the event queue, it is either sent to + * the eventsink matching the targetID (if not 0), or the target proc is + * called (if not NULL). + */ + Proc getTargetProc() const { return fTargetProc; } + + /** + * Set the target ID for this event. NULL means none. Calling this will + * automatically clear the targetID to 0. + * + * When an event is dispatched from the event queue, it is either sent to + * the eventsink matching the targetID (if not 0), or the target proc is + * called (if not NULL). + */ + SkEvent* setTargetProc(Proc proc) { + fTargetID = 0; + fTargetProc = proc; + return this; + } + + /** + * Return the event's unnamed 32bit field. Default value is 0 + */ + uint32_t getFast32() const { return f32; } + + /** + * Set the event's unnamed 32bit field. + */ + void setFast32(uint32_t x) { f32 = x; } + + /** Return true if the event contains the named 32bit field, and return the field + in value (if value is non-null). If there is no matching named field, return false + and ignore the value parameter. + */ + bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); } + /** Return true if the event contains the named SkScalar field, and return the field + in value (if value is non-null). If there is no matching named field, return false + and ignore the value parameter. + */ + bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); } + /** Return true if the event contains the named SkScalar field, and return the fields + in value[] (if value is non-null), and return the number of SkScalars in count (if count is non-null). + If there is no matching named field, return false and ignore the value and count parameters. + */ + const SkScalar* findScalars(const char name[], int* count, SkScalar values[] = NULL) const { return fMeta.findScalars(name, count, values); } + /** Return the value of the named string field, or if no matching named field exists, return null. + */ + const char* findString(const char name[]) const { return fMeta.findString(name); } + /** Return true if the event contains the named pointer field, and return the field + in value (if value is non-null). If there is no matching named field, return false + and ignore the value parameter. + */ + bool findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); } + bool findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); } + const void* findData(const char name[], size_t* byteCount = NULL) const { + return fMeta.findData(name, byteCount); + } + + /** Returns true if ethe event contains the named 32bit field, and if it equals the specified value */ + bool hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); } + /** Returns true if ethe event contains the named SkScalar field, and if it equals the specified value */ + bool hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); } + /** Returns true if ethe event contains the named string field, and if it equals (using strcmp) the specified value */ + bool hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); } + /** Returns true if ethe event contains the named pointer field, and if it equals the specified value */ + bool hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); } + bool hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); } + bool hasData(const char name[], const void* data, size_t byteCount) const { + return fMeta.hasData(name, data, byteCount); + } + + /** Add/replace the named 32bit field to the event. In XML use the subelement <data name=... s32=... /> */ + void setS32(const char name[], int32_t value) { fMeta.setS32(name, value); } + /** Add/replace the named SkScalar field to the event. In XML use the subelement <data name=... scalar=... /> */ + void setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); } + /** Add/replace the named SkScalar[] field to the event. */ + SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL) { return fMeta.setScalars(name, count, values); } + /** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */ + void setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); } + /** Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */ + void setString(const char name[], const char value[]) { fMeta.setString(name, value); } + /** Add/replace the named pointer field to the event. There is no XML equivalent for this call */ + void setPtr(const char name[], void* value) { fMeta.setPtr(name, value); } + void setBool(const char name[], bool value) { fMeta.setBool(name, value); } + void setData(const char name[], const void* data, size_t byteCount) { + fMeta.setData(name, data, byteCount); + } + + /** Return the underlying metadata object */ + SkMetaData& getMetaData() { return fMeta; } + /** Return the underlying metadata object */ + const SkMetaData& getMetaData() const { return fMeta; } + + /** Call this to initialize the event from the specified XML node */ + void inflate(const SkDOM&, const SkDOM::Node*); + + SkDEBUGCODE(void dump(const char title[] = NULL);) + + /////////////////////////////////////////////////////////////////////////// + + /** + * Post to the event queue using the event's targetID or target-proc. + * + * The event must be dynamically allocated, as ownership is transferred to + * the event queue. It cannot be allocated on the stack or in a global. + */ + void post() { + return this->postDelay(0); + } + + /** + * Post to the event queue using the event's targetID or target-proc and + * the specifed millisecond delay. + * + * The event must be dynamically allocated, as ownership is transferred to + * the event queue. It cannot be allocated on the stack or in a global. + */ + void postDelay(SkMSec delay); + + /** + * Post to the event queue using the event's targetID or target-proc. + * The event will be delivered no sooner than the specified millisecond + * time, as measured by SkTime::GetMSecs(). + * + * The event must be dynamically allocated, as ownership is transferred to + * the event queue. It cannot be allocated on the stack or in a global. + */ + void postTime(SkMSec time); + + /////////////////////////////////////////////// + /** Porting layer must call these functions **/ + /////////////////////////////////////////////// + + /** Global initialization function for the SkEvent system. Should be called exactly + once before any other event method is called, and should be called after the + call to SkGraphics::Init(). + */ + static void Init(); + /** Global cleanup function for the SkEvent system. Should be called exactly once after + all event methods have been called, and should be called before calling SkGraphics::Term(). + */ + static void Term(); + + /** Call this to process one event from the queue. If it returns true, there are more events + to process. + */ + static bool ProcessEvent(); + /** Call this whenever the requested timer has expired (requested by a call to SetQueueTimer). + It will post any delayed events whose time as "expired" onto the event queue. + It may also call SignalQueueTimer() and SignalNonEmptyQueue(). + */ + static void ServiceQueueTimer(); + + /** Return the number of queued events. note that this value may be obsolete + upon return, since another thread may have called ProcessEvent() or + Post() after the count was made. + */ + static int CountEventsOnQueue(); + + //////////////////////////////////////////////////// + /** Porting layer must implement these functions **/ + //////////////////////////////////////////////////// + + /** Called whenever an SkEvent is posted to an empty queue, so that the OS + can be told to later call Dequeue(). + */ + static void SignalNonEmptyQueue(); + /** Called whenever the delay until the next delayed event changes. If zero is + passed, then there are no more queued delay events. + */ + static void SignalQueueTimer(SkMSec delay); + +#if defined(SK_BUILD_FOR_WIN) + static bool WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +#endif + +private: + SkMetaData fMeta; + mutable char* fType; // may be characters with low bit set to know that it is not a pointer + uint32_t f32; + + // 'there can be only one' (non-zero) between target-id and target-proc + SkEventSinkID fTargetID; + Proc fTargetProc; + + // these are for our implementation of the event queue + SkMSec fTime; + SkEvent* fNextEvent; // either in the delay or normal event queue + + void initialize(const char* type, size_t typeLen, SkEventSinkID); + + static bool Enqueue(SkEvent* evt); + static SkMSec EnqueueTime(SkEvent* evt, SkMSec time); + static SkEvent* Dequeue(); + static bool QHasEvents(); +}; + +#endif diff --git a/views/SkEventSink.h b/views/SkEventSink.h new file mode 100644 index 0000000..01d4f7a --- /dev/null +++ b/views/SkEventSink.h @@ -0,0 +1,112 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkEventSink_DEFINED +#define SkEventSink_DEFINED + +#include "SkRefCnt.h" +#include "SkEvent.h" + +struct SkTagList; + +/** \class SkEventSink + + SkEventSink is the base class for all objects that receive SkEvents. +*/ +class SkEventSink : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkEventSink) + + SkEventSink(); + virtual ~SkEventSink(); + + /** + * Returns this eventsink's unique ID. Use this to post SkEvents to + * this eventsink. + */ + SkEventSinkID getSinkID() const { return fID; } + + /** + * Call this to pass an event to this object for processing. Returns true if the + * event was handled. + */ + bool doEvent(const SkEvent&); + + /** Returns true if the sink (or one of its subclasses) understands the event as a query. + If so, the sink may modify the event to communicate its "answer". + */ + bool doQuery(SkEvent* query); + + /** + * Add sinkID to the list of listeners, to receive events from calls to sendToListeners() + * and postToListeners(). If sinkID already exists in the listener list, no change is made. + */ + void addListenerID(SkEventSinkID sinkID); + + /** + * Copy listeners from one event sink to another, typically from parent to child. + * @param from the event sink to copy the listeners from + */ + void copyListeners(const SkEventSink& from); + + /** + * Remove sinkID from the list of listeners. If sinkID does not appear in the list, + * no change is made. + */ + void removeListenerID(SkEventSinkID); + + /** + * Returns true if there are 1 or more listeners attached to this eventsink + */ + bool hasListeners() const; + + /** + * Posts a copy of evt to each of the eventsinks in the lisener list. + * This ignores the targetID and target proc in evt. + */ + void postToListeners(const SkEvent& evt, SkMSec delay = 0); + + enum EventResult { + kHandled_EventResult, //!< the eventsink returned true from its doEvent method + kNotHandled_EventResult, //!< the eventsink returned false from its doEvent method + kSinkNotFound_EventResult //!< no matching eventsink was found for the event's getSink(). + }; + + /** + * DoEvent handles dispatching the event to its target ID or proc. + */ + static EventResult DoEvent(const SkEvent&); + + /** + * Returns the matching eventsink, or null if not found + */ + static SkEventSink* FindSink(SkEventSinkID); + +protected: + /** Override this to handle events in your subclass. Be sure to call the inherited version + for events that you don't handle. + */ + virtual bool onEvent(const SkEvent&); + virtual bool onQuery(SkEvent*); + + SkTagList* findTagList(U8CPU tag) const; + void addTagList(SkTagList*); + void removeTagList(U8CPU tag); + +private: + SkEventSinkID fID; + SkTagList* fTagHead; + + // for our private link-list + SkEventSink* fNextSink; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/views/SkKey.h b/views/SkKey.h new file mode 100644 index 0000000..036e2c3 --- /dev/null +++ b/views/SkKey.h @@ -0,0 +1,62 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkKey_DEFINED +#define SkKey_DEFINED + +#include "SkTypes.h" + +enum SkKey { + //reordering these to match android.app.KeyEvent + kNONE_SkKey, //corresponds to android's UNKNOWN + + kLeftSoftKey_SkKey, + kRightSoftKey_SkKey, + + kHome_SkKey, //!< the home key - added to match android + kBack_SkKey, //!< (CLR) + kSend_SkKey, //!< the green (talk) key + kEnd_SkKey, //!< the red key + + k0_SkKey, + k1_SkKey, + k2_SkKey, + k3_SkKey, + k4_SkKey, + k5_SkKey, + k6_SkKey, + k7_SkKey, + k8_SkKey, + k9_SkKey, + kStar_SkKey, //!< the * key + kHash_SkKey, //!< the # key + + kUp_SkKey, + kDown_SkKey, + kLeft_SkKey, + kRight_SkKey, + + kOK_SkKey, //!< the center key + + kVolUp_SkKey, //!< volume up - match android + kVolDown_SkKey, //!< volume down - same + kPower_SkKey, //!< power button - same + kCamera_SkKey, //!< camera - same + + kSkKeyCount +}; + +enum SkModifierKeys { + kShift_SkModifierKey = 1 << 0, + kControl_SkModifierKey = 1 << 1, + kOption_SkModifierKey = 1 << 2, // same as ALT + kCommand_SkModifierKey = 1 << 3, +}; + +#endif diff --git a/views/SkOSMenu.h b/views/SkOSMenu.h new file mode 100644 index 0000000..8801a52 --- /dev/null +++ b/views/SkOSMenu.h @@ -0,0 +1,182 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkOSMenu_DEFINED +#define SkOSMenu_DEFINED + +#include "SkEvent.h" +#include "SkTDArray.h" + +class SkOSMenu { +public: + explicit SkOSMenu(const char title[] = ""); + ~SkOSMenu(); + + /** + * Each of these (except action) has an associated value, which is stored in + * the event payload for the item. + * Each type has a specific type for its value... + * Action : none + * List : int (selected index) + * Segmented : int (selected index) + * Slider : float + * Switch : bool + * TextField : string + * TriState : TriState + * Custom : custom object/value + */ + enum Type { + kAction_Type, + kList_Type, + kSlider_Type, + kSwitch_Type, + kTriState_Type, + kTextField_Type, + kCustom_Type + }; + + enum TriState { + kMixedState = -1, + kOffState = 0, + kOnState = 1 + }; + + class Item { + public: + /** + * Auto increments a global to generate an unique ID for each new item + * Note: Thread safe + */ + Item(const char label[], SkOSMenu::Type type, const char slotName[], + SkEvent* evt); + ~Item() { delete fEvent; } + + SkEvent* getEvent() const { return fEvent; } + int getID() const { return fID; } + const char* getLabel() const { return fLabel.c_str(); } + const char* getSlotName() const { return fSlotName.c_str(); } + Type getType() const { return fType; } + void setKeyEquivalent(SkUnichar key) { fKey = key; } + SkUnichar getKeyEquivalent() const { return fKey; } + + /** + * Helper functions for predefined types + */ + void setBool(bool value) const; //For Switch + void setScalar(SkScalar value) const; //For Slider + void setInt(int value) const; //For List + void setTriState(TriState value) const; //For Tristate + void setString(const char value[]) const; //For TextField + + /** + * Post event associated with the menu item to target, any changes to + * the associated event must be made prior to calling this method + */ + void postEvent() const { (new SkEvent(*(fEvent)))->post(); } + + private: + int fID; + SkEvent* fEvent; + SkString fLabel; + SkString fSlotName; + Type fType; + SkUnichar fKey; + }; + + void reset(); + const char* getTitle() const { return fTitle.c_str(); } + void setTitle (const char title[]) { fTitle.set(title); } + int getCount() const { return fItems.count(); } + const Item* getItemByID(int itemID) const; + void getItems(const Item* items[]) const; + + /** + * Assign key to the menu item with itemID, will do nothing if there's no + * item with the id given + */ + void assignKeyEquivalentToItem(int itemID, SkUnichar key); + /** + * Call this in a SkView's onHandleChar to trigger any menu items with the + * given key equivalent. If such an item is found, the method will return + * true and its corresponding event will be triggered (default behavior + * defined for switches(toggling), tristates(cycle), and lists(cycle), + * for anything else, the event attached is posted without state changes) + * If no menu item can be matched with the key, false will be returned + */ + bool handleKeyEquivalent(SkUnichar key); + + /** + * The following functions append new items to the menu and returns their + * associated unique id, which can be used to by the client to refer to + * the menu item created and change its state. slotName specifies the string + * identifier of any state/value to be returned in the item's SkEvent object + * NOTE: evt must be dynamically allocated + */ + int appendItem(const char label[], Type type, const char slotName[], + SkEvent* evt); + + /** + * Create predefined items with the given parameters. To be used with the + * other helper functions below to retrive/update state information. + * Note: the helper functions below assume that slotName is UNIQUE for all + * menu items of the same type since it's used to identify the event + */ + int appendAction(const char label[], SkEventSinkID target); + int appendList(const char label[], const char slotName[], + SkEventSinkID target, int defaultIndex, const char[] ...); + int appendSlider(const char label[], const char slotName[], + SkEventSinkID target, SkScalar min, SkScalar max, + SkScalar defaultValue); + int appendSwitch(const char label[], const char slotName[], + SkEventSinkID target, bool defaultState = false); + int appendTriState(const char label[], const char slotName[], + SkEventSinkID target, TriState defaultState = kOffState); + int appendTextField(const char label[], const char slotName[], + SkEventSinkID target, const char placeholder[] = ""); + + + /** + * Helper functions to retrieve information other than the stored value for + * some predefined types + */ + static bool FindListItemCount(const SkEvent& evt, int* count); + /** + * Ensure that the items array can store n SkStrings where n is the count + * extracted using FindListItemCount + */ + static bool FindListItems(const SkEvent& evt, SkString items[]); + static bool FindSliderMin(const SkEvent& evt, SkScalar* min); + static bool FindSliderMax(const SkEvent& evt, SkScalar* max); + + /** + * Returns true if an action with the given label is found, false otherwise + */ + static bool FindAction(const SkEvent& evt, const char label[]); + /** + * The following helper functions will return true if evt is generated from + * a predefined item type and retrieve the corresponding state information. + * They will return false and leave value unchanged if there's a type + * mismatch or slotName is incorrect + */ + static bool FindListIndex(const SkEvent& evt, const char slotName[], int* value); + static bool FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value); + static bool FindSwitchState(const SkEvent& evt, const char slotName[], bool* value); + static bool FindTriState(const SkEvent& evt, const char slotName[], TriState* value); + static bool FindText(const SkEvent& evt, const char slotName[], SkString* value); + +private: + SkString fTitle; + SkTDArray<Item*> fItems; + + // illegal + SkOSMenu(const SkOSMenu&); + SkOSMenu& operator=(const SkOSMenu&); +}; + +#endif diff --git a/views/SkOSWindow_Android.h b/views/SkOSWindow_Android.h new file mode 100644 index 0000000..77c156c --- /dev/null +++ b/views/SkOSWindow_Android.h @@ -0,0 +1,53 @@ + +/* + * Copyright 2011 Skia + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkOSWindow_Android_DEFINED +#define SkOSWindow_Android_DEFINED + +#include "SkWindow.h" + +class SkIRect; + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void*) {} + ~SkOSWindow() {} + + enum SkBackEndTypes { + kNone_BackEndType, + kNativeGL_BackEndType, + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + bool attach(SkBackEndTypes /* attachType */, int /* msaaSampleCount */, AttachmentInfo* info) { + // These are the values requested in SkiaSampleView.java + info->fSampleCount = 0; + info->fStencilBits = 8; + return true; + } + void detach() {} + void present() {} + + virtual void onPDFSaved(const char title[], const char desc[], + const char path[]); + +protected: + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + virtual void onSetTitle(const char title[]); + +private: + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_Mac.h b/views/SkOSWindow_Mac.h new file mode 100644 index 0000000..5dea2fc --- /dev/null +++ b/views/SkOSWindow_Mac.h @@ -0,0 +1,58 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOSWindow_MacCocoa_DEFINED +#define SkOSWindow_MacCocoa_DEFINED + +#include "SkWindow.h" + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void* hwnd); + ~SkOSWindow(); + void* getHWND() const { return fHWND; } + + virtual bool onDispatchClick(int x, int y, Click::State state, + void* owner, unsigned modi); + enum SkBackEndTypes { + kNone_BackEndType, +#if SK_SUPPORT_GPU + kNativeGL_BackEndType, +#endif + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + void detach(); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + void present(); + +protected: + // overrides from SkEventSink + virtual bool onEvent(const SkEvent& evt); + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + // overrides from SkView + virtual void onAddMenu(const SkOSMenu*); + virtual void onUpdateMenu(const SkOSMenu*); + virtual void onSetTitle(const char[]); + +private: + void* fHWND; + bool fInvalEventIsPending; + void* fNotifier; +#if SK_SUPPORT_GPU + void* fGLContext; +#endif + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_NaCl.h b/views/SkOSWindow_NaCl.h new file mode 100644 index 0000000..2296023 --- /dev/null +++ b/views/SkOSWindow_NaCl.h @@ -0,0 +1,52 @@ + +/* + * Copyright 2012 Skia + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkOSWindow_NaCl_DEFINED +#define SkOSWindow_NaCl_DEFINED + +#include "SkWindow.h" + +class SkIRect; + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void*) {} + ~SkOSWindow() {} + + enum SkBackEndTypes { + kNone_BackEndType, + kNativeGL_BackEndType, + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + bool attach(SkBackEndTypes /* attachType */, int /* msaaSampleCount */, AttachmentInfo* info) { + info->fSampleCount = 0; + info->fStencilBits = 0; + return true; + } + void detach() {} + void present() {} + + virtual void onPDFSaved(const char title[], const char desc[], + const char path[]); + +protected: + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + virtual void onSetTitle(const char title[]); + +private: + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_SDL.h b/views/SkOSWindow_SDL.h new file mode 100644 index 0000000..e6b59e6 --- /dev/null +++ b/views/SkOSWindow_SDL.h @@ -0,0 +1,44 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkOSWindow_SDL_DEFINED +#define SkOSWindow_SDL_DEFINED + +#include "SDL.h" +#include "SkWindow.h" + +class SkGLCanvas; + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void* screen); + virtual ~SkOSWindow(); + + static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay); + + void handleSDLEvent(const SDL_Event& event); + +protected: + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + // overrides from SkView + virtual void onAddMenu(const SkOSMenu*); + virtual void onSetTitle(const char[]); + +private: + SDL_Surface* fScreen; + SDL_Surface* fSurface; + SkGLCanvas* fGLCanvas; + + void doDraw(); + + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_Unix.h b/views/SkOSWindow_Unix.h new file mode 100644 index 0000000..8a55ef4 --- /dev/null +++ b/views/SkOSWindow_Unix.h @@ -0,0 +1,82 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOSWindow_Unix_DEFINED +#define SkOSWindow_Unix_DEFINED + +#include <GL/glx.h> +#include <X11/Xlib.h> + +#include "SkWindow.h" + +class SkEvent; + +struct SkUnixWindow { + Display* fDisplay; + Window fWin; + size_t fOSWin; + GC fGc; + GLXContext fGLContext; +}; + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void*); + ~SkOSWindow(); + + void* getHWND() const { return (void*)fUnixWindow.fWin; } + void* getDisplay() const { return (void*)fUnixWindow.fDisplay; } + void* getUnixWindow() const { return (void*)&fUnixWindow; } + void loop(); + + enum SkBackEndTypes { + kNone_BackEndType, + kNativeGL_BackEndType, + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + void detach(); + void present(); + + int getMSAASampleCount() const { return fMSAASampleCount; } + + //static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay); + +protected: + // Overridden from from SkWindow: + virtual void onSetTitle(const char title[]) SK_OVERRIDE; + +private: + enum NextXEventResult { + kContinue_NextXEventResult, + kQuitRequest_NextXEventResult, + kPaintRequest_NextXEventResult + }; + + NextXEventResult nextXEvent(); + void doPaint(); + void mapWindowAndWait(); + + void closeWindow(); + void initWindow(int newMSAASampleCount, AttachmentInfo* info); + + SkUnixWindow fUnixWindow; + + // Needed for GL + XVisualInfo* fVi; + // we recreate the underlying xwindow if this changes + int fMSAASampleCount; + + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_Win.h b/views/SkOSWindow_Win.h new file mode 100644 index 0000000..6b5977c --- /dev/null +++ b/views/SkOSWindow_Win.h @@ -0,0 +1,101 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkOSWindow_Win_DEFINED +#define SkOSWindow_Win_DEFINED + +#include "SkWindow.h" + +#if SK_ANGLE +#include "EGL/egl.h" +#endif + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void* hwnd); + virtual ~SkOSWindow(); + + void* getHWND() const { return fHWND; } + void setSize(int width, int height); + void updateSize(); + + static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay); + + enum SkBackEndTypes { + kNone_BackEndType, +#if SK_SUPPORT_GPU + kNativeGL_BackEndType, +#if SK_ANGLE + kANGLE_BackEndType, +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + void detach(); + void present(); + + bool wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + static bool QuitOnDeactivate(HWND hWnd); + + enum { + SK_WM_SkEvent = WM_APP + 1000, + SK_WM_SkTimerID = 0xFFFF // just need a non-zero value + }; + +protected: + virtual bool quitOnDeactivate() { return true; } + + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + // overrides from SkView + virtual void onAddMenu(const SkOSMenu*); + + virtual void onSetTitle(const char title[]); + +private: + void* fHWND; + + void doPaint(void* ctx); + +#if SK_SUPPORT_GPU + void* fHGLRC; +#if SK_ANGLE + EGLDisplay fDisplay; + EGLContext fContext; + EGLSurface fSurface; + EGLConfig fConfig; +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + + HMENU fMBar; + + SkBackEndTypes fAttached; + +#if SK_SUPPORT_GPU + bool attachGL(int msaaSampleCount, AttachmentInfo* info); + void detachGL(); + void presentGL(); + +#if SK_ANGLE + bool attachANGLE(int msaaSampleCount, AttachmentInfo* info); + void detachANGLE(); + void presentANGLE(); +#endif // SK_ANGLE +#endif // SK_SUPPORT_GPU + + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkOSWindow_iOS.h b/views/SkOSWindow_iOS.h new file mode 100755 index 0000000..1984900 --- /dev/null +++ b/views/SkOSWindow_iOS.h @@ -0,0 +1,50 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkOSWindow_iOS_DEFINED +#define SkOSWindow_iOS_DEFINED + +#include "SkWindow.h" + +class SkOSWindow : public SkWindow { +public: + SkOSWindow(void* hwnd); + ~SkOSWindow(); + void* getHWND() const { return fHWND; } + + enum SkBackEndTypes { + kNone_BackEndType, + kNativeGL_BackEndType, + }; + + struct AttachmentInfo { + int fSampleCount; + int fStencilBits; + }; + + void detach(); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + void present(); + +protected: + // overrides from SkEventSink + virtual bool onEvent(const SkEvent& evt); + // overrides from SkWindow + virtual void onHandleInval(const SkIRect&); + // overrides from SkView + virtual void onAddMenu(const SkOSMenu*); + virtual void onUpdateMenu(SkOSMenu*); + virtual void onSetTitle(const char[]); + +private: + void* fHWND; + bool fInvalEventIsPending; + void* fNotifier; + typedef SkWindow INHERITED; +}; + +#endif diff --git a/views/SkStackViewLayout.h b/views/SkStackViewLayout.h new file mode 100644 index 0000000..f2a7cf0 --- /dev/null +++ b/views/SkStackViewLayout.h @@ -0,0 +1,88 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkStackViewLayout_DEFINED +#define SkStackViewLayout_DEFINED + +#include "SkView.h" + +class SkStackViewLayout : public SkView::Layout { +public: + SkStackViewLayout(); + + enum Orient { + kHorizontal_Orient, + kVertical_Orient, + + kOrientCount + }; + Orient getOrient() const { return (Orient)fOrient; } + void setOrient(Orient); + + void getMargin(SkRect*) const; + void setMargin(const SkRect&); + + SkScalar getSpacer() const { return fSpacer; } + void setSpacer(SkScalar); + + /** Controls the posititioning in the same direction as the orientation + */ + enum Pack { + kStart_Pack, + kCenter_Pack, + kEnd_Pack, + + kPackCount + }; + Pack getPack() const { return (Pack)fPack; } + void setPack(Pack); + + /** Controls the posititioning at right angles to the orientation + */ + enum Align { + kStart_Align, + kCenter_Align, + kEnd_Align, + kStretch_Align, + + kAlignCount + }; + Align getAlign() const { return (Align)fAlign; } + void setAlign(Align); + + bool getRound() const { return SkToBool(fRound); } + void setRound(bool); + +protected: + virtual void onLayoutChildren(SkView* parent); + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + +private: + SkRect fMargin; + SkScalar fSpacer; + uint8_t fOrient, fPack, fAlign, fRound; +}; + +class SkFillViewLayout : public SkView::Layout { +public: + SkFillViewLayout(); + void getMargin(SkRect*) const; + void setMargin(const SkRect&); + +protected: + // overrides; + virtual void onLayoutChildren(SkView* parent); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + +private: + SkRect fMargin; + typedef SkView::Layout INHERITED; +}; + +#endif diff --git a/views/SkSystemEventTypes.h b/views/SkSystemEventTypes.h new file mode 100644 index 0000000..bb2b5d5 --- /dev/null +++ b/views/SkSystemEventTypes.h @@ -0,0 +1,25 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkSystemEventTypes_DEFINED +#define SkSystemEventTypes_DEFINED + +/* + The goal of these strings is two-fold: + 1) make funny strings (containing at least one char < 32) to avoid colliding with "user" strings + 2) keep them <= 4 bytes, so we can avoid an allocation in SkEvent::setType() +*/ +#define SK_EventType_Delay "\xd" "lay" +#define SK_EventType_Inval "nv" "\xa" "l" +#define SK_EventType_Key "key" "\x1" +#define SK_EventType_OnEnd "on" "\xe" "n" +#define SK_EventType_Unichar "\xc" "har" +#define SK_EventType_KeyUp "key" "\xf" + +#endif diff --git a/views/SkTextBox.h b/views/SkTextBox.h new file mode 100644 index 0000000..e217076 --- /dev/null +++ b/views/SkTextBox.h @@ -0,0 +1,77 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTextBox_DEFINED +#define SkTextBox_DEFINED + +#include "SkCanvas.h" + +/** \class SkTextBox + + SkTextBox is a helper class for drawing 1 or more lines of text + within a rectangle. The textbox is positioned and clipped by its Frame. + The Margin rectangle controls where the text is drawn relative to + the Frame. Line-breaks occur inside the Margin rectangle. + + Spacing is a linear equation used to compute the distance between lines + of text. Spacing consists of two scalars: mul and add, and the spacing + between lines is computed as: spacing = paint.getTextSize() * mul + add +*/ +class SkTextBox { +public: + SkTextBox(); + + enum Mode { + kOneLine_Mode, + kLineBreak_Mode, + + kModeCount + }; + Mode getMode() const { return (Mode)fMode; } + void setMode(Mode); + + enum SpacingAlign { + kStart_SpacingAlign, + kCenter_SpacingAlign, + kEnd_SpacingAlign, + + kSpacingAlignCount + }; + SpacingAlign getSpacingAlign() const { return (SpacingAlign)fSpacingAlign; } + void setSpacingAlign(SpacingAlign); + + void getBox(SkRect*) const; + void setBox(const SkRect&); + void setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); + + void getSpacing(SkScalar* mul, SkScalar* add) const; + void setSpacing(SkScalar mul, SkScalar add); + + void draw(SkCanvas*, const char text[], size_t len, const SkPaint&); + + void setText(const char text[], size_t len, const SkPaint&); + void draw(SkCanvas*); + int countLines() const; + SkScalar getTextHeight() const; + +private: + SkRect fBox; + SkScalar fSpacingMul, fSpacingAdd; + uint8_t fMode, fSpacingAlign; + const char* fText; + size_t fLen; + const SkPaint* fPaint; +}; + +class SkTextLineBreaker { +public: + static int CountLines(const char text[], size_t len, const SkPaint&, SkScalar width); +}; + +#endif diff --git a/views/SkTouchGesture.h b/views/SkTouchGesture.h new file mode 100644 index 0000000..3a0cfce --- /dev/null +++ b/views/SkTouchGesture.h @@ -0,0 +1,77 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkTouchGesture_DEFINED +#define SkTouchGesture_DEFINED + +#include "SkTDArray.h" +#include "SkMatrix.h" + +struct SkFlingState { + SkFlingState() : fActive(false) {} + + bool isActive() const { return fActive; } + void stop() { fActive = false; } + + void reset(float sx, float sy); + bool evaluateMatrix(SkMatrix* matrix); + +private: + SkPoint fDirection; + SkScalar fSpeed0; + double fTime0; + bool fActive; +}; + +class SkTouchGesture { +public: + SkTouchGesture(); + ~SkTouchGesture(); + + void touchBegin(void* owner, float x, float y); + void touchMoved(void* owner, float x, float y); + void touchEnd(void* owner); + void reset(); + + bool isActive() { return fFlinger.isActive(); } + void stop() { fFlinger.stop(); } + + const SkMatrix& localM(); + const SkMatrix& globalM() const { return fGlobalM; } + +private: + enum State { + kEmpty_State, + kTranslate_State, + kZoom_State, + }; + + struct Rec { + void* fOwner; + float fStartX, fStartY; + float fPrevX, fPrevY; + float fLastX, fLastY; + SkMSec fPrevT, fLastT; + }; + SkTDArray<Rec> fTouches; + + State fState; + SkMatrix fLocalM, fGlobalM; + SkFlingState fFlinger; + SkMSec fLastUpT; + SkPoint fLastUpP; + + + void flushLocalM(); + int findRec(void* owner) const; + void appendNewRec(void* owner, float x, float y); + float computePinch(const Rec&, const Rec&); + float limitTotalZoom(float scale) const; + bool handleDblTap(float, float); +}; + +#endif diff --git a/views/SkView.h b/views/SkView.h new file mode 100644 index 0000000..d03c741 --- /dev/null +++ b/views/SkView.h @@ -0,0 +1,405 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkView_DEFINED +#define SkView_DEFINED + +#include "SkEventSink.h" +#include "SkRect.h" +#include "SkDOM.h" +#include "SkTDict.h" +#include "SkMatrix.h" +#include "SkMetaData.h" + +class SkCanvas; +class SkLayerView; + +/** \class SkView + + SkView is the base class for screen management. All widgets and controls inherit + from SkView. +*/ +class SkView : public SkEventSink { +public: + enum Flag_Shift { + kVisible_Shift, + kEnabled_Shift, + kFocusable_Shift, + kFlexH_Shift, + kFlexV_Shift, + kNoClip_Shift, + + kFlagShiftCount + }; + enum Flag_Mask { + kVisible_Mask = 1 << kVisible_Shift, //!< set if the view is visible + kEnabled_Mask = 1 << kEnabled_Shift, //!< set if the view is enabled + kFocusable_Mask = 1 << kFocusable_Shift, //!< set if the view can receive focus + kFlexH_Mask = 1 << kFlexH_Shift, //!< set if the view's width is stretchable + kFlexV_Mask = 1 << kFlexV_Shift, //!< set if the view's height is stretchable + kNoClip_Mask = 1 << kNoClip_Shift, //!< set if the view is not clipped to its bounds + + kAllFlagMasks = (uint32_t)(0 - 1) >> (32 - kFlagShiftCount) + }; + + SkView(uint32_t flags = 0); + virtual ~SkView(); + + /** Return the flags associated with the view + */ + uint32_t getFlags() const { return fFlags; } + /** Set the flags associated with the view + */ + void setFlags(uint32_t flags); + + /** Helper that returns non-zero if the kVisible_Mask bit is set in the view's flags + */ + int isVisible() const { return fFlags & kVisible_Mask; } + int isEnabled() const { return fFlags & kEnabled_Mask; } + int isFocusable() const { return fFlags & kFocusable_Mask; } + int isClipToBounds() const { return !(fFlags & kNoClip_Mask); } + /** Helper to set/clear the view's kVisible_Mask flag */ + void setVisibleP(bool); + void setEnabledP(bool); + void setFocusableP(bool); + void setClipToBounds(bool); + + /** Return the view's width */ + SkScalar width() const { return fWidth; } + /** Return the view's height */ + SkScalar height() const { return fHeight; } + /** Set the view's width and height. These must both be >= 0. This does not affect the view's loc */ + void setSize(SkScalar width, SkScalar height); + void setSize(const SkPoint& size) { this->setSize(size.fX, size.fY); } + void setWidth(SkScalar width) { this->setSize(width, fHeight); } + void setHeight(SkScalar height) { this->setSize(fWidth, height); } + /** Return a rectangle set to [0, 0, width, height] */ + void getLocalBounds(SkRect* bounds) const; + + /** Loc - the view's offset with respect to its parent in its view hiearchy. + NOTE: For more complex transforms, use Local Matrix. The tranformations + are applied in the following order: + canvas->translate(fLoc.fX, fLoc.fY); + canvas->concat(fMatrix); + */ + /** Return the view's left edge */ + SkScalar locX() const { return fLoc.fX; } + /** Return the view's top edge */ + SkScalar locY() const { return fLoc.fY; } + /** Set the view's left and top edge. This does not affect the view's size */ + void setLoc(SkScalar x, SkScalar y); + void setLoc(const SkPoint& loc) { this->setLoc(loc.fX, loc.fY); } + void setLocX(SkScalar x) { this->setLoc(x, fLoc.fY); } + void setLocY(SkScalar y) { this->setLoc(fLoc.fX, y); } + + /** Local Matrix - matrix used to tranform the view with respect to its + parent in its view hiearchy. Use setLocalMatrix to apply matrix + transformations to the current view and in turn affect its children. + NOTE: For simple offsets, use Loc. The transformations are applied in + the following order: + canvas->translate(fLoc.fX, fLoc.fY); + canvas->concat(fMatrix); + */ + const SkMatrix& getLocalMatrix() const { return fMatrix; } + void setLocalMatrix(const SkMatrix& matrix); + + /** Offset (move) the view by the specified dx and dy. This does not affect the view's size */ + void offset(SkScalar dx, SkScalar dy); + + /** Call this to have the view draw into the specified canvas. */ + virtual void draw(SkCanvas* canvas); + + /** Call this to invalidate part of all of a view, requesting that the view's + draw method be called. The rectangle parameter specifies the part of the view + that should be redrawn. If it is null, it specifies the entire view bounds. + */ + void inval(SkRect* rectOrNull); + + // Focus management + + SkView* getFocusView() const; + bool hasFocus() const; + + enum FocusDirection { + kNext_FocusDirection, + kPrev_FocusDirection, + + kFocusDirectionCount + }; + bool acceptFocus(); + SkView* moveFocus(FocusDirection); + + // Click handling + + class Click { + public: + Click(SkView* target); + virtual ~Click(); + + const char* getType() const { return fType; } + bool isType(const char type[]) const; + void setType(const char type[]); // does NOT make a copy of the string + void copyType(const char type[]); // makes a copy of the string + + enum State { + kDown_State, + kMoved_State, + kUp_State + }; + SkPoint fOrig, fPrev, fCurr; + SkIPoint fIOrig, fIPrev, fICurr; + State fState; + void* fOwner; + unsigned fModifierKeys; + + SkMetaData fMeta; + private: + SkEventSinkID fTargetID; + char* fType; + bool fWeOwnTheType; + + void resetType(); + + friend class SkView; + }; + Click* findClickHandler(SkScalar x, SkScalar y, unsigned modifierKeys); + + static void DoClickDown(Click*, int x, int y, unsigned modi); + static void DoClickMoved(Click*, int x, int y, unsigned modi); + static void DoClickUp(Click*, int x, int y, unsigned modi); + + /** Send the event to the view's parent, and its parent etc. until one of them + returns true from its onEvent call. This view is returned. If no parent handles + the event, null is returned. + */ + SkView* sendEventToParents(const SkEvent&); + /** Send the query to the view's parent, and its parent etc. until one of them + returns true from its onQuery call. This view is returned. If no parent handles + the query, null is returned. + */ + SkView* sendQueryToParents(SkEvent*); + + // View hierarchy management + + /** Return the view's parent, or null if it has none. This does not affect the parent's reference count. */ + SkView* getParent() const { return fParent; } + SkView* attachChildToFront(SkView* child); + /** Attach the child view to this view, and increment the child's reference count. The child view is added + such that it will be drawn before all other child views. + The child view parameter is returned. + */ + SkView* attachChildToBack(SkView* child); + /** If the view has a parent, detach the view from its parent and decrement the view's reference count. + If the parent was the only owner of the view, this will cause the view to be deleted. + */ + void detachFromParent(); + /** Attach the child view to this view, and increment the child's reference count. The child view is added + such that it will be drawn after all other child views. + The child view parameter is returned. + */ + /** Detach all child views from this view. */ + void detachAllChildren(); + + /** Convert the specified point from global coordinates into view-local coordinates + * Return true on success; false on failure + */ + bool globalToLocal(SkPoint* pt) const { + if (NULL != pt) { + return this->globalToLocal(pt->fX, pt->fY, pt); + } + return true; // nothing to do so return true + } + /** Convert the specified x,y from global coordinates into view-local coordinates, returning + the answer in the local parameter. + */ + bool globalToLocal(SkScalar globalX, SkScalar globalY, SkPoint* local) const; + + /** \class F2BIter + + Iterator that will return each of this view's children, in + front-to-back order (the order used for clicking). The first + call to next() returns the front-most child view. When + next() returns null, there are no more child views. + */ + class F2BIter { + public: + F2BIter(const SkView* parent); + SkView* next(); + private: + SkView* fFirstChild, *fChild; + }; + + /** \class B2FIter + + Iterator that will return each of this view's children, in + back-to-front order (the order they are drawn). The first + call to next() returns the back-most child view. When + next() returns null, there are no more child views. + */ + class B2FIter { + public: + B2FIter(const SkView* parent); + SkView* next(); + private: + SkView* fFirstChild, *fChild; + }; + + /** \class Artist + + Install a subclass of this in a view (calling setArtist()), and then the + default implementation of that view's onDraw() will invoke this object + automatically. + */ + class Artist : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Artist) + + void draw(SkView*, SkCanvas*); + void inflate(const SkDOM&, const SkDOM::Node*); + protected: + virtual void onDraw(SkView*, SkCanvas*) = 0; + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + private: + typedef SkRefCnt INHERITED; + }; + /** Return the artist attached to this view (or null). The artist's reference + count is not affected. + */ + Artist* getArtist() const; + /** Attach the specified artist (or null) to the view, replacing any existing + artist. If the new artist is not null, its reference count is incremented. + The artist parameter is returned. + */ + Artist* setArtist(Artist* artist); + + /** \class Layout + + Install a subclass of this in a view (calling setLayout()), and then the + default implementation of that view's onLayoutChildren() will invoke + this object automatically. + */ + class Layout : public SkRefCnt { + public: + SK_DECLARE_INST_COUNT(Layout) + + void layoutChildren(SkView* parent); + void inflate(const SkDOM&, const SkDOM::Node*); + protected: + virtual void onLayoutChildren(SkView* parent) = 0; + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + private: + typedef SkRefCnt INHERITED; + }; + + /** Return the layout attached to this view (or null). The layout's reference + count is not affected. + */ + Layout* getLayout() const; + /** Attach the specified layout (or null) to the view, replacing any existing + layout. If the new layout is not null, its reference count is incremented. + The layout parameter is returned. + */ + Layout* setLayout(Layout*, bool invokeLayoutNow = true); + /** If a layout is attached to this view, call its layoutChildren() method + */ + void invokeLayout(); + + /** Call this to initialize this view based on the specified XML node + */ + void inflate(const SkDOM& dom, const SkDOM::Node* node); + /** After a view hierarchy is inflated, this may be called with a dictionary + containing pairs of <name, view*>, where the name string was the view's + "id" attribute when it was inflated. + + This will call the virtual onPostInflate for this view, and the recursively + call postInflate on all of the view's children. + */ + void postInflate(const SkTDict<SkView*>& ids); + + SkDEBUGCODE(void dump(bool recurse) const;) + +protected: + /** Override this to draw inside the view. Be sure to call the inherited version too */ + virtual void onDraw(SkCanvas*); + /** Override this to be notified when the view's size changes. Be sure to call the inherited version too */ + virtual void onSizeChange(); + /** Override this if you want to handle an inval request from this view or one of its children. + Tyically this is only overridden by the by the "window". If your subclass does handle the + request, return true so the request will not continue to propogate to the parent. + */ + virtual bool handleInval(const SkRect*); + //! called once before all of the children are drawn (or clipped/translated) + virtual SkCanvas* beforeChildren(SkCanvas* c) { return c; } + //! called once after all of the children are drawn (or clipped/translated) + virtual void afterChildren(SkCanvas* orig) {} + + //! called right before this child's onDraw is called + virtual void beforeChild(SkView* child, SkCanvas* canvas) {} + //! called right after this child's onDraw is called + virtual void afterChild(SkView* child, SkCanvas* canvas) {} + + /** Override this if you might handle the click + */ + virtual Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi); + /** Override this to decide if your children are targets for a click. + The default returns true, in which case your children views will be + candidates for onFindClickHandler. Returning false wil skip the children + and just call your onFindClickHandler. + */ + virtual bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi); + /** Override this to track clicks, returning true as long as you want to track + the pen/mouse. + */ + virtual bool onClick(Click*); + /** Override this to initialize your subclass from the XML node. Be sure to call the inherited version too */ + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + /** Override this if you want to perform post initialization work based on the ID dictionary built + during XML parsing. Be sure to call the inherited version too. + */ + virtual void onPostInflate(const SkTDict<SkView*>&); + +public: +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif + // default action is to inval the view + virtual void onFocusChange(bool gainFocusP); + +protected: + + // override these if you're acting as a layer/host + virtual bool onGetFocusView(SkView**) const { return false; } + virtual bool onSetFocusView(SkView*) { return false; } + +private: + SkScalar fWidth, fHeight; + SkMatrix fMatrix; + SkPoint fLoc; + SkView* fParent; + SkView* fFirstChild; + SkView* fNextSibling; + SkView* fPrevSibling; + uint8_t fFlags; + uint8_t fContainsFocus; + + friend class B2FIter; + friend class F2BIter; + + friend class SkLayerView; + + bool setFocusView(SkView* fvOrNull); + SkView* acceptFocus(FocusDirection); + void detachFromParent_NoLayout(); + /** Compute the matrix to transform view-local coordinates into global ones */ + void localToGlobal(SkMatrix* matrix) const; +}; + +#endif diff --git a/views/SkViewInflate.h b/views/SkViewInflate.h new file mode 100644 index 0000000..db3689a --- /dev/null +++ b/views/SkViewInflate.h @@ -0,0 +1,71 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkViewInflate_DEFINED +#define SkViewInflate_DEFINED + +#include "SkDOM.h" +#include "SkTDict.h" +#include "SkEvent.h" + +class SkView; + +class SkViewInflate { +public: + SkViewInflate(); + virtual ~SkViewInflate(); + + /** Return the tree of inflated views. If root is null, create the root element + as a view, otherwise assume root is that view, and just "inflate" it. + + Returns null if the tree cannot be built. + */ + SkView* inflate(const SkDOM& dom, const SkDOM::Node* node, SkView* root = NULL); + SkView* inflate(const char xml[], size_t len, SkView* root = NULL); + + /** Given an id attribute value, return the corresponding view, or null + if no match is found. + */ + SkView* findViewByID(const char id[]) const; + + SkDEBUGCODE(void dump() const;) + +protected: + /* Override this in your subclass to handle instantiating views + Call the inherited version for nodes you don't recognize. + + Do not call "inflate" on the view, just return it. This will + get called automatically after createView returns. + */ + virtual SkView* createView(const SkDOM& dom, const SkDOM::Node* node); + /** Base implementation calls view->inflate(dom, node). Subclasses may override this + to perform additional initializations to view, either before or after calling + the inherited version. + */ + virtual void inflateView(SkView* view, const SkDOM& dom, const SkDOM::Node* node); + +private: + enum { + kMinIDStrAlloc = 64 + }; + SkTDict<SkView*> fIDs; + + struct IDStr { + SkView* fView; + char* fStr; + }; + SkTDArray<IDStr> fListenTo, fBroadcastTo; + SkChunkAlloc fStrings; + + void addIDStr(SkTDArray<IDStr>* list, SkView*, const char* str); + + void rInflate(const SkDOM& dom, const SkDOM::Node* node, SkView* parent); +}; + +#endif diff --git a/views/SkWidget.h b/views/SkWidget.h new file mode 100644 index 0000000..115e9a4 --- /dev/null +++ b/views/SkWidget.h @@ -0,0 +1,412 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWidget_DEFINED +#define SkWidget_DEFINED + +#include "SkBitmap.h" +#include "SkDOM.h" +#include "SkPaint.h" +#include "SkString.h" +#include "SkTDArray.h" +#include "SkTextBox.h" +#include "SkView.h" + +class SkEvent; +class SkInterpolator; +class SkShader; + +//////////////////////////////////////////////////////////////////////////////// + +class SkWidget : public SkView { +public: + SkWidget(uint32_t flags = 0) : SkView(flags | kFocusable_Mask | kEnabled_Mask) {} + + /** Call this to post the widget's event to its listeners */ + void postWidgetEvent(); + + static void Init(); + static void Term(); +protected: + // override to add slots to an event before posting + virtual void prepareWidgetEvent(SkEvent*); + virtual void onEnabledChange(); + + // <event ...> to initialize the event from XML + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + +private: + SkEvent fEvent; + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkHasLabelWidget : public SkWidget { +public: + SkHasLabelWidget(uint32_t flags = 0) : SkWidget(flags) {} + + size_t getLabel(SkString* label = NULL) const; + size_t getLabel(char lable[] = NULL) const; + void setLabel(const SkString&); + void setLabel(const char label[]); + void setLabel(const char label[], size_t len); + +protected: + // called when the label changes + virtual void onLabelChange(); + + // overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + SkString fLabel; + typedef SkWidget INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkButtonWidget : public SkHasLabelWidget { +public: + SkButtonWidget(uint32_t flags = 0) : SkHasLabelWidget(flags), fState(kOff_State) {} + + enum State { + kOff_State, //!< XML: buttonState="off" + kOn_State, //!< XML: buttonState="on" + kUnknown_State //!< XML: buttonState="unknown" + }; + State getButtonState() const { return fState; } + void setButtonState(State); + +protected: + /** called when the label changes. default behavior is to inval the widget */ + virtual void onButtonStateChange(); + + // overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + State fState; + typedef SkHasLabelWidget INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkPushButtonWidget : public SkButtonWidget { +public: + SkPushButtonWidget(uint32_t flags = 0) : SkButtonWidget(flags) {} + +protected: + virtual bool onEvent(const SkEvent&); + virtual void onDraw(SkCanvas*); + virtual Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) SK_OVERRIDE; + virtual bool onClick(Click* click); + +private: + typedef SkButtonWidget INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkCheckBoxWidget : public SkButtonWidget { +public: + SkCheckBoxWidget(uint32_t flags = 0); + +protected: + virtual bool onEvent(const SkEvent&); + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + typedef SkButtonWidget INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkStaticTextView : public SkView { +public: + SkStaticTextView(uint32_t flags = 0); + virtual ~SkStaticTextView(); + + enum Mode { + kFixedSize_Mode, + kAutoWidth_Mode, + kAutoHeight_Mode, + + kModeCount + }; + Mode getMode() const { return (Mode)fMode; } + void setMode(Mode); + + SkTextBox::SpacingAlign getSpacingAlign() const { return (SkTextBox::SpacingAlign)fSpacingAlign; } + void setSpacingAlign(SkTextBox::SpacingAlign); + + void getMargin(SkPoint* margin) const; + void setMargin(SkScalar dx, SkScalar dy); + + size_t getText(SkString* text = NULL) const; + size_t getText(char text[] = NULL) const; + void setText(const SkString&); + void setText(const char text[]); + void setText(const char text[], size_t len); + + void getPaint(SkPaint*) const; + void setPaint(const SkPaint&); + +protected: + // overrides + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + SkPoint fMargin; + SkString fText; + SkPaint fPaint; + uint8_t fMode; + uint8_t fSpacingAlign; + + void computeSize(); + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkBitmapView : public SkView { +public: + SkBitmapView(uint32_t flags = 0); + virtual ~SkBitmapView(); + + bool getBitmap(SkBitmap*) const; + void setBitmap(const SkBitmap*, bool viewOwnsPixels); + bool loadBitmapFromFile(const char path[]); + +protected: + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM&, const SkDOM::Node*); + +private: + SkBitmap fBitmap; + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkHasLabelView : public SkView { +public: + void getLabel(SkString*) const; + void setLabel(const SkString&); + void setLabel(const char label[]); + +protected: + SkString fLabel; + + // called when the label changes + virtual void onLabelChange(); + + // overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkPushButtonView : public SkHasLabelView { +public: + SkPushButtonView(uint32_t flags = 0); + +protected: + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkCheckBoxView : public SkHasLabelView { +public: + SkCheckBoxView(uint32_t flags = 0); + + enum State { + kOff_State, + kOn_State, + kMaybe_State + }; + State getState() const { return fState; } + void setState(State); + +protected: + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + State fState; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkProgressView : public SkView { +public: + SkProgressView(uint32_t flags = 0); + virtual ~SkProgressView(); + + uint16_t getValue() const { return fValue; } + uint16_t getMax() const { return fMax; } + + void setMax(U16CPU max); + void setValue(U16CPU value); + +protected: + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + +private: + uint16_t fValue, fMax; + SkShader* fOnShader, *fOffShader; + SkInterpolator* fInterp; + bool fDoInterp; + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkListSource : public SkEventSink { +public: + virtual int countRows() = 0; + virtual void getRow(int index, SkString* left, SkString* right) = 0; + virtual SkEvent* getEvent(int index); + + static SkListSource* CreateFromDir(const char path[], const char suffix[], + const char targetPrefix[]); + static SkListSource* CreateFromDOM(const SkDOM& dom, const SkDOM::Node* node); +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkListView : public SkView { +public: + SkListView(uint32_t flags = 0); + virtual ~SkListView(); + + SkScalar getRowHeight() const { return fRowHeight; } + void setRowHeight(SkScalar); + + /** Return the index of the selected row, or -1 if none + */ + int getSelection() const { return fCurrIndex; } + /** Set the index of the selected row, or -1 for none + */ + void setSelection(int); + + void moveSelectionUp(); + void moveSelectionDown(); + + enum Attr { + kBG_Attr, + kNormalText_Attr, + kHiliteText_Attr, + kHiliteCell_Attr, + kAttrCount + }; + SkPaint& paint(Attr); + + SkListSource* getListSource() const { return fSource; } + SkListSource* setListSource(SkListSource*); + +#if 0 + enum Action { + kSelectionChange_Action, + kSelectionPicked_Action, + kActionCount + }; + /** If event is not null, it is retained by the view, and a copy + of the event will be posted to its listeners when the specified + action occurs. If event is null, then no event will be posted for + the specified action. + */ + void setActionEvent(Action, SkEvent* event); +#endif + +protected: + virtual void onDraw(SkCanvas*); + virtual void onSizeChange(); + virtual bool onEvent(const SkEvent&); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + +private: + SkPaint fPaint[kAttrCount]; + SkListSource* fSource; + SkScalar fRowHeight; + int fCurrIndex; // logical index + int fScrollIndex; // logical index of top-most visible row + int fVisibleRowCount; + SkString* fStrCache; + + void dirtyStrCache(); + void ensureStrCache(int visibleCount); + + int logicalToVisualIndex(int index) const { return index - fScrollIndex; } + void invalSelection(); + bool getRowRect(int index, SkRect*) const; + void ensureSelectionIsVisible(); + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class SkGridView : public SkView { +public: + SkGridView(uint32_t flags = 0); + virtual ~SkGridView(); + + void getCellSize(SkPoint*) const; + void setCellSize(SkScalar x, SkScalar y); + + /** Return the index of the selected item, or -1 if none + */ + int getSelection() const { return fCurrIndex; } + /** Set the index of the selected row, or -1 for none + */ + void setSelection(int); + + void moveSelectionUp(); + void moveSelectionDown(); + + enum Attr { + kBG_Attr, + kHiliteCell_Attr, + kAttrCount + }; + SkPaint& paint(Attr); + + SkListSource* getListSource() const { return fSource; } + SkListSource* setListSource(SkListSource*); + +protected: + virtual void onDraw(SkCanvas*); + virtual void onSizeChange(); + virtual bool onEvent(const SkEvent&); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + +private: + SkView* fScrollBar; + SkPaint fPaint[kAttrCount]; + SkListSource* fSource; + int fCurrIndex; // logical index + + SkPoint fCellSize; + SkIPoint fVisibleCount; + + int logicalToVisualIndex(int index) const { return index; } + void invalSelection(); + bool getCellRect(int index, SkRect*) const; + void ensureSelectionIsVisible(); + + typedef SkView INHERITED; +}; + +#endif diff --git a/views/SkWindow.h b/views/SkWindow.h new file mode 100644 index 0000000..ca68e75 --- /dev/null +++ b/views/SkWindow.h @@ -0,0 +1,121 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkWindow_DEFINED +#define SkWindow_DEFINED + +#include "SkView.h" +#include "SkBitmap.h" +#include "SkMatrix.h" +#include "SkRegion.h" +#include "SkEvent.h" +#include "SkKey.h" +#include "SkTDArray.h" + +#ifdef SK_BUILD_FOR_WINCEx + #define SHOW_FPS +#endif +//#define USE_GX_SCREEN + +class SkCanvas; + +class SkOSMenu; + +class SkWindow : public SkView { +public: + SkWindow(); + virtual ~SkWindow(); + + const SkBitmap& getBitmap() const { return fBitmap; } + + void setConfig(SkBitmap::Config); + void resize(int width, int height, SkBitmap::Config config = SkBitmap::kNo_Config); + void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); + void eraseRGB(U8CPU r, U8CPU g, U8CPU b); + + bool isDirty() const { return !fDirtyRgn.isEmpty(); } + bool update(SkIRect* updateArea); + // does not call through to onHandleInval(), but does force the fDirtyRgn + // to be wide open. Call before update() to ensure we redraw everything. + void forceInvalAll(); + // return the bounds of the dirty/inval rgn, or [0,0,0,0] if none + const SkIRect& getDirtyBounds() const { return fDirtyRgn.getBounds(); } + + bool handleClick(int x, int y, Click::State, void* owner, unsigned modi = 0); + bool handleChar(SkUnichar); + bool handleKey(SkKey); + bool handleKeyUp(SkKey); + + void addMenu(SkOSMenu*); + const SkTDArray<SkOSMenu*>* getMenus() { return &fMenus; } + + const char* getTitle() const { return fTitle.c_str(); } + void setTitle(const char title[]); + + const SkMatrix& getMatrix() const { return fMatrix; } + void setMatrix(const SkMatrix&); + void preConcat(const SkMatrix&); + void postConcat(const SkMatrix&); + + virtual SkCanvas* createCanvas(); + + virtual void onPDFSaved(const char title[], const char desc[], + const char path[]) {} +protected: + virtual bool onEvent(const SkEvent&); + virtual bool onDispatchClick(int x, int y, Click::State, void* owner, unsigned modi); + // called if part of our bitmap is invalidated + virtual void onHandleInval(const SkIRect&); + virtual bool onHandleChar(SkUnichar); + virtual bool onHandleKey(SkKey); + virtual bool onHandleKeyUp(SkKey); + virtual void onAddMenu(const SkOSMenu*) {}; + virtual void onUpdateMenu(const SkOSMenu*) {}; + virtual void onSetTitle(const char title[]) {} + + // overrides from SkView + virtual bool handleInval(const SkRect*); + virtual bool onGetFocusView(SkView** focus) const; + virtual bool onSetFocusView(SkView* focus); + +private: + SkBitmap::Config fConfig; + SkBitmap fBitmap; + SkRegion fDirtyRgn; + + SkTDArray<Click*> fClicks; // to track clicks + + SkTDArray<SkOSMenu*> fMenus; + + SkView* fFocusView; + bool fWaitingOnInval; + + SkString fTitle; + SkMatrix fMatrix; + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#if defined(SK_BUILD_FOR_NACL) + #include "SkOSWindow_NaCl.h" +#elif defined(SK_BUILD_FOR_MAC) + #include "SkOSWindow_Mac.h" +#elif defined(SK_BUILD_FOR_WIN) + #include "SkOSWindow_Win.h" +#elif defined(SK_BUILD_FOR_ANDROID) + #include "SkOSWindow_Android.h" +#elif defined(SK_BUILD_FOR_UNIX) + #include "SkOSWindow_Unix.h" +#elif defined(SK_BUILD_FOR_SDL) + #include "SkOSWindow_SDL.h" +#elif defined(SK_BUILD_FOR_IOS) + #include "SkOSWindow_iOS.h" +#endif + +#endif diff --git a/views/android/AndroidKeyToSkKey.h b/views/android/AndroidKeyToSkKey.h new file mode 100644 index 0000000..6bcb148 --- /dev/null +++ b/views/android/AndroidKeyToSkKey.h @@ -0,0 +1,35 @@ + +/* + * Copyright 2011 Skia + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef _ANDROID_TO_SKIA_KEYCODES_H +#define _ANDROID_TO_SKIA_KEYCODES_H + +#include "android/keycodes.h" +#include "SkKey.h" + +// Convert an Android keycode to an SkKey. This is an incomplete list, only +// including keys used by the sample app. +SkKey AndroidKeycodeToSkKey(int keycode) { + switch (keycode) { + case AKEYCODE_DPAD_LEFT: + return kLeft_SkKey; + case AKEYCODE_DPAD_RIGHT: + return kRight_SkKey; + case AKEYCODE_DPAD_UP: + return kUp_SkKey; + case AKEYCODE_DPAD_DOWN: + return kDown_SkKey; + case AKEYCODE_BACK: + return kBack_SkKey; + default: + return kNONE_SkKey; + } +} + +#endif diff --git a/views/animated/SkBorderView.h b/views/animated/SkBorderView.h new file mode 100644 index 0000000..8b1e537 --- /dev/null +++ b/views/animated/SkBorderView.h @@ -0,0 +1,40 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBorderView_DEFINED +#define SkBorderView_DEFINED + +#include "SkView.h" +#include "SkWidgetViews.h" +#include "SkAnimator.h" + +class SkBorderView : public SkWidgetView { +public: + SkBorderView(); + ~SkBorderView(); + void setSkin(const char skin[]); + SkScalar getLeft() const { return fLeft; } + SkScalar getRight() const { return fRight; } + SkScalar getTop() const { return fTop; } + SkScalar getBottom() const { return fBottom; } +protected: + //overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + virtual void onSizeChange(); + virtual void onDraw(SkCanvas* canvas); + virtual bool onEvent(const SkEvent& evt); +private: + SkAnimator fAnim; + SkScalar fLeft, fRight, fTop, fBottom; //margin on each side + SkRect fMargin; + + typedef SkWidgetView INHERITED; +}; + +#endif diff --git a/views/animated/SkImageView.h b/views/animated/SkImageView.h new file mode 100644 index 0000000..a21da0b --- /dev/null +++ b/views/animated/SkImageView.h @@ -0,0 +1,68 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkImageView_DEFINED +#define SkImageView_DEFINED + +#include "SkView.h" +#include "SkString.h" + +class SkAnimator; +class SkBitmap; +class SkMatrix; + +class SkImageView : public SkView { +public: + SkImageView(); + virtual ~SkImageView(); + + void getUri(SkString*) const; + void setUri(const char []); + void setUri(const SkString&); + + + enum ScaleType { + kMatrix_ScaleType, + kFitXY_ScaleType, + kFitStart_ScaleType, + kFitCenter_ScaleType, + kFitEnd_ScaleType + }; + ScaleType getScaleType() const { return (ScaleType)fScaleType; } + void setScaleType(ScaleType); + + bool getImageMatrix(SkMatrix*) const; + void setImageMatrix(const SkMatrix*); + +protected: + // overrides + virtual bool onEvent(const SkEvent&); + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM&, const SkDOMNode*); + +private: + SkString fUri; + SkMatrix* fMatrix; // null or copy of caller's matrix ,,,,, + union { + SkAnimator* fAnim; + SkBitmap* fBitmap; + } fData; + uint8_t fScaleType; + SkBool8 fDataIsAnim; // as opposed to bitmap + SkBool8 fUriIsValid; + + void onUriChange(); + bool getDataBounds(SkRect* bounds); + bool freeData(); + bool ensureUriIsLoaded(); + + typedef SkView INHERITED; +}; + +#endif diff --git a/views/animated/SkProgressBarView.h b/views/animated/SkProgressBarView.h new file mode 100644 index 0000000..7e670a9 --- /dev/null +++ b/views/animated/SkProgressBarView.h @@ -0,0 +1,50 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkProgressBarView_DEFINED +#define SkProgressBarView_DEFINED + +#include "SkView.h" +#include "SkWidgetViews.h" +#include "SkAnimator.h" + +class SkProgressBarView : public SkWidgetView { + public: + SkProgressBarView(); + //SkProgressBarView(int max); + + //inflate: "sk-progress" + + void reset(); //reset progress to zero + void setProgress(int progress); + void changeProgress(int diff); + void setMax(int max); + + int getProgress() const { return fProgress; } + int getMax() const { return fMax; } + + protected: + //overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + virtual void onSizeChange(); + virtual void onDraw(SkCanvas* canvas); + virtual bool onEvent(const SkEvent& evt); + + private: + SkAnimator fAnim; + int fProgress; + int fMax; + + typedef SkWidgetView INHERITED; +}; + + + + +#endif diff --git a/views/animated/SkScrollBarView.h b/views/animated/SkScrollBarView.h new file mode 100644 index 0000000..05042f0 --- /dev/null +++ b/views/animated/SkScrollBarView.h @@ -0,0 +1,44 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkScrollBarView_DEFINED +#define SkScrollBarView_DEFINED + +#include "SkView.h" +#include "SkWidgetViews.h" +#include "SkAnimator.h" + +class SkScrollBarView : public SkWidgetView { +public: + SkScrollBarView(); + + unsigned getStart() const { return fStartPoint; } + unsigned getShown() const { return fShownLength; } + unsigned getTotal() const { return fTotalLength; } + + void setStart(unsigned start); + void setShown(unsigned shown); + void setTotal(unsigned total); + +protected: + //overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + virtual void onSizeChange(); + virtual void onDraw(SkCanvas* canvas); + virtual bool onEvent(const SkEvent& evt); + +private: + SkAnimator fAnim; + unsigned fTotalLength, fStartPoint, fShownLength; + + void adjust(); + + typedef SkWidgetView INHERITED; +}; +#endif diff --git a/views/animated/SkWidgetViews.h b/views/animated/SkWidgetViews.h new file mode 100644 index 0000000..4034660 --- /dev/null +++ b/views/animated/SkWidgetViews.h @@ -0,0 +1,309 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkWidgetViews_DEFINED +#define SkWidgetViews_DEFINED + +#include "SkView.h" + + +enum SkWidgetEnum { + kBorder_WidgetEnum, //!< <sk-border> + kButton_WidgetEnum, //!< <sk-button> + kImage_WidgetEnum, //!< <sk-image> + kList_WidgetEnum, //!< <sk-list> + kProgress_WidgetEnum, //!< <sk-progress> + kScroll_WidgetEnum, //!< <sk-scroll> + kText_WidgetEnum, //!< <sk-text> + + kWidgetEnumCount +}; + +//determines which skin to use +enum SkinEnum { + kBorder_SkinEnum, + kButton_SkinEnum, + kProgress_SkinEnum, + kScroll_SkinEnum, + kStaticText_SkinEnum, + + kSkinEnumCount +}; + +#include "SkAnimator.h" +//used for inflates +const char* get_skin_enum_path(SkinEnum se); +void init_skin_anim(const char path[], SkAnimator* anim); +void init_skin_anim(SkinEnum se, SkAnimator* anim); +void init_skin_paint(SkinEnum se, SkPaint* paint); +void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint); + +/** Given an enum value, return an instance of the specified widget. + If the enum is out of range, returns null +*/ +SkView* SkWidgetFactory(SkWidgetEnum); +/** Given the inflate/element name of a widget, return an instance of + the specified widget, or null if name does not match any known + widget type. +*/ +SkView* SkWidgetFactory(const char name[]); + +//////////////////////////////////////////////////////////////////////////////////////////////// + +class SkWidgetView : public SkView { +public: + SkWidgetView(); + + const char* getLabel() const; + void getLabel(SkString* label) const; + + void setLabel(const char[]); + void setLabel(const char[], size_t len); + void setLabel(const SkString&); + + SkEvent& event() { return fEvent; } + const SkEvent& event() const { return fEvent; } + + /** Returns true if the widget can post its event to its listeners. + */ + bool postWidgetEvent(); + + /** Returns the sinkID of the widgetview that posted the event, or 0 + */ + static SkEventSinkID GetWidgetEventSinkID(const SkEvent&); + +protected: + /** called when the label changes. override in subclasses. default action invals the view's bounds. + called with the old and new labels, before the label has actually changed. + */ + virtual void onLabelChange(const char oldLabel[], const char newLabel[]); + /** called before posting the event to our listeners. Override to add slots to the event + before posting. Return true to proceed with posting, or false to not post the event to any + listener. Note: the event passed in may not be the same as calling this->event(). + Be sure to call your INHERITED method as well, so that all classes in the hierarchy get a shot + at modifying the event (and possibly returning false to abort). + */ + virtual bool onPrepareWidgetEvent(SkEvent* evt); + + // overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + SkString fLabel; + SkEvent fEvent; + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////// + +class SkButtonView : public SkWidgetView { +public: + // inflate: "sk-button" + +protected: + // overrides + virtual bool onEvent(const SkEvent&); +private: + typedef SkWidgetView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////// + +class SkCheckButtonView : public SkWidgetView { +public: + SkCheckButtonView(); + + // inflate: "sk-checkbutton" + + enum CheckState { + kOff_CheckState, //!< inflate: check-state="off" + kOn_CheckState, //!< inflate: check-state="on" + kUnknown_CheckState //!< inflate: check-state="unknown" + }; + CheckState getCheckState() const { return (CheckState)fCheckState; } + void setCheckState(CheckState); + + /** use this to extract the CheckState from an event (i.e. one that as posted + by a SkCheckButtonView). Returns true if the proper slot was present in the event, + and sets state to that value. If no proper slot is found, returns false and does not + modify state. + */ + static bool GetWidgetEventCheckState(const SkEvent&, CheckState* state); + +protected: + // called when the check-state is about to change, but before it actually has + virtual void onCheckStateChange(CheckState oldState, CheckState newState); + + // overrides + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + virtual bool onPrepareWidgetEvent(SkEvent* evt); + +private: + uint8_t fCheckState; + + typedef SkWidgetView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////// +#include "SkTextBox.h" + +class SkStaticTextView : public SkView { +public: + SkStaticTextView(); + virtual ~SkStaticTextView(); + + enum Mode { + kFixedSize_Mode, + kAutoWidth_Mode, + kAutoHeight_Mode, + + kModeCount + }; + Mode getMode() const { return (Mode)fMode; } + void setMode(Mode); + + SkTextBox::SpacingAlign getSpacingAlign() const { return (SkTextBox::SpacingAlign)fSpacingAlign; } + void setSpacingAlign(SkTextBox::SpacingAlign); + + void getMargin(SkPoint* margin) const; + void setMargin(SkScalar dx, SkScalar dy); + + size_t getText(SkString* text = NULL) const; + size_t getText(char text[] = NULL) const; + void setText(const SkString&); + void setText(const char text[]); + void setText(const char text[], size_t len); + + void getPaint(SkPaint*) const; + void setPaint(const SkPaint&); + +protected: + // overrides + virtual void onDraw(SkCanvas*); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node*); + +private: + SkPoint fMargin; + SkString fText; + SkPaint fPaint; + uint8_t fMode; + uint8_t fSpacingAlign; + + void computeSize(); + + typedef SkView INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////// + +class SkAnimator; +class SkListSource; +class SkScrollBarView; + +class SkListView : public SkWidgetView { +public: + SkListView(); + virtual ~SkListView(); + + bool hasScrollBar() const { return fScrollBar != NULL; } + void setHasScrollBar(bool); + + /** Return the number of visible rows + */ + int getVisibleRowCount() const { return fVisibleRowCount; } + /** Return the index of the selected row, or -1 if none + */ + int getSelection() const { return fCurrIndex; } + /** Set the index of the selected row, or -1 for none + */ + void setSelection(int); + /** If possible, move the selection up and return true, + else do nothing and return false + If nothing is selected, select the last item (unless there are no items). + */ + bool moveSelectionUp(); + /** If possible, move the selection down and return true, + else do nothing and return false. + If nothing is selected, select the first item (unless there are no items). + */ + bool moveSelectionDown(); + + SkListSource* getListSource() const { return fSource; } + SkListSource* setListSource(SkListSource*); + + /** Call this in your event handler. If the specified event is from a SkListView, + then it returns the index of the selected item in this list, otherwise it + returns -1 + */ + static int GetWidgetEventListIndex(const SkEvent&); + +protected: + // overrides + virtual void onDraw(SkCanvas*); + virtual void onSizeChange(); + virtual bool onEvent(const SkEvent&); + virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); + virtual bool onPrepareWidgetEvent(SkEvent*); + +private: + enum DirtyFlags { + kAnimCount_DirtyFlag = 0x01, + kAnimContent_DirtyFlag = 0x02 + }; + void dirtyCache(unsigned dirtyFlags); + bool ensureCache(); + + int logicalToVisualIndex(int index) const { return index - fScrollIndex; } + void invalSelection(); + SkScalar getContentWidth() const; + bool getRowRect(int index, SkRect*) const; + void ensureSelectionIsVisible(); + void ensureVisibleRowCount(); + + struct BindingRec; + + enum Heights { + kNormal_Height, + kSelected_Height + }; + SkListSource* fSource; + SkScrollBarView* fScrollBar; + SkAnimator* fAnims; + BindingRec* fBindings; + SkString fSkinName; + SkScalar fHeights[2]; + int16_t fScrollIndex, fCurrIndex; + uint16_t fVisibleRowCount, fBindingCount; + SkBool8 fAnimContentDirty; + SkBool8 fAnimFocusDirty; + + typedef SkWidgetView INHERITED; +}; + +class SkListSource : public SkRefCnt { +public: + SK_DECLARE_INST_COUNT(SkListSource) + + virtual int countFields(); + virtual void getFieldName(int index, SkString* field); + /** Return the index of the named field, or -1 if not found */ + virtual int findFieldIndex(const char field[]); + + virtual int countRecords(); + virtual void getRecord(int rowIndex, int fieldIndex, SkString* data); + + virtual bool prepareWidgetEvent(SkEvent*, int rowIndex); + + static SkListSource* Factory(const char name[]); +private: + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/views/unix/XkeysToSkKeys.h b/views/unix/XkeysToSkKeys.h new file mode 100644 index 0000000..30eb97d --- /dev/null +++ b/views/unix/XkeysToSkKeys.h @@ -0,0 +1,38 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "X11/Xlib.h" +#include "X11/keysym.h" + +#include "SkKey.h" + +#ifndef XKEYS_TOSKKEYS_H +#define XKEYS_TOSKKEYS_H + +SkKey XKeyToSkKey(KeySym keysym) { + switch (keysym) { + case XK_BackSpace: + return kBack_SkKey; + case XK_Return: + return kOK_SkKey; + case XK_Home: + return kHome_SkKey; + case XK_End: + return kEnd_SkKey; + case XK_Right: + return kRight_SkKey; + case XK_Left: + return kLeft_SkKey; + case XK_Down: + return kDown_SkKey; + case XK_Up: + return kUp_SkKey; + default: + return kNONE_SkKey; + } +} +#endif diff --git a/views/unix/keysym2ucs.h b/views/unix/keysym2ucs.h new file mode 100644 index 0000000..255a930 --- /dev/null +++ b/views/unix/keysym2ucs.h @@ -0,0 +1,15 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* + * This module converts keysym values into the corresponding ISO 10646-1 + * (UCS, Unicode) values. + */ + +#include <X11/X.h> + +long keysym2ucs(KeySym keysym); diff --git a/xml/SkBML_WXMLParser.h b/xml/SkBML_WXMLParser.h new file mode 100644 index 0000000..74f164c --- /dev/null +++ b/xml/SkBML_WXMLParser.h @@ -0,0 +1,46 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBML_WXMLParser_DEFINED +#define SkBML_WXMLParser_DEFINED + +#include "SkString.h" +#include "SkXMLParser.h" + +class SkStream; +class SkWStream; + +class BML_WXMLParser : public SkXMLParser { +public: + BML_WXMLParser(SkWStream& writer); + virtual ~BML_WXMLParser(); + static void Write(SkStream& s, const char filename[]); + + /** @cond UNIT_TEST */ + SkDEBUGCODE(static void UnitTest();) + /** @endcond */ +private: + virtual bool onAddAttribute(const char name[], const char value[]); + virtual bool onEndElement(const char name[]); + virtual bool onStartElement(const char name[]); + BML_WXMLParser& operator=(const BML_WXMLParser& src); +#ifdef SK_DEBUG + int fElemsCount, fElemsReused; + int fAttrsCount, fNamesReused, fValuesReused; +#endif + SkWStream& fWriter; + char* fElems[256]; + char* fAttrNames[256]; + char* fAttrValues[256]; + + // important that these are U8, so we get automatic wrap-around + U8 fNextElem, fNextAttrName, fNextAttrValue; +}; + +#endif // SkBML_WXMLParser_DEFINED diff --git a/xml/SkBML_XMLParser.h b/xml/SkBML_XMLParser.h new file mode 100644 index 0000000..9bdbf51 --- /dev/null +++ b/xml/SkBML_XMLParser.h @@ -0,0 +1,31 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkBML_XMLParser_DEFINED +#define SkBML_XMLParser_DEFINED + +class SkStream; +class SkWStream; +class SkXMLParser; +class SkXMLWriter; + +class BML_XMLParser { +public: + /** Read the byte XML stream and write the decompressed XML. + */ + static void Read(SkStream& s, SkXMLWriter& writer); + /** Read the byte XML stream and write the decompressed XML into a writable stream. + */ + static void Read(SkStream& s, SkWStream& output); + /** Read the byte XML stream and write the decompressed XML into an XML parser. + */ + static void Read(SkStream& s, SkXMLParser& output); +}; + +#endif // SkBML_XMLParser_DEFINED diff --git a/xml/SkDOM.h b/xml/SkDOM.h new file mode 100644 index 0000000..e0bb744 --- /dev/null +++ b/xml/SkDOM.h @@ -0,0 +1,91 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkDOM_DEFINED +#define SkDOM_DEFINED + +#include "SkChunkAlloc.h" +#include "SkScalar.h" +#include "SkTemplates.h" + +struct SkDOMNode; +struct SkDOMAttr; + +class SkDOM { +public: + SkDOM(); + ~SkDOM(); + + typedef SkDOMNode Node; + typedef SkDOMAttr Attr; + + /** Returns null on failure + */ + const Node* build(const char doc[], size_t len); + const Node* copy(const SkDOM& dom, const Node* node); + + const Node* getRootNode() const; + + enum Type { + kElement_Type, + kText_Type + }; + Type getType(const Node*) const; + + const char* getName(const Node*) const; + const Node* getFirstChild(const Node*, const char elem[] = NULL) const; + const Node* getNextSibling(const Node*, const char elem[] = NULL) const; + + const char* findAttr(const Node*, const char attrName[]) const; + const Attr* getFirstAttr(const Node*) const; + const Attr* getNextAttr(const Node*, const Attr*) const; + const char* getAttrName(const Node*, const Attr*) const; + const char* getAttrValue(const Node*, const Attr*) const; + + // helpers for walking children + int countChildren(const Node* node, const char elem[] = NULL) const; + + // helpers for calling SkParse + bool findS32(const Node*, const char name[], int32_t* value) const; + bool findScalars(const Node*, const char name[], SkScalar value[], int count) const; + bool findHex(const Node*, const char name[], uint32_t* value) const; + bool findBool(const Node*, const char name[], bool*) const; + int findList(const Node*, const char name[], const char list[]) const; + + bool findScalar(const Node* node, const char name[], SkScalar value[]) const + { + return this->findScalars(node, name, value, 1); + } + + bool hasAttr(const Node*, const char name[], const char value[]) const; + bool hasS32(const Node*, const char name[], int32_t value) const; + bool hasScalar(const Node*, const char name[], SkScalar value) const; + bool hasHex(const Node*, const char name[], uint32_t value) const; + bool hasBool(const Node*, const char name[], bool value) const; + + class AttrIter { + public: + AttrIter(const class SkDOM&, const Node*); + const char* next(const char** value); + private: + const Attr* fAttr; + const Attr* fStop; + }; + + SkDEBUGCODE(void dump(const Node* node = NULL, int tabLevel = 0) const;) + SkDEBUGCODE(static void UnitTest();) + +private: + SkChunkAlloc fAlloc; + Node* fRoot; + friend class AttrIter; + friend class SkDOMParser; +}; + +#endif diff --git a/xml/SkJS.h b/xml/SkJS.h new file mode 100644 index 0000000..8a11097 --- /dev/null +++ b/xml/SkJS.h @@ -0,0 +1,39 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "SkTypes.h" +#include "SkWindow.h" + +extern "C" { + typedef long JSWord; + typedef JSWord jsword; + typedef jsword jsval; + typedef struct JSRuntime JSRuntime; + typedef struct JSContext JSContext; + typedef struct JSObject JSObject; +} + +class SkString; + +class SkJS : public SkOSWindow { +public: + SkJS(void* hwnd); + ~SkJS(); + SkBool EvaluateScript(const char* script, jsval* rVal); + SkBool ValueToString(jsval value, SkString* string); +#ifdef SK_DEBUG + static void Test(void* hwnd); +#endif +protected: + void InitializeDisplayables(const SkBitmap& , JSContext *, JSObject *, JSObject *); + void DisposeDisplayables(); + JSRuntime *fRuntime; + JSContext *fContext; + JSObject *fGlobal; +}; diff --git a/xml/SkXMLParser.h b/xml/SkXMLParser.h new file mode 100644 index 0000000..1a90bf7 --- /dev/null +++ b/xml/SkXMLParser.h @@ -0,0 +1,155 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkXMLParser_DEFINED +#define SkXMLParser_DEFINED + +#include "SkString.h" + +class SkStream; + +class SkDOM; +struct SkDOMNode; + +class SkXMLParserError { +public: + enum ErrorCode { + kNoError, + kEmptyFile, + kUnknownElement, + kUnknownAttributeName, + kErrorInAttributeValue, + kDuplicateIDs, + kUnknownError + }; + + SkXMLParserError(); + virtual ~SkXMLParserError(); + ErrorCode getErrorCode() const { return fCode; } + virtual void getErrorString(SkString* str) const; + int getLineNumber() const { return fLineNumber; } + int getNativeCode() const { return fNativeCode; } + bool hasError() const { return fCode != kNoError || fNativeCode != -1; } + bool hasNoun() const { return fNoun.size() > 0; } + void reset(); + void setCode(ErrorCode code) { fCode = code; } + void setNoun(const SkString& str) { fNoun.set(str); } + void setNoun(const char* ch) { fNoun.set(ch); } + void setNoun(const char* ch, size_t len) { fNoun.set(ch, len); } +protected: + ErrorCode fCode; +private: + int fLineNumber; + int fNativeCode; + SkString fNoun; + friend class SkXMLParser; +}; + +class SkXMLParser { +public: + SkXMLParser(SkXMLParserError* parserError = NULL); + virtual ~SkXMLParser(); + + /** Returns true for success + */ + bool parse(const char doc[], size_t len); + bool parse(SkStream& docStream); + bool parse(const SkDOM&, const SkDOMNode*); + + static void GetNativeErrorString(int nativeErrorCode, SkString* str); + +protected: + // override in subclasses; return true to stop parsing + virtual bool onStartElement(const char elem[]); + virtual bool onAddAttribute(const char name[], const char value[]); + virtual bool onEndElement(const char elem[]); + virtual bool onText(const char text[], int len); + +public: + // public for ported implementation, not meant for clients to call + virtual bool startElement(const char elem[]); + virtual bool addAttribute(const char name[], const char value[]); + virtual bool endElement(const char elem[]); + virtual bool text(const char text[], int len); + void* fParser; +protected: + SkXMLParserError* fError; +private: + void reportError(void* parser); +}; + +#if 0 +class SkXMLPullParser { +public: + SkXMLPullParser(); + explicit SkXMLPullParser(SkStream*); + virtual ~SkXMLPullParser(); + + SkStream* getStream() const { return fStream; } + SkStream* setStream(SkStream* stream); + + enum EventType { + ERROR = -1, + START_DOCUMENT, + END_DOCUMENT, + START_TAG, + END_TAG, + TEXT, + CDSECT, + ENTITY_REF, + IGNORABLE_WHITESPACE, + PROCESSING_INSTRUCTION, + COMMENT, + DOCDECL + }; + + EventType nextToken(); + EventType getEventType() const { return fCurr.fEventType; } + + struct AttrInfo { + const char* fName; + const char* fValue; + }; + + int getDepth() const { return fDepth; } + const char* getName(); + int getAttributeCount(); + void getAttributeInfo(int, AttrInfo*); + const char* getText(); + bool isWhitespace(); + +protected: + virtual bool onEntityReplacement(const char name[], + SkString* replacement); + +public: + struct Curr { + EventType fEventType; + const char* fName; + AttrInfo* fAttrInfos; + int fAttrInfoCount; + bool fIsWhitespace; + }; + +private: + // implemented in the porting layer + bool onInit(); // return false on failure + EventType onNextToken(); + void onExit(); + + SkStream* fStream; + Curr fCurr; + int fDepth; + + struct Impl; + Impl* fImpl; +}; +#endif + +#endif diff --git a/xml/SkXMLWriter.h b/xml/SkXMLWriter.h new file mode 100644 index 0000000..214fefe --- /dev/null +++ b/xml/SkXMLWriter.h @@ -0,0 +1,85 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkXMLWriter_DEFINED +#define SkXMLWriter_DEFINED + +#include "SkTDArray.h" +#include "SkString.h" +#include "SkDOM.h" + +class SkWStream; +class SkXMLParser; + +class SkXMLWriter { +public: + SkXMLWriter(bool doEscapeMarkup = true); + virtual ~SkXMLWriter(); + + void addS32Attribute(const char name[], int32_t value); + void addAttribute(const char name[], const char value[]); + void addAttributeLen(const char name[], const char value[], size_t length); + void addHexAttribute(const char name[], uint32_t value, int minDigits = 0); + void addScalarAttribute(const char name[], SkScalar value); + void endElement() { this->onEndElement(); } + void startElement(const char elem[]); + void startElementLen(const char elem[], size_t length); + void writeDOM(const SkDOM&, const SkDOM::Node*, bool skipRoot); + void flush(); + virtual void writeHeader(); + +protected: + virtual void onStartElementLen(const char elem[], size_t length) = 0; + virtual void onAddAttributeLen(const char name[], const char value[], size_t length) = 0; + virtual void onEndElement() = 0; + + struct Elem { + SkString fName; + bool fHasChildren; + }; + void doEnd(Elem* elem); + bool doStart(const char name[], size_t length); + Elem* getEnd(); + const char* getHeader(); + SkTDArray<Elem*> fElems; + +private: + bool fDoEscapeMarkup; + // illegal + SkXMLWriter& operator=(const SkXMLWriter&); +}; + +class SkXMLStreamWriter : public SkXMLWriter { +public: + SkXMLStreamWriter(SkWStream*); + virtual ~SkXMLStreamWriter(); + virtual void writeHeader(); + SkDEBUGCODE(static void UnitTest();) +protected: + virtual void onStartElementLen(const char elem[], size_t length); + virtual void onEndElement(); + virtual void onAddAttributeLen(const char name[], const char value[], size_t length); +private: + SkWStream& fStream; +}; + +class SkXMLParserWriter : public SkXMLWriter { +public: + SkXMLParserWriter(SkXMLParser*); + virtual ~SkXMLParserWriter(); +protected: + virtual void onStartElementLen(const char elem[], size_t length); + virtual void onEndElement(); + virtual void onAddAttributeLen(const char name[], const char value[], size_t length); +private: + SkXMLParser& fParser; +}; + + +#endif |