diff --git a/libazure/2D.h b/libazure/2D.h new file mode 100644 index 0000000..85529f6 --- /dev/null +++ b/libazure/2D.h @@ -0,0 +1,1266 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_2D_H +#define _MOZILLA_GFX_2D_H + +#include "Types.h" +#include "Point.h" +#include "Rect.h" +#include "Matrix.h" +#include "UserData.h" + +// GenericRefCountedBase allows us to hold on to refcounted objects of any type +// (contrary to RefCounted which requires knowing the type T) and, in particular, +// without having a dependency on that type. This is used for DrawTargetSkia +// to be able to hold on to a GLContext. +#include "GenericRefCounted.h" + +// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T** +// outparams using the &-operator. But it will have to do as there's no easy +// solution. +#include "mozilla/RefPtr.h" + +#include "mozilla/DebugOnly.h" + +// XXX - Bas - This will likely give problems on OS X! +#include + +#ifdef MOZ_ENABLE_FREETYPE +#include "ft2build.h" +#include FT_FREETYPE_H +#endif + +struct _cairo_surface; +typedef _cairo_surface cairo_surface_t; + +struct _cairo_scaled_font; +typedef _cairo_scaled_font cairo_scaled_font_t; + +struct ID3D10Device1; +struct ID3D10Texture2D; +struct ID3D11Texture2D; +struct ID3D11Device; +struct ID2D1Device; +struct IDWriteRenderingParams; + +class GrContext; +struct GrGLInterface; + +struct CGContext; +typedef struct CGContext *CGContextRef; + +namespace mozilla { + +namespace gfx { + +class SourceSurface; +class DataSourceSurface; +class DrawTarget; +class DrawEventRecorder; +class FilterNode; +class LogForwarder; + +struct NativeSurface { + NativeSurfaceType mType; + SurfaceFormat mFormat; + gfx::IntSize mSize; + void *mSurface; +}; + +struct NativeFont { + NativeFontType mType; + void *mFont; +}; + +/** + * This structure is used to send draw options that are universal to all drawing + * operations. + */ +struct DrawOptions { + /// For constructor parameter description, see member data documentation. + explicit DrawOptions(Float aAlpha = 1.0f, + CompositionOp aCompositionOp = CompositionOp::OP_OVER, + AntialiasMode aAntialiasMode = AntialiasMode::DEFAULT) + : mAlpha(aAlpha) + , mCompositionOp(aCompositionOp) + , mAntialiasMode(aAntialiasMode) + {} + + Float mAlpha; /**< Alpha value by which the mask generated by this + operation is multiplied. */ + CompositionOp mCompositionOp; /**< The operator that indicates how the source and + destination patterns are blended. */ + AntialiasMode mAntialiasMode; /**< The AntiAlias mode used for this drawing + operation. */ +}; + +/** + * This structure is used to send stroke options that are used in stroking + * operations. + */ +struct StrokeOptions { + /// For constructor parameter description, see member data documentation. + explicit StrokeOptions(Float aLineWidth = 1.0f, + JoinStyle aLineJoin = JoinStyle::MITER_OR_BEVEL, + CapStyle aLineCap = CapStyle::BUTT, + Float aMiterLimit = 10.0f, + size_t aDashLength = 0, + const Float* aDashPattern = 0, + Float aDashOffset = 0.f) + : mLineWidth(aLineWidth) + , mMiterLimit(aMiterLimit) + , mDashPattern(aDashLength > 0 ? aDashPattern : 0) + , mDashLength(aDashLength) + , mDashOffset(aDashOffset) + , mLineJoin(aLineJoin) + , mLineCap(aLineCap) + { + MOZ_ASSERT(aDashLength == 0 || aDashPattern); + } + + Float mLineWidth; //!< Width of the stroke in userspace. + Float mMiterLimit; //!< Miter limit in units of linewidth + const Float* mDashPattern; /**< Series of on/off userspace lengths defining dash. + Owned by the caller; must live at least as long as + this StrokeOptions. + mDashPattern != null <=> mDashLength > 0. */ + size_t mDashLength; //!< Number of on/off lengths in mDashPattern. + Float mDashOffset; /**< Userspace offset within mDashPattern at which + stroking begins. */ + JoinStyle mLineJoin; //!< Join style used for joining lines. + CapStyle mLineCap; //!< Cap style used for capping lines. +}; + +/** + * This structure supplies additional options for calls to DrawSurface. + */ +struct DrawSurfaceOptions { + /// For constructor parameter description, see member data documentation. + explicit DrawSurfaceOptions(Filter aFilter = Filter::LINEAR, + SamplingBounds aSamplingBounds = SamplingBounds::UNBOUNDED) + : mFilter(aFilter) + , mSamplingBounds(aSamplingBounds) + { } + + Filter mFilter; /**< Filter used when resampling source surface + region to the destination region. */ + SamplingBounds mSamplingBounds; /**< This indicates whether the implementation is + allowed to sample pixels outside the source + rectangle as specified in DrawSurface on + the surface. */ + +}; + +/** + * This class is used to store gradient stops, it can only be used with a + * matching DrawTarget. Not adhering to this condition will make a draw call + * fail. + */ +class GradientStops : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops) + virtual ~GradientStops() {} + + virtual BackendType GetBackendType() const = 0; + +protected: + GradientStops() {} +}; + +/** + * This is the base class for 'patterns'. Patterns describe the pixels used as + * the source for a masked composition operation that is done by the different + * drawing commands. These objects are not backend specific, however for + * example the gradient stops on a gradient pattern can be backend specific. + */ +class Pattern +{ +public: + virtual ~Pattern() {} + + virtual PatternType GetType() const = 0; + +protected: + Pattern() {} +}; + +class ColorPattern : public Pattern +{ +public: + explicit ColorPattern(const Color &aColor) + : mColor(aColor) + {} + + virtual PatternType GetType() const { return PatternType::COLOR; } + + Color mColor; +}; + +/** + * This class is used for Linear Gradient Patterns, the gradient stops are + * stored in a separate object and are backend dependent. This class itself + * may be used on the stack. + */ +class LinearGradientPattern : public Pattern +{ +public: + /// For constructor parameter description, see member data documentation. + LinearGradientPattern(const Point &aBegin, + const Point &aEnd, + GradientStops *aStops, + const Matrix &aMatrix = Matrix()) + : mBegin(aBegin) + , mEnd(aEnd) + , mStops(aStops) + , mMatrix(aMatrix) + { + } + + virtual PatternType GetType() const { return PatternType::LINEAR_GRADIENT; } + + Point mBegin; //!< Start of the linear gradient + Point mEnd; /**< End of the linear gradient - NOTE: In the case + of a zero length gradient it will act as the + color of the last stop. */ + RefPtr mStops; /**< GradientStops object for this gradient, this + should match the backend type of the draw + target this pattern will be used with. */ + Matrix mMatrix; /**< A matrix that transforms the pattern into + user space */ +}; + +/** + * This class is used for Radial Gradient Patterns, the gradient stops are + * stored in a separate object and are backend dependent. This class itself + * may be used on the stack. + */ +class RadialGradientPattern : public Pattern +{ +public: + /// For constructor parameter description, see member data documentation. + RadialGradientPattern(const Point &aCenter1, + const Point &aCenter2, + Float aRadius1, + Float aRadius2, + GradientStops *aStops, + const Matrix &aMatrix = Matrix()) + : mCenter1(aCenter1) + , mCenter2(aCenter2) + , mRadius1(aRadius1) + , mRadius2(aRadius2) + , mStops(aStops) + , mMatrix(aMatrix) + { + } + + virtual PatternType GetType() const { return PatternType::RADIAL_GRADIENT; } + + Point mCenter1; //!< Center of the inner (focal) circle. + Point mCenter2; //!< Center of the outer circle. + Float mRadius1; //!< Radius of the inner (focal) circle. + Float mRadius2; //!< Radius of the outer circle. + RefPtr mStops; /**< GradientStops object for this gradient, this + should match the backend type of the draw target + this pattern will be used with. */ + Matrix mMatrix; //!< A matrix that transforms the pattern into user space +}; + +/** + * This class is used for Surface Patterns, they wrap a surface and a + * repetition mode for the surface. This may be used on the stack. + */ +class SurfacePattern : public Pattern +{ +public: + /// For constructor parameter description, see member data documentation. + SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode, + const Matrix &aMatrix = Matrix(), Filter aFilter = Filter::GOOD, + const IntRect &aSamplingRect = IntRect()) + : mSurface(aSourceSurface) + , mExtendMode(aExtendMode) + , mFilter(aFilter) + , mMatrix(aMatrix) + , mSamplingRect(aSamplingRect) + {} + + virtual PatternType GetType() const { return PatternType::SURFACE; } + + RefPtr mSurface; //!< Surface to use for drawing + ExtendMode mExtendMode; /**< This determines how the image is extended + outside the bounds of the image */ + Filter mFilter; //!< Resampling filter for resampling the image. + Matrix mMatrix; //!< Transforms the pattern into user space + + IntRect mSamplingRect; /**< Rect that must not be sampled outside of, + or an empty rect if none has been specified. */ +}; + +class StoredPattern; +class DrawTargetCaptureImpl; + +/** + * This is the base class for source surfaces. These objects are surfaces + * which may be used as a source in a SurfacePattern or a DrawSurface call. + * They cannot be drawn to directly. + */ +class SourceSurface : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface) + virtual ~SourceSurface() {} + + virtual SurfaceType GetType() const = 0; + virtual IntSize GetSize() const = 0; + virtual SurfaceFormat GetFormat() const = 0; + + /** This returns false if some event has made this source surface invalid for + * usage with current DrawTargets. For example in the case of Direct2D this + * could return false if we have switched devices since this surface was + * created. + */ + virtual bool IsValid() const { return true; } + + /** + * This function will get a DataSourceSurface for this surface, a + * DataSourceSurface's data can be accessed directly. + */ + virtual TemporaryRef GetDataSurface() = 0; + + /** Tries to get this SourceSurface's native surface. This will fail if aType + * is not the type of this SourceSurface's native surface. + */ + virtual void *GetNativeSurface(NativeSurfaceType aType) { + return nullptr; + } + + void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { + mUserData.Add(key, userData, destroy); + } + void *GetUserData(UserDataKey *key) { + return mUserData.Get(key); + } + +protected: + friend class DrawTargetCaptureImpl; + friend class StoredPattern; + + // This is for internal use, it ensures the SourceSurface's data remains + // valid during the lifetime of the SourceSurface. + // @todo XXX - We need something better here :(. But we may be able to get rid + // of CreateWrappingDataSourceSurface in the future. + virtual void GuaranteePersistance() {} + + UserData mUserData; +}; + +class DataSourceSurface : public SourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurface) + DataSourceSurface() + : mIsMapped(false) + { + } + +#ifdef DEBUG + virtual ~DataSourceSurface() + { + MOZ_ASSERT(!mIsMapped, "Someone forgot to call Unmap()"); + } +#endif + + struct MappedSurface { + uint8_t *mData; + int32_t mStride; + }; + + enum MapType { + READ, + WRITE, + READ_WRITE + }; + + virtual SurfaceType GetType() const { return SurfaceType::DATA; } + /** @deprecated + * Get the raw bitmap data of the surface. + * Can return null if there was OOM allocating surface data. + */ + virtual uint8_t *GetData() = 0; + + /** @deprecated + * Stride of the surface, distance in bytes between the start of the image + * data belonging to row y and row y+1. This may be negative. + * Can return 0 if there was OOM allocating surface data. + */ + virtual int32_t Stride() = 0; + + virtual bool Map(MapType, MappedSurface *aMappedSurface) + { + aMappedSurface->mData = GetData(); + aMappedSurface->mStride = Stride(); + mIsMapped = true; + return true; + } + + virtual void Unmap() + { + MOZ_ASSERT(mIsMapped); + mIsMapped = false; + } + + /* + * Returns a DataSourceSurface with the same data as this one, but + * guaranteed to have surface->GetType() == SurfaceType::DATA. + */ + virtual TemporaryRef GetDataSurface(); + +protected: + bool mIsMapped; +}; + +/** This is an abstract object that accepts path segments. */ +class PathSink : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink) + virtual ~PathSink() {} + + /** Move the current point in the path, any figure currently being drawn will + * be considered closed during fill operations, however when stroking the + * closing line segment will not be drawn. + */ + virtual void MoveTo(const Point &aPoint) = 0; + /** Add a linesegment to the current figure */ + virtual void LineTo(const Point &aPoint) = 0; + /** Add a cubic bezier curve to the current figure */ + virtual void BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3) = 0; + /** Add a quadratic bezier curve to the current figure */ + virtual void QuadraticBezierTo(const Point &aCP1, + const Point &aCP2) = 0; + /** Close the current figure, this will essentially generate a line segment + * from the current point to the starting point for the current figure + */ + virtual void Close() = 0; + /** Add an arc to the current figure */ + virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise = false) = 0; + /** Point the current subpath is at - or where the next subpath will start + * if there is no active subpath. + */ + virtual Point CurrentPoint() const = 0; +}; + +class PathBuilder; +class FlattenedPath; + +/** The path class is used to create (sets of) figures of any shape that can be + * filled or stroked to a DrawTarget + */ +class Path : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path) + virtual ~Path(); + + virtual BackendType GetBackendType() const = 0; + + /** This returns a PathBuilder object that contains a copy of the contents of + * this path and is still writable. + */ + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const = 0; + virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, + FillRule aFillRule = FillRule::FILL_WINDING) const = 0; + + /** This function checks if a point lies within a path. It allows passing a + * transform that will transform the path to the coordinate space in which + * aPoint is given. + */ + virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0; + + + /** This function checks if a point lies within the stroke of a path using the + * specified strokeoptions. It allows passing a transform that will transform + * the path to the coordinate space in which aPoint is given. + */ + virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, + const Point &aPoint, + const Matrix &aTransform) const = 0; + + /** This functions gets the bounds of this path. These bounds are not + * guaranteed to be tight. A transform may be specified that gives the bounds + * after application of the transform. + */ + virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const = 0; + + /** This function gets the bounds of the stroke of this path using the + * specified strokeoptions. These bounds are not guaranteed to be tight. + * A transform may be specified that gives the bounds after application of + * the transform. + */ + virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, + const Matrix &aTransform = Matrix()) const = 0; + + /** Take the contents of this path and stream it to another sink, this works + * regardless of the backend that might be used for the destination sink. + */ + virtual void StreamToSink(PathSink *aSink) const = 0; + + /** This gets the fillrule this path's builder was created with. This is not + * mutable. + */ + virtual FillRule GetFillRule() const = 0; + + /** This computes the total length of the path, moves act as if the current + * point is where the path was terminated, and the new point is where the + * cumulation of the length will resume. + */ + virtual Float ComputeLength(); + + /** This computes the point and the tangent vector on the path at a certain + * distance traveled along the path, ignoring moves. + */ + virtual Point ComputePointAtLength(Float aLength, + Point* aTangent = nullptr); + +protected: + Path(); + void EnsureFlattenedPath(); + + RefPtr mFlattenedPath; +}; + +/** The PathBuilder class allows path creation. Once finish is called on the + * pathbuilder it may no longer be written to. + */ +class PathBuilder : public PathSink +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilder) + /** Finish writing to the path and return a Path object that can be used for + * drawing. Future use of the builder results in a crash! + */ + virtual TemporaryRef Finish() = 0; +}; + +struct Glyph +{ + uint32_t mIndex; + Point mPosition; +}; + +/** This class functions as a glyph buffer that can be drawn to a DrawTarget. + * @todo XXX - This should probably contain the guts of gfxTextRun in the future as + * roc suggested. But for now it's a simple container for a glyph vector. + */ +struct GlyphBuffer +{ + const Glyph *mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller. + uint32_t mNumGlyphs; //!< Number of glyphs mGlyphs points to. +}; + +/** This class is an abstraction of a backend/platform specific font object + * at a particular size. It is passed into text drawing calls to describe + * the font used for the drawing call. + */ +class ScaledFont : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont) + virtual ~ScaledFont() {} + + typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton); + + virtual FontType GetType() const = 0; + + /** This allows getting a path that describes the outline of a set of glyphs. + * A target is passed in so that the guarantee is made the returned path + * can be used with any DrawTarget that has the same backend as the one + * passed in. + */ + virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0; + + /** This copies the path describing the glyphs into a PathBuilder. We use this + * API rather than a generic API to append paths because it allows easier + * implementation in some backends, and more efficient implementation in + * others. + */ + virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint = nullptr) = 0; + + virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; } + + void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { + mUserData.Add(key, userData, destroy); + } + void *GetUserData(UserDataKey *key) { + return mUserData.Get(key); + } + +protected: + ScaledFont() {} + + UserData mUserData; +}; + +/** + * Describes a font. + * Used to pass the key informatin from a gfxFont into Azure + * @todo Should be replaced by a more long term solution, perhaps Bug 738014 + */ +struct FontOptions +{ + std::string mName; + FontStyle mStyle; +}; + +/** This class is designed to allow passing additional glyph rendering + * parameters to the glyph drawing functions. This is an empty wrapper class + * merely used to allow holding on to and passing around platform specific + * parameters. This is because different platforms have unique rendering + * parameters. + */ +class GlyphRenderingOptions : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions) + virtual ~GlyphRenderingOptions() {} + + virtual FontType GetType() const = 0; + +protected: + GlyphRenderingOptions() {} +}; + +class DrawTargetCapture; + +/** This is the main class used for all the drawing. It is created through the + * factory and accepts drawing commands. The results of drawing to a target + * may be used either through a Snapshot or by flushing the target and directly + * accessing the backing store a DrawTarget was created with. + */ +class DrawTarget : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget) + DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {} + virtual ~DrawTarget() {} + + virtual DrawTargetType GetType() const = 0; + + virtual BackendType GetBackendType() const = 0; + /** + * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget. + * Multiple calls to Snapshot() without any drawing operations in between will + * normally return the same SourceSurface object. + */ + virtual TemporaryRef Snapshot() = 0; + virtual IntSize GetSize() = 0; + + /** + * If possible returns the bits to this DrawTarget for direct manipulation. While + * the bits is locked any modifications to this DrawTarget is forbidden. + * Release takes the original data pointer for safety. + */ + virtual bool LockBits(uint8_t** aData, IntSize* aSize, + int32_t* aStride, SurfaceFormat* aFormat) { return false; } + virtual void ReleaseBits(uint8_t* aData) {} + + /** Ensure that the DrawTarget backend has flushed all drawing operations to + * this draw target. This must be called before using the backing surface of + * this draw target outside of GFX 2D code. + */ + virtual void Flush() = 0; + + /** + * Realize a DrawTargetCapture onto the draw target. + * + * @param aSource Capture DrawTarget to draw + * @param aTransform Transform to apply when replaying commands + */ + virtual void DrawCapturedDT(DrawTargetCapture *aCaptureDT, + const Matrix& aTransform); + + /** + * Draw a surface to the draw target. Possibly doing partial drawing or + * applying scaling. No sampling happens outside the source. + * + * @param aSurface Source surface to draw + * @param aDest Destination rectangle that this drawing operation should draw to + * @param aSource Source rectangle in aSurface coordinates, this area of aSurface + * will be stretched to the size of aDest. + * @param aOptions General draw options that are applied to the operation + * @param aSurfOptions DrawSurface options that are applied + */ + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Draw the output of a FilterNode to the DrawTarget. + * + * @param aNode FilterNode to draw + * @param aSourceRect Source rectangle in FilterNode space to draw + * @param aDestPoint Destination point on the DrawTarget to draw the + * SourceRectangle of the filter output to + */ + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Blend a surface to the draw target with a shadow. The shadow is drawn as a + * gaussian blur using a specified sigma. The shadow is clipped to the size + * of the input surface, so the input surface should contain a transparent + * border the size of the approximate coverage of the blur (3 * aSigma). + * NOTE: This function works in device space! + * + * @param aSurface Source surface to draw. + * @param aDest Destination point that this drawing operation should draw to. + * @param aColor Color of the drawn shadow + * @param aOffset Offset of the shadow + * @param aSigma Sigma used for the guassian filter kernel + * @param aOperator Composition operator used + */ + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) = 0; + + /** + * Clear a rectangle on the draw target to transparent black. This will + * respect the clipping region and transform. + * + * @param aRect Rectangle to clear + */ + virtual void ClearRect(const Rect &aRect) = 0; + + /** + * This is essentially a 'memcpy' between two surfaces. It moves a pixel + * aligned area from the source surface unscaled directly onto the + * drawtarget. This ignores both transform and clip. + * + * @param aSurface Surface to copy from + * @param aSourceRect Source rectangle to be copied + * @param aDest Destination point to copy the surface to + */ + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) = 0; + + /** @see CopySurface + * Same as CopySurface, except uses itself as the source. + * + * Some backends may be able to optimize this better + * than just taking a snapshot and using CopySurface. + */ + virtual void CopyRect(const IntRect &aSourceRect, + const IntPoint &aDestination) + { + RefPtr source = Snapshot(); + CopySurface(source, aSourceRect, aDestination); + } + + /** + * Fill a rectangle on the DrawTarget with a certain source pattern. + * + * @param aRect Rectangle that forms the mask of this filling operation + * @param aPattern Pattern that forms the source of this filling operation + * @param aOptions Options that are applied to this operation + */ + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Stroke a rectangle on the DrawTarget with a certain source pattern. + * + * @param aRect Rectangle that forms the mask of this stroking operation + * @param aPattern Pattern that forms the source of this stroking operation + * @param aOptions Options that are applied to this operation + */ + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Stroke a line on the DrawTarget with a certain source pattern. + * + * @param aStart Starting point of the line + * @param aEnd End point of the line + * @param aPattern Pattern that forms the source of this stroking operation + * @param aOptions Options that are applied to this operation + */ + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Stroke a path on the draw target with a certain source pattern. + * + * @param aPath Path that is to be stroked + * @param aPattern Pattern that should be used for the stroke + * @param aStrokeOptions Stroke options used for this operation + * @param aOptions Draw options used for this operation + */ + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Fill a path on the draw target with a certain source pattern. + * + * @param aPath Path that is to be filled + * @param aPattern Pattern that should be used for the fill + * @param aOptions Draw options used for this operation + */ + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Fill a series of clyphs on the draw target with a certain source pattern. + */ + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions(), + const GlyphRenderingOptions *aRenderingOptions = nullptr) = 0; + + /** + * This takes a source pattern and a mask, and composites the source pattern + * onto the destination surface using the alpha channel of the mask pattern + * as a mask for the operation. + * + * @param aSource Source pattern + * @param aMask Mask pattern + * @param aOptions Drawing options + */ + virtual void Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * This takes a source pattern and a mask, and composites the source pattern + * onto the destination surface using the alpha channel of the mask source. + * The operation is bound by the extents of the mask. + * + * @param aSource Source pattern + * @param aMask Mask surface + * @param aOffset a transformed offset that the surface is masked at + * @param aOptions Drawing options + */ + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /** + * Push a clip to the DrawTarget. + * + * @param aPath The path to clip to + */ + virtual void PushClip(const Path *aPath) = 0; + + /** + * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle + * is specified in user space. + * + * @param aRect The rect to clip to + */ + virtual void PushClipRect(const Rect &aRect) = 0; + + /** Pop a clip from the DrawTarget. A pop without a corresponding push will + * be ignored. + */ + virtual void PopClip() = 0; + + /** + * Create a SourceSurface optimized for use with this DrawTarget from + * existing bitmap data in memory. + * + * The SourceSurface does not take ownership of aData, and may be freed at any time. + */ + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const = 0; + + /** + * Create a SourceSurface optimized for use with this DrawTarget from an + * arbitrary SourceSurface type supported by this backend. This may return + * aSourceSurface or some other existing surface. + */ + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const = 0; + + /** + * Create a SourceSurface for a type of NativeSurface. This may fail if the + * draw target does not know how to deal with the type of NativeSurface passed + * in. + */ + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const = 0; + + /** + * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget. + */ + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0; + + /** + * Create a DrawTarget that captures the drawing commands and can be replayed + * onto a compatible DrawTarget afterwards. + * + * @param aSize Size of the area this DT will capture. + */ + virtual TemporaryRef CreateCaptureDT(const IntSize& aSize); + + /** + * Create a draw target optimized for drawing a shadow. + * + * Note that aSigma is the blur radius that must be used when we draw the + * shadow. Also note that this doesn't affect the size of the allocated + * surface, the caller is still responsible for including the shadow area in + * its size. + */ + virtual TemporaryRef + CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat, + float aSigma) const + { + return CreateSimilarDrawTarget(aSize, aFormat); + } + + /** + * Create a path builder with the specified fillmode. + * + * We need the fill mode up front because of Direct2D. + * ID2D1SimplifiedGeometrySink requires the fill mode + * to be set before calling BeginFigure(). + */ + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const = 0; + + /** + * Create a GradientStops object that holds information about a set of + * gradient stops, this object is required for linear or radial gradient + * patterns to represent the color stops in the gradient. + * + * @param aStops An array of gradient stops + * @param aNumStops Number of stops in the array aStops + * @param aExtendNone This describes how to extend the stop color outside of the + * gradient area. + */ + virtual TemporaryRef + CreateGradientStops(GradientStop *aStops, + uint32_t aNumStops, + ExtendMode aExtendMode = ExtendMode::CLAMP) const = 0; + + /** + * Create a FilterNode object that can be used to apply a filter to various + * inputs. + * + * @param aType Type of filter node to be created. + */ + virtual TemporaryRef CreateFilter(FilterType aType) = 0; + + Matrix GetTransform() const { return mTransform; } + + /** + * Set a transform on the surface, this transform is applied at drawing time + * to both the mask and source of the operation. + * + * Performance note: For some backends it is expensive to change the current + * transform (because transforms affect a lot of the parts of the pipeline, + * so new transform change can result in a pipeline flush). To get around + * this, DrawTarget implementations buffer transform changes and try to only + * set the current transform on the backend when required. That tracking has + * its own performance impact though, and ideally callers would be smart + * enough not to require it. At a future date this method may stop this + * doing transform buffering so, if you're a consumer, please try to be smart + * about calling this method as little as possible. For example, instead of + * concatenating a translation onto the current transform then calling + * FillRect, try to integrate the translation into FillRect's aRect + * argument's x/y offset. + */ + virtual void SetTransform(const Matrix &aTransform) + { mTransform = aTransform; mTransformDirty = true; } + + inline void ConcatTransform(const Matrix &aTransform) + { SetTransform(aTransform * Matrix(GetTransform())); } + + SurfaceFormat GetFormat() { return mFormat; } + + /** Tries to get a native surface for a DrawTarget, this may fail if the + * draw target cannot convert to this surface type. + */ + virtual void *GetNativeSurface(NativeSurfaceType aType) { return nullptr; } + + virtual bool IsDualDrawTarget() const { return false; } + virtual bool IsTiledDrawTarget() const { return false; } + + void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { + mUserData.Add(key, userData, destroy); + } + void *GetUserData(UserDataKey *key) { + return mUserData.Get(key); + } + void *RemoveUserData(UserDataKey *key) { + return mUserData.Remove(key); + } + + /** Within this rectangle all pixels will be opaque by the time the result of + * this DrawTarget is first used for drawing. Either by the underlying surface + * being used as an input to external drawing, or Snapshot() being called. + * This rectangle is specified in device space. + */ + void SetOpaqueRect(const IntRect &aRect) { + mOpaqueRect = aRect; + } + + const IntRect &GetOpaqueRect() const { + return mOpaqueRect; + } + + virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) { + mPermitSubpixelAA = aPermitSubpixelAA; + } + + bool GetPermitSubpixelAA() { + return mPermitSubpixelAA; + } + +#ifdef USE_SKIA_GPU + virtual bool InitWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat) + { + MOZ_CRASH(); + } + + virtual bool InitWithGrContextAndFBO(GrContext* aGrContext, + unsigned int aFBOID, + const IntSize &aSize, + SurfaceFormat aFormat) + { + MOZ_CRASH(); + } + +#endif + +protected: + UserData mUserData; + Matrix mTransform; + IntRect mOpaqueRect; + bool mTransformDirty : 1; + bool mPermitSubpixelAA : 1; + + SurfaceFormat mFormat; +}; + +class DrawTargetCapture : public DrawTarget +{ +}; + +class DrawEventRecorder : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder) + virtual ~DrawEventRecorder() { } +}; + +struct Tile +{ + RefPtr mDrawTarget; + IntPoint mTileOrigin; +}; + +struct TileSet +{ + Tile* mTiles; + size_t mTileCount; +}; + +class GFX2D_API Factory +{ +public: + static bool HasSSE2(); + + /** Make sure that the given dimensions don't overflow a 32-bit signed int + * using 4 bytes per pixel; optionally, make sure that either dimension + * doesn't exceed the given limit. + */ + static bool CheckSurfaceSize(const IntSize &sz, int32_t limit = 0); + + static TemporaryRef CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr); + + static TemporaryRef + CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); + + static TemporaryRef + CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT); + + static TemporaryRef + CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat); + + static TemporaryRef + CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize); + + /** + * This creates a ScaledFont from TrueType data. + * + * @param aData Pointer to the data + * @param aSize Size of the TrueType data + * @param aFaceIndex Index of the font face in the truetype data this ScaledFont needs to represent. + * @param aGlyphSize Size of the glyphs in this ScaledFont + * @param aType Type of ScaledFont that should be created. + */ + static TemporaryRef + CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, uint32_t aFaceIndex, Float aGlyphSize, FontType aType); + + /** + * This creates a scaled font with an associated cairo_scaled_font_t, and + * must be used when using the Cairo backend. The NativeFont and + * cairo_scaled_font_t* parameters must correspond to the same font. + */ + static TemporaryRef + CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont); + + /** + * This creates a simple data source surface for a certain size. It allocates + * new memory for the surface. This memory is freed when the surface is + * destroyed. The caller is responsible for handing the case where nullptr + * is returned. The surface is not zeroed unless requested. + */ + static TemporaryRef + CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat, bool aZero = false); + + /** + * This creates a simple data source surface for a certain size with a + * specific stride, which must be large enough to fit all pixels. + * It allocates new memory for the surface. This memory is freed when + * the surface is destroyed. The caller is responsible for handling the case + * where nullptr is returned. The surface is not zeroed unless requested. + */ + static TemporaryRef + CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero = false); + + /** + * This creates a simple data source surface for some existing data. It will + * wrap this data and the data for this source surface. The caller is + * responsible for deallocating the memory only after destruction of the + * surface. + */ + static TemporaryRef + CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride, + const IntSize &aSize, SurfaceFormat aFormat); + + static TemporaryRef + CreateEventRecorderForFile(const char *aFilename); + + static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder); + + // This is a little hacky at the moment, but we want to have this data. Bug 1068613. + static void SetLogForwarder(LogForwarder* aLogFwd); + + static LogForwarder* GetLogForwarder() { return mLogForwarder; } + +private: + static LogForwarder* mLogForwarder; +public: + +#ifdef USE_SKIA_GPU + static TemporaryRef + CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat); + + static TemporaryRef + CreateDrawTargetSkiaWithGrContextAndFBO(GrContext* aGrContext, + unsigned int aFBOID, + const IntSize &aSize, + SurfaceFormat aFormat); +#endif + + static void PurgeTextureCaches(); + +#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE) + static TemporaryRef + CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting); +#endif + static TemporaryRef + CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB); + + /* + * This creates a new tiled DrawTarget. When a tiled drawtarget is used the + * drawing is distributed over number of tiles which may each hold an + * individual offset. The tiles in the set must each have the same backend + * and format. + */ + static TemporaryRef CreateTiledDrawTarget(const TileSet& aTileSet); + +#ifdef XP_MACOSX + static TemporaryRef CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize); +#endif + +#ifdef MOZ_ENABLE_FREETYPE + static FT_Library GetFreetypeLibrary(); +#endif + +#ifdef WIN32 + static TemporaryRef CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat); + static TemporaryRef + CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA, + ID3D10Texture2D *aTextureB, + SurfaceFormat aFormat); + + static void SetDirect3D10Device(ID3D10Device1 *aDevice); + static ID3D10Device1 *GetDirect3D10Device(); +#ifdef USE_D2D1_1 + static TemporaryRef CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat); + + static void SetDirect3D11Device(ID3D11Device *aDevice); + static ID3D11Device *GetDirect3D11Device(); + static ID2D1Device *GetD2D1Device(); + static bool SupportsD2D1(); +#endif + + static TemporaryRef + CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams); + + static uint64_t GetD2DVRAMUsageDrawTarget(); + static uint64_t GetD2DVRAMUsageSourceSurface(); + static void D2DCleanup(); + +private: + static ID3D10Device1 *mD3D10Device; +#ifdef USE_D2D1_1 + static ID3D11Device *mD3D11Device; + static ID2D1Device *mD2D1Device; +#endif +#endif + +private: + + static DrawEventRecorder *mRecorder; + +#ifdef MOZ_ENABLE_FREETYPE + static FT_Library mFreetypeLibrary; +#endif +}; + +} +} + +#endif // _MOZILLA_GFX_2D_H diff --git a/libazure/BaseCoord.h b/libazure/BaseCoord.h new file mode 100644 index 0000000..bbccbc7 --- /dev/null +++ b/libazure/BaseCoord.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_BASECOORD_H_ +#define MOZILLA_GFX_BASECOORD_H_ + +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace gfx { + +/** + * Do not use this class directly. Subclass it, pass that subclass as the + * Sub parameter, and only use that subclass. This allows methods to safely + * cast 'this' to 'Sub*'. + */ +template +struct BaseCoord { + T value; + + // Constructors + MOZ_CONSTEXPR BaseCoord() : value(0) {} + explicit MOZ_CONSTEXPR BaseCoord(T aValue) : value(aValue) {} + + // Note that '=' isn't defined so we'll get the + // compiler generated default assignment operator + + operator T() const { return value; } + + friend bool operator==(Sub aA, Sub aB) { + return aA.value == aB.value; + } + friend bool operator!=(Sub aA, Sub aB) { + return aA.value != aB.value; + } + + friend Sub operator+(Sub aA, Sub aB) { + return Sub(aA.value + aB.value); + } + friend Sub operator-(Sub aA, Sub aB) { + return Sub(aA.value - aB.value); + } + friend Sub operator*(Sub aCoord, T aScale) { + return Sub(aCoord.value * aScale); + } + friend Sub operator*(T aScale, Sub aCoord) { + return Sub(aScale * aCoord.value); + } + friend Sub operator/(Sub aCoord, T aScale) { + return Sub(aCoord.value / aScale); + } + // 'scale / coord' is intentionally omitted because it doesn't make sense. + + Sub& operator+=(Sub aCoord) { + value += aCoord.value; + return *static_cast(this); + } + Sub& operator-=(Sub aCoord) { + value -= aCoord.value; + return *static_cast(this); + } + Sub& operator*=(T aScale) { + value *= aScale; + return *static_cast(this); + } + Sub& operator/=(T aScale) { + value /= aScale; + return *static_cast(this); + } + + // Since BaseCoord is implicitly convertible to its value type T, we need + // mixed-type operator overloads to avoid ambiguities at mixed-type call + // sites. As we transition more of our code to strongly-typed classes, we + // may be able to remove some or all of these overloads. + friend bool operator==(Sub aA, T aB) { + return aA.value == aB; + } + friend bool operator==(T aA, Sub aB) { + return aA == aB.value; + } + friend bool operator!=(Sub aA, T aB) { + return aA.value != aB; + } + friend bool operator!=(T aA, Sub aB) { + return aA != aB.value; + } + friend T operator+(Sub aA, T aB) { + return aA.value + aB; + } + friend T operator+(T aA, Sub aB) { + return aA + aB.value; + } + friend T operator-(Sub aA, T aB) { + return aA.value - aB; + } + friend T operator-(T aA, Sub aB) { + return aA - aB.value; + } + + Sub operator-() const { + return Sub(-value); + } +}; + +} +} + +#endif /* MOZILLA_GFX_BASECOORD_H_ */ diff --git a/libazure/include/mozilla/gfx/BaseMargin.h b/libazure/BaseMargin.h similarity index 57% rename from libazure/include/mozilla/gfx/BaseMargin.h rename to libazure/BaseMargin.h index e7203b0..2230e48 100644 --- a/libazure/include/mozilla/gfx/BaseMargin.h +++ b/libazure/BaseMargin.h @@ -9,6 +9,57 @@ #include "Types.h" namespace mozilla { + +/** + * Sides represents a set of physical sides. + */ +struct Sides MOZ_FINAL { + Sides() : mBits(0) {} + explicit Sides(SideBits aSideBits) + { + MOZ_ASSERT((aSideBits & ~eSideBitsAll) == 0, "illegal side bits"); + mBits = aSideBits; + } + bool IsEmpty() const { return mBits == 0; } + bool Top() const { return mBits & eSideBitsTop; } + bool Right() const { return mBits & eSideBitsRight; } + bool Bottom() const { return mBits & eSideBitsBottom; } + bool Left() const { return mBits & eSideBitsLeft; } + bool Contains(SideBits aSideBits) const + { + MOZ_ASSERT((aSideBits & ~eSideBitsAll) == 0, "illegal side bits"); + return (mBits & aSideBits) == aSideBits; + } + Sides operator|(Sides aOther) const + { + return Sides(SideBits(mBits | aOther.mBits)); + } + Sides operator|(SideBits aSideBits) const + { + return *this | Sides(aSideBits); + } + Sides& operator|=(Sides aOther) + { + mBits |= aOther.mBits; + return *this; + } + Sides& operator|=(SideBits aSideBits) + { + return *this |= Sides(aSideBits); + } + bool operator==(Sides aOther) const + { + return mBits == aOther.mBits; + } + bool operator!=(Sides aOther) const + { + return !(*this == aOther); + } + +private: + uint8_t mBits; +}; + namespace gfx { /** @@ -17,7 +68,7 @@ namespace gfx { */ template struct BaseMargin { - typedef mozilla::css::Side SideT; + typedef mozilla::Side SideT; // because we have a method named Side // Do not change the layout of these members; the Side() methods below // depend on this order. @@ -38,11 +89,27 @@ struct BaseMargin { T& Side(SideT aSide) { // This is ugly! - return *(&top + aSide); + return *(&top + T(aSide)); } T Side(SideT aSide) const { // This is ugly! - return *(&top + aSide); + return *(&top + T(aSide)); + } + + void ApplySkipSides(Sides aSkipSides) + { + if (aSkipSides.Top()) { + top = 0; + } + if (aSkipSides.Right()) { + right = 0; + } + if (aSkipSides.Bottom()) { + bottom = 0; + } + if (aSkipSides.Left()) { + left = 0; + } } // Overloaded operators. Note that '=' isn't defined so we'll get the diff --git a/libazure/include/mozilla/gfx/BasePoint.h b/libazure/BasePoint.h similarity index 68% rename from libazure/include/mozilla/gfx/BasePoint.h rename to libazure/BasePoint.h index a7da0cc..6e59b6b 100644 --- a/libazure/include/mozilla/gfx/BasePoint.h +++ b/libazure/BasePoint.h @@ -6,6 +6,10 @@ #ifndef MOZILLA_GFX_BASEPOINT_H_ #define MOZILLA_GFX_BASEPOINT_H_ +#include +#include "mozilla/Attributes.h" +#include "mozilla/ToString.h" + namespace mozilla { namespace gfx { @@ -14,13 +18,13 @@ namespace gfx { * Sub parameter, and only use that subclass. This allows methods to safely * cast 'this' to 'Sub*'. */ -template +template struct BasePoint { T x, y; // Constructors - BasePoint() : x(0), y(0) {} - BasePoint(T aX, T aY) : x(aX), y(aY) {} + MOZ_CONSTEXPR BasePoint() : x(0), y(0) {} + MOZ_CONSTEXPR BasePoint(Coord aX, Coord aY) : x(aX), y(aY) {} void MoveTo(T aX, T aY) { x = aX; y = aY; } void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; } @@ -62,6 +66,24 @@ struct BasePoint { Sub operator-() const { return Sub(-x, -y); } + + T Length() const { + return hypot(x, y); + } + + // Round() is *not* rounding to nearest integer if the values are negative. + // They are always rounding as floor(n + 0.5). + // See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14 + Sub& Round() { + x = Coord(floor(T(x) + T(0.5))); + y = Coord(floor(T(y) + T(0.5))); + return *static_cast(this); + } + + friend std::ostream& operator<<(std::ostream& stream, const BasePoint& aPoint) { + return stream << '(' << aPoint.x << ',' << aPoint.y << ')'; + } + }; } diff --git a/libazure/src/gfx/2d/BasePoint3D.h b/libazure/BasePoint3D.h similarity index 95% rename from libazure/src/gfx/2d/BasePoint3D.h rename to libazure/BasePoint3D.h index a5fb266..c64ea24 100644 --- a/libazure/src/gfx/2d/BasePoint3D.h +++ b/libazure/BasePoint3D.h @@ -6,6 +6,8 @@ #ifndef MOZILLA_BASEPOINT3D_H_ #define MOZILLA_BASEPOINT3D_H_ +#include "mozilla/Assertions.h" + namespace mozilla { namespace gfx { @@ -29,12 +31,12 @@ struct BasePoint3D { // compiler generated default assignment operator T& operator[](int aIndex) { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 2); return *((&x)+aIndex); } const T& operator[](int aIndex) const { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 2); return *((&x)+aIndex); } diff --git a/libazure/src/gfx/2d/BasePoint4D.h b/libazure/BasePoint4D.h similarity index 93% rename from libazure/src/gfx/2d/BasePoint4D.h rename to libazure/BasePoint4D.h index ab9fa45..e098876 100644 --- a/libazure/src/gfx/2d/BasePoint4D.h +++ b/libazure/BasePoint4D.h @@ -6,6 +6,8 @@ #ifndef MOZILLA_BASEPOINT4D_H_ #define MOZILLA_BASEPOINT4D_H_ +#include "mozilla/Assertions.h" + namespace mozilla { namespace gfx { @@ -86,12 +88,12 @@ struct BasePoint4D { } T& operator[](int aIndex) { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid array index"); return *((&x)+aIndex); } const T& operator[](int aIndex) const { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid array index"); return *((&x)+aIndex); } @@ -114,6 +116,8 @@ struct BasePoint4D { void Normalize() { *this /= Length(); } + + bool HasPositiveWCoord() { return w > 0; } }; } diff --git a/libazure/include/mozilla/gfx/BaseRect.h b/libazure/BaseRect.h similarity index 77% rename from libazure/include/mozilla/gfx/BaseRect.h rename to libazure/BaseRect.h index c873504..9daebad 100644 --- a/libazure/include/mozilla/gfx/BaseRect.h +++ b/libazure/BaseRect.h @@ -6,9 +6,13 @@ #ifndef MOZILLA_GFX_BASERECT_H_ #define MOZILLA_GFX_BASERECT_H_ -#include -#include #include +#include +#include + +#include "mozilla/Assertions.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/TypeTraits.h" namespace mozilla { namespace gfx { @@ -36,7 +40,7 @@ namespace gfx { * Do not use this class directly. Subclass it, pass that subclass as the * Sub parameter, and only use that subclass. */ -template +template struct BaseRect { T x, y, width, height; @@ -56,6 +60,16 @@ struct BaseRect { bool IsEmpty() const { return height <= 0 || width <= 0; } void SetEmpty() { width = height = 0; } + // "Finite" means not inf and not NaN + bool IsFinite() const + { + typedef typename mozilla::Conditional::value, float, double>::Type FloatType; + return (mozilla::IsFinite(FloatType(x)) && + mozilla::IsFinite(FloatType(y)) && + mozilla::IsFinite(FloatType(width)) && + mozilla::IsFinite(FloatType(height))); + } + // Returns true if this rectangle contains the interior of aRect. Always // returns true if aRect is empty, and always returns false is aRect is // nonempty but this rect is empty. @@ -65,13 +79,17 @@ struct BaseRect { (x <= aRect.x && aRect.XMost() <= XMost() && y <= aRect.y && aRect.YMost() <= YMost()); } - // Returns true if this rectangle contains the rectangle (aX,aY,1,1). + // Returns true if this rectangle contains the point. Points are considered + // in the rectangle if they are on the left or top edge, but outside if they + // are on the right or bottom edge. bool Contains(T aX, T aY) const { - return x <= aX && aX + 1 <= XMost() && - y <= aY && aY + 1 <= YMost(); + return x <= aX && aX < XMost() && + y <= aY && aY < YMost(); } - // Returns true if this rectangle contains the rectangle (aPoint.x,aPoint.y,1,1). + // Returns true if this rectangle contains the point. Points are considered + // in the rectangle if they are on the left or top edge, but outside if they + // are on the right or bottom edge. bool Contains(const Point& aPoint) const { return Contains(aPoint.x, aPoint.y); } // Intersection. Returns TRUE if the receiver's area has non-empty @@ -79,7 +97,8 @@ struct BaseRect { // Always returns false if aRect is empty or 'this' is empty. bool Intersects(const Sub& aRect) const { - return x < aRect.XMost() && aRect.x < XMost() && + return !IsEmpty() && !aRect.IsEmpty() && + x < aRect.XMost() && aRect.x < XMost() && y < aRect.YMost() && aRect.y < YMost(); } // Returns the rectangle containing the intersection of the points @@ -89,10 +108,10 @@ struct BaseRect { Sub Intersect(const Sub& aRect) const { Sub result; - result.x = std::max(x, aRect.x); - result.y = std::max(y, aRect.y); - result.width = std::min(XMost(), aRect.XMost()) - result.x; - result.height = std::min(YMost(), aRect.YMost()) - result.y; + result.x = std::max(x, aRect.x); + result.y = std::max(y, aRect.y); + result.width = std::min(XMost(), aRect.XMost()) - result.x; + result.height = std::min(YMost(), aRect.YMost()) - result.y; if (result.width < 0 || result.height < 0) { result.SizeTo(0, 0); } @@ -180,7 +199,7 @@ struct BaseRect { width += 2 * aDx; height += 2 * aDy; } - void Inflate(const Margin& aMargin) + void Inflate(const MarginT& aMargin) { x -= aMargin.left; y -= aMargin.top; @@ -189,6 +208,20 @@ struct BaseRect { } void Inflate(const SizeT& aSize) { Inflate(aSize.width, aSize.height); } + void InflateToMultiple(const SizeT& aMultiple) + { + T xMost = XMost(); + T yMost = YMost(); + + x = static_cast(floor(x / aMultiple.width)) * aMultiple.width; + y = static_cast(floor(y / aMultiple.height)) * aMultiple.height; + xMost = static_cast(ceil(x / aMultiple.width)) * aMultiple.width; + yMost = static_cast(ceil(y / aMultiple.height)) * aMultiple.height; + + width = xMost - x; + height = yMost - y; + } + void Deflate(T aD) { Deflate(aD, aD); } void Deflate(T aDx, T aDy) { @@ -197,7 +230,7 @@ struct BaseRect { width = std::max(T(0), width - 2 * aDx); height = std::max(T(0), height - 2 * aDy); } - void Deflate(const Margin& aMargin) + void Deflate(const MarginT& aMargin) { x += aMargin.left; y += aMargin.top; @@ -222,13 +255,25 @@ struct BaseRect { return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty()); } - Sub operator+(const Point& aPoint) const + friend Sub operator+(Sub aSub, const Point& aPoint) + { + aSub += aPoint; + return aSub; + } + friend Sub operator-(Sub aSub, const Point& aPoint) + { + aSub -= aPoint; + return aSub; + } + friend Sub operator+(Sub aSub, const SizeT& aSize) { - return Sub(x + aPoint.x, y + aPoint.y, width, height); + aSub += aSize; + return aSub; } - Sub operator-(const Point& aPoint) const + friend Sub operator-(Sub aSub, const SizeT& aSize) { - return Sub(x - aPoint.x, y - aPoint.y, width, height); + aSub -= aSize; + return aSub; } Sub& operator+=(const Point& aPoint) { @@ -240,14 +285,25 @@ struct BaseRect { MoveBy(-aPoint); return *static_cast(this); } - + Sub& operator+=(const SizeT& aSize) + { + width += aSize.width; + height += aSize.height; + return *static_cast(this); + } + Sub& operator-=(const SizeT& aSize) + { + width -= aSize.width; + height -= aSize.height; + return *static_cast(this); + } // Find difference as a Margin - Margin operator-(const Sub& aRect) const + MarginT operator-(const Sub& aRect) const { - return Margin(aRect.y - y, - XMost() - aRect.XMost(), - YMost() - aRect.YMost(), - aRect.x - x); + return MarginT(aRect.y - y, + XMost() - aRect.XMost(), + YMost() - aRect.YMost(), + aRect.x - x); } // Helpers for accessing the vertices @@ -343,6 +399,31 @@ struct BaseRect { height = y1 - y0; } + // Scale 'this' by aScale without doing any rounding. + void Scale(T aScale) { Scale(aScale, aScale); } + // Scale 'this' by aXScale and aYScale, without doing any rounding. + void Scale(T aXScale, T aYScale) + { + T right = XMost() * aXScale; + T bottom = YMost() * aYScale; + x = x * aXScale; + y = y * aYScale; + width = right - x; + height = bottom - y; + } + + // Scale 'this' by aScale without doing any rounding. + void ScaleInverse(T aScale) { ScaleInverse(aScale, aScale); } + // Scale 'this' by aXScale and aYScale, without doing any rounding. + void ScaleInverse(T aXScale, T aYScale) + { + T right = static_cast(XMost() / aXScale); + T bottom = static_cast(YMost() / aYScale); + x = static_cast(x / aXScale); + y = static_cast(y / aYScale); + width = right - x; + height = bottom - y; + } // Scale 'this' by aScale, converting coordinates to integers so that the result is // the smallest integer-coordinate rectangle containing the unrounded result. // Note: this can turn an empty rectangle into a non-empty rectangle @@ -418,6 +499,28 @@ struct BaseRect { std::max(y, std::min(YMost(), aPoint.y))); } + /** + * Clamp this rectangle to be inside aRect. The function returns a copy of + * this rect after it is forced inside the bounds of aRect. It will attempt to + * retain the size but will shrink the dimensions that don't fit. + */ + Sub ForceInside(const Sub& aRect) const + { + Sub rect(std::max(aRect.x, x), + std::max(aRect.y, y), + std::min(aRect.width, width), + std::min(aRect.height, height)); + rect.x = std::min(rect.XMost(), aRect.XMost()) - rect.width; + rect.y = std::min(rect.YMost(), aRect.YMost()) - rect.height; + return rect; + } + + friend std::ostream& operator<<(std::ostream& stream, + const BaseRect& aRect) { + return stream << '(' << aRect.x << ',' << aRect.y << ',' + << aRect.width << ',' << aRect.height << ')'; + } + private: // Do not use the default operator== or operator!= ! // Use IsEqualEdges or IsEqualInterior explicitly. diff --git a/libazure/include/mozilla/gfx/BaseSize.h b/libazure/BaseSize.h similarity index 93% rename from libazure/include/mozilla/gfx/BaseSize.h rename to libazure/BaseSize.h index 54c578d..cea5bc6 100644 --- a/libazure/include/mozilla/gfx/BaseSize.h +++ b/libazure/BaseSize.h @@ -6,6 +6,8 @@ #ifndef MOZILLA_GFX_BASESIZE_H_ #define MOZILLA_GFX_BASESIZE_H_ +#include "mozilla/Attributes.h" + namespace mozilla { namespace gfx { @@ -19,8 +21,8 @@ struct BaseSize { T width, height; // Constructors - BaseSize() : width(0), height(0) {} - BaseSize(T aWidth, T aHeight) : width(aWidth), height(aHeight) {} + MOZ_CONSTEXPR BaseSize() : width(0), height(0) {} + MOZ_CONSTEXPR BaseSize(T aWidth, T aHeight) : width(aWidth), height(aHeight) {} void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; } diff --git a/libazure/src/gfx/2d/Blur.cpp b/libazure/Blur.cpp similarity index 90% rename from libazure/src/gfx/2d/Blur.cpp rename to libazure/Blur.cpp index 77f5ee3..952f4c9 100644 --- a/libazure/src/gfx/2d/Blur.cpp +++ b/libazure/Blur.cpp @@ -1,8 +1,10 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/gfx/Blur.h" +#include "Blur.h" #include #include @@ -13,6 +15,7 @@ #include "mozilla/Util.h" #include "2D.h" +#include "DataSurfaceHelpers.h" #include "Tools.h" using namespace std; @@ -333,8 +336,7 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect, const Rect* aSkipRect) : mSpreadRadius(aSpreadRadius), mBlurRadius(aBlurRadius), - mData(nullptr), - mFreeData(true) + mSurfaceAllocationSize(0) { Rect rect(aRect); rect.Inflate(Size(aBlurRadius + aSpreadRadius)); @@ -383,40 +385,36 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect, // We need to leave room for an additional 3 bytes for a potential overrun // in our blurring code. - CheckedInt size = CheckedInt(mStride) * mRect.height + 3; - if (size.isValid()) { - mData = new uint8_t[size.value()]; - memset(mData, 0, size.value()); + size_t size = BufferSizeFromStrideAndHeight(mStride, mRect.height, 3); + if (size != 0) { + mSurfaceAllocationSize = size; } } } -AlphaBoxBlur::AlphaBoxBlur(uint8_t* aData, - const Rect& aRect, +AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect, int32_t aStride, - float aSigma) + float aSigmaX, + float aSigmaY) : mRect(int32_t(aRect.x), int32_t(aRect.y), int32_t(aRect.width), int32_t(aRect.height)), mSpreadRadius(), - mBlurRadius(CalculateBlurRadius(Point(aSigma, aSigma))), - mData(aData), - mFreeData(false), - mStride(aStride) + mBlurRadius(CalculateBlurRadius(Point(aSigmaX, aSigmaY))), + mStride(aStride), + mSurfaceAllocationSize(0) { + IntRect intRect; + if (aRect.ToIntRect(&intRect)) { + size_t minDataSize = BufferSizeFromStrideAndHeight(intRect.width, intRect.height); + if (minDataSize != 0) { + mSurfaceAllocationSize = minDataSize; + } + } } AlphaBoxBlur::~AlphaBoxBlur() { - if (mFreeData) { - delete [] mData; - } -} - -unsigned char* -AlphaBoxBlur::GetData() -{ - return mData; } IntSize @@ -448,10 +446,16 @@ AlphaBoxBlur::GetDirtyRect() return nullptr; } +size_t +AlphaBoxBlur::GetSurfaceAllocationSize() const +{ + return mSurfaceAllocationSize; +} + void -AlphaBoxBlur::Blur() +AlphaBoxBlur::Blur(uint8_t* aData) { - if (!mData) { + if (!aData) { return; } @@ -464,12 +468,16 @@ AlphaBoxBlur::Blur() if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) { // No need to use CheckedInt here - we have validated it in the constructor. size_t szB = stride * size.height; - unsigned char* tmpData = new uint8_t[szB]; + unsigned char* tmpData = new (std::nothrow) uint8_t[szB]; + + if (!tmpData) { + return; + } memset(tmpData, 0, szB); - SpreadHorizontal(mData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect); - SpreadVertical(tmpData, mData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect); + SpreadHorizontal(aData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect); + SpreadVertical(tmpData, aData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect); delete [] tmpData; } @@ -491,10 +499,14 @@ AlphaBoxBlur::Blur() // No need to use CheckedInt here - we have validated it in the constructor. size_t szB = stride * size.height; - uint8_t* tmpData = new uint8_t[szB]; + uint8_t* tmpData = new (std::nothrow) uint8_t[szB]; + if (!tmpData) { + return; + } + memset(tmpData, 0, szB); - uint8_t* a = mData; + uint8_t* a = aData; uint8_t* b = tmpData; if (mBlurRadius.width > 0) { BoxBlurHorizontal(a, b, horizontalLobes[0][0], horizontalLobes[0][1], stride, GetSize().height, mSkipRect); @@ -502,7 +514,7 @@ AlphaBoxBlur::Blur() BoxBlurHorizontal(a, b, horizontalLobes[2][0], horizontalLobes[2][1], stride, GetSize().height, mSkipRect); } else { a = tmpData; - b = mData; + b = aData; } // The result is in 'b' here. if (mBlurRadius.height > 0) { @@ -514,7 +526,7 @@ AlphaBoxBlur::Blur() } // The result is in 'a' here. if (a == tmpData) { - memcpy(mData, tmpData, szB); + memcpy(aData, tmpData, szB); } delete [] tmpData; } else { @@ -522,24 +534,33 @@ AlphaBoxBlur::Blur() // We need to leave room for an additional 12 bytes for a maximum overrun // of 3 pixels in the blurring code. - AlignedArray integralImage((integralImageStride / 4) * integralImageSize.height + 12); + size_t bufLen = BufferSizeFromStrideAndHeight(integralImageStride, integralImageSize.height, 12); + if (bufLen == 0) { + return; + } + // bufLen is a byte count, but here we want a multiple of 32-bit ints, so + // we divide by 4. + AlignedArray integralImage((bufLen / 4) + ((bufLen % 4) ? 1 : 0)); + if (!integralImage) { + return; + } #ifdef USE_SSE2 if (Factory::HasSSE2()) { - BoxBlur_SSE2(horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0], + BoxBlur_SSE2(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0], verticalLobes[0][1], integralImage, integralImageStride); - BoxBlur_SSE2(horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0], + BoxBlur_SSE2(aData, horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0], verticalLobes[1][1], integralImage, integralImageStride); - BoxBlur_SSE2(horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0], + BoxBlur_SSE2(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0], verticalLobes[2][1], integralImage, integralImageStride); } else #endif { - BoxBlur_C(horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0], + BoxBlur_C(aData, horizontalLobes[0][0], horizontalLobes[0][1], verticalLobes[0][0], verticalLobes[0][1], integralImage, integralImageStride); - BoxBlur_C(horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0], + BoxBlur_C(aData, horizontalLobes[1][0], horizontalLobes[1][1], verticalLobes[1][0], verticalLobes[1][1], integralImage, integralImageStride); - BoxBlur_C(horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0], + BoxBlur_C(aData, horizontalLobes[2][0], horizontalLobes[2][1], verticalLobes[2][0], verticalLobes[2][1], integralImage, integralImageStride); } } @@ -626,7 +647,8 @@ GenerateIntegralImage_C(int32_t aLeftInflation, int32_t aRightInflation, * Attempt to do an in-place box blur using an integral image. */ void -AlphaBoxBlur::BoxBlur_C(int32_t aLeftLobe, +AlphaBoxBlur::BoxBlur_C(uint8_t* aData, + int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, int32_t aBottomLobe, @@ -655,7 +677,7 @@ AlphaBoxBlur::BoxBlur_C(int32_t aLeftLobe, int32_t leftInflation = RoundUpToMultipleOf4(aLeftLobe).value(); GenerateIntegralImage_C(leftInflation, aRightLobe, aTopLobe, aBottomLobe, - aIntegralImage, aIntegralImageStride, mData, + aIntegralImage, aIntegralImageStride, aData, mStride, size); uint32_t reciprocal = uint32_t((uint64_t(1) << 32) / boxSize); @@ -665,7 +687,7 @@ AlphaBoxBlur::BoxBlur_C(int32_t aLeftLobe, // Storing these locally makes this about 30% faster! Presumably the compiler // can't be sure we're not altering the member variables in this loop. IntRect skipRect = mSkipRect; - uint8_t *data = mData; + uint8_t *data = aData; int32_t stride = mStride; for (int32_t y = 0; y < size.height; y++) { bool inSkipRectY = y > skipRect.y && y < skipRect.YMost(); @@ -713,8 +735,8 @@ static const Float GAUSSIAN_SCALE_FACTOR = Float((3 * sqrt(2 * M_PI) / 4) * 1.5) IntSize AlphaBoxBlur::CalculateBlurRadius(const Point& aStd) { - IntSize size(static_cast(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)), - static_cast(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5))); + IntSize size(static_cast(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5f)), + static_cast(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5f))); return size; } diff --git a/libazure/include/mozilla/gfx/Blur.h b/libazure/Blur.h similarity index 67% rename from libazure/include/mozilla/gfx/Blur.h rename to libazure/Blur.h index d425d6e..c0ed42e 100644 --- a/libazure/include/mozilla/gfx/Blur.h +++ b/libazure/Blur.h @@ -1,3 +1,5 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -5,8 +7,8 @@ #ifndef MOZILLA_GFX_BLUR_H_ #define MOZILLA_GFX_BLUR_H_ -#include "mozilla/gfx/Rect.h" -#include "mozilla/gfx/Point.h" +#include "Rect.h" +#include "Point.h" #include "mozilla/CheckedInt.h" namespace mozilla { @@ -24,21 +26,21 @@ namespace gfx { * would be obtained using a different (rotated) set of axes. A triple * box blur is a very close approximation of a Gaussian. * - * Creates an 8-bit alpha channel context for callers to draw in, - * spreads the contents of that context, and blurs the contents. + * This is a "service" class; the constructors set up all the information + * based on the values and compute the minimum size for an 8-bit alpha + * channel context. + * The callers are responsible for creating and managing the backing surface + * and passing the pointer to the data to the Blur() method. This class does + * not retain the pointer to the data outside of the Blur() call. * * A spread N makes each output pixel the maximum value of all source * pixels within a square of side length 2N+1 centered on the output pixel. - * - * A temporary surface is created in the Init function. The caller then draws - * any desired content onto the context acquired through GetContext, and lastly - * calls Paint to apply the blurred content as an alpha mask. */ class GFX2D_API AlphaBoxBlur { public: - /** Constructs a box blur and initializes the backing surface. + /** Constructs a box blur and computes the backing surface size. * * @param aRect The coordinates of the surface to create in device units. * @@ -62,29 +64,20 @@ class GFX2D_API AlphaBoxBlur const Rect* aDirtyRect, const Rect* aSkipRect); - AlphaBoxBlur(uint8_t* aData, - const Rect& aRect, + AlphaBoxBlur(const Rect& aRect, int32_t aStride, - float aSigma); + float aSigmaX, + float aSigmaY); ~AlphaBoxBlur(); /** - * Return the pointer to memory allocated by the constructor for the 8-bit - * alpha surface you need to be blurred. After you draw to this surface, call - * Blur(), below, to have its contents blurred. - */ - unsigned char* GetData(); - - /** - * Return the size, in pixels, of the 8-bit alpha surface backed by the - * pointer returned by GetData(). + * Return the size, in pixels, of the 8-bit alpha surface we'd use. */ IntSize GetSize(); /** - * Return the stride, in bytes, of the 8-bit alpha surface backed by the - * pointer returned by GetData(). + * Return the stride, in bytes, of the 8-bit alpha surface we'd use. */ int32_t GetStride(); @@ -100,10 +93,20 @@ class GFX2D_API AlphaBoxBlur Rect* GetDirtyRect(); /** - * Perform the blur in-place on the surface backed by the pointer returned by - * GetData(). + * Return the minimum buffer size that should be given to Blur() method. If + * zero, the class is not properly setup for blurring. Note that this + * includes the extra three bytes on top of the stride*width, where something + * like gfxImageSurface::GetDataSize() would report without it, even if it + * happens to have the extra bytes. */ - void Blur(); + size_t GetSurfaceAllocationSize() const; + + /** + * Perform the blur in-place on the surface backed by specified 8-bit + * alpha surface data. The size must be at least that returned by + * GetSurfaceAllocationSize() or bad things will happen. + */ + void Blur(uint8_t* aData); /** * Calculates a blur radius that, when used with box blur, approximates a @@ -115,9 +118,11 @@ class GFX2D_API AlphaBoxBlur private: - void BoxBlur_C(int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, + void BoxBlur_C(uint8_t* aData, + int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, int32_t aBottomLobe, uint32_t *aIntegralImage, size_t aIntegralImageStride); - void BoxBlur_SSE2(int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, + void BoxBlur_SSE2(uint8_t* aData, + int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, int32_t aBottomLobe, uint32_t *aIntegralImage, size_t aIntegralImageStride); static CheckedInt RoundUpToMultipleOf4(int32_t aVal); @@ -150,19 +155,14 @@ class GFX2D_API AlphaBoxBlur IntSize mBlurRadius; /** - * A pointer to the backing 8-bit alpha surface. - */ - uint8_t* mData; - - /** - * True if we need to dispose the data. + * The stride of the data passed to Blur() */ - bool mFreeData; + int32_t mStride; /** - * The stride of the data contained in mData. + * The minimum size of the buffer needed for the Blur() operation. */ - int32_t mStride; + size_t mSurfaceAllocationSize; /** * Whether mDirtyRect contains valid data. diff --git a/libazure/src/gfx/2d/BlurSSE2.cpp b/libazure/BlurSSE2.cpp similarity index 98% rename from libazure/src/gfx/2d/BlurSSE2.cpp rename to libazure/BlurSSE2.cpp index d53153d..d67cf07 100644 --- a/libazure/src/gfx/2d/BlurSSE2.cpp +++ b/libazure/BlurSSE2.cpp @@ -174,7 +174,8 @@ GenerateIntegralImage_SSE2(int32_t aLeftInflation, int32_t aRightInflation, * Attempt to do an in-place box blur using an integral image. */ void -AlphaBoxBlur::BoxBlur_SSE2(int32_t aLeftLobe, +AlphaBoxBlur::BoxBlur_SSE2(uint8_t* aData, + int32_t aLeftLobe, int32_t aRightLobe, int32_t aTopLobe, int32_t aBottomLobe, @@ -204,7 +205,7 @@ AlphaBoxBlur::BoxBlur_SSE2(int32_t aLeftLobe, int32_t leftInflation = RoundUpToMultipleOf4(aLeftLobe).value(); GenerateIntegralImage_SSE2(leftInflation, aRightLobe, aTopLobe, aBottomLobe, - aIntegralImage, aIntegralImageStride, mData, + aIntegralImage, aIntegralImageStride, aData, mStride, size); __m128i divisor = _mm_set1_epi32(reciprocal); @@ -216,7 +217,7 @@ AlphaBoxBlur::BoxBlur_SSE2(int32_t aLeftLobe, IntRect skipRect = mSkipRect; int32_t stride = mStride; - uint8_t *data = mData; + uint8_t *data = aData; for (int32_t y = 0; y < size.height; y++) { bool inSkipRectY = y > skipRect.y && y < skipRect.YMost(); diff --git a/libazure/BorrowedContext.h b/libazure/BorrowedContext.h new file mode 100644 index 0000000..f7f16f2 --- /dev/null +++ b/libazure/BorrowedContext.h @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_BORROWED_CONTEXT_H +#define _MOZILLA_GFX_BORROWED_CONTEXT_H + +#include "2D.h" + +struct _cairo; +typedef struct _cairo cairo_t; + +namespace mozilla { + +namespace gfx { + +/* This is a helper class that let's you borrow a cairo_t from a + * DrawTargetCairo. This is used for drawing themed widgets. + * + * Callers should check the cr member after constructing the object + * to see if it succeeded. The DrawTarget should not be used while + * the context is borrowed. */ +class BorrowedCairoContext +{ +public: + BorrowedCairoContext() + : mCairo(nullptr) + , mDT(nullptr) + { } + + explicit BorrowedCairoContext(DrawTarget *aDT) + : mDT(aDT) + { + mCairo = BorrowCairoContextFromDrawTarget(aDT); + } + + // We can optionally Init after construction in + // case we don't know what the DT will be at construction + // time. + cairo_t *Init(DrawTarget *aDT) + { + MOZ_ASSERT(!mDT, "Can't initialize twice!"); + mDT = aDT; + return mCairo = BorrowCairoContextFromDrawTarget(aDT); + } + + // The caller needs to call Finish if cr is non-null when + // they are done with the context. This is currently explicit + // instead of happening implicitly in the destructor to make + // what's happening in the caller more clear. It also + // let's you resume using the DrawTarget in the same scope. + void Finish() + { + if (mCairo) { + ReturnCairoContextToDrawTarget(mDT, mCairo); + mCairo = nullptr; + } + } + + ~BorrowedCairoContext() { + MOZ_ASSERT(!mCairo); + } + + cairo_t *mCairo; +private: + static cairo_t* BorrowCairoContextFromDrawTarget(DrawTarget *aDT); + static void ReturnCairoContextToDrawTarget(DrawTarget *aDT, cairo_t *aCairo); + DrawTarget *mDT; +}; + +#ifdef XP_MACOSX +/* This is a helper class that let's you borrow a CGContextRef from a + * DrawTargetCG. This is used for drawing themed widgets. + * + * Callers should check the cg member after constructing the object + * to see if it succeeded. The DrawTarget should not be used while + * the context is borrowed. */ +class BorrowedCGContext +{ +public: + BorrowedCGContext() + : cg(nullptr) + , mDT(nullptr) + { } + + explicit BorrowedCGContext(DrawTarget *aDT) + : mDT(aDT) + { + cg = BorrowCGContextFromDrawTarget(aDT); + } + + // We can optionally Init after construction in + // case we don't know what the DT will be at construction + // time. + CGContextRef Init(DrawTarget *aDT) + { + MOZ_ASSERT(!mDT, "Can't initialize twice!"); + mDT = aDT; + cg = BorrowCGContextFromDrawTarget(aDT); + return cg; + } + + // The caller needs to call Finish if cg is non-null when + // they are done with the context. This is currently explicit + // instead of happening implicitly in the destructor to make + // what's happening in the caller more clear. It also + // let's you resume using the DrawTarget in the same scope. + void Finish() + { + if (cg) { + ReturnCGContextToDrawTarget(mDT, cg); + cg = nullptr; + } + } + + ~BorrowedCGContext() { + MOZ_ASSERT(!cg); + } + + CGContextRef cg; +private: + static CGContextRef BorrowCGContextFromDrawTarget(DrawTarget *aDT); + static void ReturnCGContextToDrawTarget(DrawTarget *aDT, CGContextRef cg); + DrawTarget *mDT; +}; +#endif + +} +} + +#endif // _MOZILLA_GFX_BORROWED_CONTEXT_H diff --git a/libazure/Coord.h b/libazure/Coord.h new file mode 100644 index 0000000..2a981b0 --- /dev/null +++ b/libazure/Coord.h @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_COORD_H_ +#define MOZILLA_GFX_COORD_H_ + +#include "mozilla/Attributes.h" +#include "Types.h" +#include "BaseCoord.h" + +#include + +namespace mozilla { + +template struct IsPixel; + +namespace gfx { + +template struct IntCoordTyped; +template struct CoordTyped; + +// CommonType is a metafunction that returns the type of the +// result of an arithmetic operation on the underlying type of a strongly-typed +// coordinate type 'coord', and a primitive type 'primitive'. C++ rules for +// arithmetic conversions are designed to avoid losing information - for +// example, the result of adding an int and a float is a float - and we want +// the same behaviour when mixing our coordinate types with primitive types. +// We get C++ to compute the desired result type using 'decltype'. + +template +struct CommonType; + +template +struct CommonType, primitive> { + typedef decltype(int32_t() + primitive()) type; +}; + +template +struct CommonType, primitive> { + typedef decltype(Float() + primitive()) type; +}; + +// This is a base class that provides mixed-type operator overloads between +// a strongly-typed Coord and a primitive value. It is needed to avoid +// ambiguities at mixed-type call sites, because Coord classes are implicitly +// convertible to their underlying value type. As we transition more of our code +// to strongly-typed classes, we may be able to remove some or all of these +// overloads. +template +struct CoordOperatorsHelper { + friend bool operator==(coord aA, primitive aB) { + return aA.value == aB; + } + friend bool operator==(primitive aA, coord aB) { + return aA == aB.value; + } + friend bool operator!=(coord aA, primitive aB) { + return aA.value != aB; + } + friend bool operator!=(primitive aA, coord aB) { + return aA != aB.value; + } + + typedef typename CommonType::type result_type; + + friend result_type operator+(coord aA, primitive aB) { + return aA.value + aB; + } + friend result_type operator+(primitive aA, coord aB) { + return aA + aB.value; + } + friend result_type operator-(coord aA, primitive aB) { + return aA.value - aB; + } + friend result_type operator-(primitive aA, coord aB) { + return aA - aB.value; + } + friend result_type operator*(coord aCoord, primitive aScale) { + return aCoord.value * aScale; + } + friend result_type operator*(primitive aScale, coord aCoord) { + return aScale * aCoord.value; + } + friend result_type operator/(coord aCoord, primitive aScale) { + return aCoord.value / aScale; + } + // 'scale / coord' is intentionally omitted because it doesn't make sense. +}; + +// Note: 'IntCoordTyped' and 'CoordTyped' do not derive from +// 'units' to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61959. + +template +struct IntCoordTyped : + public BaseCoord< int32_t, IntCoordTyped >, + public CoordOperatorsHelper< IntCoordTyped, float >, + public CoordOperatorsHelper< IntCoordTyped, double > { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseCoord< int32_t, IntCoordTyped > Super; + + MOZ_CONSTEXPR IntCoordTyped() : Super() {} + MOZ_CONSTEXPR MOZ_IMPLICIT IntCoordTyped(int32_t aValue) : Super(aValue) {} +}; + +template +struct CoordTyped : + public BaseCoord< Float, CoordTyped >, + public CoordOperatorsHelper< CoordTyped, int32_t >, + public CoordOperatorsHelper< CoordTyped, uint32_t >, + public CoordOperatorsHelper< CoordTyped, double > { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseCoord< Float, CoordTyped > Super; + + MOZ_CONSTEXPR CoordTyped() : Super() {} + MOZ_CONSTEXPR MOZ_IMPLICIT CoordTyped(Float aValue) : Super(aValue) {} + explicit MOZ_CONSTEXPR CoordTyped(const IntCoordTyped& aCoord) : Super(float(aCoord.value)) {} + + void Round() { + this->value = floor(this->value + 0.5); + } + void Truncate() { + this->value = int32_t(this->value); + } + + IntCoordTyped Rounded() const { + return IntCoordTyped(int32_t(floor(this->value + 0.5))); + } + IntCoordTyped Truncated() const { + return IntCoordTyped(int32_t(this->value)); + } +}; + +} +} + +#endif /* MOZILLA_GFX_COORD_H_ */ diff --git a/libazure/DXTextureInteropNVpr.cpp b/libazure/DXTextureInteropNVpr.cpp new file mode 100644 index 0000000..4f7b58c --- /dev/null +++ b/libazure/DXTextureInteropNVpr.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DXTextureInteropNVpr.h" +#include "nvpr/WGL.h" + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +DXTextureInteropNVpr::DXTextureInteropNVpr(void* aDX, void* aDXTexture, + bool& aSuccess) + : mDXInterop(nullptr) + , mTextureInterop(nullptr) + , mTextureId(0) +{ + WGL* const wgl = static_cast(gl); + gl->MakeCurrent(); + + aSuccess = false; + + if (!wgl->HasWGLExtension(WGL::NV_DX_interop2)) { + return; + } + + mDXInterop = wgl->DXOpenDeviceNV(aDX); + if (!mDXInterop) { + return; + } + + gl->GenTextures(1, &mTextureId); + mTextureInterop = wgl->DXRegisterObjectNV(mDXInterop, aDXTexture, + mTextureId, GL_TEXTURE_2D, + WGL_ACCESS_WRITE_DISCARD_NV); + if (mTextureInterop) { + return; + } + + aSuccess = true; +} + +DXTextureInteropNVpr::~DXTextureInteropNVpr() +{ + WGL* const wgl = static_cast(gl); + gl->MakeCurrent(); + + if (mTextureInterop) { + MOZ_ASSERT(wgl->HasWGLExtension(WGL::NV_DX_interop2)); + wgl->DXUnregisterObjectNV(mDXInterop, mTextureInterop); + } + + if (mTextureId) { + gl->DeleteTexture(mTextureId); + } + + if (mDXInterop) { + MOZ_ASSERT(wgl->HasWGLExtension(WGL::NV_DX_interop2)); + wgl->DXCloseDeviceNV(mDXInterop); + } +} + +GLuint +DXTextureInteropNVpr::Lock() +{ + MOZ_ASSERT(gl->IsCurrent()); + + WGL* const wgl = static_cast(gl); + MOZ_ASSERT(wgl->HasWGLExtension(WGL::NV_DX_interop2)); + + wgl->DXLockObjectsNV(mDXInterop, 1, &mTextureInterop); + + return mTextureId; +} + +void +DXTextureInteropNVpr::Unlock() +{ + MOZ_ASSERT(gl->IsCurrent()); + + WGL* const wgl = static_cast(gl); + MOZ_ASSERT(wgl->HasWGLExtension(WGL::NV_DX_interop2)); + + wgl->DXUnlockObjectsNV(mDXInterop, 1, &mTextureInterop); +} + +} +} diff --git a/libazure/DXTextureInteropNVpr.h b/libazure/DXTextureInteropNVpr.h new file mode 100644 index 0000000..ca40fbd --- /dev/null +++ b/libazure/DXTextureInteropNVpr.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DXTEXTUREINTEROP_H_ +#define MOZILLA_GFX_DXTEXTUREINTEROP_H_ + +#include "nvpr/GL.h" +#include "Windows.h" +#include + +namespace mozilla { +namespace gfx { + +class DXTextureInteropNVpr : public RefCounted { +public: + static TemporaryRef Create(void* aDX, void* aDXTexture) + { + bool success; + RefPtr interop = + new DXTextureInteropNVpr(aDX, aDXTexture, success); + return success ? interop.forget() : nullptr; + } + ~DXTextureInteropNVpr(); + + GLuint Lock(); + void Unlock(); + +private: + DXTextureInteropNVpr(void* aDX, void* aDXTexture, bool& aSuccess); + HANDLE mDXInterop; + GLuint mTextureId; + HANDLE mTextureInterop; +}; + +} +} + +#endif /* MOZILLA_GFX_DXTEXTUREINTEROP_H_ */ diff --git a/libazure/src/gfx/2d/ScaledFontFreetype.h b/libazure/DataSourceSurface.cpp similarity index 54% rename from libazure/src/gfx/2d/ScaledFontFreetype.h rename to libazure/DataSourceSurface.cpp index bc492af..573ae03 100644 --- a/libazure/src/gfx/2d/ScaledFontFreetype.h +++ b/libazure/DataSourceSurface.cpp @@ -3,22 +3,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef MOZILLA_GFX_SCALEDFONTFREETYPE_H_ -#define MOZILLA_GFX_SCALEDFONTFREETYPE_H_ - -#include "ScaledFontBase.h" +#include "2D.h" +#include "DataSourceSurfaceWrapper.h" namespace mozilla { namespace gfx { -class ScaledFontFreetype : public ScaledFontBase +TemporaryRef +DataSourceSurface::GetDataSurface() { -public: - - ScaledFontFreetype(FontOptions* aFont, Float aSize); -}; + return (GetType() == SurfaceType::DATA) ? this : new DataSourceSurfaceWrapper(this); +} } } - -#endif /* MOZILLA_GFX_SCALEDFONTFREETYPE_H_ */ diff --git a/libazure/DataSourceSurfaceWrapper.h b/libazure/DataSourceSurfaceWrapper.h new file mode 100644 index 0000000..c49ee57 --- /dev/null +++ b/libazure/DataSourceSurfaceWrapper.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_ +#define MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_ + +#include "2D.h" + +namespace mozilla { +namespace gfx { + +// Wraps a DataSourceSurface and forwards all methods except for GetType(), +// from which it always returns SurfaceType::DATA. +class DataSourceSurfaceWrapper : public DataSourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceWrapper) + explicit DataSourceSurfaceWrapper(DataSourceSurface *aSurface) + : mSurface(aSurface) + {} + + virtual SurfaceType GetType() const MOZ_OVERRIDE { return SurfaceType::DATA; } + + virtual uint8_t *GetData() MOZ_OVERRIDE { return mSurface->GetData(); } + virtual int32_t Stride() MOZ_OVERRIDE { return mSurface->Stride(); } + virtual IntSize GetSize() const MOZ_OVERRIDE { return mSurface->GetSize(); } + virtual SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mSurface->GetFormat(); } + virtual bool IsValid() const MOZ_OVERRIDE { return mSurface->IsValid(); } + +private: + RefPtr mSurface; +}; + +} +} + +#endif /* MOZILLA_GFX_DATASOURCESURFACEWRAPPER_H_ */ diff --git a/libazure/DataSurfaceHelpers.cpp b/libazure/DataSurfaceHelpers.cpp new file mode 100644 index 0000000..9028b34 --- /dev/null +++ b/libazure/DataSurfaceHelpers.cpp @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "2D.h" +#include "DataSurfaceHelpers.h" +#include "Logging.h" +#include "mozilla/MathAlgorithms.h" +#include "Tools.h" + +namespace mozilla { +namespace gfx { + +void +ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride) +{ + uint32_t* pixel = reinterpret_cast(aData); + + for (int row = 0; row < aSize.height; ++row) { + for (int column = 0; column < aSize.width; ++column) { +#ifdef IS_BIG_ENDIAN + pixel[column] |= 0x000000FF; +#else + pixel[column] |= 0xFF000000; +#endif + } + pixel += (aStride/4); + } +} + +void +CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize, + int32_t aSrcStride, int32_t aBytesPerPixel) +{ + MOZ_ASSERT(aBytesPerPixel > 0, + "Negative stride for aDst not currently supported"); + MOZ_ASSERT(BufferSizeFromStrideAndHeight(aSrcStride, aSrcSize.height) > 0, + "How did we end up with a surface with such a big buffer?"); + + int packedStride = aSrcSize.width * aBytesPerPixel; + + if (aSrcStride == packedStride) { + // aSrc is already packed, so we can copy with a single memcpy. + memcpy(aDst, aSrc, packedStride * aSrcSize.height); + } else { + // memcpy one row at a time. + for (int row = 0; row < aSrcSize.height; ++row) { + memcpy(aDst, aSrc, packedStride); + aSrc += aSrcStride; + aDst += packedStride; + } + } +} + +void +CopyBGRXSurfaceDataToPackedBGRArray(uint8_t* aSrc, uint8_t* aDst, + IntSize aSrcSize, int32_t aSrcStride) +{ + int packedStride = aSrcSize.width * 3; + + uint8_t* srcPx = aSrc; + uint8_t* dstPx = aDst; + + for (int row = 0; row < aSrcSize.height; ++row) { + for (int col = 0; col < aSrcSize.height; ++col) { + dstPx[0] = srcPx[0]; + dstPx[1] = srcPx[1]; + dstPx[2] = srcPx[2]; + // srcPx[3] (unused or alpha component) dropped on floor + srcPx += 4; + dstPx += 3; + } + srcPx = aSrc += aSrcStride; + dstPx = aDst += packedStride; + } +} + +uint8_t* +SurfaceToPackedBGRA(DataSourceSurface *aSurface) +{ + SurfaceFormat format = aSurface->GetFormat(); + if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) { + return nullptr; + } + + IntSize size = aSurface->GetSize(); + + uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * sizeof(uint32_t)]; + if (!imageBuffer) { + return nullptr; + } + + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { + delete [] imageBuffer; + return nullptr; + } + + CopySurfaceDataToPackedArray(map.mData, imageBuffer, size, + map.mStride, 4 * sizeof(uint8_t)); + + aSurface->Unmap(); + + if (format == SurfaceFormat::B8G8R8X8) { + // Convert BGRX to BGRA by setting a to 255. + ConvertBGRXToBGRA(reinterpret_cast(imageBuffer), size, size.width * sizeof(uint32_t)); + } + + return imageBuffer; +} + +uint8_t* +SurfaceToPackedBGR(DataSourceSurface *aSurface) +{ + SurfaceFormat format = aSurface->GetFormat(); + MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported"); + + if (format != SurfaceFormat::B8G8R8X8) { + // To support B8G8R8A8 we'd need to un-pre-multiply alpha + return nullptr; + } + + IntSize size = aSurface->GetSize(); + + uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)]; + if (!imageBuffer) { + return nullptr; + } + + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { + delete [] imageBuffer; + return nullptr; + } + + CopyBGRXSurfaceDataToPackedBGRArray(map.mData, imageBuffer, size, + map.mStride); + + aSurface->Unmap(); + + return imageBuffer; +} + +void +ClearDataSourceSurface(DataSourceSurface *aSurface) +{ + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { + MOZ_ASSERT(false, "Failed to map DataSourceSurface"); + return; + } + + // We avoid writing into the gaps between the rows here since we can't be + // sure that some drivers don't use those bytes. + + uint32_t width = aSurface->GetSize().width; + uint32_t bytesPerRow = width * BytesPerPixel(aSurface->GetFormat()); + uint8_t* row = map.mData; + // converting to size_t here because otherwise the temporaries can overflow + // and we can end up with |end| being a bad address! + uint8_t* end = row + size_t(map.mStride) * size_t(aSurface->GetSize().height); + + while (row != end) { + memset(row, 0, bytesPerRow); + row += map.mStride; + } + + aSurface->Unmap(); +} + +size_t +BufferSizeFromStrideAndHeight(int32_t aStride, + int32_t aHeight, + int32_t aExtraBytes) +{ + if (MOZ_UNLIKELY(aHeight <= 0)) { + return 0; + } + + // We limit the length returned to values that can be represented by int32_t + // because we don't want to allocate buffers any bigger than that. This + // allows for a buffer size of over 2 GiB which is already rediculously + // large and will make the process janky. (Note the choice of the signed type + // is deliberate because we specifically don't want the returned value to + // overflow if someone stores the buffer length in an int32_t variable.) + + CheckedInt32 requiredBytes = + CheckedInt32(aStride) * CheckedInt32(aHeight) + CheckedInt32(aExtraBytes); + if (MOZ_UNLIKELY(!requiredBytes.isValid())) { + gfxWarning() << "Buffer size too big; returning zero"; + return 0; + } + return requiredBytes.value(); +} + +} +} diff --git a/libazure/DataSurfaceHelpers.h b/libazure/DataSurfaceHelpers.h new file mode 100644 index 0000000..f48e5f6 --- /dev/null +++ b/libazure/DataSurfaceHelpers.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_DATASURFACEHELPERS_H +#define _MOZILLA_GFX_DATASURFACEHELPERS_H + +#include "2D.h" + +namespace mozilla { +namespace gfx { + +void +ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride); + +/** + * Copy the pixel data from aSrc and pack it into aDst. aSrcSize, aSrcStride + * and aBytesPerPixel give the size, stride and bytes per pixel for aSrc's + * surface. Callers are responsible for making sure that aDst is big enough to + * contain |aSrcSize.width * aSrcSize.height * aBytesPerPixel| bytes. + */ +void +CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize, + int32_t aSrcStride, int32_t aBytesPerPixel); + +/** + * Convert aSurface to a packed buffer in BGRA format. The pixel data is + * returned in a buffer allocated with new uint8_t[]. The caller then has + * ownership of the buffer and is responsible for delete[]'ing it. + */ +uint8_t* +SurfaceToPackedBGRA(DataSourceSurface *aSurface); + +/** + * Convert aSurface to a packed buffer in BGR format. The pixel data is + * returned in a buffer allocated with new uint8_t[]. The caller then has + * ownership of the buffer and is responsible for delete[]'ing it. + * + * This function is currently only intended for use with surfaces of format + * SurfaceFormat::B8G8R8X8 since the X components of the pixel data (if any) + * are simply dropped (no attempt is made to un-pre-multiply alpha from the + * color components). + */ +uint8_t* +SurfaceToPackedBGR(DataSourceSurface *aSurface); + +/** + * Clears all the bytes in a DataSourceSurface's data array to zero (so to + * transparent black for SurfaceFormat::B8G8R8A8, for example). + * Note that DataSourceSurfaces can be initialized to zero, which is + * more efficient than zeroing the surface after initialization. + */ +void +ClearDataSourceSurface(DataSourceSurface *aSurface); + +/** + * Multiplies aStride and aHeight and makes sure the result is limited to + * something sane. To keep things consistent, this should always be used + * wherever we allocate a buffer based on surface stride and height. + * + * @param aExtra Optional argument to specify an additional number of trailing + * bytes (useful for creating intermediate surfaces for filters, for + * example). + * + * @return The result of the multiplication if it is acceptable, or else zero. + */ +size_t +BufferSizeFromStrideAndHeight(int32_t aStride, + int32_t aHeight, + int32_t aExtraBytes = 0); + +} +} + +#endif // _MOZILLA_GFX_DATASURFACEHELPERS_H diff --git a/libazure/DrawCommand.h b/libazure/DrawCommand.h new file mode 100644 index 0000000..c7f8fa8 --- /dev/null +++ b/libazure/DrawCommand.h @@ -0,0 +1,502 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWCOMMAND_H_ +#define MOZILLA_GFX_DRAWCOMMAND_H_ + +#include "2D.h" +#include "Filters.h" +#include +#include + +namespace mozilla { +namespace gfx { + +MOZ_BEGIN_ENUM_CLASS(CommandType, int8_t) + DRAWSURFACE = 0, + DRAWFILTER, + DRAWSURFACEWITHSHADOW, + CLEARRECT, + COPYSURFACE, + COPYRECT, + FILLRECT, + STROKERECT, + STROKELINE, + STROKE, + FILL, + FILLGLYPHS, + MASK, + MASKSURFACE, + PUSHCLIP, + PUSHCLIPRECT, + POPCLIP, + SETTRANSFORM +MOZ_END_ENUM_CLASS(CommandType) + +class DrawingCommand +{ +public: + virtual ~DrawingCommand() {} + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aTransform) = 0; + +protected: + explicit DrawingCommand(CommandType aType) + : mType(aType) + { + } + +private: + CommandType mType; +}; + +class StoredPattern +{ +public: + explicit StoredPattern(const Pattern& aPattern) + { + Assign(aPattern); + } + + void Assign(const Pattern& aPattern) + { + switch (aPattern.GetType()) { + case PatternType::COLOR: + new (mColor)ColorPattern(*static_cast(&aPattern)); + return; + case PatternType::SURFACE: + { + SurfacePattern* surfPat = new (mColor)SurfacePattern(*static_cast(&aPattern)); + surfPat->mSurface->GuaranteePersistance(); + return; + } + case PatternType::LINEAR_GRADIENT: + new (mColor)LinearGradientPattern(*static_cast(&aPattern)); + return; + case PatternType::RADIAL_GRADIENT: + new (mColor)RadialGradientPattern(*static_cast(&aPattern)); + return; + } + } + + ~StoredPattern() + { + reinterpret_cast(mColor)->~Pattern(); + } + + operator Pattern&() + { + return *reinterpret_cast(mColor); + } + + operator const Pattern&() const + { + return *reinterpret_cast(mColor); + } + + StoredPattern(const StoredPattern& aPattern) + { + Assign(aPattern); + } + +private: + StoredPattern operator=(const StoredPattern& aOther) + { + // Block this so that we notice if someone's doing excessive assigning. + } + + union { + char mColor[sizeof(ColorPattern)]; + char mLinear[sizeof(LinearGradientPattern)]; + char mRadial[sizeof(RadialGradientPattern)]; + char mSurface[sizeof(SurfacePattern)]; + }; +}; + +class DrawSurfaceCommand : public DrawingCommand +{ +public: + DrawSurfaceCommand(SourceSurface *aSurface, const Rect& aDest, + const Rect& aSource, const DrawSurfaceOptions& aSurfOptions, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::DRAWSURFACE) + , mSurface(aSurface), mDest(aDest) + , mSource(aSource), mSurfOptions(aSurfOptions) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions); + } + +private: + RefPtr mSurface; + Rect mDest; + Rect mSource; + DrawSurfaceOptions mSurfOptions; + DrawOptions mOptions; +}; + +class DrawFilterCommand : public DrawingCommand +{ +public: + DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect, + const Point& aDestPoint, const DrawOptions& aOptions) + : DrawingCommand(CommandType::DRAWSURFACE) + , mFilter(aFilter), mSourceRect(aSourceRect) + , mDestPoint(aDestPoint), mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions); + } + +private: + RefPtr mFilter; + Rect mSourceRect; + Point mDestPoint; + DrawOptions mOptions; +}; + +class ClearRectCommand : public DrawingCommand +{ +public: + explicit ClearRectCommand(const Rect& aRect) + : DrawingCommand(CommandType::CLEARRECT) + , mRect(aRect) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->ClearRect(mRect); + } + +private: + Rect mRect; +}; + +class CopySurfaceCommand : public DrawingCommand +{ +public: + CopySurfaceCommand(SourceSurface* aSurface, + const IntRect& aSourceRect, + const IntPoint& aDestination) + : DrawingCommand(CommandType::COPYSURFACE) + , mSurface(aSurface) + , mSourceRect(aSourceRect) + , mDestination(aDestination) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aTransform) + { + MOZ_ASSERT(!aTransform.HasNonIntegerTranslation()); + Point dest(Float(mDestination.x), Float(mDestination.y)); + dest = aTransform * dest; + aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y))); + } + +private: + RefPtr mSurface; + IntRect mSourceRect; + IntPoint mDestination; +}; + +class FillRectCommand : public DrawingCommand +{ +public: + FillRectCommand(const Rect& aRect, + const Pattern& aPattern, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::FILLRECT) + , mRect(aRect) + , mPattern(aPattern) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->FillRect(mRect, mPattern, mOptions); + } + +private: + Rect mRect; + StoredPattern mPattern; + DrawOptions mOptions; +}; + +class StrokeRectCommand : public DrawingCommand +{ +public: + StrokeRectCommand(const Rect& aRect, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::STROKERECT) + , mRect(aRect) + , mPattern(aPattern) + , mStrokeOptions(aStrokeOptions) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->StrokeRect(mRect, mPattern, mStrokeOptions, mOptions); + } + +private: + Rect mRect; + StoredPattern mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class StrokeLineCommand : public DrawingCommand +{ +public: + StrokeLineCommand(const Point& aStart, + const Point& aEnd, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::STROKELINE) + , mStart(aStart) + , mEnd(aEnd) + , mPattern(aPattern) + , mStrokeOptions(aStrokeOptions) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->StrokeLine(mStart, mEnd, mPattern, mStrokeOptions, mOptions); + } + +private: + Point mStart; + Point mEnd; + StoredPattern mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class FillCommand : public DrawingCommand +{ +public: + FillCommand(const Path* aPath, + const Pattern& aPattern, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::FILL) + , mPath(const_cast(aPath)) + , mPattern(aPattern) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->Fill(mPath, mPattern, mOptions); + } + +private: + RefPtr mPath; + StoredPattern mPattern; + DrawOptions mOptions; +}; + +class StrokeCommand : public DrawingCommand +{ +public: + StrokeCommand(const Path* aPath, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::STROKE) + , mPath(const_cast(aPath)) + , mPattern(aPattern) + , mStrokeOptions(aStrokeOptions) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->Stroke(mPath, mPattern, mStrokeOptions, mOptions); + } + +private: + RefPtr mPath; + StoredPattern mPattern; + StrokeOptions mStrokeOptions; + DrawOptions mOptions; +}; + +class FillGlyphsCommand : public DrawingCommand +{ +public: + FillGlyphsCommand(ScaledFont* aFont, + const GlyphBuffer& aBuffer, + const Pattern& aPattern, + const DrawOptions& aOptions, + const GlyphRenderingOptions* aRenderingOptions) + : DrawingCommand(CommandType::FILLGLYPHS) + , mFont(aFont) + , mPattern(aPattern) + , mOptions(aOptions) + , mRenderingOptions(const_cast(aRenderingOptions)) + { + mGlyphs.resize(aBuffer.mNumGlyphs); + memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs); + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + GlyphBuffer buf; + buf.mNumGlyphs = mGlyphs.size(); + buf.mGlyphs = &mGlyphs.front(); + aDT->FillGlyphs(mFont, buf, mPattern, mOptions, mRenderingOptions); + } + +private: + RefPtr mFont; + std::vector mGlyphs; + StoredPattern mPattern; + DrawOptions mOptions; + RefPtr mRenderingOptions; +}; + +class MaskCommand : public DrawingCommand +{ +public: + MaskCommand(const Pattern& aSource, + const Pattern& aMask, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::MASK) + , mSource(aSource) + , mMask(aMask) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->Mask(mSource, mMask, mOptions); + } + +private: + StoredPattern mSource; + StoredPattern mMask; + DrawOptions mOptions; +}; + +class MaskSurfaceCommand : public DrawingCommand +{ +public: + MaskSurfaceCommand(const Pattern& aSource, + const SourceSurface* aMask, + const Point& aOffset, + const DrawOptions& aOptions) + : DrawingCommand(CommandType::MASKSURFACE) + , mSource(aSource) + , mMask(const_cast(aMask)) + , mOffset(aOffset) + , mOptions(aOptions) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->MaskSurface(mSource, mMask, mOffset, mOptions); + } + +private: + StoredPattern mSource; + RefPtr mMask; + Point mOffset; + DrawOptions mOptions; +}; + +class PushClipCommand : public DrawingCommand +{ +public: + explicit PushClipCommand(const Path* aPath) + : DrawingCommand(CommandType::PUSHCLIP) + , mPath(const_cast(aPath)) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->PushClip(mPath); + } + +private: + RefPtr mPath; +}; + +class PushClipRectCommand : public DrawingCommand +{ +public: + explicit PushClipRectCommand(const Rect& aRect) + : DrawingCommand(CommandType::PUSHCLIPRECT) + , mRect(aRect) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->PushClipRect(mRect); + } + +private: + Rect mRect; +}; + +class PopClipCommand : public DrawingCommand +{ +public: + PopClipCommand() + : DrawingCommand(CommandType::POPCLIP) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&) + { + aDT->PopClip(); + } +}; + +class SetTransformCommand : public DrawingCommand +{ +public: + explicit SetTransformCommand(const Matrix& aTransform) + : DrawingCommand(CommandType::SETTRANSFORM) + , mTransform(aTransform) + { + } + + virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix& aMatrix) + { + Matrix transform = mTransform; + transform *= aMatrix; + aDT->SetTransform(transform); + } + +private: + Matrix mTransform; +}; + +} /* namespace mozilla */ +} /* namespace gfx */ + +#endif /* MOZILLA_GFX_DRAWCOMMAND_H_ */ diff --git a/libazure/src/gfx/2d/DrawEventRecorder.cpp b/libazure/DrawEventRecorder.cpp similarity index 96% rename from libazure/src/gfx/2d/DrawEventRecorder.cpp rename to libazure/DrawEventRecorder.cpp index 41d7680..3a66376 100644 --- a/libazure/src/gfx/2d/DrawEventRecorder.cpp +++ b/libazure/DrawEventRecorder.cpp @@ -29,7 +29,7 @@ DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent) } DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename) - : DrawEventRecorderPrivate(NULL) + : DrawEventRecorderPrivate(nullptr) , mOutputFile(aFilename, ofstream::binary) { mOutputStream = &mOutputFile; diff --git a/libazure/src/gfx/2d/DrawEventRecorder.h b/libazure/DrawEventRecorder.h similarity index 86% rename from libazure/src/gfx/2d/DrawEventRecorder.h rename to libazure/DrawEventRecorder.h index 3652996..a74cbb4 100644 --- a/libazure/src/gfx/2d/DrawEventRecorder.h +++ b/libazure/DrawEventRecorder.h @@ -25,7 +25,8 @@ class PathRecording; class DrawEventRecorderPrivate : public DrawEventRecorder { public: - DrawEventRecorderPrivate(std::ostream *aStream); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate) + explicit DrawEventRecorderPrivate(std::ostream *aStream); virtual ~DrawEventRecorderPrivate() { } void RecordEvent(const RecordedEvent &aEvent); @@ -64,7 +65,8 @@ class DrawEventRecorderPrivate : public DrawEventRecorder class DrawEventRecorderFile : public DrawEventRecorderPrivate { public: - DrawEventRecorderFile(const char *aFilename); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderFile) + explicit DrawEventRecorderFile(const char *aFilename); ~DrawEventRecorderFile(); private: diff --git a/libazure/DrawTarget.cpp b/libazure/DrawTarget.cpp new file mode 100644 index 0000000..63f7289 --- /dev/null +++ b/libazure/DrawTarget.cpp @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "2D.h" +#include "Logging.h" + +#include "DrawTargetCapture.h" + +namespace mozilla { +namespace gfx { + +TemporaryRef +DrawTarget::CreateCaptureDT(const IntSize& aSize) +{ + RefPtr dt = new DrawTargetCaptureImpl(); + + if (!dt->Init(aSize, this)) { + gfxWarning() << "Failed to initialize Capture DrawTarget!"; + return nullptr; + } + + return dt; +} + +void +DrawTarget::DrawCapturedDT(DrawTargetCapture *aCaptureDT, + const Matrix& aTransform) +{ + if (aTransform.HasNonIntegerTranslation()) { + gfxWarning() << "Non integer translations are not supported for DrawCaptureDT at this time!"; + return; + } + static_cast(aCaptureDT)->ReplayToDrawTarget(this, aTransform); +} + +} +} diff --git a/libazure/DrawTargetCG.cpp b/libazure/DrawTargetCG.cpp new file mode 100644 index 0000000..c3c6d30 --- /dev/null +++ b/libazure/DrawTargetCG.cpp @@ -0,0 +1,1659 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "BorrowedContext.h" +#include "DataSurfaceHelpers.h" +#include "DrawTargetCG.h" +#include "Logging.h" +#include "SourceSurfaceCG.h" +#include "Rect.h" +#include "ScaledFontMac.h" +#include "Tools.h" +#include +#include +#include "MacIOSurface.h" +#include "FilterNodeSoftware.h" +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" // for decltype +#include "mozilla/FloatingPoint.h" + +using namespace std; + +//CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode); + +// A private API that Cairo has been using for a long time +CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform); + +namespace mozilla { +namespace gfx { + +template +static CGRect RectToCGRect(const T& r) +{ + return CGRectMake(r.x, r.y, r.width, r.height); +} + +CGBlendMode ToBlendMode(CompositionOp op) +{ + CGBlendMode mode; + switch (op) { + case CompositionOp::OP_OVER: + mode = kCGBlendModeNormal; + break; + case CompositionOp::OP_ADD: + mode = kCGBlendModePlusLighter; + break; + case CompositionOp::OP_ATOP: + mode = kCGBlendModeSourceAtop; + break; + case CompositionOp::OP_OUT: + mode = kCGBlendModeSourceOut; + break; + case CompositionOp::OP_IN: + mode = kCGBlendModeSourceIn; + break; + case CompositionOp::OP_SOURCE: + mode = kCGBlendModeCopy; + break; + case CompositionOp::OP_DEST_IN: + mode = kCGBlendModeDestinationIn; + break; + case CompositionOp::OP_DEST_OUT: + mode = kCGBlendModeDestinationOut; + break; + case CompositionOp::OP_DEST_OVER: + mode = kCGBlendModeDestinationOver; + break; + case CompositionOp::OP_DEST_ATOP: + mode = kCGBlendModeDestinationAtop; + break; + case CompositionOp::OP_XOR: + mode = kCGBlendModeXOR; + break; + case CompositionOp::OP_MULTIPLY: + mode = kCGBlendModeMultiply; + break; + case CompositionOp::OP_SCREEN: + mode = kCGBlendModeScreen; + break; + case CompositionOp::OP_OVERLAY: + mode = kCGBlendModeOverlay; + break; + case CompositionOp::OP_DARKEN: + mode = kCGBlendModeDarken; + break; + case CompositionOp::OP_LIGHTEN: + mode = kCGBlendModeLighten; + break; + case CompositionOp::OP_COLOR_DODGE: + mode = kCGBlendModeColorDodge; + break; + case CompositionOp::OP_COLOR_BURN: + mode = kCGBlendModeColorBurn; + break; + case CompositionOp::OP_HARD_LIGHT: + mode = kCGBlendModeHardLight; + break; + case CompositionOp::OP_SOFT_LIGHT: + mode = kCGBlendModeSoftLight; + break; + case CompositionOp::OP_DIFFERENCE: + mode = kCGBlendModeDifference; + break; + case CompositionOp::OP_EXCLUSION: + mode = kCGBlendModeExclusion; + break; + case CompositionOp::OP_HUE: + mode = kCGBlendModeHue; + break; + case CompositionOp::OP_SATURATION: + mode = kCGBlendModeSaturation; + break; + case CompositionOp::OP_COLOR: + mode = kCGBlendModeColor; + break; + case CompositionOp::OP_LUMINOSITY: + mode = kCGBlendModeLuminosity; + break; + /* + case OP_CLEAR: + mode = kCGBlendModeClear; + break;*/ + default: + mode = kCGBlendModeNormal; + } + return mode; +} + +static CGInterpolationQuality +InterpolationQualityFromFilter(Filter aFilter) +{ + switch (aFilter) { + default: + case Filter::LINEAR: + return kCGInterpolationLow; + case Filter::POINT: + return kCGInterpolationNone; + case Filter::GOOD: + return kCGInterpolationDefault; + } +} + + +DrawTargetCG::DrawTargetCG() + : mColorSpace(nullptr) + , mCg(nullptr) +{ +} + +DrawTargetCG::~DrawTargetCG() +{ + MarkChanged(); + + // Both of these are OK with nullptr arguments, so we do not + // need to check (these could be nullptr if Init fails) + CGColorSpaceRelease(mColorSpace); + CGContextRelease(mCg); +} + +DrawTargetType +DrawTargetCG::GetType() const +{ + return GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED ? + DrawTargetType::HARDWARE_RASTER : DrawTargetType::SOFTWARE_RASTER; +} + +BackendType +DrawTargetCG::GetBackendType() const +{ + // It may be worth spliting Bitmap and IOSurface DrawTarget + // into seperate classes. + if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) { + return BackendType::COREGRAPHICS_ACCELERATED; + } else { + return BackendType::COREGRAPHICS; + } +} + +TemporaryRef +DrawTargetCG::Snapshot() +{ + if (!mSnapshot) { + if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) { + return new SourceSurfaceCGIOSurfaceContext(this); + } + mSnapshot = new SourceSurfaceCGBitmapContext(this); + } + + return mSnapshot; +} + +TemporaryRef +DrawTargetCG::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + // XXX: in thebes we use CGLayers to do this kind of thing. It probably makes sense + // to add that in somehow, but at a higher level + RefPtr newTarget = new DrawTargetCG(); + if (newTarget->Init(GetBackendType(), aSize, aFormat)) { + return newTarget.forget(); + } + return nullptr; +} + +TemporaryRef +DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr newSurf = new SourceSurfaceCG(); + + if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { + return nullptr; + } + + return newSurf.forget(); +} + +static void releaseDataSurface(void* info, const void *data, size_t size) +{ + static_cast(info)->Release(); +} + +// This function returns a retained CGImage that needs to be released after +// use. The reason for this is that we want to either reuse an existing CGImage +// or create a new one. +static CGImageRef +GetRetainedImageFromSourceSurface(SourceSurface *aSurface) +{ + switch(aSurface->GetType()) { + case SurfaceType::COREGRAPHICS_IMAGE: + return CGImageRetain(static_cast(aSurface)->GetImage()); + + case SurfaceType::COREGRAPHICS_CGCONTEXT: + return CGImageRetain(static_cast(aSurface)->GetImage()); + + default: + { + RefPtr data = aSurface->GetDataSurface(); + if (!data) { + MOZ_CRASH("unsupported source surface"); + } + data->AddRef(); + return CreateCGImage(releaseDataSurface, data.get(), + data->GetData(), data->GetSize(), + data->Stride(), data->GetFormat()); + } + } +} + +TemporaryRef +DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE || + aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT) { + return aSurface; + } + RefPtr data = aSurface->GetDataSurface(); + + return CreateSourceSurfaceFromData(data->GetData(), + data->GetSize(), + data->Stride(), + data->GetFormat()); +} + +class UnboundnessFixer +{ + CGRect mClipBounds; + CGLayerRef mLayer; + CGContextRef mCg; + public: + UnboundnessFixer() : mCg(nullptr) {} + + CGContextRef Check(CGContextRef baseCg, CompositionOp blend, const Rect* maskBounds = nullptr) + { + if (!IsOperatorBoundByMask(blend)) { + mClipBounds = CGContextGetClipBoundingBox(baseCg); + // If we're entirely clipped out or if the drawing operation covers the entire clip then + // we don't need to create a temporary surface. + if (CGRectIsEmpty(mClipBounds) || + (maskBounds && maskBounds->Contains(CGRectToRect(mClipBounds)))) { + return baseCg; + } + + // TransparencyLayers aren't blended using the blend mode so + // we are forced to use CGLayers + + //XXX: The size here is in default user space units, of the layer relative to the graphics context. + // is the clip bounds still correct if, for example, we have a scale applied to the context? + mLayer = CGLayerCreateWithContext(baseCg, mClipBounds.size, nullptr); + mCg = CGLayerGetContext(mLayer); + // CGContext's default to have the origin at the bottom left + // so flip it to the top left and adjust for the origin + // of the layer + CGContextTranslateCTM(mCg, -mClipBounds.origin.x, mClipBounds.origin.y + mClipBounds.size.height); + CGContextScaleCTM(mCg, 1, -1); + + return mCg; + } else { + return baseCg; + } + } + + void Fix(CGContextRef baseCg) + { + if (mCg) { + CGContextTranslateCTM(baseCg, 0, mClipBounds.size.height); + CGContextScaleCTM(baseCg, 1, -1); + mClipBounds.origin.y *= -1; + CGContextDrawLayerAtPoint(baseCg, mClipBounds.origin, mLayer); + CGContextRelease(mCg); + } + } +}; + +void +DrawTargetCG::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aDrawOptions) +{ + MarkChanged(); + + CGContextSaveGState(mCg); + + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp, &aDest); + CGContextSetAlpha(cg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(aSurfOptions.mFilter)); + + CGImageRef image = GetRetainedImageFromSourceSurface(aSurface); + + if (aSurfOptions.mFilter == Filter::POINT) { + CGImageRef subimage = CGImageCreateWithImageInRect(image, RectToCGRect(aSource)); + CGImageRelease(image); + + CGContextScaleCTM(cg, 1, -1); + + CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + aDest.height), + aDest.width, aDest.height); + + CGContextDrawImage(cg, flippedRect, subimage); + CGImageRelease(subimage); + } else { + CGRect destRect = CGRectMake(aDest.x, aDest.y, aDest.width, aDest.height); + CGContextClipToRect(cg, destRect); + + float xScale = aSource.width / aDest.width; + float yScale = aSource.height / aDest.height; + CGContextTranslateCTM(cg, aDest.x - aSource.x / xScale, aDest.y - aSource.y / yScale); + + CGRect adjustedDestRect = CGRectMake(0, 0, CGImageGetWidth(image) / xScale, + CGImageGetHeight(image) / yScale); + + CGContextTranslateCTM(cg, 0, CGRectGetHeight(adjustedDestRect)); + CGContextScaleCTM(cg, 1, -1); + + CGContextDrawImage(cg, adjustedDestRect, image); + CGImageRelease(image); + } + + fixer.Fix(mCg); + + CGContextRestoreGState(mCg); +} + +TemporaryRef +DrawTargetCG::CreateFilter(FilterType aType) +{ + return FilterNodeSoftware::Create(aType); +} + +void +DrawTargetCG::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + FilterNodeSoftware* filter = static_cast(aNode); + filter->Draw(this, aSourceRect, aDestPoint, aOptions); +} + +static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor) +{ + CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a}; + return CGColorCreate(aColorSpace, components); +} + +class GradientStopsCG : public GradientStops +{ + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsCG) + + GradientStopsCG(CGColorSpaceRef aColorSpace, + const std::vector& aStops, + ExtendMode aExtendMode) + : mGradient(nullptr) + { + // This all works fine with empty aStops vector + + mExtend = aExtendMode; + if (aExtendMode == ExtendMode::CLAMP) { + size_t numStops = aStops.size(); + + std::vector colors; + std::vector offsets; + colors.reserve(numStops*4); + offsets.reserve(numStops); + + for (size_t i = 0; i < numStops; i++) { + colors.push_back(aStops[i].color.r); + colors.push_back(aStops[i].color.g); + colors.push_back(aStops[i].color.b); + colors.push_back(aStops[i].color.a); + + offsets.push_back(aStops[i].offset); + } + + mGradient = CGGradientCreateWithColorComponents(aColorSpace, + &colors.front(), + &offsets.front(), + offsets.size()); + } else { + mStops = aStops; + } + + } + + virtual ~GradientStopsCG() { + // CGGradientRelease is OK with nullptr argument + CGGradientRelease(mGradient); + } + + // Will always report BackendType::COREGRAPHICS, but it is compatible + // with BackendType::COREGRAPHICS_ACCELERATED + BackendType GetBackendType() const { return BackendType::COREGRAPHICS; } + // XXX this should be a union + CGGradientRef mGradient; + std::vector mStops; + ExtendMode mExtend; +}; + +TemporaryRef +DrawTargetCG::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, + ExtendMode aExtendMode) const +{ + std::vector stops(aStops, aStops+aNumStops); + return new GradientStopsCG(mColorSpace, stops, aExtendMode); +} + +static void +UpdateLinearParametersToIncludePoint(double *min_t, double *max_t, + CGPoint *start, + double dx, double dy, + double x, double y) +{ + MOZ_ASSERT(IsFinite(x) && IsFinite(y)); + + /** + * Compute a parameter t such that a line perpendicular to the (dx,dy) + * vector, passing through (start->x + dx*t, start->y + dy*t), also + * passes through (x,y). + * + * Let px = x - start->x, py = y - start->y. + * t is given by + * (px - dx*t)*dx + (py - dy*t)*dy = 0 + * + * Solving for t we get + * numerator = dx*px + dy*py + * denominator = dx^2 + dy^2 + * t = numerator/denominator + * + * In CalculateRepeatingGradientParams we know the length of (dx,dy) + * is not zero. (This is checked in DrawLinearRepeatingGradient.) + */ + double px = x - start->x; + double py = y - start->y; + double numerator = dx * px + dy * py; + double denominator = dx * dx + dy * dy; + double t = numerator / denominator; + + if (*min_t > t) { + *min_t = t; + } + if (*max_t < t) { + *max_t = t; + } +} + +/** + * Repeat the gradient line such that lines extended perpendicular to the + * gradient line at both start and end would completely enclose the drawing + * extents. + */ +static void +CalculateRepeatingGradientParams(CGPoint *aStart, CGPoint *aEnd, + CGRect aExtents, int *aRepeatStartFactor, + int *aRepeatEndFactor) +{ + double t_min = INFINITY; + double t_max = -INFINITY; + double dx = aEnd->x - aStart->x; + double dy = aEnd->y - aStart->y; + + double bounds_x1 = aExtents.origin.x; + double bounds_y1 = aExtents.origin.y; + double bounds_x2 = aExtents.origin.x + aExtents.size.width; + double bounds_y2 = aExtents.origin.y + aExtents.size.height; + + UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy, + bounds_x1, bounds_y1); + UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy, + bounds_x2, bounds_y1); + UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy, + bounds_x2, bounds_y2); + UpdateLinearParametersToIncludePoint(&t_min, &t_max, aStart, dx, dy, + bounds_x1, bounds_y2); + + MOZ_ASSERT(!isinf(t_min) && !isinf(t_max), + "The first call to UpdateLinearParametersToIncludePoint should have made t_min and t_max non-infinite."); + + // Move t_min and t_max to the nearest usable integer to try to avoid + // subtle variations due to numerical instability, especially accidentally + // cutting off a pixel. Extending the gradient repetitions is always safe. + t_min = floor (t_min); + t_max = ceil (t_max); + aEnd->x = aStart->x + dx * t_max; + aEnd->y = aStart->y + dy * t_max; + aStart->x = aStart->x + dx * t_min; + aStart->y = aStart->y + dy * t_min; + + *aRepeatStartFactor = t_min; + *aRepeatEndFactor = t_max; +} + +static CGGradientRef +CreateRepeatingGradient(CGColorSpaceRef aColorSpace, + CGContextRef cg, GradientStopsCG* aStops, + int aRepeatStartFactor, int aRepeatEndFactor, + bool aReflect) +{ + int repeatCount = aRepeatEndFactor - aRepeatStartFactor; + uint32_t stopCount = aStops->mStops.size(); + double scale = 1./repeatCount; + + std::vector colors; + std::vector offsets; + colors.reserve(stopCount*repeatCount*4); + offsets.reserve(stopCount*repeatCount); + + for (int j = aRepeatStartFactor; j < aRepeatEndFactor; j++) { + bool isReflected = aReflect && (j % 2) != 0; + for (uint32_t i = 0; i < stopCount; i++) { + uint32_t stopIndex = isReflected ? stopCount - i - 1 : i; + colors.push_back(aStops->mStops[stopIndex].color.r); + colors.push_back(aStops->mStops[stopIndex].color.g); + colors.push_back(aStops->mStops[stopIndex].color.b); + colors.push_back(aStops->mStops[stopIndex].color.a); + + CGFloat offset = aStops->mStops[stopIndex].offset; + if (isReflected) { + offset = 1 - offset; + } + offsets.push_back((offset + (j - aRepeatStartFactor)) * scale); + } + } + + CGGradientRef gradient = CGGradientCreateWithColorComponents(aColorSpace, + &colors.front(), + &offsets.front(), + repeatCount*stopCount); + return gradient; +} + +static void +DrawLinearRepeatingGradient(CGColorSpaceRef aColorSpace, CGContextRef cg, + const LinearGradientPattern &aPattern, + const CGRect &aExtents, bool aReflect) +{ + GradientStopsCG *stops = static_cast(aPattern.mStops.get()); + CGPoint startPoint = { aPattern.mBegin.x, aPattern.mBegin.y }; + CGPoint endPoint = { aPattern.mEnd.x, aPattern.mEnd.y }; + + int repeatStartFactor = 0, repeatEndFactor = 1; + // if we don't have a line then we can't extend it + if (aPattern.mEnd.x != aPattern.mBegin.x || + aPattern.mEnd.y != aPattern.mBegin.y) { + CalculateRepeatingGradientParams(&startPoint, &endPoint, aExtents, + &repeatStartFactor, &repeatEndFactor); + } + + CGGradientRef gradient = CreateRepeatingGradient(aColorSpace, cg, stops, repeatStartFactor, repeatEndFactor, aReflect); + + CGContextDrawLinearGradient(cg, gradient, startPoint, endPoint, + kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); + CGGradientRelease(gradient); +} + +static CGPoint CGRectTopLeft(CGRect a) +{ return a.origin; } +static CGPoint CGRectBottomLeft(CGRect a) +{ return CGPointMake(a.origin.x, a.origin.y + a.size.height); } +static CGPoint CGRectTopRight(CGRect a) +{ return CGPointMake(a.origin.x + a.size.width, a.origin.y); } +static CGPoint CGRectBottomRight(CGRect a) +{ return CGPointMake(a.origin.x + a.size.width, a.origin.y + a.size.height); } + +static CGFloat +CGPointDistance(CGPoint a, CGPoint b) +{ + return hypot(a.x-b.x, a.y-b.y); +} + +static void +DrawRadialRepeatingGradient(CGColorSpaceRef aColorSpace, CGContextRef cg, + const RadialGradientPattern &aPattern, + const CGRect &aExtents, bool aReflect) +{ + GradientStopsCG *stops = static_cast(aPattern.mStops.get()); + CGPoint startCenter = { aPattern.mCenter1.x, aPattern.mCenter1.y }; + CGFloat startRadius = aPattern.mRadius1; + CGPoint endCenter = { aPattern.mCenter2.x, aPattern.mCenter2.y }; + CGFloat endRadius = aPattern.mRadius2; + + // find the maximum distance from endCenter to a corner of aExtents + CGFloat minimumEndRadius = endRadius; + minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectTopLeft(aExtents))); + minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectBottomLeft(aExtents))); + minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectTopRight(aExtents))); + minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectBottomRight(aExtents))); + + CGFloat length = endRadius - startRadius; + int repeatStartFactor = 0, repeatEndFactor = 1; + while (endRadius < minimumEndRadius) { + endRadius += length; + repeatEndFactor++; + } + + while (startRadius-length >= 0) { + startRadius -= length; + repeatStartFactor--; + } + + CGGradientRef gradient = CreateRepeatingGradient(aColorSpace, cg, stops, repeatStartFactor, repeatEndFactor, aReflect); + + //XXX: are there degenerate radial gradients that we should avoid drawing? + CGContextDrawRadialGradient(cg, gradient, startCenter, startRadius, endCenter, endRadius, + kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); + CGGradientRelease(gradient); +} + +static void +DrawGradient(CGColorSpaceRef aColorSpace, + CGContextRef cg, const Pattern &aPattern, const CGRect &aExtents) +{ + if (CGRectIsEmpty(aExtents)) { + return; + } + + if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) { + const LinearGradientPattern& pat = static_cast(aPattern); + GradientStopsCG *stops = static_cast(pat.mStops.get()); + CGAffineTransform patternMatrix = GfxMatrixToCGAffineTransform(pat.mMatrix); + CGContextConcatCTM(cg, patternMatrix); + CGRect extents = CGRectApplyAffineTransform(aExtents, CGAffineTransformInvert(patternMatrix)); + if (stops->mExtend == ExtendMode::CLAMP) { + + // XXX: we should take the m out of the properties of LinearGradientPatterns + CGPoint startPoint = { pat.mBegin.x, pat.mBegin.y }; + CGPoint endPoint = { pat.mEnd.x, pat.mEnd.y }; + + // Canvas spec states that we should avoid drawing degenerate gradients (XXX: should this be in common code?) + //if (startPoint.x == endPoint.x && startPoint.y == endPoint.y) + // return; + + CGContextDrawLinearGradient(cg, stops->mGradient, startPoint, endPoint, + kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); + } else if (stops->mExtend == ExtendMode::REPEAT || stops->mExtend == ExtendMode::REFLECT) { + DrawLinearRepeatingGradient(aColorSpace, cg, pat, extents, stops->mExtend == ExtendMode::REFLECT); + } + } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { + const RadialGradientPattern& pat = static_cast(aPattern); + CGAffineTransform patternMatrix = GfxMatrixToCGAffineTransform(pat.mMatrix); + CGContextConcatCTM(cg, patternMatrix); + CGRect extents = CGRectApplyAffineTransform(aExtents, CGAffineTransformInvert(patternMatrix)); + GradientStopsCG *stops = static_cast(pat.mStops.get()); + if (stops->mExtend == ExtendMode::CLAMP) { + + // XXX: we should take the m out of the properties of RadialGradientPatterns + CGPoint startCenter = { pat.mCenter1.x, pat.mCenter1.y }; + CGFloat startRadius = pat.mRadius1; + CGPoint endCenter = { pat.mCenter2.x, pat.mCenter2.y }; + CGFloat endRadius = pat.mRadius2; + + //XXX: are there degenerate radial gradients that we should avoid drawing? + CGContextDrawRadialGradient(cg, stops->mGradient, startCenter, startRadius, endCenter, endRadius, + kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); + } else if (stops->mExtend == ExtendMode::REPEAT || stops->mExtend == ExtendMode::REFLECT) { + DrawRadialRepeatingGradient(aColorSpace, cg, pat, extents, stops->mExtend == ExtendMode::REFLECT); + } + } else { + assert(0); + } + +} + +static void +drawPattern(void *info, CGContextRef context) +{ + CGImageRef image = static_cast(info); + CGRect rect = {{0, 0}, + {static_cast(CGImageGetWidth(image)), + static_cast(CGImageGetHeight(image))}}; + CGContextDrawImage(context, rect, image); +} + +static void +releaseInfo(void *info) +{ + CGImageRef image = static_cast(info); + CGImageRelease(image); +} + +CGPatternCallbacks patternCallbacks = { + 0, + drawPattern, + releaseInfo +}; + +static bool +isGradient(const Pattern &aPattern) +{ + return aPattern.GetType() == PatternType::LINEAR_GRADIENT || aPattern.GetType() == PatternType::RADIAL_GRADIENT; +} + +static bool +isNonRepeatingSurface(const Pattern& aPattern) +{ + return aPattern.GetType() == PatternType::SURFACE && + static_cast(aPattern).mExtendMode != ExtendMode::REPEAT; +} + +/* CoreGraphics patterns ignore the userspace transform so + * we need to multiply it in */ +static CGPatternRef +CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace) +{ + const SurfacePattern& pat = static_cast(aPattern); + // XXX: is .get correct here? + CGImageRef image = GetRetainedImageFromSourceSurface(pat.mSurface.get()); + Matrix patTransform = pat.mMatrix; + if (!pat.mSamplingRect.IsEmpty()) { + CGImageRef temp = CGImageCreateWithImageInRect(image, RectToCGRect(pat.mSamplingRect)); + CGImageRelease(image); + image = temp; + patTransform.PreTranslate(pat.mSamplingRect.x, pat.mSamplingRect.y); + } + CGFloat xStep, yStep; + switch (pat.mExtendMode) { + case ExtendMode::CLAMP: + // The 1 << 22 comes from Webkit see Pattern::createPlatformPattern() in PatternCG.cpp for more info + xStep = static_cast(1 << 22); + yStep = static_cast(1 << 22); + break; + case ExtendMode::REFLECT: + assert(0); + case ExtendMode::REPEAT: + xStep = static_cast(CGImageGetWidth(image)); + yStep = static_cast(CGImageGetHeight(image)); + // webkit uses wkCGPatternCreateWithImageAndTransform a wrapper around CGPatternCreateWithImage2 + // this is done to avoid pixel-cracking along pattern boundaries + // (see https://bugs.webkit.org/show_bug.cgi?id=53055) + // typedef enum { + // wkPatternTilingNoDistortion, + // wkPatternTilingConstantSpacingMinimalDistortion, + // wkPatternTilingConstantSpacing + // } wkPatternTiling; + // extern CGPatternRef (*wkCGPatternCreateWithImageAndTransform)(CGImageRef, CGAffineTransform, int); + } + + //XXX: We should be using CGContextDrawTiledImage when we can. Even though it + // creates a pattern, it seems to go down a faster path than using a delegate + // like we do below + CGRect bounds = { + {0, 0,}, + {static_cast(CGImageGetWidth(image)), static_cast(CGImageGetHeight(image))} + }; + CGAffineTransform transform = + CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformMakeScale(1, + -1), + GfxMatrixToCGAffineTransform(patTransform)), + aUserSpace); + transform = CGAffineTransformTranslate(transform, 0, -static_cast(CGImageGetHeight(image))); + return CGPatternCreate(image, bounds, transform, xStep, yStep, kCGPatternTilingConstantSpacing, + true, &patternCallbacks); +} + +static void +SetFillFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern) +{ + assert(!isGradient(aPattern)); + if (aPattern.GetType() == PatternType::COLOR) { + + const Color& color = static_cast(aPattern).mColor; + //XXX: we should cache colors + CGColorRef cgcolor = ColorToCGColor(aColorSpace, color); + CGContextSetFillColorWithColor(cg, cgcolor); + CGColorRelease(cgcolor); + } else if (aPattern.GetType() == PatternType::SURFACE) { + + CGColorSpaceRef patternSpace; + patternSpace = CGColorSpaceCreatePattern (nullptr); + CGContextSetFillColorSpace(cg, patternSpace); + CGColorSpaceRelease(patternSpace); + + CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg)); + const SurfacePattern& pat = static_cast(aPattern); + CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(pat.mFilter)); + CGFloat alpha = 1.; + CGContextSetFillPattern(cg, pattern, &alpha); + CGPatternRelease(pattern); + } +} + +static void +SetStrokeFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern) +{ + assert(!isGradient(aPattern)); + if (aPattern.GetType() == PatternType::COLOR) { + const Color& color = static_cast(aPattern).mColor; + //XXX: we should cache colors + CGColorRef cgcolor = ColorToCGColor(aColorSpace, color); + CGContextSetStrokeColorWithColor(cg, cgcolor); + CGColorRelease(cgcolor); + } else if (aPattern.GetType() == PatternType::SURFACE) { + CGColorSpaceRef patternSpace; + patternSpace = CGColorSpaceCreatePattern (nullptr); + CGContextSetStrokeColorSpace(cg, patternSpace); + CGColorSpaceRelease(patternSpace); + + CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg)); + const SurfacePattern& pat = static_cast(aPattern); + CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(pat.mFilter)); + CGFloat alpha = 1.; + CGContextSetStrokePattern(cg, pattern, &alpha); + CGPatternRelease(pattern); + } + +} + +void +DrawTargetCG::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aDrawOptions) +{ + MarkChanged(); + + CGContextSaveGState(mCg); + + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(cg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + CGImageRef image = GetRetainedImageFromSourceSurface(aMask); + + // use a negative-y so that the mask image draws right ways up + CGContextScaleCTM(cg, 1, -1); + + IntSize size = aMask->GetSize(); + + CGContextClipToMask(cg, CGRectMake(aOffset.x, -(aOffset.y + size.height), size.width, size.height), image); + + CGContextScaleCTM(cg, 1, -1); + if (isGradient(aSource)) { + // we shouldn't need to clip to an additional rectangle + // as the cliping to the mask should be sufficient. + DrawGradient(mColorSpace, cg, aSource, CGRectMake(aOffset.x, aOffset.y, size.width, size.height)); + } else { + SetFillFromPattern(cg, mColorSpace, aSource); + CGContextFillRect(cg, CGRectMake(aOffset.x, aOffset.y, size.width, size.height)); + } + + CGImageRelease(image); + + fixer.Fix(mCg); + + CGContextRestoreGState(mCg); +} + + + +void +DrawTargetCG::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aDrawOptions) +{ + MarkChanged(); + + CGContextSaveGState(mCg); + + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp, &aRect); + CGContextSetAlpha(mCg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + if (isGradient(aPattern)) { + CGContextClipToRect(cg, RectToCGRect(aRect)); + CGRect clipBounds = CGContextGetClipBoundingBox(cg); + DrawGradient(mColorSpace, cg, aPattern, clipBounds); + } else if (isNonRepeatingSurface(aPattern)) { + // SetFillFromPattern can handle this case but using CGContextDrawImage + // should give us better performance, better output, smaller PDF and + // matches what cairo does. + const SurfacePattern& pat = static_cast(aPattern); + CGImageRef image = GetRetainedImageFromSourceSurface(pat.mSurface.get()); + Matrix transform = pat.mMatrix; + if (!pat.mSamplingRect.IsEmpty()) { + CGImageRef temp = CGImageCreateWithImageInRect(image, RectToCGRect(pat.mSamplingRect)); + CGImageRelease(image); + image = temp; + transform.PreTranslate(pat.mSamplingRect.x, pat.mSamplingRect.y); + } + CGContextClipToRect(cg, RectToCGRect(aRect)); + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(transform)); + CGContextTranslateCTM(cg, 0, CGImageGetHeight(image)); + CGContextScaleCTM(cg, 1, -1); + + CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)); + + CGContextSetInterpolationQuality(cg, InterpolationQualityFromFilter(pat.mFilter)); + + CGContextDrawImage(cg, imageRect, image); + CGImageRelease(image); + } else { + SetFillFromPattern(cg, mColorSpace, aPattern); + CGContextFillRect(cg, RectToCGRect(aRect)); + } + + fixer.Fix(mCg); + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions) +{ + if (!std::isfinite(p1.x) || + !std::isfinite(p1.y) || + !std::isfinite(p2.x) || + !std::isfinite(p2.y)) { + return; + } + + MarkChanged(); + + CGContextSaveGState(mCg); + + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(mCg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + CGContextBeginPath(cg); + CGContextMoveToPoint(cg, p1.x, p1.y); + CGContextAddLineToPoint(cg, p2.x, p2.y); + + SetStrokeOptions(cg, aStrokeOptions); + + if (isGradient(aPattern)) { + CGContextReplacePathWithStrokedPath(cg); + CGRect extents = CGContextGetPathBoundingBox(cg); + //XXX: should we use EO clip here? + CGContextClip(cg); + DrawGradient(mColorSpace, cg, aPattern, extents); + } else { + SetStrokeFromPattern(cg, mColorSpace, aPattern); + CGContextStrokePath(cg); + } + + fixer.Fix(mCg); + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aDrawOptions) +{ + if (!aRect.IsFinite()) { + return; + } + + MarkChanged(); + + CGContextSaveGState(mCg); + + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(mCg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + SetStrokeOptions(cg, aStrokeOptions); + + if (isGradient(aPattern)) { + // There's no CGContextClipStrokeRect so we do it by hand + CGContextBeginPath(cg); + CGContextAddRect(cg, RectToCGRect(aRect)); + CGContextReplacePathWithStrokedPath(cg); + CGRect extents = CGContextGetPathBoundingBox(cg); + //XXX: should we use EO clip here? + CGContextClip(cg); + DrawGradient(mColorSpace, cg, aPattern, extents); + } else { + SetStrokeFromPattern(cg, mColorSpace, aPattern); + CGContextStrokeRect(cg, RectToCGRect(aRect)); + } + + fixer.Fix(mCg); + CGContextRestoreGState(mCg); +} + + +void +DrawTargetCG::ClearRect(const Rect &aRect) +{ + MarkChanged(); + + CGContextSaveGState(mCg); + CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); + + CGContextClearRect(mCg, RectToCGRect(aRect)); + + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::Stroke(const Path *aPath, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions) +{ + if (!aPath->GetBounds().IsFinite()) { + return; + } + + MarkChanged(); + + CGContextSaveGState(mCg); + + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(mCg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + + CGContextBeginPath(cg); + + assert(aPath->GetBackendType() == BackendType::COREGRAPHICS); + const PathCG *cgPath = static_cast(aPath); + CGContextAddPath(cg, cgPath->GetPath()); + + SetStrokeOptions(cg, aStrokeOptions); + + if (isGradient(aPattern)) { + CGContextReplacePathWithStrokedPath(cg); + CGRect extents = CGContextGetPathBoundingBox(cg); + //XXX: should we use EO clip here? + CGContextClip(cg); + DrawGradient(mColorSpace, cg, aPattern, extents); + } else { + // XXX: we could put fill mode into the path fill rule if we wanted + + SetStrokeFromPattern(cg, mColorSpace, aPattern); + CGContextStrokePath(cg); + } + + fixer.Fix(mCg); + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aDrawOptions) +{ + MarkChanged(); + + assert(aPath->GetBackendType() == BackendType::COREGRAPHICS); + + CGContextSaveGState(mCg); + + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(cg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + CGContextBeginPath(cg); + // XXX: we could put fill mode into the path fill rule if we wanted + const PathCG *cgPath = static_cast(aPath); + + if (isGradient(aPattern)) { + // setup a clip to draw the gradient through + CGRect extents; + if (CGPathIsEmpty(cgPath->GetPath())) { + // Adding an empty path will cause us not to clip + // so clip everything explicitly + CGContextClipToRect(mCg, CGRectZero); + extents = CGRectZero; + } else { + CGContextAddPath(cg, cgPath->GetPath()); + extents = CGContextGetPathBoundingBox(cg); + if (cgPath->GetFillRule() == FillRule::FILL_EVEN_ODD) + CGContextEOClip(mCg); + else + CGContextClip(mCg); + } + + DrawGradient(mColorSpace, cg, aPattern, extents); + } else { + CGContextAddPath(cg, cgPath->GetPath()); + + SetFillFromPattern(cg, mColorSpace, aPattern); + + if (cgPath->GetFillRule() == FillRule::FILL_EVEN_ODD) + CGContextEOFillPath(cg); + else + CGContextFillPath(cg); + } + + fixer.Fix(mCg); + CGContextRestoreGState(mCg); +} + +CGRect ComputeGlyphsExtents(CGRect *bboxes, CGPoint *positions, CFIndex count, float scale) +{ + CGFloat x1, x2, y1, y2; + if (count < 1) + return CGRectZero; + + x1 = bboxes[0].origin.x + positions[0].x; + x2 = bboxes[0].origin.x + positions[0].x + scale*bboxes[0].size.width; + y1 = bboxes[0].origin.y + positions[0].y; + y2 = bboxes[0].origin.y + positions[0].y + scale*bboxes[0].size.height; + + // accumulate max and minimum coordinates + for (int i = 1; i < count; i++) { + x1 = min(x1, bboxes[i].origin.x + positions[i].x); + y1 = min(y1, bboxes[i].origin.y + positions[i].y); + x2 = max(x2, bboxes[i].origin.x + positions[i].x + scale*bboxes[i].size.width); + y2 = max(y2, bboxes[i].origin.y + positions[i].y + scale*bboxes[i].size.height); + } + + CGRect extents = {{x1, y1}, {x2-x1, y2-y1}}; + return extents; +} + + +void +DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aDrawOptions, + const GlyphRenderingOptions*) +{ + MarkChanged(); + + assert(aBuffer.mNumGlyphs); + CGContextSaveGState(mCg); + + CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); + UnboundnessFixer fixer; + CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); + CGContextSetAlpha(cg, aDrawOptions.mAlpha); + CGContextSetShouldAntialias(cg, aDrawOptions.mAntialiasMode != AntialiasMode::NONE); + if (aDrawOptions.mAntialiasMode != AntialiasMode::DEFAULT) { + CGContextSetShouldSmoothFonts(cg, aDrawOptions.mAntialiasMode == AntialiasMode::SUBPIXEL); + } + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); + + ScaledFontMac* macFont = static_cast(aFont); + + //XXX: we should use a stack vector here when we have a class like that + std::vector glyphs; + std::vector positions; + glyphs.resize(aBuffer.mNumGlyphs); + positions.resize(aBuffer.mNumGlyphs); + + // Handle the flip + CGContextScaleCTM(cg, 1, -1); + // CGContextSetTextMatrix works differently with kCGTextClip && kCGTextFill + // It seems that it transforms the positions with TextFill and not with TextClip + // Therefore we'll avoid it. See also: + // http://cgit.freedesktop.org/cairo/commit/?id=9c0d761bfcdd28d52c83d74f46dd3c709ae0fa69 + + for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { + glyphs[i] = aBuffer.mGlyphs[i].mIndex; + // XXX: CGPointMake might not be inlined + positions[i] = CGPointMake(aBuffer.mGlyphs[i].mPosition.x, + -aBuffer.mGlyphs[i].mPosition.y); + } + + //XXX: CGContextShowGlyphsAtPositions is 10.5+ for older versions use CGContextShowGlyphsWithAdvances + if (isGradient(aPattern)) { + CGContextSetTextDrawingMode(cg, kCGTextClip); + CGRect extents; + if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) { + CGRect *bboxes = new CGRect[aBuffer.mNumGlyphs]; + CTFontGetBoundingRectsForGlyphs(macFont->mCTFont, kCTFontDefaultOrientation, + &glyphs.front(), bboxes, aBuffer.mNumGlyphs); + extents = ComputeGlyphsExtents(bboxes, &positions.front(), aBuffer.mNumGlyphs, 1.0f); + ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(), + &positions.front(), aBuffer.mNumGlyphs, cg); + delete bboxes; + } else { + CGRect *bboxes = new CGRect[aBuffer.mNumGlyphs]; + CGFontGetGlyphBBoxes(macFont->mFont, &glyphs.front(), aBuffer.mNumGlyphs, bboxes); + extents = ComputeGlyphsExtents(bboxes, &positions.front(), aBuffer.mNumGlyphs, macFont->mSize); + + CGContextSetFont(cg, macFont->mFont); + CGContextSetFontSize(cg, macFont->mSize); + CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), + aBuffer.mNumGlyphs); + delete bboxes; + } + CGContextScaleCTM(cg, 1, -1); + DrawGradient(mColorSpace, cg, aPattern, extents); + } else { + //XXX: with CoreGraphics we can stroke text directly instead of going + // through GetPath. It would be nice to add support for using that + CGContextSetTextDrawingMode(cg, kCGTextFill); + SetFillFromPattern(cg, mColorSpace, aPattern); + if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) { + ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(), + &positions.front(), + aBuffer.mNumGlyphs, cg); + } else { + CGContextSetFont(cg, macFont->mFont); + CGContextSetFontSize(cg, macFont->mSize); + CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), + aBuffer.mNumGlyphs); + } + } + + fixer.Fix(mCg); + CGContextRestoreGState(cg); +} + +extern "C" { +void +CGContextResetClip(CGContextRef); +}; + +void +DrawTargetCG::CopySurface(SourceSurface *aSurface, + const IntRect& aSourceRect, + const IntPoint &aDestination) +{ + MarkChanged(); + + if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE || + aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT || + aSurface->GetType() == SurfaceType::DATA) { + CGImageRef image = GetRetainedImageFromSourceSurface(aSurface); + + // XXX: it might be more efficient for us to do the copy directly if we have access to the bits + + CGContextSaveGState(mCg); + + // CopySurface ignores the clip, so we need to use private API to temporarily reset it + CGContextResetClip(mCg); + CGRect destRect = CGRectMake(aDestination.x, aDestination.y, + aSourceRect.width, aSourceRect.height); + CGContextClipToRect(mCg, destRect); + + CGContextSetBlendMode(mCg, kCGBlendModeCopy); + + CGContextScaleCTM(mCg, 1, -1); + + CGRect flippedRect = CGRectMake(aDestination.x - aSourceRect.x, -(aDestination.y - aSourceRect.y + double(CGImageGetHeight(image))), + CGImageGetWidth(image), CGImageGetHeight(image)); + + // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them + // to transparent first. + if (mFormat == SurfaceFormat::A8) { + CGContextClearRect(mCg, flippedRect); + } + CGContextDrawImage(mCg, flippedRect, image); + + CGContextRestoreGState(mCg); + CGImageRelease(image); + } +} + +void +DrawTargetCG::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator) +{ + MarkChanged(); + + CGImageRef image = GetRetainedImageFromSourceSurface(aSurface); + + IntSize size = aSurface->GetSize(); + CGContextSaveGState(mCg); + //XXX do we need to do the fixup here? + CGContextSetBlendMode(mCg, ToBlendMode(aOperator)); + + CGContextScaleCTM(mCg, 1, -1); + + CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + size.height), + size.width, size.height); + + CGColorRef color = ColorToCGColor(mColorSpace, aColor); + CGSize offset = {aOffset.x, -aOffset.y}; + // CoreGraphics needs twice sigma as it's amount of blur + CGContextSetShadowWithColor(mCg, offset, 2*aSigma, color); + CGColorRelease(color); + + CGContextDrawImage(mCg, flippedRect, image); + + CGImageRelease(image); + CGContextRestoreGState(mCg); + +} + +bool +DrawTargetCG::Init(BackendType aType, + unsigned char* aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) +{ + // XXX: we should come up with some consistent semantics for dealing + // with zero area drawtargets + if (aSize.width <= 0 || aSize.height <= 0 || + // 32767 is the maximum size supported by cairo + // we clamp to that to make it easier to interoperate + aSize.width > 32767 || aSize.height > 32767) { + gfxWarning() << "Failed to Init() DrawTargetCG because of bad size."; + mColorSpace = nullptr; + mCg = nullptr; + return false; + } + + //XXX: handle SurfaceFormat + + //XXX: we'd be better off reusing the Colorspace across draw targets + mColorSpace = CGColorSpaceCreateDeviceRGB(); + + if (aData == nullptr && aType != BackendType::COREGRAPHICS_ACCELERATED) { + // XXX: Currently, Init implicitly clears, that can often be a waste of time + size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height); + if (bufLen == 0) { + mColorSpace = nullptr; + mCg = nullptr; + return false; + } + static_assert(sizeof(decltype(mData[0])) == 1, + "mData.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen"); + mData.Realloc(/* actually an object count */ bufLen, true); + aData = static_cast(mData); + } + + mSize = aSize; + + if (aType == BackendType::COREGRAPHICS_ACCELERATED) { + RefPtr ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height); + mCg = ioSurface->CreateIOSurfaceContext(); + // If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null + // and we will fallback to software below + } + + mFormat = SurfaceFormat::B8G8R8A8; + + if (!mCg || aType == BackendType::COREGRAPHICS) { + int bitsPerComponent = 8; + + CGBitmapInfo bitinfo; + if (aFormat == SurfaceFormat::A8) { + if (mColorSpace) + CGColorSpaceRelease(mColorSpace); + mColorSpace = nullptr; + bitinfo = kCGImageAlphaOnly; + mFormat = SurfaceFormat::A8; + } else { + bitinfo = kCGBitmapByteOrder32Host; + if (aFormat == SurfaceFormat::B8G8R8X8) { + bitinfo |= kCGImageAlphaNoneSkipFirst; + mFormat = aFormat; + } else { + bitinfo |= kCGImageAlphaPremultipliedFirst; + } + } + // XXX: what should we do if this fails? + mCg = CGBitmapContextCreate (aData, + mSize.width, + mSize.height, + bitsPerComponent, + aStride, + mColorSpace, + bitinfo); + } + + assert(mCg); + // CGContext's default to have the origin at the bottom left + // so flip it to the top left + CGContextTranslateCTM(mCg, 0, mSize.height); + CGContextScaleCTM(mCg, 1, -1); + // See Bug 722164 for performance details + // Medium or higher quality lead to expensive interpolation + // for canvas we want to use low quality interpolation + // to have competitive performance with other canvas + // implementation. + // XXX: Create input parameter to control interpolation and + // use the default for content. + CGContextSetInterpolationQuality(mCg, kCGInterpolationLow); + + + if (aType == BackendType::COREGRAPHICS_ACCELERATED) { + // The bitmap backend uses callac to clear, we can't do that without + // reading back the surface. This should trigger something equivilent + // to glClear. + ClearRect(Rect(0, 0, mSize.width, mSize.height)); + } + + return true; +} + +void +DrawTargetCG::Flush() +{ + if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) { + CGContextFlush(mCg); + } +} + +bool +DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize) +{ + // XXX: we should come up with some consistent semantics for dealing + // with zero area drawtargets + if (aSize.width == 0 || aSize.height == 0) { + mColorSpace = nullptr; + mCg = nullptr; + return false; + } + + //XXX: handle SurfaceFormat + + //XXX: we'd be better off reusing the Colorspace across draw targets + mColorSpace = CGColorSpaceCreateDeviceRGB(); + + mSize = aSize; + + mCg = cgContext; + CGContextRetain(mCg); + + assert(mCg); + + // CGContext's default to have the origin at the bottom left. + // However, currently the only use of this function is to construct a + // DrawTargetCG around a CGContextRef from a cairo quartz surface which + // already has it's origin adjusted. + // + // CGContextTranslateCTM(mCg, 0, mSize.height); + // CGContextScaleCTM(mCg, 1, -1); + + mFormat = SurfaceFormat::B8G8R8A8; + if (GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) { + CGColorSpaceRef colorspace; + CGBitmapInfo bitinfo = CGBitmapContextGetBitmapInfo(mCg); + colorspace = CGBitmapContextGetColorSpace (mCg); + if (CGColorSpaceGetNumberOfComponents(colorspace) == 1) { + mFormat = SurfaceFormat::A8; + } else if ((bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst) { + mFormat = SurfaceFormat::B8G8R8X8; + } + } + + return true; +} + +bool +DrawTargetCG::Init(BackendType aType, const IntSize &aSize, SurfaceFormat &aFormat) +{ + int32_t stride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat)); + + // Calling Init with aData == nullptr will allocate. + return Init(aType, nullptr, aSize, stride, aFormat); +} + +TemporaryRef +DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const +{ + return new PathBuilderCG(aFillRule); +} + +void* +DrawTargetCG::GetNativeSurface(NativeSurfaceType aType) +{ + if ((aType == NativeSurfaceType::CGCONTEXT && GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) || + (aType == NativeSurfaceType::CGCONTEXT_ACCELERATED && GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE)) { + return mCg; + } else { + return nullptr; + } +} + +void +DrawTargetCG::Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aDrawOptions) +{ + MarkChanged(); + + CGContextSaveGState(mCg); + + if (isGradient(aMask)) { + assert(0); + } else { + if (aMask.GetType() == PatternType::COLOR) { + DrawOptions drawOptions(aDrawOptions); + const Color& color = static_cast(aMask).mColor; + drawOptions.mAlpha *= color.a; + assert(0); + // XXX: we need to get a rect that when transformed covers the entire surface + //Rect + //FillRect(rect, aSource, drawOptions); + } else if (aMask.GetType() == PatternType::SURFACE) { + const SurfacePattern& pat = static_cast(aMask); + CGImageRef mask = GetRetainedImageFromSourceSurface(pat.mSurface.get()); + MOZ_ASSERT(pat.mSamplingRect.IsEmpty(), "Sampling rect not supported with masks!"); + Rect rect(0,0, CGImageGetWidth(mask), CGImageGetHeight(mask)); + // XXX: probably we need to do some flipping of the image or something + CGContextClipToMask(mCg, RectToCGRect(rect), mask); + FillRect(rect, aSource, aDrawOptions); + CGImageRelease(mask); + } + } + + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::PushClipRect(const Rect &aRect) +{ + CGContextSaveGState(mCg); + + /* We go through a bit of trouble to temporarilly set the transform + * while we add the path */ + CGAffineTransform previousTransform = CGContextGetCTM(mCg); + CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); + CGContextClipToRect(mCg, RectToCGRect(aRect)); + CGContextSetCTM(mCg, previousTransform); +} + + +void +DrawTargetCG::PushClip(const Path *aPath) +{ + CGContextSaveGState(mCg); + + CGContextBeginPath(mCg); + assert(aPath->GetBackendType() == BackendType::COREGRAPHICS); + + const PathCG *cgPath = static_cast(aPath); + + // Weirdly, CoreGraphics clips empty paths as all shown + // but emtpy rects as all clipped. We detect this situation and + // workaround it appropriately + if (CGPathIsEmpty(cgPath->GetPath())) { + // XXX: should we return here? + CGContextClipToRect(mCg, CGRectZero); + } + + + /* We go through a bit of trouble to temporarilly set the transform + * while we add the path. XXX: this could be improved if we keep + * the CTM as resident state on the DrawTarget. */ + CGContextSaveGState(mCg); + CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); + CGContextAddPath(mCg, cgPath->GetPath()); + CGContextRestoreGState(mCg); + + if (cgPath->GetFillRule() == FillRule::FILL_EVEN_ODD) + CGContextEOClip(mCg); + else + CGContextClip(mCg); +} + +void +DrawTargetCG::PopClip() +{ + CGContextRestoreGState(mCg); +} + +void +DrawTargetCG::MarkChanged() +{ + if (mSnapshot) { + if (mSnapshot->refCount() > 1) { + // We only need to worry about snapshots that someone else knows about + mSnapshot->DrawTargetWillChange(); + } + mSnapshot = nullptr; + } +} + +CGContextRef +BorrowedCGContext::BorrowCGContextFromDrawTarget(DrawTarget *aDT) +{ + if ((aDT->GetBackendType() == BackendType::COREGRAPHICS || + aDT->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) && + !aDT->IsTiledDrawTarget() && !aDT->IsDualDrawTarget()) { + DrawTargetCG* cgDT = static_cast(aDT); + cgDT->MarkChanged(); + + // swap out the context + CGContextRef cg = cgDT->mCg; + cgDT->mCg = nullptr; + + // save the state to make it easier for callers to avoid mucking with things + CGContextSaveGState(cg); + + CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(cgDT->mTransform)); + + return cg; + } + return nullptr; +} + +void +BorrowedCGContext::ReturnCGContextToDrawTarget(DrawTarget *aDT, CGContextRef cg) +{ + DrawTargetCG* cgDT = static_cast(aDT); + + CGContextRestoreGState(cg); + cgDT->mCg = cg; +} + + +} +} diff --git a/libazure/src/gfx/2d/DrawTargetCG.h b/libazure/DrawTargetCG.h similarity index 79% rename from libazure/src/gfx/2d/DrawTargetCG.h rename to libazure/DrawTargetCG.h index e952a6e..4b270d3 100644 --- a/libazure/src/gfx/2d/DrawTargetCG.h +++ b/libazure/DrawTargetCG.h @@ -3,13 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef mozilla_gfx_DrawTargetCG_h +#define mozilla_gfx_DrawTargetCG_h + #include #include "2D.h" #include "Rect.h" #include "PathCG.h" #include "SourceSurfaceCG.h" -#include "GLDefs.h" +#include "Tools.h" namespace mozilla { namespace gfx { @@ -36,32 +39,38 @@ CGRectToRect(CGRect rect) rect.size.height); } +static inline Point +CGPointToPoint(CGPoint point) +{ + return Point(point.x, point.y); +} + static inline void SetStrokeOptions(CGContextRef cg, const StrokeOptions &aStrokeOptions) { switch (aStrokeOptions.mLineCap) { - case CAP_BUTT: + case CapStyle::BUTT: CGContextSetLineCap(cg, kCGLineCapButt); break; - case CAP_ROUND: + case CapStyle::ROUND: CGContextSetLineCap(cg, kCGLineCapRound); break; - case CAP_SQUARE: + case CapStyle::SQUARE: CGContextSetLineCap(cg, kCGLineCapSquare); break; } switch (aStrokeOptions.mLineJoin) { - case JOIN_BEVEL: + case JoinStyle::BEVEL: CGContextSetLineJoin(cg, kCGLineJoinBevel); break; - case JOIN_ROUND: + case JoinStyle::ROUND: CGContextSetLineJoin(cg, kCGLineJoinRound); break; - case JOIN_MITER: - case JOIN_MITER_OR_BEVEL: + case JoinStyle::MITER: + case JoinStyle::MITER_OR_BEVEL: CGContextSetLineJoin(cg, kCGLineJoinMiter); break; } @@ -85,10 +94,13 @@ SetStrokeOptions(CGContextRef cg, const StrokeOptions &aStrokeOptions) class DrawTargetCG : public DrawTarget { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCG) + friend class BorrowedCGContext; DrawTargetCG(); virtual ~DrawTargetCG(); - virtual BackendType GetType() const; + virtual DrawTargetType GetType() const MOZ_OVERRIDE; + virtual BackendType GetBackendType() const; virtual TemporaryRef Snapshot(); virtual void DrawSurface(SourceSurface *aSurface, @@ -96,6 +108,14 @@ class DrawTargetCG : public DrawTarget const Rect &aSource, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); virtual void FillRect(const Rect &aRect, const Pattern &aPattern, @@ -128,7 +148,8 @@ class DrawTargetCG : public DrawTarget virtual TemporaryRef CreateSimilarDrawTarget(const IntSize &, SurfaceFormat) const; virtual TemporaryRef CreatePathBuilder(FillRule) const; virtual TemporaryRef CreateGradientStops(GradientStop *, uint32_t, - ExtendMode aExtendMode = EXTEND_CLAMP) const; + ExtendMode aExtendMode = ExtendMode::CLAMP) const; + virtual TemporaryRef CreateFilter(FilterType aType); virtual void *GetNativeSurface(NativeSurfaceType); @@ -152,17 +173,18 @@ class DrawTargetCG : public DrawTarget CGContextRef mCg; /** - * A pointer to the image buffer if the buffer is owned by this class (set to - * nullptr otherwise). - * The data is not considered owned by DrawTargetCG if the DrawTarget was - * created for a pre-existing buffer or if the buffer's lifetime is managed - * by CoreGraphics. - * Data owned by DrawTargetCG will be deallocated in the destructor. + * The image buffer, if the buffer is owned by this class. + * If the DrawTarget was created for a pre-existing buffer or if the buffer's + * lifetime is managed by CoreGraphics, mData will be null. + * Data owned by DrawTargetCG will be deallocated in the destructor. */ - void *mData; + AlignedArray mData; RefPtr mSnapshot; }; } } + +#endif + diff --git a/libazure/DrawTargetCairo.cpp b/libazure/DrawTargetCairo.cpp new file mode 100644 index 0000000..ae85185 --- /dev/null +++ b/libazure/DrawTargetCairo.cpp @@ -0,0 +1,1577 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DrawTargetCairo.h" + +#include "SourceSurfaceCairo.h" +#include "PathCairo.h" +#include "HelpersCairo.h" +#include "ScaledFontBase.h" +#include "BorrowedContext.h" +#include "FilterNodeSoftware.h" +#include "mozilla/Scoped.h" + +#include "cairo.h" +#include "cairo-tee.h" +#include + +#include "Blur.h" +#include "Logging.h" +#include "Tools.h" + +#ifdef CAIRO_HAS_QUARTZ_SURFACE +#include "cairo-quartz.h" +#include +#endif + +#ifdef CAIRO_HAS_XLIB_SURFACE +#include "cairo-xlib.h" +#include "cairo-xlib-xrender.h" +#endif + +#ifdef CAIRO_HAS_WIN32_SURFACE +#include "cairo-win32.h" +#endif + +#include + +namespace mozilla { + +MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCairoSurface, cairo_surface_t, cairo_surface_destroy); + +namespace gfx { + +cairo_surface_t *DrawTargetCairo::mDummySurface; + +namespace { + +// An RAII class to prepare to draw a context and optional path. Saves and +// restores the context on construction/destruction. +class AutoPrepareForDrawing +{ +public: + AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx) + : mCtx(ctx) + { + dt->PrepareForDrawing(ctx); + cairo_save(mCtx); + MOZ_ASSERT(cairo_status(mCtx) || dt->GetTransform() == GetTransform()); + } + + AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx, const Path* path) + : mCtx(ctx) + { + dt->PrepareForDrawing(ctx, path); + cairo_save(mCtx); + MOZ_ASSERT(cairo_status(mCtx) || dt->GetTransform() == GetTransform()); + } + + ~AutoPrepareForDrawing() + { + cairo_restore(mCtx); + cairo_status_t status = cairo_status(mCtx); + if (status) { + gfxWarning() << "DrawTargetCairo context in error state: " << cairo_status_to_string(status) << "(" << status << ")"; + } + } + +private: +#ifdef DEBUG + Matrix GetTransform() + { + cairo_matrix_t mat; + cairo_get_matrix(mCtx, &mat); + return Matrix(mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0); + } +#endif + + cairo_t* mCtx; +}; + + +} // end anonymous namespace + +static bool +SupportsSelfCopy(cairo_surface_t* surface) +{ + switch (cairo_surface_get_type(surface)) + { +#ifdef CAIRO_HAS_QUARTZ_SURFACE + case CAIRO_SURFACE_TYPE_QUARTZ: + return true; +#endif +#ifdef CAIRO_HAS_WIN32_SURFACE + case CAIRO_SURFACE_TYPE_WIN32: + case CAIRO_SURFACE_TYPE_WIN32_PRINTING: + return true; +#endif + default: + return false; + } +} + +static bool +PatternIsCompatible(const Pattern& aPattern) +{ + switch (aPattern.GetType()) + { + case PatternType::LINEAR_GRADIENT: + { + const LinearGradientPattern& pattern = static_cast(aPattern); + return pattern.mStops->GetBackendType() == BackendType::CAIRO; + } + case PatternType::RADIAL_GRADIENT: + { + const RadialGradientPattern& pattern = static_cast(aPattern); + return pattern.mStops->GetBackendType() == BackendType::CAIRO; + } + default: + return true; + } +} + +static cairo_user_data_key_t surfaceDataKey; + +void +ReleaseData(void* aData) +{ + DataSourceSurface *data = static_cast(aData); + data->Unmap(); + data->Release(); +} + +cairo_surface_t* +CopyToImageSurface(unsigned char *aData, + const IntRect &aRect, + int32_t aStride, + SurfaceFormat aFormat) +{ + cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), + aRect.width, + aRect.height); + // In certain scenarios, requesting larger than 8k image fails. Bug 803568 + // covers the details of how to run into it, but the full detailed + // investigation hasn't been done to determine the underlying cause. We + // will just handle the failure to allocate the surface to avoid a crash. + if (cairo_surface_status(surf)) { + return nullptr; + } + + unsigned char* surfData = cairo_image_surface_get_data(surf); + int surfStride = cairo_image_surface_get_stride(surf); + int32_t pixelWidth = BytesPerPixel(aFormat); + + unsigned char* source = aData + + aRect.y * aStride + + aRect.x * pixelWidth; + + for (int32_t y = 0; y < aRect.height; ++y) { + memcpy(surfData + y * surfStride, + source + y * aStride, + aRect.width * pixelWidth); + } + cairo_surface_mark_dirty(surf); + return surf; +} + +/** + * If aSurface can be represented as a surface of type + * CAIRO_SURFACE_TYPE_IMAGE then returns that surface. Does + * not add a reference. + */ +cairo_surface_t* GetAsImageSurface(cairo_surface_t* aSurface) +{ + if (cairo_surface_get_type(aSurface) == CAIRO_SURFACE_TYPE_IMAGE) { + return aSurface; +#ifdef CAIRO_HAS_WIN32_SURFACE + } else if (cairo_surface_get_type(aSurface) == CAIRO_SURFACE_TYPE_WIN32) { + return cairo_win32_surface_get_image(aSurface); +#endif + } + + return nullptr; +} + +cairo_surface_t* CreateSubImageForData(unsigned char* aData, + const IntRect& aRect, + int aStride, + SurfaceFormat aFormat) +{ + unsigned char *data = aData + + aRect.y * aStride + + aRect.x * BytesPerPixel(aFormat); + + cairo_surface_t *image = + cairo_image_surface_create_for_data(data, + GfxFormatToCairoFormat(aFormat), + aRect.width, + aRect.height, + aStride); + cairo_surface_set_device_offset(image, -aRect.x, -aRect.y); + return image; +} + +/** + * Returns a referenced cairo_surface_t representing the + * sub-image specified by aSubImage. + */ +cairo_surface_t* ExtractSubImage(cairo_surface_t* aSurface, + const IntRect& aSubImage, + SurfaceFormat aFormat) +{ + // No need to worry about retaining a reference to the original + // surface since the only caller of this function guarantees + // that aSurface will stay alive as long as the result + + cairo_surface_t* image = GetAsImageSurface(aSurface); + if (image) { + image = CreateSubImageForData(cairo_image_surface_get_data(image), + aSubImage, + cairo_image_surface_get_stride(image), + aFormat); + return image; + } + + cairo_surface_t* similar = + cairo_surface_create_similar(aSurface, + cairo_surface_get_content(aSurface), + aSubImage.width, aSubImage.height); + + cairo_t* ctx = cairo_create(similar); + cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(ctx, aSurface, -aSubImage.x, -aSubImage.y); + cairo_paint(ctx); + cairo_destroy(ctx); + + cairo_surface_set_device_offset(similar, -aSubImage.x, -aSubImage.y); + return similar; +} + +/** + * Returns cairo surface for the given SourceSurface. + * If possible, it will use the cairo_surface associated with aSurface, + * otherwise, it will create a new cairo_surface. + * In either case, the caller must call cairo_surface_destroy on the + * result when it is done with it. + */ +cairo_surface_t* +GetCairoSurfaceForSourceSurface(SourceSurface *aSurface, + bool aExistingOnly = false, + const IntRect& aSubImage = IntRect()) +{ + IntRect subimage = IntRect(IntPoint(), aSurface->GetSize()); + if (!aSubImage.IsEmpty()) { + MOZ_ASSERT(!aExistingOnly); + MOZ_ASSERT(subimage.Contains(aSubImage)); + subimage = aSubImage; + } + + if (aSurface->GetType() == SurfaceType::CAIRO) { + cairo_surface_t* surf = static_cast(aSurface)->GetSurface(); + if (aSubImage.IsEmpty()) { + cairo_surface_reference(surf); + } else { + surf = ExtractSubImage(surf, subimage, aSurface->GetFormat()); + } + return surf; + } + + if (aSurface->GetType() == SurfaceType::CAIRO_IMAGE) { + cairo_surface_t* surf = + static_cast(aSurface)->GetSurface(); + if (aSubImage.IsEmpty()) { + cairo_surface_reference(surf); + } else { + surf = ExtractSubImage(surf, subimage, aSurface->GetFormat()); + } + return surf; + } + + if (aExistingOnly) { + return nullptr; + } + + RefPtr data = aSurface->GetDataSurface(); + if (!data) { + return nullptr; + } + + DataSourceSurface::MappedSurface map; + if (!data->Map(DataSourceSurface::READ, &map)) { + return nullptr; + } + + cairo_surface_t* surf = + CreateSubImageForData(map.mData, subimage, + map.mStride, data->GetFormat()); + + // In certain scenarios, requesting larger than 8k image fails. Bug 803568 + // covers the details of how to run into it, but the full detailed + // investigation hasn't been done to determine the underlying cause. We + // will just handle the failure to allocate the surface to avoid a crash. + if (cairo_surface_status(surf)) { + if (cairo_surface_status(surf) == CAIRO_STATUS_INVALID_STRIDE) { + // If we failed because of an invalid stride then copy into + // a new surface with a stride that cairo chooses. No need to + // set user data since we're not dependent on the original + // data. + cairo_surface_t* result = + CopyToImageSurface(map.mData, + subimage, + map.mStride, + data->GetFormat()); + data->Unmap(); + return result; + } + data->Unmap(); + return nullptr; + } + + cairo_surface_set_user_data(surf, + &surfaceDataKey, + data.forget().drop(), + ReleaseData); + return surf; +} + +// An RAII class to temporarily clear any device offset set +// on a surface. Note that this does not take a reference to the +// surface. +class AutoClearDeviceOffset +{ +public: + explicit AutoClearDeviceOffset(SourceSurface* aSurface) + : mSurface(nullptr) + { + Init(aSurface); + } + + explicit AutoClearDeviceOffset(const Pattern& aPattern) + : mSurface(nullptr) + { + if (aPattern.GetType() == PatternType::SURFACE) { + const SurfacePattern& pattern = static_cast(aPattern); + Init(pattern.mSurface); + } + } + + ~AutoClearDeviceOffset() + { + if (mSurface) { + cairo_surface_set_device_offset(mSurface, mX, mY); + } + } + +private: + void Init(SourceSurface* aSurface) + { + cairo_surface_t* surface = GetCairoSurfaceForSourceSurface(aSurface, true); + if (surface) { + Init(surface); + cairo_surface_destroy(surface); + } + } + + void Init(cairo_surface_t *aSurface) + { + mSurface = aSurface; + cairo_surface_get_device_offset(mSurface, &mX, &mY); + cairo_surface_set_device_offset(mSurface, 0, 0); + } + + cairo_surface_t* mSurface; + double mX; + double mY; +}; + +// Never returns nullptr. As such, you must always pass in Cairo-compatible +// patterns, most notably gradients with a GradientStopCairo. +// The pattern returned must have cairo_pattern_destroy() called on it by the +// caller. +// As the cairo_pattern_t returned may depend on the Pattern passed in, the +// lifetime of the cairo_pattern_t returned must not exceed the lifetime of the +// Pattern passed in. +static cairo_pattern_t* +GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha) +{ + cairo_pattern_t* pat; + const Matrix* matrix = nullptr; + + switch (aPattern.GetType()) + { + case PatternType::COLOR: + { + Color color = static_cast(aPattern).mColor; + pat = cairo_pattern_create_rgba(color.r, color.g, color.b, color.a * aAlpha); + break; + } + + case PatternType::SURFACE: + { + const SurfacePattern& pattern = static_cast(aPattern); + cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(pattern.mSurface, + false, + pattern.mSamplingRect); + if (!surf) + return nullptr; + + pat = cairo_pattern_create_for_surface(surf); + + matrix = &pattern.mMatrix; + + cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(pattern.mFilter)); + cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(pattern.mExtendMode)); + + cairo_surface_destroy(surf); + break; + } + case PatternType::LINEAR_GRADIENT: + { + const LinearGradientPattern& pattern = static_cast(aPattern); + + pat = cairo_pattern_create_linear(pattern.mBegin.x, pattern.mBegin.y, + pattern.mEnd.x, pattern.mEnd.y); + + MOZ_ASSERT(pattern.mStops->GetBackendType() == BackendType::CAIRO); + GradientStopsCairo* cairoStops = static_cast(pattern.mStops.get()); + cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(cairoStops->GetExtendMode())); + + matrix = &pattern.mMatrix; + + const std::vector& stops = cairoStops->GetStops(); + for (size_t i = 0; i < stops.size(); ++i) { + const GradientStop& stop = stops[i]; + cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r, + stop.color.g, stop.color.b, + stop.color.a); + } + + break; + } + case PatternType::RADIAL_GRADIENT: + { + const RadialGradientPattern& pattern = static_cast(aPattern); + + pat = cairo_pattern_create_radial(pattern.mCenter1.x, pattern.mCenter1.y, pattern.mRadius1, + pattern.mCenter2.x, pattern.mCenter2.y, pattern.mRadius2); + + MOZ_ASSERT(pattern.mStops->GetBackendType() == BackendType::CAIRO); + GradientStopsCairo* cairoStops = static_cast(pattern.mStops.get()); + cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(cairoStops->GetExtendMode())); + + matrix = &pattern.mMatrix; + + const std::vector& stops = cairoStops->GetStops(); + for (size_t i = 0; i < stops.size(); ++i) { + const GradientStop& stop = stops[i]; + cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r, + stop.color.g, stop.color.b, + stop.color.a); + } + + break; + } + default: + { + // We should support all pattern types! + MOZ_ASSERT(false); + } + } + + // The pattern matrix is a matrix that transforms the pattern into user + // space. Cairo takes a matrix that converts from user space to pattern + // space. Cairo therefore needs the inverse. + if (matrix) { + cairo_matrix_t mat; + GfxMatrixToCairoMatrix(*matrix, mat); + cairo_matrix_invert(&mat); + cairo_pattern_set_matrix(pat, &mat); + } + + return pat; +} + +static bool +NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions) +{ + // We pre-multiply colours' alpha by the global alpha, so we don't need to + // use an intermediate surface for them. + if (aPattern.GetType() == PatternType::COLOR) + return false; + + if (aOptions.mAlpha == 1.0) + return false; + + return true; +} + +DrawTargetCairo::DrawTargetCairo() + : mContext(nullptr) + , mLockedBits(nullptr) +{ +} + +DrawTargetCairo::~DrawTargetCairo() +{ + cairo_destroy(mContext); + if (mSurface) { + cairo_surface_destroy(mSurface); + } + MOZ_ASSERT(!mLockedBits); +} + +DrawTargetType +DrawTargetCairo::GetType() const +{ + if (mContext) { + cairo_surface_type_t type = cairo_surface_get_type(mSurface); + if (type == CAIRO_SURFACE_TYPE_TEE) { + type = cairo_surface_get_type(cairo_tee_surface_index(mSurface, 0)); + MOZ_ASSERT(type != CAIRO_SURFACE_TYPE_TEE, "C'mon!"); + MOZ_ASSERT(type == cairo_surface_get_type(cairo_tee_surface_index(mSurface, 1)), + "What should we do here?"); + } + switch (type) { + case CAIRO_SURFACE_TYPE_PDF: + case CAIRO_SURFACE_TYPE_PS: + case CAIRO_SURFACE_TYPE_SVG: + case CAIRO_SURFACE_TYPE_WIN32_PRINTING: + case CAIRO_SURFACE_TYPE_XML: + return DrawTargetType::VECTOR; + + case CAIRO_SURFACE_TYPE_VG: + case CAIRO_SURFACE_TYPE_GL: + case CAIRO_SURFACE_TYPE_GLITZ: + case CAIRO_SURFACE_TYPE_QUARTZ: + case CAIRO_SURFACE_TYPE_DIRECTFB: + return DrawTargetType::HARDWARE_RASTER; + + case CAIRO_SURFACE_TYPE_SKIA: + case CAIRO_SURFACE_TYPE_QT: + MOZ_ASSERT(false, "Can't determine actual DrawTargetType for DrawTargetCairo - assuming SOFTWARE_RASTER"); + // fallthrough + case CAIRO_SURFACE_TYPE_IMAGE: + case CAIRO_SURFACE_TYPE_XLIB: + case CAIRO_SURFACE_TYPE_XCB: + case CAIRO_SURFACE_TYPE_WIN32: + case CAIRO_SURFACE_TYPE_BEOS: + case CAIRO_SURFACE_TYPE_OS2: + case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: + case CAIRO_SURFACE_TYPE_SCRIPT: + case CAIRO_SURFACE_TYPE_RECORDING: + case CAIRO_SURFACE_TYPE_DRM: + case CAIRO_SURFACE_TYPE_SUBSURFACE: +#ifdef CAIRO_HAS_D2D_SURFACE + case CAIRO_SURFACE_TYPE_D2D: +#endif + case CAIRO_SURFACE_TYPE_TEE: // included to silence warning about unhandled enum value + return DrawTargetType::SOFTWARE_RASTER; + default: + MOZ_CRASH("Unsupported cairo surface type"); + } + } + MOZ_ASSERT(false, "Could not determine DrawTargetType for DrawTargetCairo"); + return DrawTargetType::SOFTWARE_RASTER; +} + +IntSize +DrawTargetCairo::GetSize() +{ + return mSize; +} + +TemporaryRef +DrawTargetCairo::Snapshot() +{ + if (mSnapshot) { + return mSnapshot; + } + + IntSize size = GetSize(); + + cairo_content_t content = cairo_surface_get_content(mSurface); + mSnapshot = new SourceSurfaceCairo(mSurface, + size, + CairoContentToGfxFormat(content), + this); + return mSnapshot; +} + +bool +DrawTargetCairo::LockBits(uint8_t** aData, IntSize* aSize, + int32_t* aStride, SurfaceFormat* aFormat) +{ + if (cairo_surface_get_type(mSurface) == CAIRO_SURFACE_TYPE_IMAGE) { + WillChange(); + + mLockedBits = cairo_image_surface_get_data(mSurface); + *aData = mLockedBits; + *aSize = GetSize(); + *aStride = cairo_image_surface_get_stride(mSurface); + *aFormat = GetFormat(); + return true; + } + + return false; +} + +void +DrawTargetCairo::ReleaseBits(uint8_t* aData) +{ + MOZ_ASSERT(mLockedBits == aData); + mLockedBits = nullptr; +} + +void +DrawTargetCairo::Flush() +{ + cairo_surface_t* surf = cairo_get_target(mContext); + cairo_surface_flush(surf); +} + +void +DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = nullptr */) +{ + WillChange(aPath); +} + +cairo_surface_t* +DrawTargetCairo::GetDummySurface() +{ + if (mDummySurface) { + return mDummySurface; + } + + mDummySurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + + return mDummySurface; +} + +void +DrawTargetCairo::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + AutoPrepareForDrawing prep(this, mContext); + AutoClearDeviceOffset clear(aSurface); + + float sx = aSource.Width() / aDest.Width(); + float sy = aSource.Height() / aDest.Height(); + + cairo_matrix_t src_mat; + cairo_matrix_init_translate(&src_mat, aSource.X(), aSource.Y()); + cairo_matrix_scale(&src_mat, sx, sy); + + cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface); + cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf); + cairo_surface_destroy(surf); + + cairo_pattern_set_matrix(pat, &src_mat); + cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter)); + cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD); + + cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode)); + + // If the destination rect covers the entire clipped area, then unbounded and bounded + // operations are identical, and we don't need to push a group. + bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) && + !aDest.Contains(GetUserSpaceClip()); + + cairo_translate(mContext, aDest.X(), aDest.Y()); + + if (needsGroup) { + cairo_push_group(mContext); + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); + cairo_set_source(mContext, pat); + cairo_fill(mContext); + cairo_pop_group_to_source(mContext); + } else { + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); + cairo_clip(mContext); + cairo_set_source(mContext, pat); + } + + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + + cairo_paint_with_alpha(mContext, aOptions.mAlpha); + + cairo_pattern_destroy(pat); +} + +void +DrawTargetCairo::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + FilterNodeSoftware* filter = static_cast(aNode); + filter->Draw(this, aSourceRect, aDestPoint, aOptions); +} + +void +DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) +{ + if (aSurface->GetType() != SurfaceType::CAIRO) { + return; + } + + AutoClearDeviceOffset clear(aSurface); + + Float width = Float(aSurface->GetSize().width); + Float height = Float(aSurface->GetSize().height); + + SourceSurfaceCairo* source = static_cast(aSurface); + cairo_surface_t* sourcesurf = source->GetSurface(); + cairo_surface_t* blursurf; + cairo_surface_t* surf; + + // We only use the A8 surface for blurred shadows. Unblurred shadows can just + // use the RGBA surface directly. + if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) { + blursurf = cairo_tee_surface_index(sourcesurf, 0); + surf = cairo_tee_surface_index(sourcesurf, 1); + + MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE); + Rect extents(0, 0, width, height); + AlphaBoxBlur blur(extents, + cairo_image_surface_get_stride(blursurf), + aSigma, aSigma); + blur.Blur(cairo_image_surface_get_data(blursurf)); + } else { + blursurf = sourcesurf; + surf = sourcesurf; + } + + WillChange(); + ClearSurfaceForUnboundedSource(aOperator); + + cairo_save(mContext); + cairo_set_operator(mContext, GfxOpToCairoOp(aOperator)); + cairo_identity_matrix(mContext); + cairo_translate(mContext, aDest.x, aDest.y); + + if (IsOperatorBoundByMask(aOperator)){ + cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); + cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); + + // Now that the shadow has been drawn, we can draw the surface on top. + cairo_set_source_surface(mContext, surf, 0, 0); + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, width, height); + cairo_fill(mContext); + } else { + cairo_push_group(mContext); + cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); + cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); + + // Now that the shadow has been drawn, we can draw the surface on top. + cairo_set_source_surface(mContext, surf, 0, 0); + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, width, height); + cairo_fill(mContext); + cairo_pop_group_to_source(mContext); + cairo_paint(mContext); + } + + cairo_restore(mContext); +} + +void +DrawTargetCairo::DrawPattern(const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions, + DrawPatternType aDrawType, + bool aPathBoundsClip) +{ + if (!PatternIsCompatible(aPattern)) { + return; + } + + AutoClearDeviceOffset clear(aPattern); + + cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha); + if (!pat) { + return; + } + if (cairo_pattern_status(pat)) { + cairo_pattern_destroy(pat); + gfxWarning() << "Invalid pattern"; + return; + } + + cairo_set_source(mContext, pat); + + cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode)); + + if (NeedIntermediateSurface(aPattern, aOptions) || + (!IsOperatorBoundByMask(aOptions.mCompositionOp) && !aPathBoundsClip)) { + cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA); + + // Don't want operators to be applied twice + cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); + + if (aDrawType == DRAW_STROKE) { + SetCairoStrokeOptions(mContext, aStrokeOptions); + cairo_stroke_preserve(mContext); + } else { + cairo_fill_preserve(mContext); + } + + cairo_pop_group_to_source(mContext); + + // Now draw the content using the desired operator + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + cairo_paint_with_alpha(mContext, aOptions.mAlpha); + } else { + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + + if (aDrawType == DRAW_STROKE) { + SetCairoStrokeOptions(mContext, aStrokeOptions); + cairo_stroke_preserve(mContext); + } else { + cairo_fill_preserve(mContext); + } + } + + cairo_pattern_destroy(pat); +} + +void +DrawTargetCairo::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + AutoPrepareForDrawing prep(this, mContext); + + cairo_new_path(mContext); + cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height()); + + bool pathBoundsClip = false; + + if (aRect.Contains(GetUserSpaceClip())) { + pathBoundsClip = true; + } + + DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL, pathBoundsClip); +} + +void +DrawTargetCairo::CopySurfaceInternal(cairo_surface_t* aSurface, + const IntRect &aSource, + const IntPoint &aDest) +{ + if (cairo_surface_status(aSurface)) { + gfxWarning() << "Invalid surface"; + return; + } + + cairo_identity_matrix(mContext); + + cairo_set_source_surface(mContext, aSurface, aDest.x - aSource.x, aDest.y - aSource.y); + cairo_set_operator(mContext, CAIRO_OPERATOR_SOURCE); + cairo_set_antialias(mContext, CAIRO_ANTIALIAS_NONE); + + cairo_reset_clip(mContext); + cairo_new_path(mContext); + cairo_rectangle(mContext, aDest.x, aDest.y, aSource.width, aSource.height); + cairo_fill(mContext); +} + +void +DrawTargetCairo::CopySurface(SourceSurface *aSurface, + const IntRect &aSource, + const IntPoint &aDest) +{ + AutoPrepareForDrawing prep(this, mContext); + AutoClearDeviceOffset clear(aSurface); + + if (!aSurface) { + gfxWarning() << "Unsupported surface type specified"; + return; + } + + cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface); + if (!surf) { + gfxWarning() << "Unsupported surface type specified"; + return; + } + + CopySurfaceInternal(surf, aSource, aDest); + cairo_surface_destroy(surf); +} + +void +DrawTargetCairo::CopyRect(const IntRect &aSource, + const IntPoint &aDest) +{ + AutoPrepareForDrawing prep(this, mContext); + + IntRect source = aSource; + cairo_surface_t* surf = mSurface; + + if (!SupportsSelfCopy(mSurface) && + aDest.y >= aSource.y && + aDest.y < aSource.YMost()) { + cairo_surface_t* similar = cairo_surface_create_similar(mSurface, + GfxFormatToCairoContent(GetFormat()), + aSource.width, aSource.height); + cairo_t* ctx = cairo_create(similar); + cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(ctx, surf, -aSource.x, -aSource.y); + cairo_paint(ctx); + cairo_destroy(ctx); + + source.x = 0; + source.y = 0; + surf = similar; + } + + CopySurfaceInternal(surf, source, aDest); + + if (surf != mSurface) { + cairo_surface_destroy(surf); + } +} + +void +DrawTargetCairo::ClearRect(const Rect& aRect) +{ + AutoPrepareForDrawing prep(this, mContext); + + cairo_set_antialias(mContext, CAIRO_ANTIALIAS_NONE); + cairo_new_path(mContext); + cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); + cairo_rectangle(mContext, aRect.X(), aRect.Y(), + aRect.Width(), aRect.Height()); + cairo_fill(mContext); +} + +void +DrawTargetCairo::StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, + const DrawOptions &aOptions /* = DrawOptions() */) +{ + AutoPrepareForDrawing prep(this, mContext); + + cairo_new_path(mContext); + cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height()); + + DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); +} + +void +DrawTargetCairo::StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, + const DrawOptions &aOptions /* = DrawOptions() */) +{ + AutoPrepareForDrawing prep(this, mContext); + + cairo_new_path(mContext); + cairo_move_to(mContext, aStart.x, aStart.y); + cairo_line_to(mContext, aEnd.x, aEnd.y); + + DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); +} + +void +DrawTargetCairo::Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, + const DrawOptions &aOptions /* = DrawOptions() */) +{ + AutoPrepareForDrawing prep(this, mContext, aPath); + + if (aPath->GetBackendType() != BackendType::CAIRO) + return; + + PathCairo* path = const_cast(static_cast(aPath)); + path->SetPathOnContext(mContext); + + DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); +} + +void +DrawTargetCairo::Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions /* = DrawOptions() */) +{ + AutoPrepareForDrawing prep(this, mContext, aPath); + + if (aPath->GetBackendType() != BackendType::CAIRO) + return; + + PathCairo* path = const_cast(static_cast(aPath)); + path->SetPathOnContext(mContext); + + DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL); +} + +void +DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA) +{ + DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA); +#ifdef MOZ2D_HAS_MOZ_CAIRO + cairo_surface_set_subpixel_antialiasing(mSurface, + aPermitSubpixelAA ? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED); +#endif +} + +void +DrawTargetCairo::FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions, + const GlyphRenderingOptions*) +{ + AutoPrepareForDrawing prep(this, mContext); + AutoClearDeviceOffset clear(aPattern); + + ScaledFontBase* scaledFont = static_cast(aFont); + cairo_set_scaled_font(mContext, scaledFont->GetCairoScaledFont()); + + cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha); + if (!pat) + return; + + cairo_set_source(mContext, pat); + cairo_pattern_destroy(pat); + + cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode)); + + // Convert our GlyphBuffer into an array of Cairo glyphs. + std::vector glyphs(aBuffer.mNumGlyphs); + for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { + glyphs[i].index = aBuffer.mGlyphs[i].mIndex; + glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; + glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; + } + + cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs); +} + +void +DrawTargetCairo::Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions /* = DrawOptions() */) +{ + AutoPrepareForDrawing prep(this, mContext); + AutoClearDeviceOffset clearSource(aSource); + AutoClearDeviceOffset clearMask(aMask); + + cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode)); + + cairo_pattern_t* source = GfxPatternToCairoPattern(aSource, aOptions.mAlpha); + if (!source) { + return; + } + + cairo_pattern_t* mask = GfxPatternToCairoPattern(aMask, aOptions.mAlpha); + if (!mask) { + cairo_pattern_destroy(source); + return; + } + + if (cairo_pattern_status(source) || cairo_pattern_status(mask)) { + cairo_pattern_destroy(source); + cairo_pattern_destroy(mask); + gfxWarning() << "Invalid pattern"; + return; + } + + cairo_set_source(mContext, source); + cairo_mask(mContext, mask); + + cairo_pattern_destroy(mask); + cairo_pattern_destroy(source); +} + +void +DrawTargetCairo::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + AutoPrepareForDrawing prep(this, mContext); + AutoClearDeviceOffset clearSource(aSource); + AutoClearDeviceOffset clearMask(aMask); + + if (!PatternIsCompatible(aSource)) { + return; + } + + cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode)); + + cairo_pattern_t* pat = GfxPatternToCairoPattern(aSource, aOptions.mAlpha); + if (!pat) { + return; + } + + if (cairo_pattern_status(pat)) { + cairo_pattern_destroy(pat); + gfxWarning() << "Invalid pattern"; + return; + } + + cairo_set_source(mContext, pat); + + if (NeedIntermediateSurface(aSource, aOptions)) { + cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA); + + // Don't want operators to be applied twice + cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); + + // Now draw the content using the desired operator + cairo_paint_with_alpha(mContext, aOptions.mAlpha); + + cairo_pop_group_to_source(mContext); + } + + cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aMask); + if (!surf) { + cairo_pattern_destroy(pat); + return; + } + cairo_pattern_t* mask = cairo_pattern_create_for_surface(surf); + cairo_matrix_t matrix; + + cairo_matrix_init_translate (&matrix, -aOffset.x, -aOffset.y); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + + cairo_mask(mContext, mask); + + cairo_surface_destroy(surf); + cairo_pattern_destroy(mask); + cairo_pattern_destroy(pat); +} + +void +DrawTargetCairo::PushClip(const Path *aPath) +{ + if (aPath->GetBackendType() != BackendType::CAIRO) { + return; + } + + WillChange(aPath); + cairo_save(mContext); + + PathCairo* path = const_cast(static_cast(aPath)); + path->SetPathOnContext(mContext); + cairo_clip_preserve(mContext); +} + +void +DrawTargetCairo::PushClipRect(const Rect& aRect) +{ + WillChange(); + cairo_save(mContext); + + cairo_new_path(mContext); + cairo_rectangle(mContext, aRect.X(), aRect.Y(), aRect.Width(), aRect.Height()); + cairo_clip_preserve(mContext); +} + +void +DrawTargetCairo::PopClip() +{ + // save/restore does not affect the path, so no need to call WillChange() + + // cairo_restore will restore the transform too and we don't want to do that + // so we'll save it now and restore it after the cairo_restore + cairo_matrix_t mat; + cairo_get_matrix(mContext, &mat); + + cairo_restore(mContext); + + cairo_set_matrix(mContext, &mat); + + MOZ_ASSERT(cairo_status(mContext) || GetTransform() == Matrix(mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0), + "Transforms are out of sync"); +} + +TemporaryRef +DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FillRule::FILL_WINDING */) const +{ + return new PathBuilderCairo(aFillRule); +} + +void +DrawTargetCairo::ClearSurfaceForUnboundedSource(const CompositionOp &aOperator) +{ + if (aOperator != CompositionOp::OP_SOURCE) + return; + cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); + // It doesn't really matter what the source is here, since Paint + // isn't bounded by the source and the mask covers the entire clip + // region. + cairo_paint(mContext); +} + + +TemporaryRef +DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, + ExtendMode aExtendMode) const +{ + return new GradientStopsCairo(aStops, aNumStops, aExtendMode); +} + +TemporaryRef +DrawTargetCairo::CreateFilter(FilterType aType) +{ + return FilterNodeSoftware::Create(aType); +} + +TemporaryRef +DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + cairo_surface_t* surf = CopyToImageSurface(aData, IntRect(IntPoint(), aSize), + aStride, aFormat); + + RefPtr source_surf = new SourceSurfaceCairo(surf, aSize, aFormat); + cairo_surface_destroy(surf); + + return source_surf.forget(); +} + +#ifdef CAIRO_HAS_XLIB_SURFACE +static cairo_user_data_key_t gDestroyPixmapKey; + +struct DestroyPixmapClosure { + DestroyPixmapClosure(Drawable d, Screen *s) : mPixmap(d), mScreen(s) {} + ~DestroyPixmapClosure() { + XFreePixmap(DisplayOfScreen(mScreen), mPixmap); + } + Drawable mPixmap; + Screen *mScreen; +}; + +static void +DestroyPixmap(void *data) +{ + delete static_cast(data); +} +#endif + +TemporaryRef +DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const +{ +#ifdef CAIRO_HAS_XLIB_SURFACE + if (cairo_surface_get_type(mSurface) != CAIRO_SURFACE_TYPE_XLIB) { + return aSurface; + } + + IntSize size = aSurface->GetSize(); + if (!size.width || !size.height) { + return aSurface; + } + + // Although the dimension parameters in the xCreatePixmapReq wire protocol are + // 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if + // either dimension cannot be represented by a 16-bit *signed* integer. + #define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff + + if (size.width > XLIB_IMAGE_SIDE_SIZE_LIMIT || + size.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) { + return aSurface; + } + + SurfaceFormat format = aSurface->GetFormat(); + Screen *screen = cairo_xlib_surface_get_screen(mSurface); + Display *dpy = DisplayOfScreen(screen); + XRenderPictFormat* xrenderFormat = nullptr; + switch (format) { + case SurfaceFormat::B8G8R8A8: + xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardARGB32); + break; + case SurfaceFormat::B8G8R8X8: + xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardRGB24); + break; + case SurfaceFormat::A8: + xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardA8); + break; + default: + return aSurface; + } + if (!xrenderFormat) { + return aSurface; + } + + Drawable pixmap = XCreatePixmap(dpy, RootWindowOfScreen(screen), + size.width, size.height, + xrenderFormat->depth); + if (!pixmap) { + return aSurface; + } + + ScopedDeletePtr closure( + new DestroyPixmapClosure(pixmap, screen)); + + ScopedCairoSurface csurf( + cairo_xlib_surface_create_with_xrender_format(dpy, pixmap, + screen, xrenderFormat, + size.width, size.height)); + if (!csurf || cairo_surface_status(csurf)) { + return aSurface; + } + + cairo_surface_set_user_data(csurf, &gDestroyPixmapKey, + closure.forget(), DestroyPixmap); + + RefPtr dt = new DrawTargetCairo(); + if (!dt->Init(csurf, size, &format)) { + return aSurface; + } + + dt->CopySurface(aSurface, + IntRect(0, 0, size.width, size.height), + IntPoint(0, 0)); + dt->Flush(); + + return new SourceSurfaceCairo(csurf, size, format); +#endif + + return aSurface; +} + +TemporaryRef +DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const +{ + if (aSurface.mType == NativeSurfaceType::CAIRO_SURFACE) { + if (aSurface.mSize.width <= 0 || + aSurface.mSize.height <= 0) { + gfxWarning() << "Can't create a SourceSurface without a valid size"; + return nullptr; + } + cairo_surface_t* surf = static_cast(aSurface.mSurface); + return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat); + } + + return nullptr; +} + +TemporaryRef +DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + cairo_surface_t* similar = cairo_surface_create_similar(mSurface, + GfxFormatToCairoContent(aFormat), + aSize.width, aSize.height); + + if (!cairo_surface_status(similar)) { + RefPtr target = new DrawTargetCairo(); + target->InitAlreadyReferenced(similar, aSize); + return target.forget(); + } + + gfxCriticalError() << "Failed to create similar cairo surface! Size: " << aSize << " Status: " << cairo_surface_status(similar); + + return nullptr; +} + +bool +DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat) +{ + if (cairo_surface_status(aSurface)) { + gfxCriticalError() << "Attempt to create DrawTarget for invalid surface. " + << aSize << " Cairo Status: " << cairo_surface_status(aSurface); + cairo_surface_destroy(aSurface); + return false; + } + + mContext = cairo_create(aSurface); + mSurface = aSurface; + mSize = aSize; + mFormat = aFormat ? *aFormat : CairoContentToGfxFormat(cairo_surface_get_content(aSurface)); + + // Cairo image surface have a bug where they will allocate a mask surface (for clipping) + // the size of the clip extents, and don't take the surface extents into account. + // Add a manual clip to the surface extents to prevent this. + cairo_new_path(mContext); + cairo_rectangle(mContext, 0, 0, mSize.width, mSize.height); + cairo_clip(mContext); + + if (mFormat == SurfaceFormat::B8G8R8A8 || + mFormat == SurfaceFormat::R8G8B8A8) { + SetPermitSubpixelAA(false); + } else { + SetPermitSubpixelAA(true); + } + + return true; +} + +TemporaryRef +DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat, + float aSigma) const +{ + cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext), + GfxFormatToCairoContent(aFormat), + aSize.width, aSize.height); + + if (cairo_surface_status(similar)) { + return nullptr; + } + + // If we don't have a blur then we can use the RGBA mask and keep all the + // operations in graphics memory. + if (aSigma == 0.0F) { + RefPtr target = new DrawTargetCairo(); + target->InitAlreadyReferenced(similar, aSize); + return target.forget(); + } + + cairo_surface_t* blursurf = cairo_image_surface_create(CAIRO_FORMAT_A8, + aSize.width, + aSize.height); + + if (cairo_surface_status(blursurf)) { + return nullptr; + } + + cairo_surface_t* tee = cairo_tee_surface_create(blursurf); + cairo_surface_destroy(blursurf); + if (cairo_surface_status(tee)) { + cairo_surface_destroy(similar); + return nullptr; + } + + cairo_tee_surface_add(tee, similar); + cairo_surface_destroy(similar); + + RefPtr target = new DrawTargetCairo(); + target->InitAlreadyReferenced(tee, aSize); + return target.forget(); +} + +bool +DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat) +{ + cairo_surface_reference(aSurface); + return InitAlreadyReferenced(aSurface, aSize, aFormat); +} + +bool +DrawTargetCairo::Init(const IntSize& aSize, SurfaceFormat aFormat) +{ + cairo_surface_t *surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), aSize.width, aSize.height); + return InitAlreadyReferenced(surf, aSize); +} + +bool +DrawTargetCairo::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) +{ + cairo_surface_t* surf = + cairo_image_surface_create_for_data(aData, + GfxFormatToCairoFormat(aFormat), + aSize.width, + aSize.height, + aStride); + return InitAlreadyReferenced(surf, aSize); +} + +void * +DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType) +{ + if (aType == NativeSurfaceType::CAIRO_SURFACE) { + return cairo_get_target(mContext); + } + if (aType == NativeSurfaceType::CAIRO_CONTEXT) { + return mContext; + } + + return nullptr; +} + +void +DrawTargetCairo::MarkSnapshotIndependent() +{ + if (mSnapshot) { + if (mSnapshot->refCount() > 1) { + // We only need to worry about snapshots that someone else knows about + mSnapshot->DrawTargetWillChange(); + } + mSnapshot = nullptr; + } +} + +void +DrawTargetCairo::WillChange(const Path* aPath /* = nullptr */) +{ + MarkSnapshotIndependent(); + MOZ_ASSERT(!mLockedBits); +} + +void +DrawTargetCairo::SetTransform(const Matrix& aTransform) +{ + mTransform = aTransform; + + cairo_matrix_t mat; + GfxMatrixToCairoMatrix(mTransform, mat); + cairo_set_matrix(mContext, &mat); +} + +Rect +DrawTargetCairo::GetUserSpaceClip() +{ + double clipX1, clipY1, clipX2, clipY2; + cairo_clip_extents(mContext, &clipX1, &clipY1, &clipX2, &clipY2); + return Rect(clipX1, clipY1, clipX2 - clipX1, clipY2 - clipY1); // Narrowing of doubles to floats +} + +cairo_t* +BorrowedCairoContext::BorrowCairoContextFromDrawTarget(DrawTarget* aDT) +{ + if (aDT->GetBackendType() != BackendType::CAIRO || + aDT->IsDualDrawTarget() || + aDT->IsTiledDrawTarget()) { + return nullptr; + } + DrawTargetCairo* cairoDT = static_cast(aDT); + + cairoDT->WillChange(); + + // save the state to make it easier for callers to avoid mucking with things + cairo_save(cairoDT->mContext); + + // Neuter the DrawTarget while the context is being borrowed + cairo_t* cairo = cairoDT->mContext; + cairoDT->mContext = nullptr; + + return cairo; +} + +void +BorrowedCairoContext::ReturnCairoContextToDrawTarget(DrawTarget* aDT, + cairo_t* aCairo) +{ + if (aDT->GetBackendType() != BackendType::CAIRO || + aDT->IsDualDrawTarget() || + aDT->IsTiledDrawTarget()) { + return; + } + DrawTargetCairo* cairoDT = static_cast(aDT); + + cairo_restore(aCairo); + cairoDT->mContext = aCairo; +} + +} +} diff --git a/libazure/src/gfx/2d/DrawTargetCairo.h b/libazure/DrawTargetCairo.h similarity index 76% rename from libazure/src/gfx/2d/DrawTargetCairo.h rename to libazure/DrawTargetCairo.h index 8eec8ef..c497784 100644 --- a/libazure/src/gfx/2d/DrawTargetCairo.h +++ b/libazure/DrawTargetCairo.h @@ -20,6 +20,7 @@ class SourceSurfaceCairo; class GradientStopsCairo : public GradientStops { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsCairo) GradientStopsCairo(GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) : mExtendMode(aExtendMode) @@ -41,7 +42,7 @@ class GradientStopsCairo : public GradientStops return mExtendMode; } - virtual BackendType GetBackendType() const { return BACKEND_CAIRO; } + virtual BackendType GetBackendType() const { return BackendType::CAIRO; } private: std::vector mStops; @@ -51,19 +52,33 @@ class GradientStopsCairo : public GradientStops class DrawTargetCairo : public DrawTarget { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCairo) + friend class BorrowedCairoContext; + DrawTargetCairo(); virtual ~DrawTargetCairo(); - virtual BackendType GetType() const { return BACKEND_CAIRO; } + virtual DrawTargetType GetType() const MOZ_OVERRIDE; + virtual BackendType GetBackendType() const { return BackendType::CAIRO; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize(); + virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA); + + virtual bool LockBits(uint8_t** aData, IntSize* aSize, + int32_t* aStride, SurfaceFormat* aFormat); + virtual void ReleaseBits(uint8_t* aData); + virtual void Flush(); virtual void DrawSurface(SourceSurface *aSurface, const Rect &aDest, const Rect &aSource, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, @@ -76,6 +91,8 @@ class DrawTargetCairo : public DrawTarget virtual void CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect, const IntPoint &aDestination); + virtual void CopyRect(const IntRect &aSourceRect, + const IntPoint &aDestination); virtual void FillRect(const Rect &aRect, const Pattern &aPattern, @@ -107,12 +124,16 @@ class DrawTargetCairo : public DrawTarget virtual void Mask(const Pattern &aSource, const Pattern &aMask, const DrawOptions &aOptions = DrawOptions()); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); virtual void PushClip(const Path *aPath); virtual void PushClipRect(const Rect &aRect); virtual void PopClip(); - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, const IntSize &aSize, @@ -130,13 +151,15 @@ class DrawTargetCairo : public DrawTarget virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode = EXTEND_CLAMP) const; + ExtendMode aExtendMode = ExtendMode::CLAMP) const; - virtual void *GetNativeSurface(NativeSurfaceType aType); + virtual TemporaryRef CreateFilter(FilterType aType); - bool Init(cairo_surface_t* aSurface, const IntSize& aSize); + virtual void *GetNativeSurface(NativeSurfaceType aType); - void SetPathObserver(CairoPathContext* aPathObserver); + bool Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr); + bool Init(const IntSize& aSize, SurfaceFormat aFormat); + bool Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat); virtual void SetTransform(const Matrix& aTransform); @@ -145,15 +168,23 @@ class DrawTargetCairo : public DrawTarget // Implicitly calls WillChange(aPath). void PrepareForDrawing(cairo_t* aContext, const Path* aPath = nullptr); + static cairo_surface_t *GetDummySurface(); + private: // methods // Init cairo surface without doing a cairo_surface_reference() call. - bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize); - + bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr); enum DrawPatternType { DRAW_FILL, DRAW_STROKE }; void DrawPattern(const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aOptions, - DrawPatternType aDrawType); + DrawPatternType aDrawType, + bool aPathBoundsClip = false); + + void CopySurfaceInternal(cairo_surface_t* aSurface, + const IntRect& aSource, + const IntPoint& aDest); + + Rect GetUserSpaceClip(); // Call before you make any changes to the backing surface with which this // context is associated. Pass the path you're going to be using if you have @@ -167,20 +198,18 @@ class DrawTargetCairo : public DrawTarget // If the current operator is "source" then clear the destination before we // draw into it, to simulate the effect of an unbounded source operator. void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator); + private: // data cairo_t* mContext; cairo_surface_t* mSurface; IntSize mSize; + uint8_t* mLockedBits; + // The latest snapshot of this surface. This needs to be told when this // target is modified. We keep it alive as a cache. RefPtr mSnapshot; - - // It is safe to use a regular pointer here because the CairoPathContext will - // deregister itself on destruction. Using a RefPtr would extend the life- - // span of the CairoPathContext. This causes a problem when - // PathBuilderCairo.Finish() - mutable CairoPathContext* mPathObserver; + static cairo_surface_t *mDummySurface; }; } diff --git a/libazure/DrawTargetCapture.cpp b/libazure/DrawTargetCapture.cpp new file mode 100644 index 0000000..d53a98e --- /dev/null +++ b/libazure/DrawTargetCapture.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DrawTargetCapture.h" +#include "DrawCommand.h" + +namespace mozilla { +namespace gfx { + + +DrawTargetCaptureImpl::~DrawTargetCaptureImpl() +{ + uint8_t* start = &mDrawCommandStorage.front(); + + uint8_t* current = start; + + while (current < start + mDrawCommandStorage.size()) { + reinterpret_cast(current + sizeof(uint32_t))->~DrawingCommand(); + current += *(uint32_t*)current; + } +} + +bool +DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT) +{ + if (!aRefDT) { + return false; + } + + mRefDT = aRefDT; + + mSize = aSize; + return true; +} + +TemporaryRef +DrawTargetCaptureImpl::Snapshot() +{ + RefPtr dt = mRefDT->CreateSimilarDrawTarget(mSize, mRefDT->GetFormat()); + + ReplayToDrawTarget(dt, Matrix()); + + return dt->Snapshot(); +} + +#define AppendCommand(arg) new (AppendToCommandList()) arg + +void +DrawTargetCaptureImpl::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + aSurface->GuaranteePersistance(); + AppendCommand(DrawSurfaceCommand)(aSurface, aDest, aSource, aSurfOptions, aOptions); +} + +void +DrawTargetCaptureImpl::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + // @todo XXX - this won't work properly long term yet due to filternodes not + // being immutable. + AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions); +} + +void +DrawTargetCaptureImpl::ClearRect(const Rect &aRect) +{ + AppendCommand(ClearRectCommand)(aRect); +} + +void +DrawTargetCaptureImpl::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + aMask->GuaranteePersistance(); + AppendCommand(MaskSurfaceCommand)(aSource, aMask, aOffset, aOptions); +} + +void +DrawTargetCaptureImpl::CopySurface(SourceSurface* aSurface, + const IntRect& aSourceRect, + const IntPoint& aDestination) +{ + aSurface->GuaranteePersistance(); + AppendCommand(CopySurfaceCommand)(aSurface, aSourceRect, aDestination); +} + +void +DrawTargetCaptureImpl::FillRect(const Rect& aRect, + const Pattern& aPattern, + const DrawOptions& aOptions) +{ + AppendCommand(FillRectCommand)(aRect, aPattern, aOptions); +} + +void +DrawTargetCaptureImpl::StrokeRect(const Rect& aRect, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + AppendCommand(StrokeRectCommand)(aRect, aPattern, aStrokeOptions, aOptions); +} + +void +DrawTargetCaptureImpl::StrokeLine(const Point& aStart, + const Point& aEnd, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + AppendCommand(StrokeLineCommand)(aStart, aEnd, aPattern, aStrokeOptions, aOptions); +} + +void +DrawTargetCaptureImpl::Stroke(const Path* aPath, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + AppendCommand(StrokeCommand)(aPath, aPattern, aStrokeOptions, aOptions); +} + +void +DrawTargetCaptureImpl::Fill(const Path* aPath, + const Pattern& aPattern, + const DrawOptions& aOptions) +{ + AppendCommand(FillCommand)(aPath, aPattern, aOptions); +} + +void +DrawTargetCaptureImpl::FillGlyphs(ScaledFont* aFont, + const GlyphBuffer& aBuffer, + const Pattern& aPattern, + const DrawOptions& aOptions, + const GlyphRenderingOptions* aRenderingOptions) +{ + AppendCommand(FillGlyphsCommand)(aFont, aBuffer, aPattern, aOptions, aRenderingOptions); +} + +void +DrawTargetCaptureImpl::Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions) +{ + AppendCommand(MaskCommand)(aSource, aMask, aOptions); +} + +void +DrawTargetCaptureImpl::PushClip(const Path* aPath) +{ + AppendCommand(PushClipCommand)(aPath); +} + +void +DrawTargetCaptureImpl::PushClipRect(const Rect& aRect) +{ + AppendCommand(PushClipRectCommand)(aRect); +} + +void +DrawTargetCaptureImpl::PopClip() +{ + AppendCommand(PopClipCommand)(); +} + +void +DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform) +{ + AppendCommand(SetTransformCommand)(aTransform); +} + +void +DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform) +{ + uint8_t* start = &mDrawCommandStorage.front(); + + uint8_t* current = start; + + while (current < start + mDrawCommandStorage.size()) { + reinterpret_cast(current + sizeof(uint32_t))->ExecuteOnDT(aDT, aTransform); + current += *(uint32_t*)current; + } +} + +} +} diff --git a/libazure/DrawTargetCapture.h b/libazure/DrawTargetCapture.h new file mode 100644 index 0000000..2ef8f0e --- /dev/null +++ b/libazure/DrawTargetCapture.h @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWTARGETCAPTURE_H_ +#define MOZILLA_GFX_DRAWTARGETCAPTURE_H_ + +#include "2D.h" +#include + +#include "Filters.h" + +namespace mozilla { +namespace gfx { + +class DrawingCommand; + +class DrawTargetCaptureImpl : public DrawTargetCapture +{ +public: + DrawTargetCaptureImpl() + {} + + bool Init(const IntSize& aSize, DrawTarget* aRefDT); + + virtual BackendType GetBackendType() const { return mRefDT->GetBackendType(); } + virtual DrawTargetType GetType() const { return mRefDT->GetType(); } + + virtual TemporaryRef Snapshot(); + virtual IntSize GetSize() { return mSize; } + + virtual void Flush() {} + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) { /* Not implemented */ } + + virtual void ClearRect(const Rect &aRect); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination); + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions(), + const GlyphRenderingOptions *aRenderingOptions = nullptr); + virtual void Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions = DrawOptions()); + virtual void PushClip(const Path *aPath); + virtual void PushClipRect(const Rect &aRect); + virtual void PopClip(); + + virtual void SetTransform(const Matrix &aTransform); + + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const + { + return mRefDT->CreateSourceSurfaceFromData(aData, aSize, aStride, aFormat); + } + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const + { + return mRefDT->OptimizeSourceSurface(aSurface); + } + + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const + { + return mRefDT->CreateSourceSurfaceFromNativeSurface(aSurface); + } + + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const + { + return mRefDT->CreateSimilarDrawTarget(aSize, aFormat); + } + + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const + { + return mRefDT->CreatePathBuilder(aFillRule); + } + + virtual TemporaryRef + CreateGradientStops(GradientStop *aStops, + uint32_t aNumStops, + ExtendMode aExtendMode = ExtendMode::CLAMP) const + { + return mRefDT->CreateGradientStops(aStops, aNumStops, aExtendMode); + } + virtual TemporaryRef CreateFilter(FilterType aType) + { + return mRefDT->CreateFilter(aType); + } + + void ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform); + +protected: + ~DrawTargetCaptureImpl(); + +private: + + // This storage system was used to minimize the amount of heap allocations + // that are required while recording. It should be noted there's no + // guarantees on the alignments of DrawingCommands allocated in this array. + template + T* AppendToCommandList() + { + size_t oldSize = mDrawCommandStorage.size(); + mDrawCommandStorage.resize(mDrawCommandStorage.size() + sizeof(T) + sizeof(uint32_t)); + uint8_t* nextDrawLocation = &mDrawCommandStorage.front() + oldSize; + *(uint32_t*)(nextDrawLocation) = sizeof(T) + sizeof(uint32_t); + return reinterpret_cast(nextDrawLocation + sizeof(uint32_t)); + } + RefPtr mRefDT; + + IntSize mSize; + + std::vector mDrawCommandStorage; +}; + +} /* namespace mozilla */ +} /* namespace gfx */ + +#endif /* MOZILLA_GFX_DRAWTARGETCAPTURE_H_ */ diff --git a/libazure/src/gfx/2d/DrawTargetD2D.cpp b/libazure/DrawTargetD2D.cpp similarity index 84% rename from libazure/src/gfx/2d/DrawTargetD2D.cpp rename to libazure/DrawTargetD2D.cpp index a38e1a4..86cfa33 100644 --- a/libazure/src/gfx/2d/DrawTargetD2D.cpp +++ b/libazure/DrawTargetD2D.cpp @@ -3,8 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include "DrawTargetD2D.h" #include "SourceSurfaceD2D.h" +#ifdef USE_D2D1_1 +#include "SourceSurfaceD2D1.h" +#endif #include "SourceSurfaceD2DTarget.h" #include "ShadersD2D.h" #include "PathD2D.h" @@ -15,9 +19,15 @@ #include "Tools.h" #include #include "mozilla/Constants.h" +#include "FilterNodeSoftware.h" + +#ifdef USE_D2D1_1 +#include "FilterNodeD2D1.h" +#endif #include +// decltype is not usable for overloaded functions. typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)( D2D1_FACTORY_TYPE factoryType, REFIID iid, @@ -25,21 +35,6 @@ typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)( void **factory ); -typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)( - void *pData, - SIZE_T DataLength, - UINT FXFlags, - ID3D10Device *pDevice, - ID3D10EffectPool *pEffectPool, - ID3D10Effect **ppEffect -); - -typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( - DWRITE_FACTORY_TYPE factoryType, - REFIID iid, - IUnknown **factory -); - using namespace std; namespace mozilla { @@ -81,13 +76,14 @@ class AutoSaveRestoreClippedOut HRESULT hr = mDT->mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpTexture)); if (FAILED(hr)) { - gfxWarning() << "Failed to create temporary texture to hold surface data."; + gfxCriticalError() << "[D2D] CreateTexture2D failure " << size << " Code: " << hr; + // Crash debug builds but try to recover in release builds. + MOZ_ASSERT(false); + return; } mDT->mDevice->CopyResource(tmpTexture, mDT->mTexture); - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(format), - AlphaMode(format))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(format)); RefPtr surf; @@ -97,7 +93,10 @@ class AutoSaveRestoreClippedOut &props, byRef(mOldSurfBitmap)); if (FAILED(hr)) { - gfxWarning() << "Failed to create shared bitmap for old surface."; + gfxCriticalError() << "[D2D] CreateSharedBitmap failure " << size << " Code: " << hr; + // Crash debug builds but try to recover in release builds. + MOZ_ASSERT(false); + return; } IntRect clipBounds; @@ -113,7 +112,7 @@ class AutoSaveRestoreClippedOut Float(clipBounds.YMost())), byRef(rectGeom)); - mClippedArea = mDT->Intersect(mClippedArea, rectGeom); + mClippedArea = IntersectGeometry(mClippedArea, rectGeom); } } @@ -162,6 +161,19 @@ class AutoSaveRestoreClippedOut RefPtr mClippedArea; }; +ID2D1Factory *D2DFactory() +{ + return DrawTargetD2D::factory(); +} + +template +inline static Log& +operator <<(Log& aStream, const DrawTargetD2D& aDrawTarget) +{ + aStream << "DrawTargetD2D(" << &aDrawTarget << ")"; + return aStream; +} + DrawTargetD2D::DrawTargetD2D() : mCurrentCachedLayer(0) , mClipsArePushed(false) @@ -257,36 +269,21 @@ DrawTargetD2D::AddDependencyOnSource(SourceSurfaceD2DTarget* aSource) } } -void -DrawTargetD2D::DrawSurface(SourceSurface *aSurface, - const Rect &aDest, - const Rect &aSource, - const DrawSurfaceOptions &aSurfOptions, - const DrawOptions &aOptions) +TemporaryRef +DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface, + Rect &aSource) { RefPtr bitmap; - ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color())); - - PrepareForDrawing(rt); - - rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); - - Rect srcRect = aSource; - switch (aSurface->GetType()) { - case SURFACE_D2D1_BITMAP: + case SurfaceType::D2D1_BITMAP: { SourceSurfaceD2D *srcSurf = static_cast(aSurface); bitmap = srcSurf->GetBitmap(); - - if (!bitmap) { - return; - } } break; - case SURFACE_D2D1_DRAWTARGET: + case SurfaceType::D2D1_DRAWTARGET: { SourceSurfaceD2DTarget *srcSurf = static_cast(aSurface); bitmap = srcSurf->GetBitmap(mRT); @@ -299,37 +296,154 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface, if (!srcSurf) { gfxDebug() << "Not able to deal with non-data source surface."; - return; + return nullptr; } - if (aSource.width > rt->GetMaximumBitmapSize() || - aSource.height > rt->GetMaximumBitmapSize()) { + // We need to include any pixels that are overlapped by aSource + Rect sourceRect(aSource); + sourceRect.RoundOut(); + + if (sourceRect.IsEmpty()) { + gfxDebug() << "Bitmap source is empty. DrawBitmap will silently fail."; + return nullptr; + } + + if (sourceRect.width > mRT->GetMaximumBitmapSize() || + sourceRect.height > mRT->GetMaximumBitmapSize()) { gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail."; // Don't know how to deal with this yet. - return; + return nullptr; } int stride = srcSurf->Stride(); unsigned char *data = srcSurf->GetData() + - (uint32_t)aSource.y * stride + - (uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat()); + (uint32_t)sourceRect.y * stride + + (uint32_t)sourceRect.x * BytesPerPixel(srcSurf->GetFormat()); D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat()))); - mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap)); + D2D1::BitmapProperties(D2DPixelFormat(srcSurf->GetFormat())); + mRT->CreateBitmap(D2D1::SizeU(UINT32(sourceRect.width), UINT32(sourceRect.height)), data, stride, props, byRef(bitmap)); - srcRect.x -= (uint32_t)aSource.x; - srcRect.y -= (uint32_t)aSource.y; + // subtract the integer part leaving the fractional part + aSource.x -= (uint32_t)aSource.x; + aSource.y -= (uint32_t)aSource.y; } break; } + return bitmap; +} + +#ifdef USE_D2D1_1 +TemporaryRef +DrawTargetD2D::GetImageForSurface(SourceSurface *aSurface) +{ + RefPtr image; + + Rect r(Point(), Size(aSurface->GetSize())); + image = GetBitmapForSurface(aSurface, r); + + return image; +} +#endif + +void +DrawTargetD2D::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + RefPtr bitmap; + + ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color())); + + PrepareForDrawing(rt); + + rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + Rect srcRect = aSource; + + bitmap = GetBitmapForSurface(aSurface, srcRect); + if (!bitmap) { + return; + } + rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect)); FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), aDest); } +void +DrawTargetD2D::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ +#ifdef USE_D2D1_1 + RefPtr dc; + HRESULT hr; + + hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc)); + + if (SUCCEEDED(hr) && aNode->GetBackendType() == FILTER_BACKEND_DIRECT2D1_1) { + ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color())); + + PrepareForDrawing(rt); + + rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + hr = rt->QueryInterface((ID2D1DeviceContext**)byRef(dc)); + + if (SUCCEEDED(hr)) { + dc->DrawImage(static_cast(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect)); + + Rect destRect = aSourceRect; + destRect.MoveBy(aDestPoint); + FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), destRect); + return; + } + } +#endif + + if (aNode->GetBackendType() != FILTER_BACKEND_SOFTWARE) { + gfxWarning() << "Invalid filter backend passed to DrawTargetD2D!"; + return; + } + + FilterNodeSoftware* filter = static_cast(aNode); + filter->Draw(this, aSourceRect, aDestPoint, aOptions); +} + +void +DrawTargetD2D::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + RefPtr bitmap; + + ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color())); + + PrepareForDrawing(rt); + + // FillOpacityMask only works if the antialias mode is MODE_ALIASED + rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + + IntSize size = aMask->GetSize(); + Rect maskRect = Rect(0.f, 0.f, size.width, size.height); + bitmap = GetBitmapForSurface(aMask, maskRect); + if (!bitmap) { + return; + } + + Rect dest = Rect(aOffset.x, aOffset.y, size.width, size.height); + RefPtr brush = CreateBrushForPattern(aSource, aOptions.mAlpha); + rt->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect)); + + FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), dest); +} + void DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, @@ -339,7 +453,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, CompositionOp aOperator) { RefPtr srView = nullptr; - if (aSurface->GetType() != SURFACE_D2D1_DRAWTARGET) { + if (aSurface->GetType() != SurfaceType::D2D1_DRAWTARGET) { return; } @@ -426,8 +540,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mipTexture)); if (FAILED(hr)) { - gfxWarning() << "Failure to create temporary texture. Size: " << - aSurface->GetSize() << " Code: " << hr; + gfxCriticalError() << "[D2D] CreateTexture2D failure " << aSurface->GetSize() << " Code: " << hr; return; } @@ -454,7 +567,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpDSTexture)); if (FAILED(hr)) { - gfxWarning() << "Failure to create temporary texture. Size: " << dsSize << " Code: " << hr; + gfxCriticalError() << "[D2D] CreateTexture2D failure " << dsSize << " Code: " << hr; return; } @@ -493,7 +606,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, mPrivateData->mEffect->GetTechniqueByName("SampleTexture")-> GetPassByIndex(0)->Apply(0); - mDevice->OMSetBlendState(GetBlendStateForOperator(OP_OVER), nullptr, 0xffffffff); + mDevice->OMSetBlendState(GetBlendStateForOperator(CompositionOp::OP_OVER), nullptr, 0xffffffff); mDevice->Draw(4, 0); @@ -676,27 +789,37 @@ void DrawTargetD2D::ClearRect(const Rect &aRect) { MarkChanged(); + PushClipRect(aRect); - FlushTransformToRT(); PopAllClips(); AutoSaveRestoreClippedOut restoreClippedOut(this); - restoreClippedOut.Save(); - - bool needsClip = false; - - needsClip = aRect.x > 0 || aRect.y > 0 || - aRect.XMost() < mSize.width || - aRect.YMost() < mSize.height; + D2D1_RECT_F clipRect; + bool isPixelAligned; + bool pushedClip = false; + if (mTransform.IsRectilinear() && + GetDeviceSpaceClipRect(clipRect, isPixelAligned)) { + if (mTransformDirty || + !mTransform.IsIdentity()) { + mRT->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + } - if (needsClip) { - mRT->PushAxisAlignedClip(D2DRect(aRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + mRT->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + pushedClip = true; + } else { + FlushTransformToRT(); + restoreClippedOut.Save(); } + mRT->Clear(D2D1::ColorF(0, 0.0f)); - if (needsClip) { + + if (pushedClip) { mRT->PopAxisAlignedClip(); } + + PopClip(); return; } @@ -718,33 +841,22 @@ DrawTargetD2D::CopySurface(SourceSurface *aSurface, mRT->Clear(D2D1::ColorF(0, 0.0f)); mRT->PopAxisAlignedClip(); - RefPtr bitmap; - - switch (aSurface->GetType()) { - case SURFACE_D2D1_BITMAP: - { - SourceSurfaceD2D *srcSurf = static_cast(aSurface); - bitmap = srcSurf->GetBitmap(); - } - break; - case SURFACE_D2D1_DRAWTARGET: - { - SourceSurfaceD2DTarget *srcSurf = static_cast(aSurface); - bitmap = srcSurf->GetBitmap(mRT); - AddDependencyOnSource(srcSurf); - } - break; - default: - return; - } - + RefPtr bitmap = GetBitmapForSurface(aSurface, srcRect); if (!bitmap) { return; } - mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f, - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - D2DRect(srcRect)); + if (aSurface->GetFormat() == SurfaceFormat::A8) { + RefPtr brush; + mRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), + D2D1::BrushProperties(), byRef(brush)); + mRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + mRT->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS); + } else { + mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + D2DRect(srcRect)); + } } void @@ -820,7 +932,7 @@ DrawTargetD2D::Stroke(const Path *aPath, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { - if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + if (aPath->GetBackendType() != BackendType::DIRECT2D) { gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; return; } @@ -849,7 +961,7 @@ DrawTargetD2D::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aOptions) { - if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + if (aPath->GetBackendType() != BackendType::DIRECT2D) { gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; return; } @@ -869,7 +981,7 @@ DrawTargetD2D::Fill(const Path *aPath, } Rect bounds; - if (aOptions.mCompositionOp != OP_OVER) { + if (aOptions.mCompositionOp != CompositionOp::OP_OVER) { D2D1_RECT_F d2dbounds; d2dPath->mGeometry->GetBounds(D2D1::IdentityMatrix(), &d2dbounds); bounds = ToRect(d2dbounds); @@ -884,7 +996,7 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont, const DrawOptions &aOptions, const GlyphRenderingOptions* aRenderOptions) { - if (aFont->GetType() != FONT_DWRITE) { + if (aFont->GetType() != FontType::DWRITE) { gfxDebug() << *this << ": Ignoring drawing call for incompatible font."; return; } @@ -893,7 +1005,7 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont, IDWriteRenderingParams *params = nullptr; if (aRenderOptions) { - if (aRenderOptions->GetType() != FONT_DWRITE) { + if (aRenderOptions->GetType() != FontType::DWRITE) { gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions."; // This should never happen. MOZ_ASSERT(false); @@ -904,13 +1016,13 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont, AntialiasMode aaMode = font->GetDefaultAAMode(); - if (aOptions.mAntialiasMode != AA_DEFAULT) { + if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) { aaMode = aOptions.mAntialiasMode; } - if (mFormat == FORMAT_B8G8R8A8 && mPermitSubpixelAA && - aOptions.mCompositionOp == OP_OVER && aPattern.GetType() == PATTERN_COLOR && - aaMode == AA_SUBPIXEL) { + if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA && + aOptions.mCompositionOp == CompositionOp::OP_OVER && aPattern.GetType() == PatternType::COLOR && + aaMode == AntialiasMode::SUBPIXEL) { if (FillGlyphsManual(font, aBuffer, static_cast(&aPattern)->mColor, params, aOptions)) { @@ -925,13 +1037,13 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont, D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; switch (aaMode) { - case AA_NONE: + case AntialiasMode::NONE: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; break; - case AA_GRAY: + case AntialiasMode::GRAY: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; break; - case AA_SUBPIXEL: + case AntialiasMode::SUBPIXEL: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; break; default: @@ -939,7 +1051,7 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont, } if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && - mFormat != FORMAT_B8G8R8X8) { + mFormat != SurfaceFormat::B8G8R8X8) { d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; } @@ -999,7 +1111,7 @@ DrawTargetD2D::Mask(const Pattern &aSource, void DrawTargetD2D::PushClip(const Path *aPath) { - if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + if (aPath->GetBackendType() != BackendType::DIRECT2D) { gfxDebug() << *this << ": Ignoring clipping call for incompatible path."; return; } @@ -1094,20 +1206,39 @@ DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData, return nullptr; } - return newSurf; + return newSurf.forget(); } TemporaryRef DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const { - // Unsupported! - return nullptr; + if (aSurface->GetType() == SurfaceType::D2D1_BITMAP || + aSurface->GetType() == SurfaceType::D2D1_DRAWTARGET) { + return aSurface; + } + + RefPtr data = aSurface->GetDataSurface(); + + DataSourceSurface::MappedSurface map; + if (!data->Map(DataSourceSurface::MapType::READ, &map)) { + return nullptr; + } + + RefPtr newSurf = new SourceSurfaceD2D(); + bool success = newSurf->InitFromData(map.mData, data->GetSize(), map.mStride, data->GetFormat(), mRT); + + data->Unmap(); + + if (!success) { + return data.forget(); + } + return newSurf.forget(); } TemporaryRef DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const { - if (aSurface.mType != NATIVE_SURFACE_D3D10_TEXTURE) { + if (aSurface.mType != NativeSurfaceType::D3D10_TEXTURE) { gfxDebug() << *this << ": Failure to create source surface from non-D3D10 texture native surface."; return nullptr; } @@ -1121,7 +1252,7 @@ DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurfac return nullptr; } - return newSurf; + return newSurf.forget(); } TemporaryRef @@ -1135,7 +1266,7 @@ DrawTargetD2D::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aForm return nullptr; } - return newTarget; + return newTarget.forget(); } TemporaryRef @@ -1156,7 +1287,7 @@ DrawTargetD2D::CreatePathBuilder(FillRule aFillRule) const return nullptr; } - if (aFillRule == FILL_WINDING) { + if (aFillRule == FillRule::FILL_WINDING) { sink->SetFillMode(D2D1_FILL_MODE_WINDING); } @@ -1189,10 +1320,24 @@ DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, E return new GradientStopsD2D(stopCollection); } +TemporaryRef +DrawTargetD2D::CreateFilter(FilterType aType) +{ +#ifdef USE_D2D1_1 + RefPtr dc; + HRESULT hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc)); + + if (SUCCEEDED(hr)) { + return FilterNodeD2D1::Create(this, dc, aType); + } +#endif + return FilterNodeSoftware::Create(aType); +} + void* DrawTargetD2D::GetNativeSurface(NativeSurfaceType aType) { - if (aType != NATIVE_SURFACE_D3D10_TEXTURE) { + if (aType != NativeSurfaceType::D3D10_TEXTURE) { return nullptr; } @@ -1211,7 +1356,7 @@ DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat) mFormat = aFormat; if (!Factory::GetDirect3D10Device()) { - gfxDebug() << "Failed to Init Direct2D DrawTarget (No D3D10 Device set.)"; + gfxCriticalError() << "Failed to Init Direct2D DrawTarget (No D3D10 Device set.)"; return false; } mDevice = Factory::GetDirect3D10Device(); @@ -1225,7 +1370,7 @@ DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat) hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture)); if (FAILED(hr)) { - gfxDebug() << "Failed to init Direct2D DrawTarget. Size: " << mSize << " Code: " << hr; + gfxCriticalError() << "Failed to init Direct2D DrawTarget. Size: " << mSize << " Code: " << hr; return false; } @@ -1256,7 +1401,7 @@ DrawTargetD2D::Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat) hr = device->QueryInterface((ID3D10Device1**)byRef(mDevice)); if (FAILED(hr)) { - gfxWarning() << "Failed to get D3D10 device from texture."; + gfxCriticalError() << "Failed to get D3D10 device from texture."; return false; } @@ -1287,9 +1432,9 @@ DrawTargetD2D::InitD3D10Data() mPrivateData = new PrivateD3D10DataD2D; - D3D10CreateEffectFromMemoryFunc createD3DEffect; + decltype(D3D10CreateEffectFromMemory)* createD3DEffect; HMODULE d3dModule = LoadLibraryW(L"d3d10_1.dll"); - createD3DEffect = (D3D10CreateEffectFromMemoryFunc) + createD3DEffect = (decltype(D3D10CreateEffectFromMemory)*) GetProcAddress(d3dModule, "D3D10CreateEffectFromMemory"); hr = createD3DEffect((void*)d2deffect, sizeof(d2deffect), 0, mDevice, nullptr, byRef(mPrivateData->mEffect)); @@ -1361,7 +1506,7 @@ DrawTargetD2D::GetCachedLayer() } mCurrentCachedLayer++; - return layer; + return layer.forget(); } void @@ -1375,6 +1520,7 @@ bool DrawTargetD2D::InitD2DRenderTarget() { if (!factory()) { + gfxCriticalError() << "No valid D2D factory available."; return false; } @@ -1386,7 +1532,7 @@ DrawTargetD2D::InitD2DRenderTarget() mRT->BeginDraw(); - if (mFormat == FORMAT_B8G8R8X8) { + if (mFormat == SurfaceFormat::B8G8R8X8) { mRT->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE); } @@ -1446,8 +1592,9 @@ DrawTargetD2D::MarkChanged() ID3D10BlendState* DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator) { - if (mPrivateData->mBlendStates[aOperator]) { - return mPrivateData->mBlendStates[aOperator]; + size_t operatorIndex = static_cast(aOperator); + if (mPrivateData->mBlendStates[operatorIndex]) { + return mPrivateData->mBlendStates[operatorIndex]; } D3D10_BLEND_DESC desc; @@ -1460,43 +1607,43 @@ DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator) desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD; switch (aOperator) { - case OP_ADD: + case CompositionOp::OP_ADD: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE; break; - case OP_IN: + case CompositionOp::OP_IN: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; break; - case OP_OUT: + case CompositionOp::OP_OUT: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; break; - case OP_ATOP: + case CompositionOp::OP_ATOP: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; break; - case OP_DEST_IN: + case CompositionOp::OP_DEST_IN: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA; break; - case OP_DEST_OUT: + case CompositionOp::OP_DEST_OUT: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; break; - case OP_DEST_ATOP: + case CompositionOp::OP_DEST_ATOP: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA; break; - case OP_DEST_OVER: + case CompositionOp::OP_DEST_OVER: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE; break; - case OP_XOR: + case CompositionOp::OP_XOR: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; break; - case OP_SOURCE: + case CompositionOp::OP_SOURCE: desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE; desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; break; @@ -1505,9 +1652,9 @@ DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator) desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; } - mDevice->CreateBlendState(&desc, byRef(mPrivateData->mBlendStates[aOperator])); + mDevice->CreateBlendState(&desc, byRef(mPrivateData->mBlendStates[operatorIndex])); - return mPrivateData->mBlendStates[aOperator]; + return mPrivateData->mBlendStates[operatorIndex]; } /* This function prepares the temporary RT for drawing and returns it when a @@ -1516,13 +1663,13 @@ DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator) ID2D1RenderTarget* DrawTargetD2D::GetRTForOperation(CompositionOp aOperator, const Pattern &aPattern) { - if (aOperator == OP_OVER && IsPatternSupportedByD2D(aPattern)) { + if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) { return mRT; } PopAllClips(); - if (aOperator > OP_XOR) { + if (aOperator > CompositionOp::OP_XOR) { mRT->Flush(); } @@ -1534,11 +1681,11 @@ DrawTargetD2D::GetRTForOperation(CompositionOp aOperator, const Pattern &aPatter EnsureViews(); if (!mRTView || !mSRView) { - gfxDebug() << *this << ": Failed to get required views. Defaulting to OP_OVER."; + gfxDebug() << *this << ": Failed to get required views. Defaulting to CompositionOp::OP_OVER."; return mRT; } - mTempRT = CreateRTForTexture(mTempTexture, FORMAT_B8G8R8A8); + mTempRT = CreateRTForTexture(mTempTexture, SurfaceFormat::B8G8R8A8); if (!mTempRT) { return mRT; @@ -1563,7 +1710,7 @@ DrawTargetD2D::GetRTForOperation(CompositionOp aOperator, const Pattern &aPatter void DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aPattern, const Rect &aBounds) { - if (aOperator == OP_OVER && IsPatternSupportedByD2D(aPattern)) { + if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) { return; } @@ -1617,7 +1764,7 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(mSRView); // Handle the case where we blend with the backdrop - if (aOperator > OP_XOR) { + if (aOperator > CompositionOp::OP_XOR) { IntSize size = mSize; SurfaceFormat format = mFormat; @@ -1645,14 +1792,14 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP return; } - unsigned int compop = (unsigned int)aOperator - (unsigned int)OP_XOR; + unsigned int compop = (unsigned int)aOperator - (unsigned int)CompositionOp::OP_XOR; mPrivateData->mEffect->GetVariableByName("bcktex")->AsShaderResource()->SetResource(mBckSRView); mPrivateData->mEffect->GetVariableByName("blendop")->AsScalar()->SetInt(compop); - if (aOperator > OP_EXCLUSION) + if (aOperator > CompositionOp::OP_EXCLUSION) mPrivateData->mEffect->GetTechniqueByName("SampleTextureForNonSeparableBlending")-> GetPassByIndex(0)->Apply(0); - else if (aOperator > OP_COLOR_DODGE) + else if (aOperator > CompositionOp::OP_COLOR_DODGE) mPrivateData->mEffect->GetTechniqueByName("SampleTextureForSeparableBlending_2")-> GetPassByIndex(0)->Apply(0); else @@ -1663,7 +1810,7 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->Apply(0); } - } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) { + } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { const RadialGradientPattern *pat = static_cast(&aPattern); if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) { @@ -1682,40 +1829,6 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP mDevice->Draw(4, 0); } -TemporaryRef -DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect) -{ - RefPtr rectGeom; - factory()->CreateRectangleGeometry(&aRect, byRef(rectGeom)); - return rectGeom.forget(); -} - -TemporaryRef -DrawTargetD2D::GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform) -{ - RefPtr tmpGeometry; - factory()->CreatePathGeometry(byRef(tmpGeometry)); - RefPtr currentSink; - tmpGeometry->Open(byRef(currentSink)); - aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, - aTransform, currentSink); - currentSink->Close(); - return tmpGeometry; -} - -TemporaryRef -DrawTargetD2D::Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB) -{ - RefPtr pathGeom; - factory()->CreatePathGeometry(byRef(pathGeom)); - RefPtr sink; - pathGeom->Open(byRef(sink)); - aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink); - sink->Close(); - - return pathGeom; -} - static D2D1_RECT_F IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2) { @@ -1724,9 +1837,40 @@ IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2) result.top = max(aRect1.top, aRect2.top); result.right = min(aRect1.right, aRect2.right); result.bottom = min(aRect1.bottom, aRect2.bottom); + + result.right = max(result.right, result.left); + result.bottom = max(result.bottom, result.top); + return result; } +bool +DrawTargetD2D::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned) +{ + if (!mPushedClips.size()) { + return false; + } + + std::vector::iterator iter = mPushedClips.begin(); + if (iter->mPath) { + return false; + } + aClipRect = iter->mBounds; + aIsPixelAligned = iter->mIsPixelAligned; + + iter++; + for (;iter != mPushedClips.end(); iter++) { + if (iter->mPath) { + return false; + } + aClipRect = IntersectRect(aClipRect, iter->mBounds); + if (!iter->mIsPixelAligned) { + aIsPixelAligned = false; + } + } + return true; +} + TemporaryRef DrawTargetD2D::GetClippedGeometry(IntRect *aClipBounds) { @@ -1802,10 +1946,10 @@ DrawTargetD2D::GetClippedGeometry(IntRect *aClipBounds) pathGeom = newGeom.forget(); } - // For now we need mCurrentClippedGeometry to always be non-NULL. This method - // might seem a little strange but it is just fine, if pathGeom is NULL - // pathRect will always still contain 1 clip unaccounted for regardless of - // mCurrentClipBounds. + // For now we need mCurrentClippedGeometry to always be non-nullptr. This + // method might seem a little strange but it is just fine, if pathGeom is + // nullptr pathRect will always still contain 1 clip unaccounted for + // regardless of mCurrentClipBounds. if (!pathGeom) { pathGeom = ConvertRectToGeometry(pathRect); } @@ -1825,7 +1969,7 @@ DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aForm hr = aTexture->QueryInterface((IDXGISurface**)byRef(surface)); if (FAILED(hr)) { - gfxWarning() << "Failed to QI texture to surface."; + gfxCriticalError() << "Failed to QI texture to surface. Code: " << hr; return nullptr; } @@ -1834,7 +1978,7 @@ DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aForm D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - if (aFormat == FORMAT_B8G8R8X8 && aTexture == mTexture) { + if (aFormat == SurfaceFormat::B8G8R8X8 && aTexture == mTexture) { alphaMode = D2D1_ALPHA_MODE_IGNORE; } @@ -1843,11 +1987,11 @@ DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aForm hr = factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); if (FAILED(hr)) { - gfxWarning() << "Failed to create D2D render target for texture."; + gfxCriticalError() << "Failed to create D2D render target for texture. Code:" << hr << " " << mSize << " Format: " << uint32_t(aFormat); return nullptr; } - return rt; + return rt.forget(); } void @@ -1945,7 +2089,7 @@ DrawTargetD2D::EnsureClipMaskTexture(IntRect *aBounds) return; } - RefPtr rt = CreateRTForTexture(mCurrentClipMaskTexture, FORMAT_A8); + RefPtr rt = CreateRTForTexture(mCurrentClipMaskTexture, SurfaceFormat::A8); if (!rt) { gfxWarning() << "Failed to create RT for ClipMask!"; @@ -2147,18 +2291,19 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) if (!IsPatternSupportedByD2D(aPattern)) { RefPtr colBrush; mRT->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush)); - return colBrush; + return colBrush.forget(); } - if (aPattern.GetType() == PATTERN_COLOR) { + if (aPattern.GetType() == PatternType::COLOR) { RefPtr colBrush; Color color = static_cast(&aPattern)->mColor; mRT->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g, color.b, color.a), D2D1::BrushProperties(aAlpha), byRef(colBrush)); - return colBrush; - } else if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) { + return colBrush.forget(); + } + if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) { RefPtr gradBrush; const LinearGradientPattern *pat = static_cast(&aPattern); @@ -2178,7 +2323,7 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) mRT->CreateSolidColorBrush(d2dStops.back().color, D2D1::BrushProperties(aAlpha), byRef(colBrush)); - return colBrush; + return colBrush.forget(); } mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin), @@ -2186,8 +2331,9 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), stops->mStopCollection, byRef(gradBrush)); - return gradBrush; - } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) { + return gradBrush.forget(); + } + if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { RefPtr gradBrush; const RadialGradientPattern *pat = static_cast(&aPattern); @@ -2208,8 +2354,9 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) stops->mStopCollection, byRef(gradBrush)); - return gradBrush; - } else if (aPattern.GetType() == PATTERN_SURFACE) { + return gradBrush.forget(); + } + if (aPattern.GetType() == PatternType::SURFACE) { RefPtr bmBrush; const SurfacePattern *pat = static_cast(&aPattern); @@ -2222,11 +2369,29 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) RefPtr bitmap; Matrix mat = pat->mMatrix; + + RefPtr source = pat->mSurface; + + if (!pat->mSamplingRect.IsEmpty()) { + IntRect samplingRect = pat->mSamplingRect; + + RefPtr dt = new DrawTargetD2D(); + if (!dt->Init(samplingRect.Size(), + source->GetFormat())) { + MOZ_ASSERT("Invalid sampling rect size!"); + return nullptr; + } + + dt->CopySurface(source, samplingRect, IntPoint()); + source = dt->Snapshot(); + + mat.PreTranslate(samplingRect.x, samplingRect.y); + } - switch (pat->mSurface->GetType()) { - case SURFACE_D2D1_BITMAP: + switch (source->GetType()) { + case SurfaceType::D2D1_BITMAP: { - SourceSurfaceD2D *surf = static_cast(pat->mSurface.get()); + SourceSurfaceD2D *surf = static_cast(source.get()); bitmap = surf->mBitmap; @@ -2235,23 +2400,23 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) } } break; - case SURFACE_D2D1_DRAWTARGET: + case SurfaceType::D2D1_DRAWTARGET: { SourceSurfaceD2DTarget *surf = - static_cast(pat->mSurface.get()); + static_cast(source.get()); bitmap = surf->GetBitmap(mRT); AddDependencyOnSource(surf); } break; default: { - RefPtr dataSurf = pat->mSurface->GetDataSurface(); + RefPtr dataSurf = source->GetDataSurface(); if (!dataSurf) { gfxWarning() << "Invalid surface type."; return nullptr; } - bitmap = CreatePartialBitmapForSurface(dataSurf, mat, pat->mExtendMode); + bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT); if (!bitmap) { return nullptr; } @@ -2266,87 +2431,13 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) D2D1::BrushProperties(aAlpha, D2DMatrix(mat)), byRef(bmBrush)); - return bmBrush; + return bmBrush.forget(); } gfxWarning() << "Invalid pattern type detected."; return nullptr; } -TemporaryRef -DrawTargetD2D::CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions) -{ - RefPtr style; - - D2D1_CAP_STYLE capStyle; - D2D1_LINE_JOIN joinStyle; - - switch (aStrokeOptions.mLineCap) { - case CAP_BUTT: - capStyle = D2D1_CAP_STYLE_FLAT; - break; - case CAP_ROUND: - capStyle = D2D1_CAP_STYLE_ROUND; - break; - case CAP_SQUARE: - capStyle = D2D1_CAP_STYLE_SQUARE; - break; - } - - switch (aStrokeOptions.mLineJoin) { - case JOIN_MITER: - joinStyle = D2D1_LINE_JOIN_MITER; - break; - case JOIN_MITER_OR_BEVEL: - joinStyle = D2D1_LINE_JOIN_MITER_OR_BEVEL; - break; - case JOIN_ROUND: - joinStyle = D2D1_LINE_JOIN_ROUND; - break; - case JOIN_BEVEL: - joinStyle = D2D1_LINE_JOIN_BEVEL; - break; - } - - - HRESULT hr; - if (aStrokeOptions.mDashPattern) { - typedef vector FloatVector; - // D2D "helpfully" multiplies the dash pattern by the line width. - // That's not what cairo does, or is what 's dash wants. - // So fix the multiplication in advance. - Float lineWidth = aStrokeOptions.mLineWidth; - FloatVector dash(aStrokeOptions.mDashPattern, - aStrokeOptions.mDashPattern + aStrokeOptions.mDashLength); - for (FloatVector::iterator it = dash.begin(); it != dash.end(); ++it) { - *it /= lineWidth; - } - - hr = factory()->CreateStrokeStyle( - D2D1::StrokeStyleProperties(capStyle, capStyle, - capStyle, joinStyle, - aStrokeOptions.mMiterLimit, - D2D1_DASH_STYLE_CUSTOM, - aStrokeOptions.mDashOffset), - &dash[0], // data() is not C++98, although it's in recent gcc - // and VC10's STL - dash.size(), - byRef(style)); - } else { - hr = factory()->CreateStrokeStyle( - D2D1::StrokeStyleProperties(capStyle, capStyle, - capStyle, joinStyle, - aStrokeOptions.mMiterLimit), - nullptr, 0, byRef(style)); - } - - if (FAILED(hr)) { - gfxWarning() << "Failed to create Direct2D stroke style."; - } - - return style; -} - TemporaryRef DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops) { @@ -2416,7 +2507,7 @@ DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops) RefPtr tex; mDevice->CreateTexture2D(&desc, &data, byRef(tex)); - return tex; + return tex.forget(); } TemporaryRef @@ -2481,132 +2572,7 @@ DrawTargetD2D::CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, cons return nullptr; } - return tex; -} - -TemporaryRef -DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix, ExtendMode aExtendMode) -{ - RefPtr bitmap; - - // This is where things get complicated. The source surface was - // created for a surface that was too large to fit in a texture. - // We'll need to figure out if we can work with a partial upload - // or downsample in software. - - Matrix transform = mTransform; - Matrix invTransform = transform = aMatrix * transform; - if (!invTransform.Invert()) { - // Singular transform, nothing to be drawn. - return nullptr; - } - - Rect rect(0, 0, Float(mSize.width), Float(mSize.height)); - - // Calculate the rectangle of the source mapped to our surface. - rect = invTransform.TransformBounds(rect); - rect.RoundOut(); - - IntSize size = aSurface->GetSize(); - - Rect uploadRect(0, 0, Float(size.width), Float(size.height)); - - // Limit the uploadRect as much as possible without supporting discontiguous uploads - // - // region we will paint from - // uploadRect - // .---------------. .---------------. resulting uploadRect - // | |rect | | - // | .---------. .----. .----. .---------------. - // | | | ----> | | | | ----> | | - // | '---------' '----' '----' '---------------' - // '---------------' '---------------' - // - // - - if (uploadRect.Contains(rect)) { - // Extend mode is irrelevant, the displayed rect is completely contained - // by the source bitmap. - uploadRect = rect; - } else if (aExtendMode == EXTEND_CLAMP && uploadRect.Intersects(rect)) { - // Calculate the rectangle on the source bitmap that touches our - // surface, and upload that, for EXTEND_CLAMP we can actually guarantee - // correct behaviour in this case. - uploadRect = uploadRect.Intersect(rect); - - // We now proceed to check if we can limit at least one dimension of the - // upload rect safely without looking at extend mode. - } else if (rect.x >= 0 && rect.XMost() < size.width) { - uploadRect.x = rect.x; - uploadRect.width = rect.width; - } else if (rect.y >= 0 && rect.YMost() < size.height) { - uploadRect.y = rect.y; - uploadRect.height = rect.height; - } - - - int stride = aSurface->Stride(); - - if (uploadRect.width <= mRT->GetMaximumBitmapSize() && - uploadRect.height <= mRT->GetMaximumBitmapSize()) { - - // A partial upload will suffice. - mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)), - aSurface->GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * stride, - stride, - D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())), - byRef(bitmap)); - - aMatrix.Translate(uploadRect.x, uploadRect.y); - - return bitmap; - } else { - int Bpp = BytesPerPixel(aSurface->GetFormat()); - - if (Bpp != 4) { - // This shouldn't actually happen in practice! - MOZ_ASSERT(false); - return nullptr; - } - - ImageHalfScaler scaler(aSurface->GetData(), stride, size); - - // Calculate the maximum width/height of the image post transform. - Point topRight = transform * Point(Float(size.width), 0); - Point topLeft = transform * Point(0, 0); - Point bottomRight = transform * Point(Float(size.width), Float(size.height)); - Point bottomLeft = transform * Point(0, Float(size.height)); - - IntSize scaleSize; - - scaleSize.width = int32_t(max(Distance(topRight, topLeft), - Distance(bottomRight, bottomLeft))); - scaleSize.height = int32_t(max(Distance(topRight, bottomRight), - Distance(topLeft, bottomLeft))); - - if (unsigned(scaleSize.width) > mRT->GetMaximumBitmapSize()) { - // Ok, in this case we'd really want a downscale of a part of the bitmap, - // perhaps we can do this later but for simplicity let's do something - // different here and assume it's good enough, this should be rare! - scaleSize.width = 4095; - } - if (unsigned(scaleSize.height) > mRT->GetMaximumBitmapSize()) { - scaleSize.height = 4095; - } - - scaler.ScaleForSize(scaleSize); - - IntSize newSize = scaler.GetSize(); - - mRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height), - scaler.GetScaledData(), scaler.GetStride(), - D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())), - byRef(bitmap)); - - aMatrix.Scale(Float(size.width / newSize.width), - Float(size.height / newSize.height)); - return bitmap; - } + return tex.forget(); } void @@ -2729,6 +2695,7 @@ DrawTargetD2D::factory() #else options.debugLevel = D2D1_DEBUG_LEVEL_NONE; #endif + //options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; HRESULT hr = createD2DFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, __uuidof(ID2D1Factory), @@ -2758,9 +2725,9 @@ DrawTargetD2D::GetDWriteFactory() return mDWriteFactory; } - DWriteCreateFactoryFunc createDWriteFactory; + decltype(DWriteCreateFactory)* createDWriteFactory; HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll"); - createDWriteFactory = (DWriteCreateFactoryFunc) + createDWriteFactory = (decltype(DWriteCreateFactory)*) GetProcAddress(dwriteModule, "DWriteCreateFactory"); if (!createDWriteFactory) { diff --git a/libazure/src/gfx/2d/DrawTargetD2D.h b/libazure/DrawTargetD2D.h similarity index 87% rename from libazure/src/gfx/2d/DrawTargetD2D.h rename to libazure/DrawTargetD2D.h index 1e8ed63..7f692f0 100644 --- a/libazure/src/gfx/2d/DrawTargetD2D.h +++ b/libazure/DrawTargetD2D.h @@ -37,16 +37,18 @@ struct PrivateD3D10DataD2D RefPtr mEffect; RefPtr mInputLayout; RefPtr mVB; - RefPtr mBlendStates[OP_COUNT]; + RefPtr mBlendStates[size_t(CompositionOp::OP_COUNT)]; }; class DrawTargetD2D : public DrawTarget { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D) DrawTargetD2D(); virtual ~DrawTargetD2D(); - virtual BackendType GetType() const { return BACKEND_DIRECT2D; } + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; } + virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return mSize; } @@ -56,6 +58,10 @@ class DrawTargetD2D : public DrawTarget const Rect &aSource, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, @@ -63,6 +69,11 @@ class DrawTargetD2D : public DrawTarget Float aSigma, CompositionOp aOperator); virtual void ClearRect(const Rect &aRect); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + virtual void CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect, @@ -111,12 +122,14 @@ class DrawTargetD2D : public DrawTarget virtual TemporaryRef CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const; - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode = EXTEND_CLAMP) const; + ExtendMode aExtendMode = ExtendMode::CLAMP) const; + + virtual TemporaryRef CreateFilter(FilterType aType); virtual void *GetNativeSurface(NativeSurfaceType aType); @@ -127,21 +140,22 @@ class DrawTargetD2D : public DrawTarget TemporaryRef GetCachedLayer(); void PopCachedLayer(ID2D1RenderTarget *aRT); +#ifdef USE_D2D1_1 + TemporaryRef GetImageForSurface(SourceSurface *aSurface); +#endif + static ID2D1Factory *factory(); static void CleanupD2D(); - static TemporaryRef CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions); static IDWriteFactory *GetDWriteFactory(); - - operator std::string() const { - std::stringstream stream; - stream << "DrawTargetD2D(" << this << ")"; - return stream.str(); - } + ID2D1RenderTarget *GetRT() { return mRT; } static uint64_t mVRAMUsageDT; static uint64_t mVRAMUsageSS; private: + TemporaryRef + DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface, + Rect &aSource); friend class AutoSaveRestoreClippedOut; friend class SourceSurfaceD2DTarget; @@ -184,9 +198,6 @@ class DrawTargetD2D : public DrawTarget const DrawOptions &aOptions = DrawOptions()); TemporaryRef CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat); - TemporaryRef ConvertRectToGeometry(const D2D1_RECT_F& aRect); - TemporaryRef GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform); - TemporaryRef Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB); // This returns the clipped geometry, in addition it returns aClipBounds which // represents the intersection of all pixel-aligned rectangular clips that @@ -194,22 +205,18 @@ class DrawTargetD2D : public DrawTarget // bounds to correctly reflect the total clip. This is in device space. TemporaryRef GetClippedGeometry(IntRect *aClipBounds); + bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned); + TemporaryRef CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f); TemporaryRef CreateGradientTexture(const GradientStopsD2D *aStops); TemporaryRef CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds); - // This creates a (partially) uploaded bitmap for a DataSourceSurface. It - // uploads the minimum requirement and possibly downscales. It adjusts the - // input Matrix to compensate. - TemporaryRef CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix, - ExtendMode aExtendMode); - void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern); void SetupStateForRendering(); // Set the scissor rect to a certain IntRects, resets the scissor rect to - // surface bounds when NULL is specified. + // surface bounds when nullptr is specified. void SetScissorToRect(IntRect *aRect); void PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID2D1Layer *aLayer, const D2D1_MATRIX_3X2_F &aTransform); @@ -244,7 +251,7 @@ class DrawTargetD2D : public DrawTarget RefPtr mLayer; D2D1_RECT_F mBounds; union { - // If mPath is non-NULL, the mTransform member will be used, otherwise + // If mPath is non-nullptr, the mTransform member will be used, otherwise // the mIsPixelAligned member is valid. D2D1_MATRIX_3X2_F mTransform; bool mIsPixelAligned; diff --git a/libazure/DrawTargetD2D1.cpp b/libazure/DrawTargetD2D1.cpp new file mode 100644 index 0000000..1859166 --- /dev/null +++ b/libazure/DrawTargetD2D1.cpp @@ -0,0 +1,1313 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "DrawTargetD2D1.h" +#include "DrawTargetD2D.h" +#include "FilterNodeSoftware.h" +#include "GradientStopsD2D.h" +#include "SourceSurfaceD2D1.h" +#include "SourceSurfaceD2D.h" +#include "RadialGradientEffectD2D1.h" + +#include "HelpersD2D.h" +#include "FilterNodeD2D1.h" +#include "Tools.h" + +using namespace std; + +namespace mozilla { +namespace gfx { + +uint64_t DrawTargetD2D1::mVRAMUsageDT; +uint64_t DrawTargetD2D1::mVRAMUsageSS; +ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr; + +ID2D1Factory1 *D2DFactory1() +{ + return DrawTargetD2D1::factory(); +} + +DrawTargetD2D1::DrawTargetD2D1() + : mClipsArePushed(false) +{ +} + +DrawTargetD2D1::~DrawTargetD2D1() +{ + PopAllClips(); + + if (mSnapshot) { + // We may hold the only reference. MarkIndependent will clear mSnapshot; + // keep the snapshot object alive so it doesn't get destroyed while + // MarkIndependent is running. + RefPtr deathGrip = mSnapshot; + // mSnapshot can be treated as independent of this DrawTarget since we know + // this DrawTarget won't change again. + deathGrip->MarkIndependent(); + // mSnapshot will be cleared now. + } + + mDC->EndDraw(); + + // Targets depending on us can break that dependency, since we're obviously not going to + // be modified in the future. + for (auto iter = mDependentTargets.begin(); + iter != mDependentTargets.end(); iter++) { + (*iter)->mDependingOnTargets.erase(this); + } + // Our dependencies on other targets no longer matter. + for (TargetSet::iterator iter = mDependingOnTargets.begin(); + iter != mDependingOnTargets.end(); iter++) { + (*iter)->mDependentTargets.erase(this); + } +} + +TemporaryRef +DrawTargetD2D1::Snapshot() +{ + if (mSnapshot) { + return mSnapshot; + } + PopAllClips(); + + mDC->Flush(); + + mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this); + + return mSnapshot; +} + +void +DrawTargetD2D1::Flush() +{ + mDC->Flush(); + + // We no longer depend on any target. + for (TargetSet::iterator iter = mDependingOnTargets.begin(); + iter != mDependingOnTargets.end(); iter++) { + (*iter)->mDependentTargets.erase(this); + } + mDependingOnTargets.clear(); +} + +void +DrawTargetD2D1::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color())); + + D2D1_RECT_F samplingBounds; + + if (aSurfOptions.mSamplingBounds == SamplingBounds::BOUNDED) { + samplingBounds = D2DRect(aSource); + } else { + samplingBounds = D2D1::RectF(0, 0, Float(aSurface->GetSize().width), Float(aSurface->GetSize().height)); + } + + Float xScale = aDest.width / aSource.width; + Float yScale = aDest.height / aSource.height; + + RefPtr brush; + + // Here we scale the source pattern up to the size and position where we want + // it to be. + Matrix transform; + transform.PreTranslate(aDest.x - aSource.x * xScale, aDest.y - aSource.y * yScale); + transform.PreScale(xScale, yScale); + + RefPtr image = GetImageForSurface(aSurface, transform, ExtendMode::CLAMP); + + if (!image) { + gfxWarning() << *this << ": Unable to get D2D image for surface."; + return; + } + + mDC->CreateImageBrush(image, + D2D1::ImageBrushProperties(samplingBounds, + D2D1_EXTEND_MODE_CLAMP, + D2D1_EXTEND_MODE_CLAMP, + D2DInterpolationMode(aSurfOptions.mFilter)), + D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)), + byRef(brush)); + mDC->FillRectangle(D2DRect(aDest), brush); + + FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color())); +} + +void +DrawTargetD2D1::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + if (aNode->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { + gfxWarning() << *this << ": Incompatible filter passed to DrawFilter."; + return; + } + + PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color())); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + mDC->DrawImage(static_cast(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect)); + + FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color())); +} + +void +DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) +{ + MarkChanged(); + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + Matrix mat; + RefPtr image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP); + + if (!mat.IsIdentity()) { + gfxDebug() << *this << ": At this point complex partial uploads are not supported for Shadow surfaces."; + return; + } + + // Step 1, create the shadow effect. + RefPtr shadowEffect; + mDC->CreateEffect(CLSID_D2D1Shadow, byRef(shadowEffect)); + shadowEffect->SetInput(0, image); + shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma); + D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a }; + shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color); + + D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset); + mDC->DrawImage(shadowEffect, &shadowPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator)); + + D2D1_POINT_2F imgPoint = D2DPoint(aDest); + mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator)); +} + +void +DrawTargetD2D1::ClearRect(const Rect &aRect) +{ + MarkChanged(); + + PopAllClips(); + + PushClipRect(aRect); + + if (mTransformDirty || + !mTransform.IsIdentity()) { + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + } + + D2D1_RECT_F clipRect; + bool isPixelAligned; + if (mTransform.IsRectilinear() && + GetDeviceSpaceClipRect(clipRect, isPixelAligned)) { + mDC->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + mDC->Clear(); + mDC->PopAxisAlignedClip(); + + PopClip(); + return; + } + + mDC->SetTarget(mTempBitmap); + mDC->Clear(); + + IntRect addClipRect; + RefPtr geom = GetClippedGeometry(&addClipRect); + + RefPtr brush; + mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush)); + mDC->PushAxisAlignedClip(D2D1::RectF(addClipRect.x, addClipRect.y, addClipRect.XMost(), addClipRect.YMost()), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + mDC->FillGeometry(geom, brush); + mDC->PopAxisAlignedClip(); + + mDC->SetTarget(mBitmap); + mDC->DrawImage(mTempBitmap, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT); + + PopClip(); + + return; +} + +void +DrawTargetD2D1::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, aSource); + + RefPtr bitmap; + + RefPtr image = GetImageForSurface(aMask, ExtendMode::CLAMP); + + // FillOpacityMask only works if the antialias mode is MODE_ALIASED + mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + + IntSize size = aMask->GetSize(); + Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height)); + image->QueryInterface((ID2D1Bitmap**)&bitmap); + if (!bitmap) { + gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces."; + return; + } + + Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height)); + RefPtr brush = CreateBrushForPattern(aSource, aOptions.mAlpha); + mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect)); + + mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + + FinalizeDrawing(aOptions.mCompositionOp, aSource); +} + +void +DrawTargetD2D1::CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) +{ + MarkChanged(); + + PopAllClips(); + + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + Matrix mat; + RefPtr image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP); + + if (!mat.IsIdentity()) { + gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface."; + return; + } + + if (mFormat == SurfaceFormat::A8) { + RefPtr bitmap; + image->QueryInterface((ID2D1Bitmap**)byRef(bitmap)); + + mDC->PushAxisAlignedClip(D2D1::RectF(aDestination.x, aDestination.y, + aDestination.x + aSourceRect.width, + aDestination.y + aSourceRect.height), + D2D1_ANTIALIAS_MODE_ALIASED); + mDC->Clear(); + mDC->PopAxisAlignedClip(); + + RefPtr brush; + mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), + D2D1::BrushProperties(), byRef(brush)); + mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS); + mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + return; + } + + mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)), + D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y), + Float(aSourceRect.XMost()), Float(aSourceRect.YMost())), + D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY); +} + +void +DrawTargetD2D1::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + mDC->FillRectangle(D2DRect(aRect), brush); + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + mDC->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle); + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + mDC->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle); + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + if (aPath->GetBackendType() != BackendType::DIRECT2D) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; + return; + } + const PathD2D *d2dPath = static_cast(aPath); + + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + mDC->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle); + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + if (aPath->GetBackendType() != BackendType::DIRECT2D) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; + return; + } + const PathD2D *d2dPath = static_cast(aPath); + + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode)); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + mDC->FillGeometry(d2dPath->mGeometry, brush); + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions, + const GlyphRenderingOptions *aRenderingOptions) +{ + if (aFont->GetType() != FontType::DWRITE) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible font."; + return; + } + + ScaledFontDWrite *font = static_cast(aFont); + + IDWriteRenderingParams *params = nullptr; + if (aRenderingOptions) { + if (aRenderingOptions->GetType() != FontType::DWRITE) { + gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions."; + // This should never happen. + MOZ_ASSERT(false); + } else { + params = static_cast(aRenderingOptions)->mParams; + } + } + + AntialiasMode aaMode = font->GetDefaultAAMode(); + + if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) { + aaMode = aOptions.mAntialiasMode; + } + + PrepareForDrawing(aOptions.mCompositionOp, aPattern); + + bool forceClearType = false; + if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA && + aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) { + forceClearType = true; + } + + + D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + + switch (aaMode) { + case AntialiasMode::NONE: + d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + break; + case AntialiasMode::GRAY: + d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + break; + case AntialiasMode::SUBPIXEL: + d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + break; + default: + d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + } + + if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && + mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) { + d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + } + + mDC->SetTextAntialiasMode(d2dAAMode); + + if (params != mTextRenderingParams) { + mDC->SetTextRenderingParams(params); + mTextRenderingParams = params; + } + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + AutoDWriteGlyphRun autoRun; + DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun); + + if (brush) { + mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush); + } + + FinalizeDrawing(aOptions.mCompositionOp, aPattern); +} + +void +DrawTargetD2D1::Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions) +{ + PrepareForDrawing(aOptions.mCompositionOp, aSource); + + RefPtr source = CreateBrushForPattern(aSource, aOptions.mAlpha); + RefPtr mask = CreateBrushForPattern(aMask, 1.0f); + mDC->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + D2D1::IdentityMatrix(), + 1.0f, mask), + nullptr); + + Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height); + Matrix mat = mTransform; + mat.Invert(); + + mDC->FillRectangle(D2DRect(mat.TransformBounds(rect)), source); + + mDC->PopLayer(); + + FinalizeDrawing(aOptions.mCompositionOp, aSource); +} + +void +DrawTargetD2D1::PushClip(const Path *aPath) +{ + if (aPath->GetBackendType() != BackendType::DIRECT2D) { + gfxDebug() << *this << ": Ignoring clipping call for incompatible path."; + return; + } + + mCurrentClippedGeometry = nullptr; + + RefPtr pathD2D = static_cast(const_cast(aPath)); + + PushedClip clip; + clip.mTransform = D2DMatrix(mTransform); + clip.mPath = pathD2D; + + pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds); + + mPushedClips.push_back(clip); + + // The transform of clips is relative to the world matrix, since we use the total + // transform for the clips, make the world matrix identity. + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + if (mClipsArePushed) { + PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform); + } +} + +void +DrawTargetD2D1::PushClipRect(const Rect &aRect) +{ + if (!mTransform.IsRectilinear()) { + // Whoops, this isn't a rectangle in device space, Direct2D will not deal + // with this transform the way we want it to. + // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx + + RefPtr pathBuilder = CreatePathBuilder(); + pathBuilder->MoveTo(aRect.TopLeft()); + pathBuilder->LineTo(aRect.TopRight()); + pathBuilder->LineTo(aRect.BottomRight()); + pathBuilder->LineTo(aRect.BottomLeft()); + pathBuilder->Close(); + RefPtr path = pathBuilder->Finish(); + return PushClip(path); + } + + mCurrentClippedGeometry = nullptr; + + PushedClip clip; + Rect rect = mTransform.TransformBounds(aRect); + IntRect intRect; + clip.mIsPixelAligned = rect.ToIntRect(&intRect); + + // Do not store the transform, just store the device space rectangle directly. + clip.mBounds = D2DRect(rect); + + mPushedClips.push_back(clip); + + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + if (mClipsArePushed) { + mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + } +} + +void +DrawTargetD2D1::PopClip() +{ + mCurrentClippedGeometry = nullptr; + + if (mClipsArePushed) { + if (mPushedClips.back().mPath) { + mDC->PopLayer(); + } else { + mDC->PopAxisAlignedClip(); + } + } + mPushedClips.pop_back(); +} + +TemporaryRef +DrawTargetD2D1::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr bitmap; + + HRESULT hr = mDC->CreateBitmap(D2DIntSize(aSize), aData, aStride, + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(aFormat)), + byRef(bitmap)); + + if (FAILED(hr)) { + gfxCriticalError() << "[D2D1.1] CreateBitmap failure " << aSize << " Code: " << hr; + } + + if (!bitmap) { + return nullptr; + } + + return new SourceSurfaceD2D1(bitmap.get(), mDC, aFormat, aSize); +} + +TemporaryRef +DrawTargetD2D1::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + RefPtr dt = new DrawTargetD2D1(); + + if (!dt->Init(aSize, aFormat)) { + return nullptr; + } + + return dt.forget(); +} + +TemporaryRef +DrawTargetD2D1::CreatePathBuilder(FillRule aFillRule) const +{ + RefPtr path; + HRESULT hr = factory()->CreatePathGeometry(byRef(path)); + + if (FAILED(hr)) { + gfxWarning() << *this << ": Failed to create Direct2D Path Geometry. Code: " << hr; + return nullptr; + } + + RefPtr sink; + hr = path->Open(byRef(sink)); + if (FAILED(hr)) { + gfxWarning() << *this << ": Failed to access Direct2D Path Geometry. Code: " << hr; + return nullptr; + } + + if (aFillRule == FillRule::FILL_WINDING) { + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + } + + return new PathBuilderD2D(sink, path, aFillRule); +} + +TemporaryRef +DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const +{ + if (aNumStops == 0) { + gfxWarning() << *this << ": Failed to create GradientStopCollection with no stops."; + return nullptr; + } + + D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops]; + + for (uint32_t i = 0; i < aNumStops; i++) { + stops[i].position = rawStops[i].offset; + stops[i].color = D2DColor(rawStops[i].color); + } + + RefPtr stopCollection; + + HRESULT hr = + mDC->CreateGradientStopCollection(stops, aNumStops, + D2D1_GAMMA_2_2, D2DExtend(aExtendMode), + byRef(stopCollection)); + delete [] stops; + + if (FAILED(hr)) { + gfxWarning() << *this << ": Failed to create GradientStopCollection. Code: " << hr; + return nullptr; + } + + return new GradientStopsD2D(stopCollection); +} + +TemporaryRef +DrawTargetD2D1::CreateFilter(FilterType aType) +{ + return FilterNodeD2D1::Create(this, mDC, aType); +} + +bool +DrawTargetD2D1::Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat) +{ + HRESULT hr; + + hr = Factory::GetD2D1Device()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, byRef(mDC)); + + if (FAILED(hr)) { + gfxWarning() << *this << ": Error " << hr << " failed to initialize new DeviceContext."; + return false; + } + + RefPtr dxgiSurface; + aTexture->QueryInterface(__uuidof(IDXGISurface), + (void**)((IDXGISurface**)byRef(dxgiSurface))); + if (!dxgiSurface) { + return false; + } + + D2D1_BITMAP_PROPERTIES1 props; + props.dpiX = 96; + props.dpiY = 96; + props.pixelFormat = D2DPixelFormat(aFormat); + props.colorContext = nullptr; + props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET; + hr = mDC->CreateBitmapFromDxgiSurface(dxgiSurface, props, (ID2D1Bitmap1**)byRef(mBitmap)); + + if (FAILED(hr)) { + gfxCriticalError() << "[D2D1.1] CreateBitmapFromDxgiSurface failure Code: " << hr; + return false; + } + + mFormat = aFormat; + D3D11_TEXTURE2D_DESC desc; + aTexture->GetDesc(&desc); + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + mSize.width = desc.Width; + mSize.height = desc.Height; + props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + + hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mTempBitmap)); + + if (FAILED(hr)) { + gfxCriticalError() << "[D2D1.1] CreateBitmap failure " << mSize << " Code: " << hr; + return false; + } + + mDC->SetTarget(mBitmap); + + mDC->BeginDraw(); + return true; +} + +bool +DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat) +{ + HRESULT hr; + + hr = Factory::GetD2D1Device()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, byRef(mDC)); + + if (FAILED(hr)) { + gfxWarning() << *this << ": Error " << hr << " failed to initialize new DeviceContext."; + return false; + } + + if (mDC->GetMaximumBitmapSize() < UINT32(aSize.width) || + mDC->GetMaximumBitmapSize() < UINT32(aSize.height)) { + // This is 'ok' + gfxDebug() << *this << ": Attempt to use unsupported surface size for D2D 1.1."; + return false; + } + + D2D1_BITMAP_PROPERTIES1 props; + props.dpiX = 96; + props.dpiY = 96; + props.pixelFormat = D2DPixelFormat(aFormat); + props.colorContext = nullptr; + props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET; + mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << *this << ": Error " << hr << " failed to create new CommandList."; + return false; + } + + props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + + mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mTempBitmap)); + + mDC->SetTarget(mBitmap); + + mDC->BeginDraw(); + + mDC->Clear(); + + mFormat = aFormat; + mSize = aSize; + + return true; +} + +/** + * Private helpers. + */ +uint32_t +DrawTargetD2D1::GetByteSize() const +{ + return mSize.width * mSize.height * BytesPerPixel(mFormat); +} + +ID2D1Factory1* +DrawTargetD2D1::factory() +{ + if (mFactory) { + return mFactory; + } + + HRESULT hr = D2DFactory()->QueryInterface((ID2D1Factory1**)&mFactory); + + if (FAILED(hr)) { + return nullptr; + } + + RadialGradientEffectD2D1::Register(mFactory); + + return mFactory; +} + +void +DrawTargetD2D1::MarkChanged() +{ + if (mSnapshot) { + if (mSnapshot->hasOneRef()) { + // Just destroy it, since no-one else knows about it. + mSnapshot = nullptr; + } else { + mSnapshot->DrawTargetWillChange(); + // The snapshot will no longer depend on this target. + MOZ_ASSERT(!mSnapshot); + } + } + if (mDependentTargets.size()) { + // Copy mDependentTargets since the Flush()es below will modify it. + TargetSet tmpTargets = mDependentTargets; + for (TargetSet::iterator iter = tmpTargets.begin(); + iter != tmpTargets.end(); iter++) { + (*iter)->Flush(); + } + // The Flush() should have broken all dependencies on this target. + MOZ_ASSERT(!mDependentTargets.size()); + } +} + +void +DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern) +{ + MarkChanged(); + + // It's important to do this before FlushTransformToDC! As this will cause + // the transform to become dirty. + if (!mClipsArePushed) { + mClipsArePushed = true; + PushClipsToDC(mDC); + } + + FlushTransformToDC(); + + if (aOp == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) { + return; + } + + mDC->SetTarget(mTempBitmap); + mDC->Clear(D2D1::ColorF(0, 0)); +} + +void +DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern) +{ + bool patternSupported = IsPatternSupportedByD2D(aPattern); + + if (aOp == CompositionOp::OP_OVER && patternSupported) { + return; + } + + RefPtr image; + mDC->GetTarget(byRef(image)); + + mDC->SetTarget(mBitmap); + + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + if (patternSupported) { + if (D2DSupportsCompositeMode(aOp)) { + mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp)); + return; + } + + if (!mBlendEffect) { + mDC->CreateEffect(CLSID_D2D1Blend, byRef(mBlendEffect)); + + if (!mBlendEffect) { + gfxWarning() << "Failed to create blend effect!"; + return; + } + } + + RefPtr tmpBitmap; + mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap)); + + // This flush is important since the copy method will not know about the context drawing to the surface. + mDC->Flush(); + + // We need to use a copy here because affects don't accept a surface on + // both their in- and outputs. + tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr); + + mBlendEffect->SetInput(0, tmpBitmap); + mBlendEffect->SetInput(1, mTempBitmap); + mBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp)); + + mDC->DrawImage(mBlendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY); + return; + } + + RefPtr radialGradientEffect; + + mDC->CreateEffect(CLSID_RadialGradientEffect, byRef(radialGradientEffect)); + const RadialGradientPattern *pat = static_cast(&aPattern); + + radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION, + static_cast(pat->mStops.get())->mStopCollection); + radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y)); + radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y)); + radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1); + radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2); + radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2); + radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform)); + radialGradientEffect->SetInput(0, image); + + mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp)); +} + +void +DrawTargetD2D1::AddDependencyOnSource(SourceSurfaceD2D1* aSource) +{ + if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) { + aSource->mDrawTarget->mDependentTargets.insert(this); + mDependingOnTargets.insert(aSource->mDrawTarget); + } +} + +static D2D1_RECT_F +IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2) +{ + D2D1_RECT_F result; + result.left = max(aRect1.left, aRect2.left); + result.top = max(aRect1.top, aRect2.top); + result.right = min(aRect1.right, aRect2.right); + result.bottom = min(aRect1.bottom, aRect2.bottom); + + result.right = max(result.right, result.left); + result.bottom = max(result.bottom, result.top); + + return result; +} + +bool +DrawTargetD2D1::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned) +{ + if (!mPushedClips.size()) { + return false; + } + + aClipRect = D2D1::RectF(0, 0, mSize.width, mSize.height); + for (auto iter = mPushedClips.begin();iter != mPushedClips.end(); iter++) { + if (iter->mPath) { + return false; + } + aClipRect = IntersectRect(aClipRect, iter->mBounds); + if (!iter->mIsPixelAligned) { + aIsPixelAligned = false; + } + } + return true; +} + +TemporaryRef +DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds) +{ + if (mCurrentClippedGeometry) { + *aClipBounds = mCurrentClipBounds; + return mCurrentClippedGeometry; + } + + mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize); + + // if pathGeom is null then pathRect represents the path. + RefPtr pathGeom; + D2D1_RECT_F pathRect; + bool pathRectIsAxisAligned = false; + auto iter = mPushedClips.begin(); + + if (iter->mPath) { + pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform); + } else { + pathRect = iter->mBounds; + pathRectIsAxisAligned = iter->mIsPixelAligned; + } + + iter++; + for (;iter != mPushedClips.end(); iter++) { + // Do nothing but add it to the current clip bounds. + if (!iter->mPath && iter->mIsPixelAligned) { + mCurrentClipBounds.IntersectRect(mCurrentClipBounds, + IntRect(int32_t(iter->mBounds.left), int32_t(iter->mBounds.top), + int32_t(iter->mBounds.right - iter->mBounds.left), + int32_t(iter->mBounds.bottom - iter->mBounds.top))); + continue; + } + + if (!pathGeom) { + if (pathRectIsAxisAligned) { + mCurrentClipBounds.IntersectRect(mCurrentClipBounds, + IntRect(int32_t(pathRect.left), int32_t(pathRect.top), + int32_t(pathRect.right - pathRect.left), + int32_t(pathRect.bottom - pathRect.top))); + } + if (iter->mPath) { + // See if pathRect needs to go into the path geometry. + if (!pathRectIsAxisAligned) { + pathGeom = ConvertRectToGeometry(pathRect); + } else { + pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform); + } + } else { + pathRect = IntersectRect(pathRect, iter->mBounds); + pathRectIsAxisAligned = false; + continue; + } + } + + RefPtr newGeom; + factory()->CreatePathGeometry(byRef(newGeom)); + + RefPtr currentSink; + newGeom->Open(byRef(currentSink)); + + if (iter->mPath) { + pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT, + iter->mTransform, currentSink); + } else { + RefPtr rectGeom = ConvertRectToGeometry(iter->mBounds); + pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT, + D2D1::IdentityMatrix(), currentSink); + } + + currentSink->Close(); + + pathGeom = newGeom.forget(); + } + + // For now we need mCurrentClippedGeometry to always be non-nullptr. This + // method might seem a little strange but it is just fine, if pathGeom is + // nullptr pathRect will always still contain 1 clip unaccounted for + // regardless of mCurrentClipBounds. + if (!pathGeom) { + pathGeom = ConvertRectToGeometry(pathRect); + } + mCurrentClippedGeometry = pathGeom.forget(); + *aClipBounds = mCurrentClipBounds; + return mCurrentClippedGeometry; +} + +void +DrawTargetD2D1::PopAllClips() +{ + if (mClipsArePushed) { + PopClipsFromDC(mDC); + + mClipsArePushed = false; + } +} + +void +DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC) +{ + mDC->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + for (std::vector::iterator iter = mPushedClips.begin(); + iter != mPushedClips.end(); iter++) { + if (iter->mPath) { + PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform); + } else { + mDC->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + } + } +} + +void +DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC) +{ + for (int i = mPushedClips.size() - 1; i >= 0; i--) { + if (mPushedClips[i].mPath) { + aDC->PopLayer(); + } else { + aDC->PopAxisAlignedClip(); + } + } +} + +TemporaryRef +DrawTargetD2D1::CreateTransparentBlackBrush() +{ + RefPtr brush; + mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), byRef(brush)); + return brush; +} + +TemporaryRef +DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) +{ + if (!IsPatternSupportedByD2D(aPattern)) { + RefPtr colBrush; + mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush)); + return colBrush.forget(); + } + + if (aPattern.GetType() == PatternType::COLOR) { + RefPtr colBrush; + Color color = static_cast(&aPattern)->mColor; + mDC->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g, + color.b, color.a), + D2D1::BrushProperties(aAlpha), + byRef(colBrush)); + return colBrush.forget(); + } + if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) { + RefPtr gradBrush; + const LinearGradientPattern *pat = + static_cast(&aPattern); + + GradientStopsD2D *stops = static_cast(pat->mStops.get()); + + if (!stops) { + gfxDebug() << "No stops specified for gradient pattern."; + return CreateTransparentBlackBrush(); + } + + if (pat->mBegin == pat->mEnd) { + RefPtr colBrush; + uint32_t stopCount = stops->mStopCollection->GetGradientStopCount(); + vector d2dStops(stopCount); + stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount); + mDC->CreateSolidColorBrush(d2dStops.back().color, + D2D1::BrushProperties(aAlpha), + byRef(colBrush)); + return colBrush.forget(); + } + + mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin), + D2DPoint(pat->mEnd)), + D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), + stops->mStopCollection, + byRef(gradBrush)); + return gradBrush.forget(); + } + if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { + RefPtr gradBrush; + const RadialGradientPattern *pat = + static_cast(&aPattern); + + GradientStopsD2D *stops = static_cast(pat->mStops.get()); + + if (!stops) { + gfxDebug() << "No stops specified for gradient pattern."; + return CreateTransparentBlackBrush(); + } + + // This will not be a complex radial gradient brush. + mDC->CreateRadialGradientBrush( + D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2), + D2DPoint(pat->mCenter1 - pat->mCenter2), + pat->mRadius2, pat->mRadius2), + D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), + stops->mStopCollection, + byRef(gradBrush)); + + return gradBrush.forget(); + } + if (aPattern.GetType() == PatternType::SURFACE) { + const SurfacePattern *pat = + static_cast(&aPattern); + + if (!pat->mSurface) { + gfxDebug() << "No source surface specified for surface pattern"; + return CreateTransparentBlackBrush(); + } + + D2D1_RECT_F samplingBounds; + if (!pat->mSamplingRect.IsEmpty()) { + samplingBounds = D2DRect(pat->mSamplingRect); + } else { + samplingBounds = D2D1::RectF(0, 0, + Float(pat->mSurface->GetSize().width), + Float(pat->mSurface->GetSize().height)); + } + + Matrix mat = pat->mMatrix; + + RefPtr imageBrush; + RefPtr image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode); + mDC->CreateImageBrush(image, + D2D1::ImageBrushProperties(samplingBounds, + D2DExtend(pat->mExtendMode), + D2DExtend(pat->mExtendMode), + D2DInterpolationMode(pat->mFilter)), + D2D1::BrushProperties(aAlpha, D2DMatrix(mat)), + byRef(imageBrush)); + return imageBrush.forget(); + } + + gfxWarning() << "Invalid pattern type detected."; + return CreateTransparentBlackBrush(); +} + +TemporaryRef +DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform, + ExtendMode aExtendMode) +{ + RefPtr image; + + switch (aSurface->GetType()) { + case SurfaceType::D2D1_1_IMAGE: + { + SourceSurfaceD2D1 *surf = static_cast(aSurface); + image = surf->GetImage(); + AddDependencyOnSource(surf); + } + break; + default: + { + RefPtr dataSurf = aSurface->GetDataSurface(); + if (!dataSurf) { + gfxWarning() << "Invalid surface type."; + return nullptr; + } + return CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode, + aSourceTransform, mDC); + } + break; + } + + return image.forget(); +} + +TemporaryRef +DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const +{ + if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) { + return aSurface; + } + + RefPtr data = aSurface->GetDataSurface(); + + DataSourceSurface::MappedSurface map; + if (!data->Map(DataSourceSurface::MapType::READ, &map)) { + return nullptr; + } + + RefPtr bitmap; + HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride, + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())), + byRef(bitmap)); + + if (FAILED(hr)) { + gfxCriticalError() << "[D2D1.1] CreateBitmap failure " << data->GetSize() << " Code: " << hr; + } + + data->Unmap(); + + if (!bitmap) { + return data.forget(); + } + + return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize()); +} + +void +DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform) +{ + D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE; + + if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) { + options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND; + } + + mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform, + 1.0, nullptr, options), nullptr); +} + +} +} diff --git a/libazure/DrawTargetD2D1.h b/libazure/DrawTargetD2D1.h new file mode 100644 index 0000000..82f0076 --- /dev/null +++ b/libazure/DrawTargetD2D1.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWTARGETD2D1_H_ +#define MOZILLA_GFX_DRAWTARGETD2D1_H_ + +#include "2D.h" +#include +#include +#include "PathD2D.h" +#include "HelpersD2D.h" + +#include +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +struct IDWriteFactory; + +namespace mozilla { +namespace gfx { + +class SourceSurfaceD2D1; +class GradientStopsD2D; +class ScaledFontDWrite; + +const int32_t kLayerCacheSize1 = 5; + +class DrawTargetD2D1 : public DrawTarget +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D1) + DrawTargetD2D1(); + virtual ~DrawTargetD2D1(); + + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return DrawTargetType::HARDWARE_RASTER; } + virtual BackendType GetBackendType() const { return BackendType::DIRECT2D1_1; } + virtual TemporaryRef Snapshot(); + virtual IntSize GetSize() { return mSize; } + + virtual void Flush(); + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator); + virtual void ClearRect(const Rect &aRect); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination); + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions(), + const GlyphRenderingOptions *aRenderingOptions = nullptr); + virtual void Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions = DrawOptions()); + virtual void PushClip(const Path *aPath); + virtual void PushClipRect(const Rect &aRect); + virtual void PopClip(); + + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const; + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const; + + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const { return nullptr; } + + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const; + + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; + + virtual TemporaryRef + CreateGradientStops(GradientStop *aStops, + uint32_t aNumStops, + ExtendMode aExtendMode = ExtendMode::CLAMP) const; + + virtual TemporaryRef CreateFilter(FilterType aType); + + virtual void *GetNativeSurface(NativeSurfaceType aType) { return nullptr; } + + bool Init(const IntSize &aSize, SurfaceFormat aFormat); + bool Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat); + uint32_t GetByteSize() const; + + TemporaryRef GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform, + ExtendMode aExtendMode); + + TemporaryRef GetImageForSurface(SourceSurface *aSurface, ExtendMode aExtendMode) { + Matrix mat; + return GetImageForSurface(aSurface, mat, aExtendMode); + } + + static ID2D1Factory1 *factory(); + static void CleanupD2D(); + static IDWriteFactory *GetDWriteFactory(); + + operator std::string() const { + std::stringstream stream; + stream << "DrawTargetD2D 1.1 (" << this << ")"; + return stream.str(); + } + + static uint64_t mVRAMUsageDT; + static uint64_t mVRAMUsageSS; + +private: + friend class SourceSurfaceD2D1; + +#ifdef _MSC_VER + typedef stdext::hash_set TargetSet; +#else + typedef std::unordered_set TargetSet; +#endif + + // This function will mark the surface as changing, and make sure any + // copy-on-write snapshots are notified. + void MarkChanged(); + void PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern); + void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern); + void FlushTransformToDC() { + if (mTransformDirty) { + mDC->SetTransform(D2DMatrix(mTransform)); + mTransformDirty = false; + } + } + void AddDependencyOnSource(SourceSurfaceD2D1* aSource); + + // This returns the clipped geometry, in addition it returns aClipBounds which + // represents the intersection of all pixel-aligned rectangular clips that + // are currently set. The returned clipped geometry must be clipped by these + // bounds to correctly reflect the total clip. This is in device space. + TemporaryRef GetClippedGeometry(IntRect *aClipBounds); + + bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned); + + void PopAllClips(); + void PushClipsToDC(ID2D1DeviceContext *aDC); + void PopClipsFromDC(ID2D1DeviceContext *aDC); + + TemporaryRef CreateTransparentBlackBrush(); + TemporaryRef CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f); + + void PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform); + + IntSize mSize; + + RefPtr mDevice; + RefPtr mTexture; + RefPtr mCurrentClippedGeometry; + // This is only valid if mCurrentClippedGeometry is non-null. And will + // only be the intersection of all pixel-aligned retangular clips. This is in + // device space. + IntRect mCurrentClipBounds; + mutable RefPtr mDC; + RefPtr mBitmap; + RefPtr mTempBitmap; + RefPtr mBlendEffect; + + // We store this to prevent excessive SetTextRenderingParams calls. + RefPtr mTextRenderingParams; + + // List of pushed clips. + struct PushedClip + { + D2D1_RECT_F mBounds; + union { + // If mPath is non-null, the mTransform member will be used, otherwise + // the mIsPixelAligned member is valid. + D2D1_MATRIX_3X2_F mTransform; + bool mIsPixelAligned; + }; + RefPtr mPath; + }; + std::vector mPushedClips; + + // The latest snapshot of this surface. This needs to be told when this + // target is modified. We keep it alive as a cache. + RefPtr mSnapshot; + // A list of targets we need to flush when we're modified. + TargetSet mDependentTargets; + // A list of targets which have this object in their mDependentTargets set + TargetSet mDependingOnTargets; + + // True of the current clip stack is pushed to the main RT. + bool mClipsArePushed; + static ID2D1Factory1 *mFactory; + static IDWriteFactory *mDWriteFactory; +}; + +} +} + +#endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */ diff --git a/libazure/src/gfx/2d/DrawTargetDual.cpp b/libazure/DrawTargetDual.cpp similarity index 83% rename from libazure/src/gfx/2d/DrawTargetDual.cpp rename to libazure/DrawTargetDual.cpp index 1235a85..9695679 100644 --- a/libazure/src/gfx/2d/DrawTargetDual.cpp +++ b/libazure/DrawTargetDual.cpp @@ -5,6 +5,7 @@ #include "DrawTargetDual.h" #include "Tools.h" +#include "Logging.h" namespace mozilla { namespace gfx { @@ -12,9 +13,9 @@ namespace gfx { class DualSurface { public: - inline DualSurface(SourceSurface *aSurface) + inline explicit DualSurface(SourceSurface *aSurface) { - if (aSurface->GetType() != SURFACE_DUAL_DT) { + if (aSurface->GetType() != SurfaceType::DUAL_DT) { mA = mB = aSurface; return; } @@ -36,10 +37,10 @@ class DualSurface class DualPattern { public: - inline DualPattern(const Pattern &aPattern) + inline explicit DualPattern(const Pattern &aPattern) : mPatternsInitialized(false) { - if (aPattern.GetType() != PATTERN_SURFACE) { + if (aPattern.GetType() != PatternType::SURFACE) { mA = mB = &aPattern; return; } @@ -47,7 +48,7 @@ class DualPattern const SurfacePattern *surfPat = static_cast(&aPattern); - if (surfPat->mSurface->GetType() != SURFACE_DUAL_DT) { + if (surfPat->mSurface->GetType() != SurfaceType::DUAL_DT) { mA = mB = &aPattern; return; } @@ -97,6 +98,26 @@ DrawTargetDual::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDes mB->DrawSurfaceWithShadow(surface.mB, aDest, aColor, aOffset, aSigma, aOp); } +void +DrawTargetDual::DrawFilter(FilterNode *aNode, const Rect &aSourceRect, + const Point &aDestPoint, const DrawOptions &aOptions) +{ + mA->DrawFilter(aNode, aSourceRect, aDestPoint, aOptions); + mB->DrawFilter(aNode, aSourceRect, aDestPoint, aOptions); +} + +void +DrawTargetDual::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + DualPattern source(aSource); + DualSurface mask(aMask); + mA->MaskSurface(*source.mA, mask.mA, aOffset, aOptions); + mB->MaskSurface(*source.mB, mask.mB, aOffset, aOptions); +} + void DrawTargetDual::CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect, const IntPoint &aDestination) @@ -174,6 +195,11 @@ DrawTargetDual::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFor RefPtr dtA = mA->CreateSimilarDrawTarget(aSize, aFormat); RefPtr dtB = mB->CreateSimilarDrawTarget(aSize, aFormat); + if (!dtA || !dtB) { + gfxWarning() << "Failure to allocate a similar DrawTargetDual. Size: " << aSize; + return nullptr; + } + return new DrawTargetDual(dtA, dtB); } diff --git a/libazure/src/gfx/2d/DrawTargetDual.h b/libazure/DrawTargetDual.h similarity index 83% rename from libazure/src/gfx/2d/DrawTargetDual.h rename to libazure/DrawTargetDual.h index b2fb0b3..8954de4 100644 --- a/libazure/src/gfx/2d/DrawTargetDual.h +++ b/libazure/DrawTargetDual.h @@ -12,6 +12,7 @@ #include "SourceSurfaceDual.h" #include "2D.h" +#include "Filters.h" namespace mozilla { namespace gfx { @@ -34,6 +35,7 @@ namespace gfx { class DrawTargetDual : public DrawTarget { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetDual) DrawTargetDual(DrawTarget *aA, DrawTarget *aB) : mA(aA) , mB(aB) @@ -41,7 +43,8 @@ class DrawTargetDual : public DrawTarget mFormat = aA->GetFormat(); } - virtual BackendType GetType() const { return mA->GetType(); } + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mA->GetType(); } + virtual BackendType GetBackendType() const { return mA->GetBackendType(); } virtual TemporaryRef Snapshot() { return new SourceSurfaceDual(mA, mB); } virtual IntSize GetSize() { return mA->GetSize(); } @@ -59,7 +62,17 @@ class DrawTargetDual : public DrawTarget virtual void DrawSurface(SourceSurface *aSurface, const Rect &aDest, const Rect & aSource, const DrawSurfaceOptions &aSurfOptions, const DrawOptions &aOptions); - + + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOp); @@ -109,7 +122,7 @@ class DrawTargetDual : public DrawTarget virtual TemporaryRef CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const; - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const { return mA->CreatePathBuilder(aFillRule); } @@ -117,16 +130,26 @@ class DrawTargetDual : public DrawTarget virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode = EXTEND_CLAMP) const + ExtendMode aExtendMode = ExtendMode::CLAMP) const { return mA->CreateGradientStops(aStops, aNumStops, aExtendMode); } - + + virtual TemporaryRef CreateFilter(FilterType aType) + { + return mA->CreateFilter(aType); + } + virtual void *GetNativeSurface(NativeSurfaceType aType) { return nullptr; } - + + virtual bool IsDualDrawTarget() + { + return true; + } + private: RefPtr mA; RefPtr mB; diff --git a/libazure/DrawTargetNVpr.cpp b/libazure/DrawTargetNVpr.cpp new file mode 100644 index 0000000..642d2be --- /dev/null +++ b/libazure/DrawTargetNVpr.cpp @@ -0,0 +1,964 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DrawTargetNVpr.h" +#include "GradientStopsNVpr.h" +#include "Logging.h" +#include "PathBuilderNVpr.h" +#include "PathNVpr.h" +#include "ScaledFontNVpr.h" +#include "SourceSurfaceNVpr.h" +#include "nvpr/Clip.h" +#include "nvpr/Paint.h" +#include "nvpr/ShadowShaders.h" +#include +#include + +#ifdef WIN32 +#include "DXTextureInteropNVpr.h" +#endif + +static const size_t sMaxScratchTextures = 2; + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +template +inline static Log& +operator <<(Log& aStream, const DrawTargetNVpr& aDrawTarget) +{ + aStream << "DrawTargetNVpr(" << &aDrawTarget << ")"; + return aStream; +} + +class DrawTargetNVpr::ScratchSurface : public SourceSurfaceNVpr { +public: + ScratchSurface(WeakPtr aDrawTarget, + TemporaryRef aTexture) + : SourceSurfaceNVpr(aTexture) + , mDrawTarget(aDrawTarget) + {} + + virtual ~ScratchSurface() + { + if (mDrawTarget) { + mDrawTarget->OnScratchSurfaceDeleted(Texture()); + } + } + +private: + WeakPtr mDrawTarget; +}; + +DrawTargetNVpr::DrawTargetNVpr(const IntSize& aSize, SurfaceFormat aFormat, + bool& aSuccess) + : mSize(aSize) + , mFormat(aFormat) + , mColorBuffer(0) + , mStencilBuffer(0) + , mFramebuffer(0) + , mScratchTextureCount(0) + , mPoppedStencilClips(nullptr) + , mTransformId(0) + , mStencilClipBits(0) +{ + aSuccess = false; + + MOZ_ASSERT(mSize.width >= 0 && mSize.height >= 0); + + InitializeGLIfNeeded(); + if (!gl->IsValid()) { + return; + } + + gl->MakeCurrent(); + + if (max(mSize.width, mSize.height) > gl->MaxRenderbufferSize() + || max(mSize.width, mSize.height) > gl->MaxTextureSize()) { + return; + } + + GLenum colorBufferFormat; + switch (mFormat) { + case SurfaceFormat::YUV: + case SurfaceFormat::UNKNOWN: + default: + mHasAlpha = false; + return; + case SurfaceFormat::B8G8R8A8: + case SurfaceFormat::R8G8B8A8: + colorBufferFormat = GL_RGBA8; + mHasAlpha = true; + break; + case SurfaceFormat::B8G8R8X8: + case SurfaceFormat::R8G8B8X8: + colorBufferFormat = GL_RGB8; + mHasAlpha = false; + break; + case SurfaceFormat::R5G6B5: + colorBufferFormat = GL_RGB565; + mHasAlpha = false; + break; + case SurfaceFormat::A8: + colorBufferFormat = GL_ALPHA; + mHasAlpha = true; + break; + } + gl->GenRenderbuffers(1, &mColorBuffer); + gl->NamedRenderbufferStorageMultisampleEXT(mColorBuffer, 16, colorBufferFormat, + mSize.width, mSize.height); + + gl->GenRenderbuffers(1, &mStencilBuffer); + gl->NamedRenderbufferStorageMultisampleEXT(mStencilBuffer, 16, GL_STENCIL_INDEX8, + mSize.width, mSize.height); + + gl->GenFramebuffers(1, &mFramebuffer); + gl->NamedFramebufferRenderbufferEXT(mFramebuffer, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, mColorBuffer); + gl->NamedFramebufferRenderbufferEXT(mFramebuffer, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, mStencilBuffer); + + Validate(FRAMEBUFFER | COLOR_WRITE_MASK); + + gl->DisableScissorTest(); + gl->SetClearColor(Color()); + gl->Clear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + aSuccess = true; +} + +DrawTargetNVpr::~DrawTargetNVpr() +{ + gl->MakeCurrent(); + gl->DeleteRenderbuffers(1, &mColorBuffer); + gl->DeleteRenderbuffers(1, &mStencilBuffer); + gl->DeleteFramebuffers(1, &mFramebuffer); +} + +TemporaryRef +DrawTargetNVpr::GetScratchSurface() +{ + RefPtr texture; + + if (!mScratchTexturePool.empty()) { + texture = mScratchTexturePool.front(); + mScratchTexturePool.front(); + } else { + mScratchTextureCount++; + texture = TextureObjectNVpr::Create(mFormat, mSize); + } + + return new ScratchSurface(this, texture.forget()); +} + +void +DrawTargetNVpr::OnScratchSurfaceDeleted(TemporaryRef aBackingTexture) +{ + if (mScratchTextureCount > sMaxScratchTextures) { + mScratchTextureCount--; + return; + } + + mScratchTexturePool.push_back(aBackingTexture); +} + +TemporaryRef +DrawTargetNVpr::Snapshot() +{ + if (!mSnapshot) { + mSnapshot = GetScratchSurface(); + + gl->MakeCurrent(); + + gl->SetFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer); + gl->SetFramebufferToTexture(GL_DRAW_FRAMEBUFFER, GL_TEXTURE_2D, *mSnapshot); + gl->DisableScissorTest(); + gl->SetColorWriteMask(GL::WRITE_COLOR_AND_ALPHA); + + gl->BlitFramebuffer(0, 0, mSize.width, mSize.height, + 0, 0, mSize.width, mSize.height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + mSnapshot->MarkChanged(); + } + + return mSnapshot; +} + +bool +DrawTargetNVpr::BlitToForeignTexture(void* aForeignContext, + GLuint aForeignTextureId) +{ + Snapshot(); + return gl->BlitTextureToForeignTexture(mSize, *mSnapshot, + aForeignContext, aForeignTextureId); +} + +#ifdef WIN32 + +TemporaryRef +DrawTargetNVpr::OpenDXTextureInterop(void* aDX, void* aDXTexture) +{ + return DXTextureInteropNVpr::Create(aDX, aDXTexture); +} + +void +DrawTargetNVpr::BlitToDXTexture(DXTextureInteropNVpr* aDXTexture) +{ + gl->MakeCurrent(); + + GLuint dxTextureId = aDXTexture->Lock(); + + gl->SetFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer); + gl->SetFramebufferToTexture(GL_DRAW_FRAMEBUFFER, GL_TEXTURE_2D, dxTextureId); + gl->DisableScissorTest(); + gl->SetColorWriteMask(GL::WRITE_COLOR_AND_ALPHA); + + gl->BlitFramebuffer(0, 0, mSize.width, mSize.height, + 0, 0, mSize.width, mSize.height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + aDXTexture->Unlock(); +} + +#endif + +void +DrawTargetNVpr::Flush() +{ + gl->MakeCurrent(); + gl->Flush(); +} + +void +DrawTargetNVpr::DrawSurface(SourceSurface* aSurface, + const Rect& aDestRect, + const Rect& aSourceRect, + const DrawSurfaceOptions& aSurfOptions, + const DrawOptions& aOptions) +{ + MOZ_ASSERT(aSurface->GetType() == SURFACE_NVPR_TEXTURE); + + SourceSurfaceNVpr* const surface = static_cast(aSurface); + + gl->MakeCurrent(); + + Validate(); + + Paint paint; + if (aSurfOptions.mSamplingBounds == SamplingBounds::UNBOUNDED) { + paint.SetToSurface(surface, aSurfOptions.mFilter); + } else { + paint.SetToClampedSurface(surface, aSurfOptions.mFilter, aSourceRect); + } + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + if (mStencilClipBits) { + gl->EnableStencilTest(GL::PASS_IF_ALL_SET, mStencilClipBits, + GL::LEAVE_UNCHANGED); + } else { + gl->DisableStencilTest(); + } + + Rect textureRect = aSourceRect; + textureRect.ScaleInverse(surface->GetSize().width, surface->GetSize().height); + gl->EnableTexCoordArrayToRect(PaintShader::PAINT_UNIT, textureRect); + gl->DisableTexCoordArray(PaintShader::MASK_UNIT); + gl->SetVertexArrayToRect(aDestRect); + + gl->DrawArrays(GL_QUADS, 0, 4); + gl->BlendBarrier(); + + MarkChanged(); +} + +void +DrawTargetNVpr::DrawSurfaceWithShadow(SourceSurface* aSurface, + const Point& aDest, + const Color& aColor, + const Point& aOffset, + Float aSigma, + CompositionOp aOperator) +{ + MOZ_ASSERT(aSurface->GetType() == SURFACE_NVPR_TEXTURE); + + SourceSurfaceNVpr* const surface = static_cast(aSurface); + RefPtr horizontalConvolution = GetScratchSurface(); + ShadowShaders& shadowShaders = + gl->GetUserObject(&nvpr::UserData::mShadowShaders); + const Rect shadowRect(aDest + aOffset, Size(surface->GetSize())); + + gl->MakeCurrent(); + + // We take advantage of the fact that a Gaussian blur is separable by drawing + // the shadow in two passes: Once with a 1-dimensional kernel in the horizontal + // direction, and again with that same kernel in the vertical direction. + Rect horizontalConvolutionRect; + GLuint horizontalConvolutionShader; + GLuint shadowShader; + shadowShaders.ConfigureShaders(mSize, shadowRect, aColor, aSigma, + mHasAlpha ? ShadowShaders::ALPHA : ShadowShaders::RED, + &horizontalConvolutionRect, + &horizontalConvolutionShader, &shadowShader); + + // Step 1: Draw the horizontal convolution into a scratch texture. + gl->SetSize(mSize); + gl->SetFramebufferToTexture(GL_FRAMEBUFFER, GL_TEXTURE_2D, + *horizontalConvolution); + gl->SetTransformToIdentity(); + gl->DisableScissorTest(); + gl->DisableClipPlanes(); + gl->DisableStencilTest(); + gl->SetBlendMode(CompositionOp::OP_SOURCE); + gl->SetColorWriteMask(mHasAlpha ? GL::WRITE_ALPHA : GL::WRITE_RED); + gl->DisableTexCoordArray(GL::UNIT_1); + + gl->SetShaderProgram(horizontalConvolutionShader); + + surface->SetWrapMode(GL_CLAMP_TO_BORDER); + surface->SetFilter(horizontalConvolutionRect.width == shadowRect.width + ? Filter::LINEAR : Filter::GOOD); + gl->SetTexture(GL::UNIT_0, GL_TEXTURE_2D, *surface); + + gl->EnableTexCoordArrayToUnitRect(GL::UNIT_0); + gl->SetVertexArrayToRect(horizontalConvolutionRect); + + gl->DrawArrays(GL_QUADS, 0, 4); + + horizontalConvolution->MarkChanged(); + + // Step 2: Use the horizontal convolution to draw the shadow. + Validate(FRAMEBUFFER | CLIPPING | COLOR_WRITE_MASK); + ApplyDrawOptions(aOperator, AntialiasMode::DEFAULT); + + gl->SetShaderProgram(shadowShader); + + if (mStencilClipBits) { + gl->EnableStencilTest(GL::PASS_IF_ALL_SET, mStencilClipBits, + GL::LEAVE_UNCHANGED); + } + + horizontalConvolution->SetWrapMode(GL_CLAMP_TO_EDGE); + horizontalConvolution->SetFilter(Filter::LINEAR); + gl->SetTexture(GL::UNIT_0, GL_TEXTURE_2D, *horizontalConvolution); + + horizontalConvolutionRect.ScaleInverse(mSize.width, mSize.height); + gl->EnableTexCoordArrayToRect(GL::UNIT_0, horizontalConvolutionRect); + gl->SetVertexArrayToRect(shadowRect); + + gl->DrawArrays(GL_QUADS, 0, 4); + gl->BlendBarrier(); + + // Step 3: Draw the surface on top of its shadow. + Paint paint; + paint.SetToSurface(surface, Filter::LINEAR); + ApplyPaint(paint); + + gl->EnableTexCoordArrayToUnitRect(GL::UNIT_0); + gl->SetVertexArrayToRect(aDest, Size(surface->GetSize())); + + gl->DrawArrays(GL_QUADS, 0, 4); + gl->BlendBarrier(); + + MarkChanged(); +} + +void +DrawTargetNVpr::ClearRect(const Rect& aRect) +{ + FillRect(aRect, ColorPattern(Color()), DrawOptions(1, CompositionOp::OP_SOURCE)); +} + +void +DrawTargetNVpr::CopySurface(SourceSurface* aSurface, + const IntRect& aSourceRect, + const IntPoint& aDestination) +{ + MOZ_ASSERT(aSurface->GetType() == SURFACE_NVPR_TEXTURE); + + SourceSurfaceNVpr* const surface = static_cast(aSurface); + + gl->MakeCurrent(); + + // TODO: Consider using NV_draw_texture instead. + + gl->SetFramebufferToTexture(GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, *surface); + gl->SetFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer); + gl->DisableScissorTest(); + gl->SetColorWriteMask(GL::WRITE_COLOR_AND_ALPHA); + + gl->BlitFramebuffer(aSourceRect.x, aSourceRect.y, aSourceRect.XMost(), + aSourceRect.YMost(), aDestination.x, aDestination.y, + aDestination.x + aSourceRect.width, aDestination.y + + aSourceRect.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); +} + +void +DrawTargetNVpr::FillRect(const Rect& aRect, + const Pattern& aPattern, + const DrawOptions& aOptions) +{ + gl->MakeCurrent(); + + if (aPattern.GetType() == PatternType::COLOR) { + const Color& color = static_cast(aPattern).mColor; + const bool needsBlending = aOptions.mCompositionOp != CompositionOp::OP_SOURCE + && (aOptions.mCompositionOp != CompositionOp::OP_OVER + || aOptions.mAlpha != 1 || color.a != 1); + const bool hasComplexClips = mTopPlanesClip || (mTopStencilClip + && (!mPoppedStencilClips + || mPoppedStencilClips->GetPrevious())); + + IntRect scissorRect; + if (!needsBlending && !hasComplexClips && GetTransform().IsRectilinear() + && GetTransform().TransformBounds(aRect).ToIntRect(&scissorRect)) { + + Validate(FRAMEBUFFER | COLOR_WRITE_MASK); + + if (mTopScissorClip) { + scissorRect.IntersectRect(scissorRect, mTopScissorClip->ScissorRect()); + } + gl->EnableScissorTest(scissorRect); + gl->SetClearColor(color, aOptions.mAlpha); + gl->Clear(GL_COLOR_BUFFER_BIT); + + MarkChanged(); + return; + } + } + + Validate(); + + Paint paint; + paint.SetToPattern(aPattern); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + if (mStencilClipBits) { + gl->EnableStencilTest(GL::PASS_IF_ALL_SET, mStencilClipBits, + GL::LEAVE_UNCHANGED); + } else { + gl->DisableStencilTest(); + } + + gl->Rectf(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height); + gl->BlendBarrier(); + + MarkChanged(); +} + +void +DrawTargetNVpr::StrokeRect(const Rect& aRect, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + PathBuilderNVpr pathBuilder(FillRule::FILL_WINDING); + pathBuilder.MoveTo(aRect.BottomRight()); + pathBuilder.LineTo(aRect.TopRight()); + pathBuilder.LineTo(aRect.TopLeft()); + pathBuilder.LineTo(aRect.BottomLeft()); + pathBuilder.Close(); + RefPtr path = pathBuilder.Finish(); + + Stroke(path.get(), aPattern, aStrokeOptions, aOptions); +} + +void +DrawTargetNVpr::StrokeLine(const Point& aStart, + const Point& aEnd, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + PathBuilderNVpr pathBuilder(FillRule::FILL_WINDING); + pathBuilder.MoveTo(aStart); + pathBuilder.LineTo(aEnd); + RefPtr path = pathBuilder.Finish(); + + Stroke(path.get(), aPattern, aStrokeOptions, aOptions); +} + +void +DrawTargetNVpr::Stroke(const Path* aPath, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions, + const DrawOptions& aOptions) +{ + MOZ_ASSERT(aPath->GetBackendType() == BACKEND_NVPR); + + const PathNVpr* const path = static_cast(aPath); + + gl->MakeCurrent(); + + Validate(); + + Paint paint; + paint.SetToPattern(aPattern); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + gl->ConfigurePathStencilTest(mStencilClipBits); + path->ApplyStrokeOptions(aStrokeOptions); + gl->StencilStrokePathNV(*path, 0x1, 0x1); + + gl->EnableStencilTest(GL::PASS_IF_NOT_ZERO, 1, GL::CLEAR_PASSING_VALUES, 1); + gl->CoverStrokePathNV(*path, GL_BOUNDING_BOX_NV); + + MarkChanged(); +} + +void +DrawTargetNVpr::Fill(const Path* aPath, + const Pattern& aPattern, + const DrawOptions& aOptions) +{ + MOZ_ASSERT(aPath->GetBackendType() == BACKEND_NVPR); + + const PathNVpr* const path = static_cast(aPath); + const GLubyte countingMask = + path->GetFillRule() == FillRule::FILL_WINDING ? (~mStencilClipBits & 0xff) : 0x1; + + gl->MakeCurrent(); + + Validate(); + + Paint paint; + paint.SetToPattern(aPattern); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + gl->ConfigurePathStencilTest(mStencilClipBits); + gl->StencilFillPathNV(*path, GL_COUNT_UP_NV, countingMask); + + gl->EnableStencilTest(GL::PASS_IF_NOT_ZERO, countingMask, + GL::CLEAR_PASSING_VALUES, countingMask); + gl->CoverFillPathNV(*path, GL_BOUNDING_BOX_NV); + + MarkChanged(); +} + +void +DrawTargetNVpr::FillGlyphs(ScaledFont* aFont, + const GlyphBuffer& aBuffer, + const Pattern& aPattern, + const DrawOptions& aOptions, + const GlyphRenderingOptions* aRenderOptions) +{ + MOZ_ASSERT(aFont->GetType() == FONT_NVPR); + + if (!aBuffer.mNumGlyphs) { + return; + } + + const ScaledFontNVpr* const font = static_cast(aFont); + const GLubyte countingMask = (~mStencilClipBits & 0xff); + + gl->MakeCurrent(); + + Validate(); + + Paint paint; + paint.SetToPattern(aPattern); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + gl->ScaleTransform(font->Size(), -font->Size()); + + struct Position {GLfloat x, y;}; + vector characters(aBuffer.mNumGlyphs); + vector positions(aBuffer.mNumGlyphs); + + for (size_t i = 0; i < aBuffer.mNumGlyphs; i++) { + // TODO: How can we know the real mapping index -> unicode? + characters[i] = aBuffer.mGlyphs[i].mIndex + 29; + positions[i].x = aBuffer.mGlyphs[i].mPosition.x * font->InverseSize(); + positions[i].y = aBuffer.mGlyphs[i].mPosition.y * -font->InverseSize(); + } + + gl->ConfigurePathStencilTest(mStencilClipBits); + gl->StencilFillPathInstancedNV(aBuffer.mNumGlyphs, GL_UNSIGNED_INT, + &characters.front(), *font, GL_COUNT_UP_NV, + countingMask, GL_TRANSLATE_2D_NV, + &positions[0].x); + + gl->EnableStencilTest(GL::PASS_IF_NOT_ZERO, countingMask, + GL::CLEAR_PASSING_VALUES, countingMask); + gl->CoverFillPathInstancedNV(aBuffer.mNumGlyphs, GL_UNSIGNED_INT, + &characters.front(), *font, + GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV, + GL_TRANSLATE_2D_NV, &positions[0].x); + + MarkChanged(); +} + +void +DrawTargetNVpr::Mask(const Pattern& aSource, + const Pattern& aMask, + const DrawOptions& aOptions) +{ + gl->MakeCurrent(); + + Validate(); + + Paint paint; + paint.SetToPattern(aSource); + paint.mMask.SetToPattern(aMask); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + if (mStencilClipBits) { + gl->EnableStencilTest(GL::PASS_IF_ALL_SET, mStencilClipBits, + GL::LEAVE_UNCHANGED); + } else { + gl->DisableStencilTest(); + } + + Matrix inverse = GetTransform(); + inverse.Invert(); + Point topLeft = inverse * Point(0, 0); + Point bottomRight = inverse * Point(mSize.width, mSize.height); + + gl->Rectf(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); + gl->BlendBarrier(); + + MarkChanged(); +} + +void +DrawTargetNVpr::MaskSurface(const Pattern& aSource, + SourceSurface* aMask, + Point aOffset, + const DrawOptions& aOptions) +{ + MOZ_ASSERT(aMask->GetType() == SURFACE_NVPR_TEXTURE); + + SourceSurfaceNVpr* const mask = static_cast(aMask); + const Rect maskRect(aOffset, Size(mask->GetSize())); + + gl->MakeCurrent(); + + Validate(); + + Paint paint; + paint.SetToPattern(aSource); + paint.mMask.SetToSurface(mask); + paint.mGlobalAlpha = aOptions.mAlpha; + ApplyPaint(paint); + + ApplyDrawOptions(aOptions.mCompositionOp, aOptions.mAntialiasMode); + + if (mStencilClipBits) { + gl->EnableStencilTest(GL::PASS_IF_ALL_SET, mStencilClipBits, + GL::LEAVE_UNCHANGED); + } else { + gl->DisableStencilTest(); + } + + gl->DisableTexCoordArray(PaintShader::PAINT_UNIT); + gl->EnableTexCoordArrayToUnitRect(PaintShader::MASK_UNIT); + gl->SetVertexArrayToRect(maskRect); + + gl->DrawArrays(GL_QUADS, 0, 4); + gl->BlendBarrier(); + + MarkChanged(); +} + +void +DrawTargetNVpr::PushClip(const Path* aPath) +{ + MOZ_ASSERT(aPath->GetBackendType() == BACKEND_NVPR); + + const PathNVpr* const path = static_cast(aPath); + + if (!path->Polygon().IsEmpty()) { + if (RefPtr planesClip = + PlanesClip::Create(this, mTopPlanesClip, GetTransform(), + ConvexPolygon(path->Polygon()))) { + mTopPlanesClip = planesClip.forget(); + mClipTypeStack.push(PLANES_CLIP_TYPE); + return; + } + } + + Validate(FRAMEBUFFER | CLIPPING); + + mTopStencilClip = StencilClip::Create(this, mTopStencilClip.forget(), + GetTransform(), mTransformId, + path->Clone()); + + mTopStencilClip->ApplyToStencilBuffer(); + + mClipTypeStack.push(STENCIL_CLIP_TYPE); +} + +void +DrawTargetNVpr::PushClipRect(const Rect& aRect) +{ + if (RefPtr scissorClip = + ScissorClip::Create(this, mTopScissorClip, GetTransform(), aRect)) { + mTopScissorClip = scissorClip.forget(); + mClipTypeStack.push(SCISSOR_CLIP_TYPE); + return; + } + + if (RefPtr planesClip = + PlanesClip::Create(this, mTopPlanesClip, GetTransform(), + ConvexPolygon(aRect))) { + mTopPlanesClip = planesClip.forget(); + mClipTypeStack.push(PLANES_CLIP_TYPE); + return; + } + + if (!mUnitSquarePath) { + PathBuilderNVpr pathBuilder(FillRule::FILL_WINDING); + pathBuilder.MoveTo(Point(0, 0)); + pathBuilder.LineTo(Point(1, 0)); + pathBuilder.LineTo(Point(1, 1)); + pathBuilder.LineTo(Point(0, 1)); + RefPtr path = pathBuilder.Finish(); + + mUnitSquarePath = static_cast(path.get()); + } + + Matrix transform = GetTransform(); + transform.PreTranslate(aRect.x, aRect.y); + transform.PreScale(aRect.width, aRect.height); + + Validate(FRAMEBUFFER | CLIPPING); + + mTopStencilClip = StencilClip::Create(this, mTopStencilClip.forget(), + transform, gl->GetUniqueId(), + mUnitSquarePath->Clone()); + + mTopStencilClip->ApplyToStencilBuffer(); + + mClipTypeStack.push(STENCIL_CLIP_TYPE); +} + +void +DrawTargetNVpr::PopClip() +{ + switch (mClipTypeStack.top()) { + case SCISSOR_CLIP_TYPE: + mTopScissorClip = mTopScissorClip->Pop(); + break; + case PLANES_CLIP_TYPE: + mTopPlanesClip = mTopPlanesClip->Pop(); + break; + case STENCIL_CLIP_TYPE: + mPoppedStencilClips = !mPoppedStencilClips ? mTopStencilClip.get() + : mPoppedStencilClips->GetPrevious(); + break; + default: + MOZ_ASSERT(!"Invalid clip type."); + } + + mClipTypeStack.pop(); +} + +TemporaryRef +DrawTargetNVpr::CreateSourceSurfaceFromData(unsigned char* aData, + const IntSize& aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr texture = + TextureObjectNVpr::Create(aFormat, aSize, aData, aStride); + + return texture ? new SourceSurfaceNVpr(texture.forget()) : nullptr; +} + +TemporaryRef +DrawTargetNVpr::OptimizeSourceSurface(SourceSurface* aSurface) const +{ + if (aSurface->GetType() == SurfaceType::NVPR_TEXTURE) { + return aSurface; + } + + RefPtr data = aSurface->GetDataSurface(); + RefPtr texture = TextureObjectNVpr::Create(data); + + return texture ? new SourceSurfaceNVpr(texture.forget()) : nullptr; +} + +TemporaryRef +DrawTargetNVpr::CreateSourceSurfaceFromNativeSurface(const NativeSurface& aSurface) const +{ + gfxWarning() << *this << ": CreateSourceSurfaceFromNativeSurface not implemented"; + return 0; +} + +TemporaryRef +DrawTargetNVpr::CreateSimilarDrawTarget(const IntSize& aSize, + SurfaceFormat aFormat) const +{ + return Create(aSize, aFormat); +} + +TemporaryRef +DrawTargetNVpr::CreatePathBuilder(FillRule aFillRule) const +{ + return new PathBuilderNVpr(aFillRule); +} + +TemporaryRef +DrawTargetNVpr::CreateGradientStops(GradientStop* rawStops, uint32_t aNumStops, + ExtendMode aExtendMode) const +{ + return GradientStopsNVpr::create(rawStops, aNumStops, aExtendMode); +} + +void* +DrawTargetNVpr::GetNativeSurface(NativeSurfaceType aType) +{ + gfxWarning() << *this << ": GetNativeSurface not implemented"; + return 0; +} + +void +DrawTargetNVpr::SetTransform(const Matrix& aTransform) +{ + DrawTarget::SetTransform(aTransform); + mTransformId = gl->GetUniqueId(); +} + +void +DrawTargetNVpr::Validate(ValidationFlags aFlags) +{ + MOZ_ASSERT(gl->IsCurrent()); + + if (aFlags & FRAMEBUFFER) { + gl->SetSize(mSize); + gl->SetFramebuffer(GL_FRAMEBUFFER, mFramebuffer); + } + + if (aFlags & CLIPPING) { + if (mTopScissorClip) { + gl->EnableScissorTest(mTopScissorClip->ScissorRect()); + } else { + gl->DisableScissorTest(); + } + + if (mTopPlanesClip) { + if (gl->ClipPolygonId() != mTopPlanesClip->PolygonId()) { + gl->SetTransformToIdentity(); + gl->EnableClipPlanes(mTopPlanesClip->Polygon(), + mTopPlanesClip->PolygonId()); + } + } else { + gl->DisableClipPlanes(); + } + + if (mPoppedStencilClips) { + mPoppedStencilClips->RestoreStencilBuffer(); + mTopStencilClip = mPoppedStencilClips->Pop(); + mPoppedStencilClips = nullptr; + } + } + + if (aFlags & TRANSFORM) { + gl->SetTransform(GetTransform(), mTransformId); + } + + if (aFlags & COLOR_WRITE_MASK) { + gl->SetColorWriteMask(GL::WRITE_COLOR_AND_ALPHA); + } +} + +void +DrawTargetNVpr::ApplyPaint(const Paint& aPaint) +{ + MOZ_ASSERT(gl->IsCurrent()); + + struct PaintShaders : public nvpr::UserData::Object { + RefPtr mShaders[PaintConfig::MODE_COUNT] + [PaintConfig::MODE_COUNT][2]; + }; + + PaintShaders& shaders = + gl->GetUserObject(&nvpr::UserData::mPaintShaders); + + RefPtr& shader = shaders.mShaders[aPaint.mPaintMode] + [aPaint.mMask.mPaintMode] + [aPaint.mGlobalAlpha != 1]; + if (!shader) { + shader = PaintShader::Create(aPaint); + } + + gl->SetTexGen(PaintShader::PAINT_UNIT, aPaint.mTexGenComponents, + aPaint.mTexGenCoefficients); + gl->SetTexGen(PaintShader::MASK_UNIT, aPaint.mMask.mTexGenComponents, + aPaint.mMask.mTexGenCoefficients); + + shader->ApplyFragmentUniforms(aPaint); + + gl->SetShaderProgram(*shader); +} + +void +DrawTargetNVpr::ApplyDrawOptions(CompositionOp aCompositionOp, + AntialiasMode aAntialiasMode) +{ + MOZ_ASSERT(gl->IsCurrent()); + + gl->SetBlendMode(aCompositionOp); + + if (aAntialiasMode == AntialiasMode::NONE) { + gl->DisableMultisample(); + } else { + gl->EnableMultisample(); + } +} + +void +DrawTargetNVpr::MarkChanged() +{ + mSnapshot = nullptr; +} + +GLubyte +DrawTargetNVpr::ReserveStencilClipBit() +{ + // Don't reserve more than two bit planes for clipping. + if (mStencilClipBits >= 0xc0) { + return 0; + } + + mStencilClipBits = 0x80 | (mStencilClipBits >> 1); + + return (~mStencilClipBits & 0xff) + 1; +} + +void +DrawTargetNVpr::ReleaseStencilClipBits(GLubyte aBits) +{ + mStencilClipBits &= (~aBits & 0xff); + + // The clip bits need to be a consecutive run of most-significant bits (in + // other words, they need to be released in reverse order). + MOZ_ASSERT((~mStencilClipBits & 0xff) & ((~mStencilClipBits & 0xff) - 1)); +} + +} +} diff --git a/libazure/DrawTargetNVpr.h b/libazure/DrawTargetNVpr.h new file mode 100644 index 0000000..6b7617a --- /dev/null +++ b/libazure/DrawTargetNVpr.h @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWTARGETNVPR_H_ +#define MOZILLA_GFX_DRAWTARGETNVPR_H_ + +#include "2D.h" +#include "Filters.h" +#include "nvpr/GL.h" +#include +#include +#include +#include +#include + +namespace mozilla { +namespace gfx { + +class PathNVpr; +class SourceSurfaceNVpr; +class TextureObjectNVpr; + +#ifdef WIN32 +class DXTextureInteropNVpr; +#endif + +namespace nvpr { +class ScissorClip; +class PlanesClip; +class StencilClip; +struct Paint; +} + +class DrawTargetNVpr + : public DrawTarget + , public SupportsWeakPtr +{ + class ScratchSurface; + friend class ScratchSurface; + +public: + static TemporaryRef Create(const IntSize& aSize, + SurfaceFormat aFormat) + { + bool success; + RefPtr drawTarget = new DrawTargetNVpr(aSize, aFormat, success); + return success ? drawTarget.forget() : nullptr; + } + virtual ~DrawTargetNVpr(); + + virtual DrawTargetType GetType() const { return DrawTargetType::HARDWARE_RASTER; } + + virtual BackendType GetBackendType() const { return BackendType::NVPR; } + + virtual IntSize GetSize() { return mSize; } + + virtual TemporaryRef Snapshot(); + + bool BlitToForeignTexture(void* aForeignContext, GLuint aForeignTextureId); + +#ifdef WIN32 + TemporaryRef + OpenDXTextureInterop(void* aDX, void* aDXTexture); + void BlitToDXTexture(DXTextureInteropNVpr* aDXTexture); +#endif + + virtual void Flush(); + + virtual void DrawSurface(SourceSurface* aSurface, + const Rect& aDestRect, + const Rect& aSourceRect, + const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(), + const DrawOptions& aOptions = DrawOptions()); + + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()) { /* Implement me! */ MOZ_ASSERT(0); } + + virtual void DrawSurfaceWithShadow(SourceSurface* aSurface, + const Point& aDest, + const Color& aColor, + const Point& aOffset, + Float aSigma, + CompositionOp aOperator); + + virtual void ClearRect(const Rect& aRect); + + virtual void CopySurface(SourceSurface* aSurface, + const IntRect& aSourceRect, + const IntPoint& aDestination); + + virtual void FillRect(const Rect& aRect, + const Pattern& aPattern, + const DrawOptions& aOptions = DrawOptions()); + + virtual void StrokeRect(const Rect& aRect, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions = StrokeOptions(), + const DrawOptions& aOptions = DrawOptions()); + + virtual void StrokeLine(const Point& aStart, + const Point& aEnd, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions = StrokeOptions(), + const DrawOptions& aOptions = DrawOptions()); + + virtual void Stroke(const Path* aPath, + const Pattern& aPattern, + const StrokeOptions& aStrokeOptions = StrokeOptions(), + const DrawOptions& aOptions = DrawOptions()); + + virtual void Fill(const Path* aPath, + const Pattern& aPattern, + const DrawOptions& aOptions = DrawOptions()); + + virtual void FillGlyphs(ScaledFont* aFont, + const GlyphBuffer& aBuffer, + const Pattern& aPattern, + const DrawOptions& aOptions = DrawOptions(), + const GlyphRenderingOptions* aRenderingOptions = nullptr); + + virtual void Mask(const Pattern& aSource, + const Pattern& aMask, + const DrawOptions& aOptions = DrawOptions()); + + virtual void MaskSurface(const Pattern& aSource, + SourceSurface* aMask, + Point aOffset, + const DrawOptions& aOptions = DrawOptions()); + + virtual void PushClip(const Path* aPath); + + virtual void PushClipRect(const Rect& aRect); + + virtual void PopClip(); + + virtual TemporaryRef + CreateSourceSurfaceFromData(unsigned char* aData, const IntSize& aSize, + int32_t aStride, SurfaceFormat aFormat) const; + + virtual TemporaryRef + OptimizeSourceSurface(SourceSurface* aSurface) const; + + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface& aSurface) const; + + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) const; + + virtual TemporaryRef + CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; + + virtual TemporaryRef + CreateGradientStops(GradientStop* aStops, uint32_t aNumStops, + ExtendMode aExtendMode = ExtendMode::CLAMP) const; + + virtual TemporaryRef CreateFilter(FilterType aType) { /* Implement me! */ MOZ_ASSERT(0); return nullptr; } + + virtual void* GetNativeSurface(NativeSurfaceType aType); + + virtual void SetTransform(const Matrix& aTransform); + + GLubyte ReserveStencilClipBit(); + void ReleaseStencilClipBits(GLubyte aBits); + +private: + DrawTargetNVpr(const IntSize& aSize, SurfaceFormat aFormat, bool& aSuccess); + + TemporaryRef GetScratchSurface(); + void OnScratchSurfaceDeleted(TemporaryRef aBackingTexture); + + enum ValidationFlag { + FRAMEBUFFER = 1 << 0, + CLIPPING = 1 << 1, + TRANSFORM = 1 << 2, + COLOR_WRITE_MASK = 1 << 3 + }; + typedef unsigned ValidationFlags; + void Validate(ValidationFlags aFlags = ~0); + + void ApplyPaint(const nvpr::Paint& aPaint); + + void ApplyDrawOptions(CompositionOp aCompositionOp, + AntialiasMode aAntialiasMode); + + void MarkChanged(); + + const IntSize mSize; + const SurfaceFormat mFormat; + bool mHasAlpha; + GLuint mColorBuffer; + GLuint mStencilBuffer; + GLuint mFramebuffer; + size_t mScratchTextureCount; + std::deque > mScratchTexturePool; + RefPtr mSnapshot; + RefPtr mUnitSquarePath; + enum ClipType { SCISSOR_CLIP_TYPE, PLANES_CLIP_TYPE, STENCIL_CLIP_TYPE }; + std::stack mClipTypeStack; + RefPtr mTopScissorClip; + RefPtr mTopPlanesClip; + RefPtr mTopStencilClip; + nvpr::StencilClip* mPoppedStencilClips; + nvpr::UniqueId mTransformId; + GLubyte mStencilClipBits; +}; + +} +} + +#endif /* MOZILLA_GFX_DRAWTARGETNVPR_H_ */ diff --git a/libazure/src/gfx/2d/DrawTargetRecording.cpp b/libazure/DrawTargetRecording.cpp similarity index 73% rename from libazure/src/gfx/2d/DrawTargetRecording.cpp rename to libazure/DrawTargetRecording.cpp index 5c5e559..e32250c 100644 --- a/libazure/src/gfx/2d/DrawTargetRecording.cpp +++ b/libazure/DrawTargetRecording.cpp @@ -9,6 +9,7 @@ #include "Logging.h" #include "Tools.h" +#include "Filters.h" namespace mozilla { namespace gfx { @@ -16,6 +17,7 @@ namespace gfx { class SourceSurfaceRecording : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording) SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder) : mFinalSurface(aFinalSurface), mRecorder(aRecorder) { @@ -26,7 +28,7 @@ class SourceSurfaceRecording : public SourceSurface mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this)); } - virtual SurfaceType GetType() const { return SURFACE_RECORDING; } + virtual SurfaceType GetType() const { return SurfaceType::RECORDING; } virtual IntSize GetSize() const { return mFinalSurface->GetSize(); } virtual SurfaceFormat GetFormat() const { return mFinalSurface->GetFormat(); } virtual TemporaryRef GetDataSurface() { return mFinalSurface->GetDataSurface(); } @@ -38,6 +40,7 @@ class SourceSurfaceRecording : public SourceSurface class GradientStopsRecording : public GradientStops { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording) GradientStopsRecording(GradientStops *aFinalGradientStops, DrawEventRecorderPrivate *aRecorder) : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder) { @@ -48,7 +51,7 @@ class GradientStopsRecording : public GradientStops mRecorder->RecordEvent(RecordedGradientStopsDestruction(this)); } - virtual BackendType GetBackendType() const { return BACKEND_RECORDING; } + virtual BackendType GetBackendType() const { return BackendType::RECORDING; } RefPtr mFinalGradientStops; RefPtr mRecorder; @@ -57,7 +60,7 @@ class GradientStopsRecording : public GradientStops static SourceSurface * GetSourceSurface(SourceSurface *aSurface) { - if (aSurface->GetType() != SURFACE_RECORDING) { + if (aSurface->GetType() != SurfaceType::RECORDING) { return aSurface; } @@ -67,17 +70,95 @@ GetSourceSurface(SourceSurface *aSurface) static GradientStops * GetGradientStops(GradientStops *aStops) { - if (aStops->GetBackendType() != BACKEND_RECORDING) { + if (aStops->GetBackendType() != BackendType::RECORDING) { return aStops; } return static_cast(aStops)->mFinalGradientStops; } +class FilterNodeRecording : public FilterNode +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording) + using FilterNode::SetAttribute; + + FilterNodeRecording(FilterNode *aFinalFilterNode, DrawEventRecorderPrivate *aRecorder) + : mFinalFilterNode(aFinalFilterNode), mRecorder(aRecorder) + { + } + + ~FilterNodeRecording() + { + mRecorder->RecordEvent(RecordedFilterNodeDestruction(this)); + } + + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) + { + mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface)); + mFinalFilterNode->SetInput(aIndex, GetSourceSurface(aSurface)); + } + virtual void SetInput(uint32_t aIndex, FilterNode *aFilter) + { + FilterNode *finalNode = aFilter; + if (aFilter->GetBackendType() != FILTER_BACKEND_RECORDING) { + gfxWarning() << "Non recording filter node used with recording DrawTarget!"; + } else { + finalNode = static_cast(aFilter)->mFinalFilterNode; + } + + mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter)); + mFinalFilterNode->SetInput(aIndex, finalNode); + } + + +#define FORWARD_SET_ATTRIBUTE(type, argtype) \ + virtual void SetAttribute(uint32_t aIndex, type aValue) { \ + mRecorder->RecordEvent(RecordedFilterNodeSetAttribute(this, aIndex, aValue, RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \ + mFinalFilterNode->SetAttribute(aIndex, aValue); \ + } + + FORWARD_SET_ATTRIBUTE(bool, BOOL); + FORWARD_SET_ATTRIBUTE(uint32_t, UINT32); + FORWARD_SET_ATTRIBUTE(Float, FLOAT); + FORWARD_SET_ATTRIBUTE(const Size&, SIZE); + FORWARD_SET_ATTRIBUTE(const IntSize&, INTSIZE); + FORWARD_SET_ATTRIBUTE(const IntPoint&, INTPOINT); + FORWARD_SET_ATTRIBUTE(const Rect&, RECT); + FORWARD_SET_ATTRIBUTE(const IntRect&, INTRECT); + FORWARD_SET_ATTRIBUTE(const Point&, POINT); + FORWARD_SET_ATTRIBUTE(const Matrix5x4&, MATRIX5X4); + FORWARD_SET_ATTRIBUTE(const Point3D&, POINT3D); + FORWARD_SET_ATTRIBUTE(const Color&, COLOR); + +#undef FORWARD_SET_ATTRIBUTE + + virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) { + mRecorder->RecordEvent(RecordedFilterNodeSetAttribute(this, aIndex, aFloat, aSize)); + mFinalFilterNode->SetAttribute(aIndex, aFloat, aSize); + } + + virtual FilterBackend GetBackendType() MOZ_OVERRIDE { return FILTER_BACKEND_RECORDING; } + + RefPtr mFinalFilterNode; + RefPtr mRecorder; +}; + +static FilterNode* +GetFilterNode(FilterNode* aNode) +{ + if (aNode->GetBackendType() != FILTER_BACKEND_RECORDING) { + gfxWarning() << "Non recording filter node used with recording DrawTarget!"; + return aNode; + } + + return static_cast(aNode)->mFinalFilterNode; +} + struct AdjustedPattern { - AdjustedPattern(const Pattern &aPattern) - : mPattern(NULL) + explicit AdjustedPattern(const Pattern &aPattern) + : mPattern(nullptr) { mOrigPattern = const_cast(&aPattern); } @@ -91,9 +172,9 @@ struct AdjustedPattern operator Pattern*() { switch(mOrigPattern->GetType()) { - case PATTERN_COLOR: + case PatternType::COLOR: return mOrigPattern; - case PATTERN_SURFACE: + case PatternType::SURFACE: { SurfacePattern *surfPat = static_cast(mOrigPattern); mPattern = @@ -102,7 +183,7 @@ struct AdjustedPattern surfPat->mFilter); return mPattern; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { LinearGradientPattern *linGradPat = static_cast(mOrigPattern); mPattern = @@ -111,7 +192,7 @@ struct AdjustedPattern linGradPat->mMatrix); return mPattern; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { RadialGradientPattern *radGradPat = static_cast(mOrigPattern); mPattern = @@ -139,11 +220,16 @@ struct AdjustedPattern Pattern *mPattern; }; -DrawTargetRecording::DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT) +DrawTargetRecording::DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData) : mRecorder(static_cast(aRecorder)) , mFinalDT(aDT) { - mRecorder->RecordEvent(RecordedDrawTargetCreation(this, mFinalDT->GetType(), mFinalDT->GetSize(), mFinalDT->GetFormat())); + RefPtr snapshot = aHasData ? mFinalDT->Snapshot() : nullptr; + mRecorder->RecordEvent(RecordedDrawTargetCreation(this, + mFinalDT->GetBackendType(), + mFinalDT->GetSize(), + mFinalDT->GetFormat(), + aHasData, snapshot)); mFormat = mFinalDT->GetFormat(); } @@ -185,8 +271,8 @@ DrawTargetRecording::StrokeLine(const Point &aBegin, Path* DrawTargetRecording::GetPathForPathRecording(const Path *aPath) const { - if (aPath->GetBackendType() != BACKEND_RECORDING) { - return NULL; + if (aPath->GetBackendType() != BackendType::RECORDING) { + return nullptr; } return static_cast(aPath)->mPath; @@ -214,7 +300,10 @@ void RecordingFontUserDataDestroyFunc(void *aUserData) RecordingFontUserData *userData = static_cast(aUserData); + // TODO support font in b2g recordings +#ifndef MOZ_WIDGET_GONK userData->recorder->RecordEvent(RecordedScaledFontDestruction(userData->refPtr)); +#endif delete userData; } @@ -227,7 +316,10 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont, const GlyphRenderingOptions *aRenderingOptions) { if (!aFont->GetUserData(reinterpret_cast(mRecorder.get()))) { + // TODO support font in b2g recordings +#ifndef MOZ_WIDGET_GONK mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, aFont)); +#endif RecordingFontUserData *userData = new RecordingFontUserData; userData->refPtr = aFont; userData->recorder = mRecorder; @@ -235,7 +327,10 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont, &RecordingFontUserDataDestroyFunc); } + // TODO support font in b2g recordings +#ifndef MOZ_WIDGET_GONK mRecorder->RecordEvent(RecordedFillGlyphs(this, aFont, aPattern, aOptions, aBuffer.mGlyphs, aBuffer.mNumGlyphs)); +#endif mFinalDT->FillGlyphs(aFont, aBuffer, aPattern, aOptions, aRenderingOptions); } @@ -248,6 +343,16 @@ DrawTargetRecording::Mask(const Pattern &aSource, mFinalDT->Mask(*AdjustedPattern(aSource), *AdjustedPattern(aMask), aOptions); } +void +DrawTargetRecording::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + mRecorder->RecordEvent(RecordedMaskSurface(this, aSource, aMask, aOffset, aOptions)); + mFinalDT->MaskSurface(*AdjustedPattern(aSource), GetSourceSurface(aMask), aOffset, aOptions); +} + void DrawTargetRecording::Stroke(const Path *aPath, const Pattern &aPattern, @@ -269,7 +374,7 @@ DrawTargetRecording::Snapshot() mRecorder->RecordEvent(RecordedSnapshot(retSurf, this)); - return retSurf; + return retSurf.forget(); } void @@ -295,6 +400,28 @@ DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface *aSurface, mFinalDT->DrawSurfaceWithShadow(GetSourceSurface(aSurface), aDest, aColor, aOffset, aSigma, aOp); } +void +DrawTargetRecording::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + mRecorder->RecordEvent(RecordedDrawFilter(this, aNode, aSourceRect, aDestPoint, aOptions)); + mFinalDT->DrawFilter(GetFilterNode(aNode), aSourceRect, aDestPoint, aOptions); +} + +TemporaryRef +DrawTargetRecording::CreateFilter(FilterType aType) +{ + RefPtr node = mFinalDT->CreateFilter(aType); + + RefPtr retNode = new FilterNodeRecording(node, mRecorder); + + mRecorder->RecordEvent(RecordedFilterNodeCreation(retNode, aType)); + + return retNode.forget(); +} + void DrawTargetRecording::ClearRect(const Rect &aRect) { @@ -346,7 +473,7 @@ DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData, mRecorder->RecordEvent(RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat)); - return retSurf; + return retSurf.forget(); } TemporaryRef @@ -379,7 +506,7 @@ DrawTargetRecording::OptimizeSourceSurface(SourceSurface *aSurface) const dataSurf->GetSize(), dataSurf->GetFormat())); } - return retSurf; + return retSurf.forget(); } TemporaryRef @@ -407,17 +534,14 @@ DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface &a dataSurf->GetSize(), dataSurf->GetFormat())); } - return retSurf; + return retSurf.forget(); } TemporaryRef DrawTargetRecording::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const { RefPtr dt = mFinalDT->CreateSimilarDrawTarget(aSize, aFormat); - - RefPtr retDT = new DrawTargetRecording(mRecorder.get(), dt); - - return retDT; + return new DrawTargetRecording(mRecorder.get(), dt); } TemporaryRef @@ -438,7 +562,7 @@ DrawTargetRecording::CreateGradientStops(GradientStop *aStops, mRecorder->RecordEvent(RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode)); - return retStops; + return retStops.forget(); } void @@ -453,7 +577,7 @@ void DrawTargetRecording::EnsureStored(const Path *aPath) { if (!mRecorder->HasStoredPath(aPath)) { - if (aPath->GetBackendType() != BACKEND_RECORDING) { + if (aPath->GetBackendType() != BackendType::RECORDING) { gfxWarning() << "Cannot record this fill path properly!"; } else { PathRecording *recPath = const_cast(static_cast(aPath)); diff --git a/libazure/src/gfx/2d/DrawTargetRecording.h b/libazure/DrawTargetRecording.h similarity index 91% rename from libazure/src/gfx/2d/DrawTargetRecording.h rename to libazure/DrawTargetRecording.h index b74b78a..9bb8836 100644 --- a/libazure/src/gfx/2d/DrawTargetRecording.h +++ b/libazure/DrawTargetRecording.h @@ -15,10 +15,12 @@ namespace gfx { class DrawTargetRecording : public DrawTarget { public: - DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetRecording) + DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData = false); ~DrawTargetRecording(); - virtual BackendType GetType() const { return mFinalDT->GetType(); } + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mFinalDT->GetType(); } + virtual BackendType GetBackendType() const { return mFinalDT->GetBackendType(); } virtual TemporaryRef Snapshot(); @@ -47,6 +49,11 @@ class DrawTargetRecording : public DrawTarget const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + /* * Blend a surface to the draw target with a shadow. The shadow is drawn as a * gaussian blur using a specified sigma. The shadow is clipped to the size @@ -157,7 +164,7 @@ class DrawTargetRecording : public DrawTarget const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aOptions = DrawOptions(), - const GlyphRenderingOptions *aRenderingOptions = NULL); + const GlyphRenderingOptions *aRenderingOptions = nullptr); /* * This takes a source pattern and a mask, and composites the source pattern @@ -172,6 +179,11 @@ class DrawTargetRecording : public DrawTarget const Pattern &aMask, const DrawOptions &aOptions = DrawOptions()); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + /* * Push a clip to the DrawTarget. * @@ -231,7 +243,7 @@ class DrawTargetRecording : public DrawTarget * ID2D1SimplifiedGeometrySink requires the fill mode * to be set before calling BeginFigure(). */ - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; /* * Create a GradientStops object that holds information about a set of @@ -246,7 +258,9 @@ class DrawTargetRecording : public DrawTarget virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode = EXTEND_CLAMP) const; + ExtendMode aExtendMode = ExtendMode::CLAMP) const; + + virtual TemporaryRef CreateFilter(FilterType aType); /* * Set a transform on the surface, this transform is applied at drawing time diff --git a/libazure/DrawTargetSkia.cpp b/libazure/DrawTargetSkia.cpp new file mode 100644 index 0000000..9354786 --- /dev/null +++ b/libazure/DrawTargetSkia.cpp @@ -0,0 +1,977 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DrawTargetSkia.h" +#ifdef USE_CAIRO +#include "SourceSurfaceCairo.h" +#endif +#include "SourceSurfaceSkia.h" +#include "ScaledFontBase.h" +#include "ScaledFontCairo.h" +#include "FilterNodeSoftware.h" + +#include "core/SkDevice.h" +#include "core/SkTypeface.h" +#include "core/SkBitmapDevice.h" +#include "gpu/SkGpuDevice.h" +#include "effects/SkGradientShader.h" +#include "effects/SkBlurDrawLooper.h" +#include "effects/SkBlurMaskFilter.h" +#include "effects/SkDropShadowImageFilter.h" +#include "core/SkColorFilter.h" +#include "effects/SkLayerRasterizer.h" +#include "effects/SkLayerDrawLooper.h" +#include "effects/SkDashPathEffect.h" +#include "Logging.h" +#include "Tools.h" +#include "DataSurfaceHelpers.h" +#include + +#ifdef USE_SKIA_GPU +#include "gpu/SkGpuDevice.h" +#include "gpu/gl/GrGLInterface.h" +#endif + +using namespace std; + +namespace mozilla { +namespace gfx { + +class GradientStopsSkia : public GradientStops +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsSkia) + GradientStopsSkia(const std::vector& aStops, uint32_t aNumStops, ExtendMode aExtendMode) + : mCount(aNumStops) + , mExtendMode(aExtendMode) + { + if (mCount == 0) { + return; + } + + // Skia gradients always require a stop at 0.0 and 1.0, insert these if + // we don't have them. + uint32_t shift = 0; + if (aStops[0].offset != 0) { + mCount++; + shift = 1; + } + if (aStops[aNumStops-1].offset != 1) { + mCount++; + } + mColors.resize(mCount); + mPositions.resize(mCount); + if (aStops[0].offset != 0) { + mColors[0] = ColorToSkColor(aStops[0].color, 1.0); + mPositions[0] = 0; + } + for (uint32_t i = 0; i < aNumStops; i++) { + mColors[i + shift] = ColorToSkColor(aStops[i].color, 1.0); + mPositions[i + shift] = SkFloatToScalar(aStops[i].offset); + } + if (aStops[aNumStops-1].offset != 1) { + mColors[mCount-1] = ColorToSkColor(aStops[aNumStops-1].color, 1.0); + mPositions[mCount-1] = SK_Scalar1; + } + } + + BackendType GetBackendType() const { return BackendType::SKIA; } + + std::vector mColors; + std::vector mPositions; + int mCount; + ExtendMode mExtendMode; +}; + +inline static ostream& +operator <<(ostream& aStream, const DrawTargetSkia& aDrawTarget) +{ + aStream << "DrawTargetSkia (" << &aDrawTarget << ")"; + return aStream; +} + +/** + * When constructing a temporary SkBitmap via GetBitmapForSurface, we may also + * have to construct a temporary DataSourceSurface, which must live as long as + * the SkBitmap. So we return a pair of the SkBitmap and the (optional) + * temporary surface. + */ +struct TempBitmap +{ + SkBitmap mBitmap; + RefPtr mTmpSurface; +}; + +static TempBitmap +GetBitmapForSurface(SourceSurface* aSurface) +{ + TempBitmap result; + + if (aSurface->GetType() == SurfaceType::SKIA) { + result.mBitmap = static_cast(aSurface)->GetBitmap(); + return result; + } + + RefPtr surf = aSurface->GetDataSurface(); + if (!surf) { + MOZ_CRASH("Non-skia SourceSurfaces need to be DataSourceSurfaces"); + } + + SkAlphaType alphaType = (surf->GetFormat() == SurfaceFormat::B8G8R8X8) ? + kOpaque_SkAlphaType : kPremul_SkAlphaType; + + SkImageInfo info = SkImageInfo::Make(surf->GetSize().width, + surf->GetSize().height, + GfxFormatToSkiaColorType(surf->GetFormat()), + alphaType); + result.mBitmap.setInfo(info, surf->Stride()); + + result.mBitmap.setPixels(surf->GetData()); + result.mTmpSurface = surf.forget(); + return result; +} + +DrawTargetSkia::DrawTargetSkia() + : mTexture(0), mSnapshot(nullptr) +{ +} + +DrawTargetSkia::~DrawTargetSkia() +{ +} + +TemporaryRef +DrawTargetSkia::Snapshot() +{ + RefPtr snapshot = mSnapshot; + if (!snapshot) { + snapshot = new SourceSurfaceSkia(); + mSnapshot = snapshot; + if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this)) + return nullptr; + } + + return snapshot.forget(); +} + +static void +SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap, + Float aAlpha = 1.0) +{ + switch (aPattern.GetType()) { + case PatternType::COLOR: { + Color color = static_cast(aPattern).mColor; + aPaint.setColor(ColorToSkColor(color, aAlpha)); + break; + } + case PatternType::LINEAR_GRADIENT: { + const LinearGradientPattern& pat = static_cast(aPattern); + GradientStopsSkia *stops = static_cast(pat.mStops.get()); + SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); + + if (stops->mCount >= 2) { + SkPoint points[2]; + points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y)); + points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y)); + + SkShader* shader = SkGradientShader::CreateLinear(points, + &stops->mColors.front(), + &stops->mPositions.front(), + stops->mCount, + mode); + + if (shader) { + SkMatrix mat; + GfxMatrixToSkiaMatrix(pat.mMatrix, mat); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); + } + + } else { + aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); + } + break; + } + case PatternType::RADIAL_GRADIENT: { + const RadialGradientPattern& pat = static_cast(aPattern); + GradientStopsSkia *stops = static_cast(pat.mStops.get()); + SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); + + if (stops->mCount >= 2) { + SkPoint points[2]; + points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y)); + points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y)); + + SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0], + SkFloatToScalar(pat.mRadius1), + points[1], + SkFloatToScalar(pat.mRadius2), + &stops->mColors.front(), + &stops->mPositions.front(), + stops->mCount, + mode); + if (shader) { + SkMatrix mat; + GfxMatrixToSkiaMatrix(pat.mMatrix, mat); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); + } + + } else { + aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); + } + break; + } + case PatternType::SURFACE: { + const SurfacePattern& pat = static_cast(aPattern); + aTmpBitmap = GetBitmapForSurface(pat.mSurface); + SkBitmap& bitmap = aTmpBitmap.mBitmap; + + SkMatrix mat; + GfxMatrixToSkiaMatrix(pat.mMatrix, mat); + + if (!pat.mSamplingRect.IsEmpty()) { + SkIRect rect = IntRectToSkIRect(pat.mSamplingRect); + bitmap.extractSubset(&bitmap, rect); + mat.preTranslate(rect.x(), rect.y()); + } + + SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode); + SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); + if (pat.mFilter == Filter::POINT) { + aPaint.setFilterLevel(SkPaint::kNone_FilterLevel); + } + break; + } + } +} + +static inline Rect +GetClipBounds(SkCanvas *aCanvas) +{ + SkRect clipBounds; + aCanvas->getClipBounds(&clipBounds); + return SkRectToRect(clipBounds); +} + +struct AutoPaintSetup { + AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern, const Rect* aMaskBounds = nullptr) + : mNeedsRestore(false), mAlpha(1.0) + { + Init(aCanvas, aOptions, aMaskBounds); + SetPaintPattern(mPaint, aPattern, mTmpBitmap, mAlpha); + } + + AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr) + : mNeedsRestore(false), mAlpha(1.0) + { + Init(aCanvas, aOptions, aMaskBounds); + } + + ~AutoPaintSetup() + { + if (mNeedsRestore) { + mCanvas->restore(); + } + } + + void Init(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds) + { + mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); + mCanvas = aCanvas; + + //TODO: Can we set greyscale somehow? + if (aOptions.mAntialiasMode != AntialiasMode::NONE) { + mPaint.setAntiAlias(true); + } else { + mPaint.setAntiAlias(false); + } + + Rect clipBounds = GetClipBounds(aCanvas); + bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) && + (!aMaskBounds || !aMaskBounds->Contains(clipBounds)); + + // TODO: We could skip the temporary for operator_source and just + // clear the clip rect. The other operators would be harder + // but could be worth it to skip pushing a group. + if (needsGroup) { + mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + SkPaint temp; + temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); + temp.setAlpha(ColorFloatToByte(aOptions.mAlpha)); + //TODO: Get a rect here + mCanvas->saveLayer(nullptr, &temp); + mNeedsRestore = true; + } else { + mPaint.setAlpha(ColorFloatToByte(aOptions.mAlpha)); + mAlpha = aOptions.mAlpha; + } + mPaint.setFilterLevel(SkPaint::kLow_FilterLevel); + } + + // TODO: Maybe add an operator overload to access this easier? + SkPaint mPaint; + TempBitmap mTmpBitmap; + bool mNeedsRestore; + SkCanvas* mCanvas; + Float mAlpha; +}; + +void +DrawTargetSkia::Flush() +{ + mCanvas->flush(); +} + +void +DrawTargetSkia::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + if (aSource.IsEmpty()) { + return; + } + + MarkChanged(); + + SkRect destRect = RectToSkRect(aDest); + SkRect sourceRect = RectToSkRect(aSource); + + TempBitmap bitmap = GetBitmapForSurface(aSurface); + + AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest); + if (aSurfOptions.mFilter == Filter::POINT) { + paint.mPaint.setFilterLevel(SkPaint::kNone_FilterLevel); + } + + mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint); +} + +DrawTargetType +DrawTargetSkia::GetType() const +{ +#ifdef USE_SKIA_GPU + if (mGrContext) { + return DrawTargetType::HARDWARE_RASTER; + } +#endif + return DrawTargetType::SOFTWARE_RASTER; +} + +void +DrawTargetSkia::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + FilterNodeSoftware* filter = static_cast(aNode); + filter->Draw(this, aSourceRect, aDestPoint, aOptions); +} + +void +DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) +{ + if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) { + return; + } + + MarkChanged(); + + mCanvas->save(); + mCanvas->resetMatrix(); + + TempBitmap bitmap = GetBitmapForSurface(aSurface); + + SkPaint paint; + + SkImageFilter* filter = SkDropShadowImageFilter::Create(aOffset.x, aOffset.y, + aSigma, aSigma, + ColorToSkColor(aColor, 1.0)); + + paint.setImageFilter(filter); + paint.setXfermodeMode(GfxOpToSkiaOp(aOperator)); + + mCanvas->drawBitmap(bitmap.mBitmap, aDest.x, aDest.y, &paint); + mCanvas->restore(); +} + +void +DrawTargetSkia::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + MarkChanged(); + SkRect rect = RectToSkRect(aRect); + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern, &aRect); + + mCanvas->drawRect(rect, paint.mPaint); +} + +void +DrawTargetSkia::Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + MarkChanged(); + MOZ_ASSERT(aPath, "Null path"); + if (aPath->GetBackendType() != BackendType::SKIA) { + return; + } + + const PathSkia *skiaPath = static_cast(aPath); + + + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { + return; + } + + mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); +} + +void +DrawTargetSkia::StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + MarkChanged(); + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { + return; + } + + mCanvas->drawRect(RectToSkRect(aRect), paint.mPaint); +} + +void +DrawTargetSkia::StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + MarkChanged(); + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { + return; + } + + mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y), + SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y), + paint.mPaint); +} + +void +DrawTargetSkia::Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + MarkChanged(); + if (aPath->GetBackendType() != BackendType::SKIA) { + return; + } + + const PathSkia *skiaPath = static_cast(aPath); + + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + + mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); +} + +void +DrawTargetSkia::FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions, + const GlyphRenderingOptions *aRenderingOptions) +{ + if (aFont->GetType() != FontType::MAC && + aFont->GetType() != FontType::SKIA && + aFont->GetType() != FontType::GDI) { + return; + } + + MarkChanged(); + + ScaledFontBase* skiaFont = static_cast(aFont); + + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + paint.mPaint.setTypeface(skiaFont->GetSkTypeface()); + paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize)); + paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + if (aRenderingOptions && aRenderingOptions->GetType() == FontType::CAIRO) { + switch (static_cast(aRenderingOptions)->GetHinting()) { + case FontHinting::NONE: + paint.mPaint.setHinting(SkPaint::kNo_Hinting); + break; + case FontHinting::LIGHT: + paint.mPaint.setHinting(SkPaint::kSlight_Hinting); + break; + case FontHinting::NORMAL: + paint.mPaint.setHinting(SkPaint::kNormal_Hinting); + break; + case FontHinting::FULL: + paint.mPaint.setHinting(SkPaint::kFull_Hinting); + break; + } + + if (static_cast(aRenderingOptions)->GetAutoHinting()) { + paint.mPaint.setAutohinted(true); + } + } else { + paint.mPaint.setHinting(SkPaint::kNormal_Hinting); + } + + std::vector indices; + std::vector offsets; + indices.resize(aBuffer.mNumGlyphs); + offsets.resize(aBuffer.mNumGlyphs); + + for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { + indices[i] = aBuffer.mGlyphs[i].mIndex; + offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x); + offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y); + } + + mCanvas->drawPosText(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), paint.mPaint); +} + +void +DrawTargetSkia::Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions) +{ + MarkChanged(); + AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); + + SkPaint maskPaint; + TempBitmap tmpBitmap; + SetPaintPattern(maskPaint, aMask, tmpBitmap); + + SkLayerRasterizer::Builder builder; + builder.addLayer(maskPaint); + SkAutoTUnref raster(builder.detachRasterizer()); + paint.mPaint.setRasterizer(raster.get()); + + mCanvas->drawRect(SkRectCoveringWholeSurface(), paint.mPaint); +} + +void +DrawTargetSkia::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + MarkChanged(); + AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); + + TempBitmap bitmap = GetBitmapForSurface(aMask); + if (bitmap.mBitmap.colorType() == kAlpha_8_SkColorType) { + mCanvas->drawBitmap(bitmap.mBitmap, aOffset.x, aOffset.y, &paint.mPaint); + } else { + SkPaint maskPaint; + TempBitmap tmpBitmap; + SetPaintPattern(maskPaint, SurfacePattern(aMask, ExtendMode::CLAMP), tmpBitmap); + + SkMatrix transform = maskPaint.getShader()->getLocalMatrix(); + transform.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(maskPaint.getShader(), transform); + SkSafeUnref(maskPaint.setShader(matrixShader)); + + SkLayerRasterizer::Builder builder; + builder.addLayer(maskPaint); + SkAutoTUnref raster(builder.detachRasterizer()); + paint.mPaint.setRasterizer(raster.get()); + + IntSize size = aMask->GetSize(); + Rect rect = Rect(aOffset.x, aOffset.y, size.width, size.height); + mCanvas->drawRect(RectToSkRect(rect), paint.mPaint); + } +} + +TemporaryRef +DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr newSurf = new SourceSurfaceSkia(); + + if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { + gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize; + return nullptr; + } + + return newSurf.forget(); +} + +TemporaryRef +DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + RefPtr target = new DrawTargetSkia(); + if (!target->Init(aSize, aFormat)) { + return nullptr; + } + return target.forget(); +} + +bool +DrawTargetSkia::UsingSkiaGPU() const +{ +#ifdef USE_SKIA_GPU + return !!mTexture; +#else + return false; +#endif +} + +TemporaryRef +DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + if (aSurface->GetType() == SurfaceType::SKIA) { + return aSurface; + } + + if (!UsingSkiaGPU()) { + // If we're not using skia-gl then drawing doesn't require any + // uploading, so any data surface is fine. Call GetDataSurface + // to trigger any required readback so that it only happens + // once. + return aSurface->GetDataSurface(); + } + + // If we are using skia-gl then we want to copy into a surface that + // will cache the uploaded gl texture. + RefPtr dataSurf = aSurface->GetDataSurface(); + DataSourceSurface::MappedSurface map; + if (!dataSurf->Map(DataSourceSurface::READ, &map)) { + return nullptr; + } + + RefPtr result = CreateSourceSurfaceFromData(map.mData, + dataSurf->GetSize(), + map.mStride, + dataSurf->GetFormat()); + dataSurf->Unmap(); + return result.forget(); +} + +TemporaryRef +DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const +{ +#ifdef USE_CAIRO + if (aSurface.mType == NativeSurfaceType::CAIRO_SURFACE) { + if (aSurface.mSize.width <= 0 || + aSurface.mSize.height <= 0) { + gfxWarning() << "Can't create a SourceSurface without a valid size"; + return nullptr; + } + cairo_surface_t* surf = static_cast(aSurface.mSurface); + return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat); + } +#endif + + return nullptr; +} + +void +DrawTargetSkia::CopySurface(SourceSurface *aSurface, + const IntRect& aSourceRect, + const IntPoint &aDestination) +{ + //TODO: We could just use writePixels() here if the sourceRect is the entire source + + if (aSurface->GetType() != SurfaceType::SKIA && aSurface->GetType() != SurfaceType::DATA) { + return; + } + + MarkChanged(); + + TempBitmap bitmap = GetBitmapForSurface(aSurface); + + // This is a fast path that is disabled for now to mimimize risk + if (false && !bitmap.mBitmap.getTexture() && mCanvas->imageInfo() == bitmap.mBitmap.info()) { + SkBitmap bm(bitmap.mBitmap); + bm.lockPixels(); + if (bm.getPixels()) { + SkImageInfo info = bm.info(); + info.fWidth = aSourceRect.width; + info.fHeight = aSourceRect.height; + uint8_t* pixels = static_cast(bm.getPixels()); + // adjust pixels for the source offset + pixels += aSourceRect.x + aSourceRect.y*bm.rowBytes(); + mCanvas->writePixels(info, pixels, bm.rowBytes(), aDestination.x, aDestination.y); + return; + } + } + + mCanvas->save(); + mCanvas->resetMatrix(); + SkRect dest = IntRectToSkRect(IntRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height)); + SkIRect source = IntRectToSkIRect(aSourceRect); + mCanvas->clipRect(dest, SkRegion::kReplace_Op); + SkPaint paint; + + if (mCanvas->imageInfo().colorType() == kRGB_565_SkColorType) { + // Set the xfermode to SOURCE_OVER to workaround + // http://code.google.com/p/skia/issues/detail?id=628 + // RGB565 is opaque so they're equivalent anyway + paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + } else { + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + } + // drawBitmapRect with A8 bitmaps ends up doing a mask operation + // so we need to clear before + if (bitmap.mBitmap.colorType() == kAlpha_8_SkColorType) { + SkPaint clearPaint; + clearPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); + clearPaint.setXfermodeMode(SkXfermode::kSrc_Mode); + mCanvas->drawPaint(clearPaint); + } + mCanvas->drawBitmapRect(bitmap.mBitmap, &source, dest, &paint); + mCanvas->restore(); +} + +bool +DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) +{ + SkAlphaType alphaType = (aFormat == SurfaceFormat::B8G8R8X8) ? + kOpaque_SkAlphaType : kPremul_SkAlphaType; + + SkImageInfo skiInfo = SkImageInfo::Make( + aSize.width, aSize.height, + GfxFormatToSkiaColorType(aFormat), + alphaType); + + SkAutoTUnref device(SkBitmapDevice::Create(skiInfo)); + if (!device) { + return false; + } + + SkBitmap bitmap = device->accessBitmap(true); + if (!bitmap.allocPixels()) { + return false; + } + + bitmap.eraseARGB(0, 0, 0, 0); + + mCanvas.adopt(new SkCanvas(device.get())); + mSize = aSize; + + mFormat = aFormat; + return true; +} + +#ifdef USE_SKIA_GPU +bool +DrawTargetSkia::InitWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat) +{ + MOZ_ASSERT(aGrContext, "null GrContext"); + + mGrContext = aGrContext; + mSize = aSize; + mFormat = aFormat; + + GrTextureDesc targetDescriptor; + + targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit; + targetDescriptor.fWidth = mSize.width; + targetDescriptor.fHeight = mSize.height; + targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat); + targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin; + targetDescriptor.fSampleCnt = 0; + + SkAutoTUnref skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0)); + if (!skiaTexture) { + return false; + } + + mTexture = (uint32_t)skiaTexture->getTextureHandle(); + + SkAutoTUnref device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget())); + mCanvas.adopt(new SkCanvas(device.get())); + + return true; + +} + +bool +DrawTargetSkia::InitWithGrContextAndFBO(GrContext* aGrContext, + unsigned int aFBOID, + const IntSize &aSize, + SurfaceFormat aFormat) +{ + GrBackendRenderTargetDesc targetDescriptor; + + targetDescriptor.fWidth = aSize.width; + targetDescriptor.fHeight = aSize.height; + targetDescriptor.fConfig = GfxFormatToGrConfig(aFormat); + targetDescriptor.fSampleCnt = 0; + targetDescriptor.fRenderTargetHandle = aFBOID; + + mGrContext = aGrContext; + mSize = aSize; + mFormat = aFormat; + + SkAutoTUnref target(mGrContext->wrapBackendRenderTarget(targetDescriptor)); + SkAutoTUnref device(new SkGpuDevice(aGrContext, target.get())); + mCanvas.adopt(new SkCanvas(device.get())); + + return true; +} + +#endif + +void +DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) +{ + SkAlphaType alphaType = kPremul_SkAlphaType; + if (aFormat == SurfaceFormat::B8G8R8X8) { + // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX + ConvertBGRXToBGRA(aData, aSize, aStride); + alphaType = kOpaque_SkAlphaType; + } + + SkBitmap bitmap; + + SkImageInfo info = SkImageInfo::Make(aSize.width, + aSize.height, + GfxFormatToSkiaColorType(aFormat), + alphaType); + bitmap.setInfo(info, aStride); + bitmap.setPixels(aData); + mCanvas.adopt(new SkCanvas(new SkBitmapDevice(bitmap))); + + mSize = aSize; + mFormat = aFormat; +} + +void +DrawTargetSkia::SetTransform(const Matrix& aTransform) +{ + SkMatrix mat; + GfxMatrixToSkiaMatrix(aTransform, mat); + mCanvas->setMatrix(mat); + mTransform = aTransform; +} + +void* +DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType) +{ + if (aType == NativeSurfaceType::OPENGL_TEXTURE) { + return (void*)((uintptr_t)mTexture); + } + + return nullptr; +} + + +TemporaryRef +DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const +{ + return new PathBuilderSkia(aFillRule); +} + +void +DrawTargetSkia::ClearRect(const Rect &aRect) +{ + MarkChanged(); + SkPaint paint; + mCanvas->save(); + mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, true); + paint.setColor(SkColorSetARGB(0, 0, 0, 0)); + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + mCanvas->drawPaint(paint); + mCanvas->restore(); +} + +void +DrawTargetSkia::PushClip(const Path *aPath) +{ + if (aPath->GetBackendType() != BackendType::SKIA) { + return; + } + + const PathSkia *skiaPath = static_cast(aPath); + mCanvas->save(); + mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, true); +} + +void +DrawTargetSkia::PushClipRect(const Rect& aRect) +{ + SkRect rect = RectToSkRect(aRect); + + mCanvas->save(); + mCanvas->clipRect(rect, SkRegion::kIntersect_Op, true); +} + +void +DrawTargetSkia::PopClip() +{ + mCanvas->restore(); +} + +TemporaryRef +DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const +{ + std::vector stops; + stops.resize(aNumStops); + for (uint32_t i = 0; i < aNumStops; i++) { + stops[i] = aStops[i]; + } + std::stable_sort(stops.begin(), stops.end()); + + return new GradientStopsSkia(stops, aNumStops, aExtendMode); +} + +TemporaryRef +DrawTargetSkia::CreateFilter(FilterType aType) +{ + return FilterNodeSoftware::Create(aType); +} + +void +DrawTargetSkia::MarkChanged() +{ + if (mSnapshot) { + mSnapshot->DrawTargetWillChange(); + mSnapshot = nullptr; + } +} + +// Return a rect (in user space) that covers the entire surface by applying +// the inverse of GetTransform() to (0, 0, mSize.width, mSize.height). +SkRect +DrawTargetSkia::SkRectCoveringWholeSurface() const +{ + return RectToSkRect(mTransform.TransformBounds(Rect(0, 0, mSize.width, mSize.height))); +} + +void +DrawTargetSkia::SnapshotDestroyed() +{ + mSnapshot = nullptr; +} + +} +} diff --git a/libazure/src/gfx/2d/DrawTargetSkia.h b/libazure/DrawTargetSkia.h similarity index 71% rename from libazure/src/gfx/2d/DrawTargetSkia.h rename to libazure/DrawTargetSkia.h index 02f315b..8153b4b 100644 --- a/libazure/src/gfx/2d/DrawTargetSkia.h +++ b/libazure/DrawTargetSkia.h @@ -3,16 +3,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#pragma once +#ifndef _MOZILLA_GFX_SOURCESURFACESKIA_H +#define _MOZILLA_GFX_SOURCESURFACESKIA_H #ifdef USE_SKIA_GPU -#include "GrContext.h" -#include "GrGLInterface.h" +#include "gpu/GrContext.h" +#include "gpu/gl/GrGLInterface.h" #endif -#include "SkCanvas.h" +#include "core/SkCanvas.h" #include "2D.h" +#include "HelpersSkia.h" #include "Rect.h" #include "PathSkia.h" #include @@ -26,10 +28,12 @@ class SourceSurfaceSkia; class DrawTargetSkia : public DrawTarget { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetSkia) DrawTargetSkia(); virtual ~DrawTargetSkia(); - virtual BackendType GetType() const { return BACKEND_SKIA; } + virtual DrawTargetType GetType() const MOZ_OVERRIDE; + virtual BackendType GetBackendType() const { return BackendType::SKIA; } virtual TemporaryRef Snapshot(); virtual IntSize GetSize() { return mSize; } virtual void Flush(); @@ -38,6 +42,10 @@ class DrawTargetSkia : public DrawTarget const Rect &aSource, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, @@ -75,6 +83,10 @@ class DrawTargetSkia : public DrawTarget virtual void Mask(const Pattern &aSource, const Pattern &aMask, const DrawOptions &aOptions = DrawOptions()); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); virtual void PushClip(const Path *aPath); virtual void PushClipRect(const Rect& aRect); virtual void PopClip(); @@ -87,34 +99,52 @@ class DrawTargetSkia : public DrawTarget CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const; virtual TemporaryRef CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const; - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const; - virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = EXTEND_CLAMP) const; + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; + virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = ExtendMode::CLAMP) const; + virtual TemporaryRef CreateFilter(FilterType aType); virtual void SetTransform(const Matrix &aTransform); + virtual void *GetNativeSurface(NativeSurfaceType aType); bool Init(const IntSize &aSize, SurfaceFormat aFormat); void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat); + #ifdef USE_SKIA_GPU - void InitWithFBO(unsigned int aFBOID, GrContext* aGrContext, const IntSize &aSize, SurfaceFormat aFormat); + bool InitWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat) MOZ_OVERRIDE; + bool InitWithGrContextAndFBO(GrContext* aGrContext, + unsigned int aFBOID, + const IntSize &aSize, + SurfaceFormat aFormat) MOZ_OVERRIDE; #endif - + operator std::string() const { std::stringstream stream; stream << "DrawTargetSkia(" << this << ")"; return stream.str(); } + private: friend class SourceSurfaceSkia; - void AppendSnapshot(SourceSurfaceSkia* aSnapshot); - void RemoveSnapshot(SourceSurfaceSkia* aSnapshot); + void SnapshotDestroyed(); void MarkChanged(); + SkRect SkRectCoveringWholeSurface() const; + + bool UsingSkiaGPU() const; + +#ifdef USE_SKIA_GPU + RefPtrSkia mGrContext; + uint32_t mTexture; +#endif + IntSize mSize; - SkBitmap mBitmap; - SkRefPtr mCanvas; - SkRefPtr mDevice; - std::vector mSnapshots; + RefPtrSkia mCanvas; + SourceSurfaceSkia* mSnapshot; }; } } + +#endif // _MOZILLA_GFX_SOURCESURFACESKIA_H diff --git a/libazure/DrawTargetTiled.cpp b/libazure/DrawTargetTiled.cpp new file mode 100644 index 0000000..463d5a5 --- /dev/null +++ b/libazure/DrawTargetTiled.cpp @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define _USE_MATH_DEFINES +#include + +#include "DrawTargetTiled.h" +#include "Logging.h" + +using namespace std; + +namespace mozilla { +namespace gfx { + +DrawTargetTiled::DrawTargetTiled() +{ +} + +bool +DrawTargetTiled::Init(const TileSet& aTiles) +{ + if (!aTiles.mTileCount) { + return false; + } + + mTiles.reserve(aTiles.mTileCount); + for (size_t i = 0; i < aTiles.mTileCount; ++i) { + mTiles.push_back(TileInternal(aTiles.mTiles[i])); + if (!aTiles.mTiles[i].mDrawTarget) { + return false; + } + if (mTiles[0].mDrawTarget->GetFormat() != mTiles.back().mDrawTarget->GetFormat() || + mTiles[0].mDrawTarget->GetBackendType() != mTiles.back().mDrawTarget->GetBackendType()) { + return false; + } + uint32_t newXMost = max(mRect.XMost(), + mTiles[i].mTileOrigin.x + mTiles[i].mDrawTarget->GetSize().width); + uint32_t newYMost = max(mRect.YMost(), + mTiles[i].mTileOrigin.y + mTiles[i].mDrawTarget->GetSize().height); + mRect.x = min(mRect.x, mTiles[i].mTileOrigin.x); + mRect.y = min(mRect.y, mTiles[i].mTileOrigin.y); + mRect.width = newXMost - mRect.x; + mRect.height = newYMost - mRect.y; + } + mFormat = mTiles[0].mDrawTarget->GetFormat(); + return true; +} + +TemporaryRef +DrawTargetTiled::Snapshot() +{ + return new SnapshotTiled(mTiles, mRect); +} + +// Skip the mClippedOut check since this is only used for Flush() which +// should happen even if we're clipped. +#define TILED_COMMAND(command) \ + void \ + DrawTargetTiled::command() \ + { \ + for (size_t i = 0; i < mTiles.size(); i++) { \ + mTiles[i].mDrawTarget->command(); \ + } \ + } +#define TILED_COMMAND1(command, type1) \ + void \ + DrawTargetTiled::command(type1 arg1) \ + { \ + for (size_t i = 0; i < mTiles.size(); i++) { \ + if (!mTiles[i].mClippedOut) \ + mTiles[i].mDrawTarget->command(arg1); \ + } \ + } +#define TILED_COMMAND3(command, type1, type2, type3) \ + void \ + DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3) \ + { \ + for (size_t i = 0; i < mTiles.size(); i++) { \ + if (!mTiles[i].mClippedOut) \ + mTiles[i].mDrawTarget->command(arg1, arg2, arg3); \ + } \ + } +#define TILED_COMMAND4(command, type1, type2, type3, type4) \ + void \ + DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ + { \ + for (size_t i = 0; i < mTiles.size(); i++) { \ + if (!mTiles[i].mClippedOut) \ + mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4); \ + } \ + } +#define TILED_COMMAND5(command, type1, type2, type3, type4, type5) \ + void \ + DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ + { \ + for (size_t i = 0; i < mTiles.size(); i++) { \ + if (!mTiles[i].mClippedOut) \ + mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4, arg5); \ + } \ + } + +TILED_COMMAND(Flush) +TILED_COMMAND4(DrawFilter, FilterNode*, const Rect&, const Point&, const DrawOptions&) +TILED_COMMAND1(ClearRect, const Rect&) +TILED_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point, const DrawOptions&) +TILED_COMMAND4(StrokeRect, const Rect&, const Pattern&, const StrokeOptions&, const DrawOptions&) +TILED_COMMAND5(StrokeLine, const Point&, const Point&, const Pattern&, const StrokeOptions&, const DrawOptions&) +TILED_COMMAND5(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&, const GlyphRenderingOptions*) +TILED_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&) + +void +DrawTargetTiled::PushClip(const Path* aPath) +{ + mClippedOutTilesStack.push_back(std::vector()); + std::vector& clippedTiles = mClippedOutTilesStack.back(); + + Rect deviceRect = aPath->GetBounds(mTransform); + + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut) { + if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->PushClip(aPath); + } else { + mTiles[i].mClippedOut = true; + clippedTiles.push_back(i); + } + } + } +} + +void +DrawTargetTiled::PushClipRect(const Rect& aRect) +{ + mClippedOutTilesStack.push_back(std::vector()); + std::vector& clippedTiles = mClippedOutTilesStack.back(); + + Rect deviceRect = mTransform.TransformBounds(aRect); + + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut) { + if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->PushClipRect(aRect); + } else { + mTiles[i].mClippedOut = true; + clippedTiles.push_back(i); + } + } + } +} + +void +DrawTargetTiled::PopClip() +{ + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut) { + mTiles[i].mDrawTarget->PopClip(); + } + } + + std::vector& clippedTiles = mClippedOutTilesStack.back(); + for (size_t i = 0; i < clippedTiles.size(); i++) { + mTiles[clippedTiles[i]].mClippedOut = false; + } + + mClippedOutTilesStack.pop_back(); +} + +void +DrawTargetTiled::CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) +{ + // CopySurface ignores the transform, account for that here. + for (size_t i = 0; i < mTiles.size(); i++) { + IntRect src = aSourceRect; + src.x += mTiles[i].mTileOrigin.x; + src.width -= mTiles[i].mTileOrigin.x; + src.y = mTiles[i].mTileOrigin.y; + src.height -= mTiles[i].mTileOrigin.y; + + if (src.width <= 0 || src.height <= 0) { + continue; + } + + mTiles[i].mDrawTarget->CopySurface(aSurface, src, aDestination); + } +} + +void +DrawTargetTiled::SetTransform(const Matrix& aTransform) +{ + for (size_t i = 0; i < mTiles.size(); i++) { + Matrix mat = aTransform; + mat.PostTranslate(Float(-mTiles[i].mTileOrigin.x), Float(-mTiles[i].mTileOrigin.y)); + mTiles[i].mDrawTarget->SetTransform(mat); + } + DrawTarget::SetTransform(aTransform); +} + +void +DrawTargetTiled::DrawSurface(SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, const DrawSurfaceOptions& aSurfaceOptions, const DrawOptions& aDrawOptions) +{ + Rect deviceRect = mTransform.TransformBounds(aDest); + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut && + deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->DrawSurface(aSurface, aDest, aSource, aSurfaceOptions, aDrawOptions); + } + } +} + +void +DrawTargetTiled::FillRect(const Rect& aRect, const Pattern& aPattern, const DrawOptions& aDrawOptions) +{ + Rect deviceRect = mTransform.TransformBounds(aRect); + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut && + deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->FillRect(aRect, aPattern, aDrawOptions); + } + } +} + +// The logic for this comes from _cairo_stroke_style_max_distance_from_path +static Rect +PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions, + const Rect &aRect, + const Matrix &aTransform) +{ + double styleExpansionFactor = 0.5f; + + if (aStrokeOptions.mLineCap == CapStyle::SQUARE) { + styleExpansionFactor = M_SQRT1_2; + } + + if (aStrokeOptions.mLineJoin == JoinStyle::MITER && + styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) { + styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit; + } + + styleExpansionFactor *= aStrokeOptions.mLineWidth; + + double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21); + double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12); + + Rect result = aRect; + result.Inflate(dx, dy); + return result; +} + +void +DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aDrawOptions) +{ + // Approximate the stroke extents, since Path::GetStrokeExtents can be slow + Rect deviceRect = PathExtentsToMaxStrokeExtents(aStrokeOptions, + aPath->GetBounds(mTransform), + mTransform); + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut && + deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->Stroke(aPath, aPattern, aStrokeOptions, aDrawOptions); + } + } +} + +void +DrawTargetTiled::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aDrawOptions) +{ + Rect deviceRect = aPath->GetBounds(mTransform); + for (size_t i = 0; i < mTiles.size(); i++) { + if (!mTiles[i].mClippedOut && + deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x, + mTiles[i].mTileOrigin.y, + mTiles[i].mDrawTarget->GetSize().width, + mTiles[i].mDrawTarget->GetSize().height))) { + mTiles[i].mDrawTarget->Fill(aPath, aPattern, aDrawOptions); + } + } +} + +} +} diff --git a/libazure/DrawTargetTiled.h b/libazure/DrawTargetTiled.h new file mode 100644 index 0000000..7190c98 --- /dev/null +++ b/libazure/DrawTargetTiled.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWTARGETTILED_H_ +#define MOZILLA_GFX_DRAWTARGETTILED_H_ + +#include "2D.h" +#include "Filters.h" + +#include + +namespace mozilla { +namespace gfx { + +struct TileInternal : public Tile { + TileInternal() + : mClippedOut(false) + {} + + explicit TileInternal(const Tile& aOther) + : Tile(aOther) + , mClippedOut(false) + {} + + bool mClippedOut; +}; + + +class DrawTargetTiled : public DrawTarget +{ +public: + DrawTargetTiled(); + + bool Init(const TileSet& mTiles); + + virtual bool IsTiledDrawTarget() const { return true; } + + virtual DrawTargetType GetType() const MOZ_OVERRIDE { return mTiles[0].mDrawTarget->GetType(); } + virtual BackendType GetBackendType() const { return mTiles[0].mDrawTarget->GetBackendType(); } + virtual TemporaryRef Snapshot(); + virtual IntSize GetSize() { return IntSize(mRect.XMost(), mRect.YMost()); } + + virtual void Flush(); + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions); + virtual void DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma, + CompositionOp aOperator) { /* Not implemented */ MOZ_CRASH(); } + + virtual void ClearRect(const Rect &aRect); + virtual void MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions = DrawOptions()); + + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination); + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions(), + const GlyphRenderingOptions *aRenderingOptions = nullptr); + virtual void Mask(const Pattern &aSource, + const Pattern &aMask, + const DrawOptions &aOptions = DrawOptions()); + virtual void PushClip(const Path *aPath); + virtual void PushClipRect(const Rect &aRect); + virtual void PopClip(); + + virtual void SetTransform(const Matrix &aTransform); + + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const + { + return mTiles[0].mDrawTarget->CreateSourceSurfaceFromData(aData, aSize, aStride, aFormat); + } + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const + { + return mTiles[0].mDrawTarget->OptimizeSourceSurface(aSurface); + } + + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const + { + return mTiles[0].mDrawTarget->CreateSourceSurfaceFromNativeSurface(aSurface); + } + + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const + { + return mTiles[0].mDrawTarget->CreateSimilarDrawTarget(aSize, aFormat); + } + + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const + { + return mTiles[0].mDrawTarget->CreatePathBuilder(aFillRule); + } + + virtual TemporaryRef + CreateGradientStops(GradientStop *aStops, + uint32_t aNumStops, + ExtendMode aExtendMode = ExtendMode::CLAMP) const + { + return mTiles[0].mDrawTarget->CreateGradientStops(aStops, aNumStops, aExtendMode); + } + virtual TemporaryRef CreateFilter(FilterType aType) + { + return mTiles[0].mDrawTarget->CreateFilter(aType); + } + +private: + std::vector mTiles; + std::vector > mClippedOutTilesStack; + IntRect mRect; +}; + +class SnapshotTiled : public SourceSurface +{ +public: + SnapshotTiled(const std::vector& aTiles, const IntRect& aRect) + : mRect(aRect) + { + for (size_t i = 0; i < aTiles.size(); i++) { + mSnapshots.push_back(aTiles[i].mDrawTarget->Snapshot()); + mOrigins.push_back(aTiles[i].mTileOrigin); + } + } + + virtual SurfaceType GetType() const { return SurfaceType::TILED; } + virtual IntSize GetSize() const { return IntSize(mRect.XMost(), mRect.YMost()); } + virtual SurfaceFormat GetFormat() const { return mSnapshots[0]->GetFormat(); } + + virtual TemporaryRef GetDataSurface() + { + RefPtr surf = Factory::CreateDataSourceSurface(GetSize(), GetFormat()); + + DataSourceSurface::MappedSurface mappedSurf; + surf->Map(DataSourceSurface::MapType::WRITE, &mappedSurf); + + { + RefPtr dt = + Factory::CreateDrawTargetForData(BackendType::CAIRO, mappedSurf.mData, + GetSize(), mappedSurf.mStride, GetFormat()); + + for (size_t i = 0; i < mSnapshots.size(); i++) { + RefPtr dataSurf = mSnapshots[i]->GetDataSurface(); + dt->CopySurface(dataSurf, IntRect(IntPoint(0, 0), mSnapshots[i]->GetSize()), mOrigins[i]); + } + } + surf->Unmap(); + + return surf.forget(); + } + + std::vector> mSnapshots; + std::vector mOrigins; + IntRect mRect; +}; + +} +} + +#endif diff --git a/libazure/DrawingCommand.h b/libazure/DrawingCommand.h new file mode 100644 index 0000000..c014fca --- /dev/null +++ b/libazure/DrawingCommand.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_DRAWINGCOMMAND_H_ +#define MOZILLA_GFX_DRAWINGCOMMAND_H_ + +#include "2D.h" + +namespace mozilla { +namespace gfx { + +class DrawingCommand +{ +public: + virtual ~DrawingCommand() { } + + virtual void ReplayToDT(DrawTarget *aDT) = 0; +}; + +class DrawingCommandPattern +{ +public: + DrawingCommandPattern(const Pattern& aPattern) + { + mType = aPattern.GetType(); + + switch (mType) { + case PatternType::COLOR: + new (mColorPattern.addr()) ColorPattern(static_cast(aPattern)); + break; + case PatternType::SURFACE: + new (mSurfacePattern.addr()) SurfacePattern(static_cast(aPattern)); + break; + case PatternType::LINEAR_GRADIENT: + new (mLinearGradientPattern.addr()) LinearGradientPattern(static_cast(aPattern)); + break; + case PatternType::RADIAL_GRADIENT: + new (mRadialGradientPattern.addr()) RadialGradientPattern(static_cast(aPattern)); + break; + } + } + + ~DrawingCommandPattern() + { + mPattern.addr()->~Pattern(); + } + + operator Pattern& () + { + return *mPattern.addr(); + } + +private: + PatternType mType; + union { + ClassStorage mPattern; + ClassStorage mColorPattern; + ClassStorage mSurfacePattern; + ClassStorage mLinearGradientPattern; + ClassStorage mRadialGradientPattern; + }; +}; + +class DrawSurfaceCommand : public DrawingCommand +{ +public: + DrawSurfaceCommand(SourceSurface* aSurface, + const Rect& aDest, + const Rect& aSource, + const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(), + const DrawOptions& aOptions = DrawOptions()) + : mSurface(aSurface) + , mDest(aDest) + , mSource(aSource) + , mSurfOptions(aSurfOptions) + , mOptions(aOptions) + { + } + + void ReplayToDT(DrawTarget* aDT) + { + aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions); + } + +private: + RefPtr mSurface; + Rect mDest; + Rect mSource; + DrawSurfaceOptions mSurfOptions; + DrawOptions mOptions; +}; + +class ClearRectCommand : public DrawingCommand +{ +public: + ClearRectCommand(const Rect &aRect) + : mRect(aRect) + { } + + void ReplayToDT(DrawTarget *aDT) + { + aDT->ClearRect(mRect); + } +private: + Rect mRect; +}; + +class CopySurfaceCommand : public DrawingCommand +{ +public: + CopySurfaceCommand(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) + : mSurface(aSurface) + , mSourceRect(aSourceRect) + , mDestination(aDestination) + { + } + + void ReplayToDT(DrawTarget* aDT) + { + aDT->CopySurface(mSurface, mSourceRect, mDestination); + } + +private: + RefPtr mSurface; + IntRect mSourceRect; + IntPoint mDestination; +}; + +class FillRectCommand : public DrawingCommand +{ +public: + FillRectCommand(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) + : mRect(aRect) + , mPattern(aPattern) + , mOptions(aOptions) + { + } + + void ReplayToDT(DrawTarget* aDT) + { + aDT->FillRect(mRect, mPattern, mOptions); + } + +private: + Rect mRect; + DrawingCommandPattern mPattern; + DrawOptions mOptions; +}; + +} +} + +#endif diff --git a/libazure/src/gfx/2d/Factory.cpp b/libazure/Factory.cpp similarity index 51% rename from libazure/src/gfx/2d/Factory.cpp rename to libazure/Factory.cpp index 56e4889..cae1e09 100644 --- a/libazure/src/gfx/2d/Factory.cpp +++ b/libazure/Factory.cpp @@ -7,18 +7,19 @@ #ifdef USE_CAIRO #include "DrawTargetCairo.h" -#include "ScaledFontBase.h" +#include "ScaledFontCairo.h" #endif #ifdef USE_SKIA #include "DrawTargetSkia.h" #include "ScaledFontBase.h" -#ifdef MOZ_ENABLE_FREETYPE -#include "ScaledFontFreetype.h" +#if defined(MOZ_ENABLE_FREETYPE) && defined(USE_CAIRO) +#define USE_SKIA_FREETYPE +#include "ScaledFontCairo.h" #endif #endif -#if defined(WIN32) && defined(USE_SKIA) +#if defined(WIN32) #include "ScaledFontWin.h" #endif @@ -33,11 +34,16 @@ #ifdef WIN32 #include "DrawTargetD2D.h" +#ifdef USE_D2D1_1 +#include "DrawTargetD2D1.h" +#endif #include "ScaledFontDWrite.h" #include +#include "HelpersD2D.h" #endif #include "DrawTargetDual.h" +#include "DrawTargetTiled.h" #include "DrawTargetRecording.h" #include "SourceSurfaceRawData.h" @@ -46,7 +52,9 @@ #include "Logging.h" -#ifdef PR_LOGGING +#include "mozilla/CheckedInt.h" + +#if defined(DEBUG) || defined(PR_LOGGING) PRLogModuleInfo * GetGFX2DLog() { @@ -146,10 +154,18 @@ namespace mozilla { namespace gfx { // XXX - Need to define an API to set this. -int sGfxLogLevel = LOG_DEBUG; +GFX2D_API int sGfxLogLevel = LOG_DEBUG; #ifdef WIN32 ID3D10Device1 *Factory::mD3D10Device; +#ifdef USE_D2D1_1 +ID3D11Device *Factory::mD3D11Device; +ID2D1Device *Factory::mD2D1Device; +#endif +#endif + +#ifdef MOZ_ENABLE_FREETYPE +FT_Library Factory::mFreetypeLibrary = nullptr; #endif DrawEventRecorder *Factory::mRecorder; @@ -163,19 +179,77 @@ Factory::HasSSE2() // cl.exe with -arch:SSE2 (default on x64 compiler) return true; #elif defined(HAVE_CPU_DETECTION) - return HasCPUIDBit(1u, edx, (1u<<26)); + static enum { + UNINITIALIZED, + NO_SSE2, + HAS_SSE2 + } sDetectionState = UNINITIALIZED; + + if (sDetectionState == UNINITIALIZED) { + sDetectionState = HasCPUIDBit(1u, edx, (1u<<26)) ? HAS_SSE2 : NO_SSE2; + } + return sDetectionState == HAS_SSE2; #else return false; #endif } +bool +Factory::CheckSurfaceSize(const IntSize &sz, int32_t limit) +{ + if (sz.width < 0 || sz.height < 0) { + gfxDebug() << "Surface width or height < 0!"; + return false; + } + + // reject images with sides bigger than limit + if (limit && (sz.width > limit || sz.height > limit)) { + gfxDebug() << "Surface size too large (exceeds caller's limit)!"; + return false; + } + + // make sure the surface area doesn't overflow a int32_t + CheckedInt tmp = sz.width; + tmp *= sz.height; + if (!tmp.isValid()) { + gfxDebug() << "Surface size too large (would overflow)!"; + return false; + } + + // assuming 4 bytes per pixel, make sure the allocation size + // doesn't overflow a int32_t either + CheckedInt stride = sz.width; + stride *= 4; + + // When aligning the stride to 16 bytes, it can grow by up to 15 bytes. + stride += 16 - 1; + + if (!stride.isValid()) { + gfxDebug() << "Surface size too large (stride overflows int32_t)!"; + return false; + } + + CheckedInt numBytes = GetAlignedStride<16>(sz.width * 4); + numBytes *= sz.height; + if (!numBytes.isValid()) { + gfxDebug() << "Surface size too large (allocation size would overflow int32_t)!"; + return false; + } + + return true; +} + TemporaryRef Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat) { + if (!CheckSurfaceSize(aSize)) { + return nullptr; + } + RefPtr retVal; switch (aBackend) { #ifdef WIN32 - case BACKEND_DIRECT2D: + case BackendType::DIRECT2D: { RefPtr newTarget; newTarget = new DrawTargetD2D(); @@ -184,9 +258,20 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor } break; } +#ifdef USE_D2D1_1 + case BackendType::DIRECT2D1_1: + { + RefPtr newTarget; + newTarget = new DrawTargetD2D1(); + if (newTarget->Init(aSize, aFormat)) { + retVal = newTarget; + } + break; + } +#endif #elif defined XP_MACOSX - case BACKEND_COREGRAPHICS: - case BACKEND_COREGRAPHICS_ACCELERATED: + case BackendType::COREGRAPHICS: + case BackendType::COREGRAPHICS_ACCELERATED: { RefPtr newTarget; newTarget = new DrawTargetCG(); @@ -197,7 +282,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor } #endif #ifdef USE_SKIA - case BACKEND_SKIA: + case BackendType::SKIA: { RefPtr newTarget; newTarget = new DrawTargetSkia(); @@ -206,6 +291,17 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor } break; } +#endif +#ifdef USE_CAIRO + case BackendType::CAIRO: + { + RefPtr newTarget; + newTarget = new DrawTargetCairo(); + if (newTarget->Init(aSize, aFormat)) { + retVal = newTarget; + } + break; + } #endif default: gfxDebug() << "Invalid draw target type specified."; @@ -213,17 +309,15 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor } if (mRecorder && retVal) { - RefPtr recordDT; - recordDT = new DrawTargetRecording(mRecorder, retVal); - return recordDT; + return new DrawTargetRecording(mRecorder, retVal); } if (!retVal) { // Failed - gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize; + gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize; } - return retVal; + return retVal.forget(); } TemporaryRef @@ -239,24 +333,40 @@ Factory::CreateDrawTargetForData(BackendType aBackend, int32_t aStride, SurfaceFormat aFormat) { + if (!CheckSurfaceSize(aSize)) { + return nullptr; + } + RefPtr retVal; switch (aBackend) { #ifdef USE_SKIA - case BACKEND_SKIA: + case BackendType::SKIA: { RefPtr newTarget; newTarget = new DrawTargetSkia(); newTarget->Init(aData, aSize, aStride, aFormat); - return newTarget; + retVal = newTarget; + break; } #endif #ifdef XP_MACOSX - case BACKEND_COREGRAPHICS: + case BackendType::COREGRAPHICS: { RefPtr newTarget = new DrawTargetCG(); if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat)) - return newTarget; + return newTarget.forget(); + break; + } +#endif +#ifdef USE_CAIRO + case BackendType::CAIRO: + { + RefPtr newTarget; + newTarget = new DrawTargetCairo(); + if (newTarget->Init(aData, aSize, aStride, aFormat)) { + retVal = newTarget.forget(); + } break; } #endif @@ -266,13 +376,26 @@ Factory::CreateDrawTargetForData(BackendType aBackend, } if (mRecorder && retVal) { - RefPtr recordDT = new DrawTargetRecording(mRecorder, retVal); - return recordDT; + return new DrawTargetRecording(mRecorder, retVal, true); } - gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize; - // Failed - return nullptr; + if (!retVal) { + gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize; + } + + return retVal.forget(); +} + +TemporaryRef +Factory::CreateTiledDrawTarget(const TileSet& aTileSet) +{ + RefPtr dt = new DrawTargetTiled(); + + if (!dt->Init(aTileSet)) { + return nullptr; + } + + return dt.forget(); } TemporaryRef @@ -280,37 +403,27 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz { switch (aNativeFont.mType) { #ifdef WIN32 - case NATIVE_FONT_DWRITE_FONT_FACE: + case NativeFontType::DWRITE_FONT_FACE: { return new ScaledFontDWrite(static_cast(aNativeFont.mFont), aSize); } #if defined(USE_CAIRO) || defined(USE_SKIA) - case NATIVE_FONT_GDI_FONT_FACE: + case NativeFontType::GDI_FONT_FACE: { return new ScaledFontWin(static_cast(aNativeFont.mFont), aSize); } #endif #endif #ifdef XP_MACOSX - case NATIVE_FONT_MAC_FONT_FACE: + case NativeFontType::MAC_FONT_FACE: { return new ScaledFontMac(static_cast(aNativeFont.mFont), aSize); } #endif -#ifdef USE_SKIA -#ifdef MOZ_ENABLE_FREETYPE - case NATIVE_FONT_SKIA_FONT_FACE: +#if defined(USE_CAIRO) || defined(USE_SKIA_FREETYPE) + case NativeFontType::CAIRO_FONT_FACE: { - return new ScaledFontFreetype(static_cast(aNativeFont.mFont), aSize); - } -#endif -#endif -#ifdef USE_CAIRO - case NATIVE_FONT_CAIRO_FONT_FACE: - { - ScaledFontBase* fontBase = new ScaledFontBase(aSize); - fontBase->SetCairoScaledFont(static_cast(aNativeFont.mFont)); - return fontBase; + return new ScaledFontCairo(static_cast(aNativeFont.mFont), aSize); } #endif default: @@ -326,7 +439,7 @@ Factory::CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, { switch (aType) { #ifdef WIN32 - case FONT_DWRITE: + case FontType::DWRITE: { return new ScaledFontDWrite(aData, aSize, aFaceIndex, aGlyphSize); } @@ -347,12 +460,38 @@ Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, c // Therefore, we just reuse CreateScaledFontForNativeFont's implementation. RefPtr font = CreateScaledFontForNativeFont(aNativeFont, aSize); static_cast(font.get())->SetCairoScaledFont(aScaledFont); - return font; + return font.forget(); #else return nullptr; #endif } +TemporaryRef +Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB) +{ + RefPtr newTarget = + new DrawTargetDual(targetA, targetB); + + RefPtr retVal = newTarget; + + if (mRecorder) { + retVal = new DrawTargetRecording(mRecorder, retVal); + } + + return retVal.forget(); +} + +#ifdef MOZ_ENABLE_FREETYPE +FT_Library +Factory::GetFreetypeLibrary() +{ + if (!mFreetypeLibrary) { + FT_Init_FreeType(&mFreetypeLibrary); + } + return mFreetypeLibrary; +} +#endif + #ifdef WIN32 TemporaryRef Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat) @@ -364,10 +503,10 @@ Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceForma RefPtr retVal = newTarget; if (mRecorder) { - retVal = new DrawTargetRecording(mRecorder, retVal); + retVal = new DrawTargetRecording(mRecorder, retVal, true); } - return retVal; + return retVal.forget(); } gfxWarning() << "Failed to create draw target for D3D10 texture."; @@ -405,28 +544,88 @@ Factory::CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA, retVal = new DrawTargetRecording(mRecorder, retVal); } - return retVal; + return retVal.forget(); } void Factory::SetDirect3D10Device(ID3D10Device1 *aDevice) { + // do not throw on failure; return error codes and disconnect the device + // On Windows 8 error codes are the default, but on Windows 7 the + // default is to throw (or perhaps only with some drivers?) + aDevice->SetExceptionMode(0); mD3D10Device = aDevice; } ID3D10Device1* Factory::GetDirect3D10Device() + { +#ifdef DEBUG + UINT mode = mD3D10Device->GetExceptionMode(); + MOZ_ASSERT(0 == mode); +#endif return mD3D10Device; } +#ifdef USE_D2D1_1 +TemporaryRef +Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat) +{ + RefPtr newTarget; + + newTarget = new DrawTargetD2D1(); + if (newTarget->Init(aTexture, aFormat)) { + RefPtr retVal = newTarget; + + if (mRecorder) { + retVal = new DrawTargetRecording(mRecorder, retVal, true); + } + + return retVal; + } + + gfxWarning() << "Failed to create draw target for D3D10 texture."; + + // Failed + return nullptr; +} + +void +Factory::SetDirect3D11Device(ID3D11Device *aDevice) +{ + mD3D11Device = aDevice; + + RefPtr factory = D2DFactory1(); + + RefPtr device; + aDevice->QueryInterface((IDXGIDevice**)byRef(device)); + factory->CreateDevice(device, &mD2D1Device); +} + +ID3D11Device* +Factory::GetDirect3D11Device() +{ + return mD3D11Device; +} + +ID2D1Device* +Factory::GetD2D1Device() +{ + return mD2D1Device; +} + +bool +Factory::SupportsD2D1() +{ + return !!D2DFactory1(); +} +#endif + TemporaryRef Factory::CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams) { - RefPtr options = - new GlyphRenderingOptionsDWrite(aParams); - - return options; + return new GlyphRenderingOptionsDWrite(aParams); } uint64_t @@ -451,45 +650,144 @@ Factory::D2DCleanup() #ifdef USE_SKIA_GPU TemporaryRef -Factory::CreateSkiaDrawTargetForFBO(unsigned int aFBOID, GrContext *aGrContext, const IntSize &aSize, SurfaceFormat aFormat) +Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat) { - RefPtr newTarget = new DrawTargetSkia(); - newTarget->InitWithFBO(aFBOID, aGrContext, aSize, aFormat); - return newTarget; + RefPtr newTarget = new DrawTargetSkia(); + if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) { + return nullptr; + } + return newTarget.forget(); } + +TemporaryRef +Factory::CreateDrawTargetSkiaWithGrContextAndFBO(GrContext* aGrContext, + unsigned int aFBOID, + const IntSize &aSize, + SurfaceFormat aFormat) +{ + RefPtr newTarget = new DrawTargetSkia(); + if (!newTarget->InitWithGrContextAndFBO(aGrContext, aFBOID, aSize, aFormat)) { + return nullptr; + } + + return newTarget.forget(); +} + #endif // USE_SKIA_GPU +void +Factory::PurgeTextureCaches() +{ +} + +#ifdef USE_SKIA_FREETYPE +TemporaryRef +Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting) +{ + RefPtr options = + new GlyphRenderingOptionsCairo(); + + options->SetHinting(aHinting); + options->SetAutoHinting(aAutoHinting); + return options.forget(); +} +#endif + TemporaryRef -Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize) +Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat) { RefPtr retVal; #ifdef USE_CAIRO RefPtr newTarget = new DrawTargetCairo(); - if (newTarget->Init(aSurface, aSize)) { + if (newTarget->Init(aSurface, aSize, aFormat)) { retVal = newTarget; } if (mRecorder && retVal) { - RefPtr recordDT = new DrawTargetRecording(mRecorder, retVal); - return recordDT; + RefPtr recordDT = new DrawTargetRecording(mRecorder, retVal, true); + return recordDT.forget(); } #endif - return retVal; + return retVal.forget(); } +#ifdef XP_MACOSX +TemporaryRef +Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize) +{ + RefPtr retVal; + + RefPtr newTarget = new DrawTargetCG(); + + if (newTarget->Init(cg, aSize)) { + retVal = newTarget; + } + + if (mRecorder && retVal) { + return new DrawTargetRecording(mRecorder, retVal); + } + return retVal.forget(); +} +#endif + TemporaryRef Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride, const IntSize &aSize, SurfaceFormat aFormat) { + if (aSize.width <= 0 || aSize.height <= 0) { + return nullptr; + } + RefPtr newSurf = new SourceSurfaceRawData(); if (newSurf->InitWrappingData(aData, aSize, aStride, aFormat, false)) { - return newSurf; + return newSurf.forget(); + } + + return nullptr; +} + +TemporaryRef +Factory::CreateDataSourceSurface(const IntSize &aSize, + SurfaceFormat aFormat, + bool aZero) +{ + if (!CheckSurfaceSize(aSize)) { + gfxWarning() << "CreateDataSourceSurface failed with bad size"; + return nullptr; } + RefPtr newSurf = new SourceSurfaceAlignedRawData(); + if (newSurf->Init(aSize, aFormat, aZero)) { + return newSurf.forget(); + } + + gfxWarning() << "CreateDataSourceSurface failed in init"; + return nullptr; +} + +TemporaryRef +Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize, + SurfaceFormat aFormat, + int32_t aStride, + bool aZero) +{ + if (aStride < aSize.width * BytesPerPixel(aFormat)) { + gfxWarning() << "CreateDataSourceSurfaceWithStride failed with bad stride"; + return nullptr; + } + + RefPtr newSurf = new SourceSurfaceAlignedRawData(); + if (newSurf->InitWithStride(aSize, aFormat, aStride, aZero)) { + return newSurf.forget(); + } + + gfxWarning() << "CreateDataSourceSurfaceWithStride failed to initialize"; return nullptr; } @@ -505,5 +803,24 @@ Factory::SetGlobalEventRecorder(DrawEventRecorder *aRecorder) mRecorder = aRecorder; } +LogForwarder* Factory::mLogForwarder = nullptr; + +// static +void +Factory::SetLogForwarder(LogForwarder* aLogFwd) { + mLogForwarder = aLogFwd; +} + +// static +void +CriticalLogger::OutputMessage(const std::string &aString, int aLevel) +{ + if (Factory::GetLogForwarder()) { + Factory::GetLogForwarder()->Log(aString); + } + + BasicLogger::OutputMessage(aString, aLevel); +} + } } diff --git a/libazure/FilterNodeD2D1.cpp b/libazure/FilterNodeD2D1.cpp new file mode 100644 index 0000000..870eafd --- /dev/null +++ b/libazure/FilterNodeD2D1.cpp @@ -0,0 +1,1036 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FilterNodeD2D1.h" + +#include "Logging.h" + +#include "SourceSurfaceD2D1.h" +#include "SourceSurfaceD2D.h" +#include "SourceSurfaceD2DTarget.h" +#include "DrawTargetD2D.h" +#include "DrawTargetD2D1.h" + +namespace mozilla { +namespace gfx { + +D2D1_COLORMATRIX_ALPHA_MODE D2DAlphaMode(uint32_t aMode) +{ + switch (aMode) { + case ALPHA_MODE_PREMULTIPLIED: + return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED; + case ALPHA_MODE_STRAIGHT: + return D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT; + default: + MOZ_CRASH("Unknown enum value!"); + } + + return D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED; +} + +D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE D2DAffineTransformInterpolationMode(Filter aFilter) +{ + switch (aFilter) { + case Filter::GOOD: + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; + case Filter::LINEAR: + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; + case Filter::POINT: + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + default: + MOZ_CRASH("Unknown enum value!"); + } + + return D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR; +} + +D2D1_BLEND_MODE D2DBlendMode(uint32_t aMode) +{ + switch (aMode) { + case BLEND_MODE_DARKEN: + return D2D1_BLEND_MODE_DARKEN; + case BLEND_MODE_LIGHTEN: + return D2D1_BLEND_MODE_LIGHTEN; + case BLEND_MODE_MULTIPLY: + return D2D1_BLEND_MODE_MULTIPLY; + case BLEND_MODE_SCREEN: + return D2D1_BLEND_MODE_SCREEN; + case BLEND_MODE_OVERLAY: + return D2D1_BLEND_MODE_OVERLAY; + case BLEND_MODE_COLOR_DODGE: + return D2D1_BLEND_MODE_COLOR_DODGE; + case BLEND_MODE_COLOR_BURN: + return D2D1_BLEND_MODE_COLOR_BURN; + case BLEND_MODE_HARD_LIGHT: + return D2D1_BLEND_MODE_HARD_LIGHT; + case BLEND_MODE_SOFT_LIGHT: + return D2D1_BLEND_MODE_SOFT_LIGHT; + case BLEND_MODE_DIFFERENCE: + return D2D1_BLEND_MODE_DIFFERENCE; + case BLEND_MODE_EXCLUSION: + return D2D1_BLEND_MODE_EXCLUSION; + case BLEND_MODE_HUE: + return D2D1_BLEND_MODE_HUE; + case BLEND_MODE_SATURATION: + return D2D1_BLEND_MODE_SATURATION; + case BLEND_MODE_COLOR: + return D2D1_BLEND_MODE_COLOR; + case BLEND_MODE_LUMINOSITY: + return D2D1_BLEND_MODE_LUMINOSITY; + + default: + MOZ_CRASH("Unknown enum value!"); + } + + return D2D1_BLEND_MODE_DARKEN; +} + +D2D1_MORPHOLOGY_MODE D2DMorphologyMode(uint32_t aMode) +{ + switch (aMode) { + case MORPHOLOGY_OPERATOR_DILATE: + return D2D1_MORPHOLOGY_MODE_DILATE; + case MORPHOLOGY_OPERATOR_ERODE: + return D2D1_MORPHOLOGY_MODE_ERODE; + } + + MOZ_CRASH("Unknown enum value!"); + return D2D1_MORPHOLOGY_MODE_DILATE; +} + +D2D1_TURBULENCE_NOISE D2DTurbulenceNoise(uint32_t aMode) +{ + switch (aMode) { + case TURBULENCE_TYPE_FRACTAL_NOISE: + return D2D1_TURBULENCE_NOISE_FRACTAL_SUM; + case TURBULENCE_TYPE_TURBULENCE: + return D2D1_TURBULENCE_NOISE_TURBULENCE; + } + + MOZ_CRASH("Unknown enum value!"); + return D2D1_TURBULENCE_NOISE_TURBULENCE; +} + +D2D1_COMPOSITE_MODE D2DFilterCompositionMode(uint32_t aMode) +{ + switch (aMode) { + case COMPOSITE_OPERATOR_OVER: + return D2D1_COMPOSITE_MODE_SOURCE_OVER; + case COMPOSITE_OPERATOR_IN: + return D2D1_COMPOSITE_MODE_SOURCE_IN; + case COMPOSITE_OPERATOR_OUT: + return D2D1_COMPOSITE_MODE_SOURCE_OUT; + case COMPOSITE_OPERATOR_ATOP: + return D2D1_COMPOSITE_MODE_SOURCE_ATOP; + case COMPOSITE_OPERATOR_XOR: + return D2D1_COMPOSITE_MODE_XOR; + } + + MOZ_CRASH("Unknown enum value!"); + return D2D1_COMPOSITE_MODE_SOURCE_OVER; +} + +D2D1_CHANNEL_SELECTOR D2DChannelSelector(uint32_t aMode) +{ + switch (aMode) { + case COLOR_CHANNEL_R: + return D2D1_CHANNEL_SELECTOR_R; + case COLOR_CHANNEL_G: + return D2D1_CHANNEL_SELECTOR_G; + case COLOR_CHANNEL_B: + return D2D1_CHANNEL_SELECTOR_B; + case COLOR_CHANNEL_A: + return D2D1_CHANNEL_SELECTOR_A; + } + + MOZ_CRASH("Unknown enum value!"); + return D2D1_CHANNEL_SELECTOR_R; +} + +TemporaryRef GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface) +{ + if (aDT->IsTiledDrawTarget() || aDT->IsDualDrawTarget()) { + MOZ_CRASH("Incompatible draw target type!"); + return nullptr; + } + switch (aDT->GetBackendType()) { + case BackendType::DIRECT2D1_1: + return static_cast(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP); + case BackendType::DIRECT2D: + return static_cast(aDT)->GetImageForSurface(aSurface); + default: + MOZ_CRASH("Unknown draw target type!"); + return nullptr; + } +} + +uint32_t ConvertValue(FilterType aType, uint32_t aAttribute, uint32_t aValue) +{ + switch (aType) { + case FilterType::COLOR_MATRIX: + if (aAttribute == ATT_COLOR_MATRIX_ALPHA_MODE) { + aValue = D2DAlphaMode(aValue); + } + break; + case FilterType::TRANSFORM: + if (aAttribute == ATT_TRANSFORM_FILTER) { + aValue = D2DAffineTransformInterpolationMode(Filter(aValue)); + } + break; + case FilterType::BLEND: + if (aAttribute == ATT_BLEND_BLENDMODE) { + aValue = D2DBlendMode(aValue); + } + break; + case FilterType::MORPHOLOGY: + if (aAttribute == ATT_MORPHOLOGY_OPERATOR) { + aValue = D2DMorphologyMode(aValue); + } + break; + case FilterType::DISPLACEMENT_MAP: + if (aAttribute == ATT_DISPLACEMENT_MAP_X_CHANNEL || + aAttribute == ATT_DISPLACEMENT_MAP_Y_CHANNEL) { + aValue = D2DChannelSelector(aValue); + } + break; + case FilterType::TURBULENCE: + if (aAttribute == ATT_TURBULENCE_TYPE) { + aValue = D2DTurbulenceNoise(aValue); + } + break; + case FilterType::COMPOSITE: + if (aAttribute == ATT_COMPOSITE_OPERATOR) { + aValue = D2DFilterCompositionMode(aValue); + } + break; + } + + return aValue; +} + +void ConvertValue(FilterType aType, uint32_t aAttribute, IntSize &aValue) +{ + switch (aType) { + case FilterType::MORPHOLOGY: + if (aAttribute == ATT_MORPHOLOGY_RADII) { + aValue.width *= 2; + aValue.width += 1; + aValue.height *= 2; + aValue.height += 1; + } + break; + } +} + +UINT32 +GetD2D1InputForInput(FilterType aType, uint32_t aIndex) +{ + return aIndex; +} + +#define CONVERT_PROP(moz2dname, d2dname) \ + case ATT_##moz2dname: \ + return D2D1_##d2dname + +UINT32 +GetD2D1PropForAttribute(FilterType aType, uint32_t aIndex) +{ + switch (aType) { + case FilterType::COLOR_MATRIX: + switch (aIndex) { + CONVERT_PROP(COLOR_MATRIX_MATRIX, COLORMATRIX_PROP_COLOR_MATRIX); + CONVERT_PROP(COLOR_MATRIX_ALPHA_MODE, COLORMATRIX_PROP_ALPHA_MODE); + } + break; + case FilterType::TRANSFORM: + switch (aIndex) { + CONVERT_PROP(TRANSFORM_MATRIX, 2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX); + CONVERT_PROP(TRANSFORM_FILTER, 2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE); + } + case FilterType::BLEND: + switch (aIndex) { + CONVERT_PROP(BLEND_BLENDMODE, BLEND_PROP_MODE); + } + break; + case FilterType::MORPHOLOGY: + switch (aIndex) { + CONVERT_PROP(MORPHOLOGY_OPERATOR, MORPHOLOGY_PROP_MODE); + } + break; + case FilterType::FLOOD: + switch (aIndex) { + CONVERT_PROP(FLOOD_COLOR, FLOOD_PROP_COLOR); + } + break; + case FilterType::TILE: + switch (aIndex) { + CONVERT_PROP(TILE_SOURCE_RECT, TILE_PROP_RECT); + } + break; + case FilterType::TABLE_TRANSFER: + switch (aIndex) { + CONVERT_PROP(TABLE_TRANSFER_DISABLE_R, TABLETRANSFER_PROP_RED_DISABLE); + CONVERT_PROP(TABLE_TRANSFER_DISABLE_G, TABLETRANSFER_PROP_GREEN_DISABLE); + CONVERT_PROP(TABLE_TRANSFER_DISABLE_B, TABLETRANSFER_PROP_BLUE_DISABLE); + CONVERT_PROP(TABLE_TRANSFER_DISABLE_A, TABLETRANSFER_PROP_ALPHA_DISABLE); + CONVERT_PROP(TABLE_TRANSFER_TABLE_R, TABLETRANSFER_PROP_RED_TABLE); + CONVERT_PROP(TABLE_TRANSFER_TABLE_G, TABLETRANSFER_PROP_GREEN_TABLE); + CONVERT_PROP(TABLE_TRANSFER_TABLE_B, TABLETRANSFER_PROP_BLUE_TABLE); + CONVERT_PROP(TABLE_TRANSFER_TABLE_A, TABLETRANSFER_PROP_ALPHA_TABLE); + } + break; + case FilterType::DISCRETE_TRANSFER: + switch (aIndex) { + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_R, DISCRETETRANSFER_PROP_RED_DISABLE); + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_G, DISCRETETRANSFER_PROP_GREEN_DISABLE); + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_B, DISCRETETRANSFER_PROP_BLUE_DISABLE); + CONVERT_PROP(DISCRETE_TRANSFER_DISABLE_A, DISCRETETRANSFER_PROP_ALPHA_DISABLE); + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_R, DISCRETETRANSFER_PROP_RED_TABLE); + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_G, DISCRETETRANSFER_PROP_GREEN_TABLE); + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_B, DISCRETETRANSFER_PROP_BLUE_TABLE); + CONVERT_PROP(DISCRETE_TRANSFER_TABLE_A, DISCRETETRANSFER_PROP_ALPHA_TABLE); + } + break; + case FilterType::LINEAR_TRANSFER: + switch (aIndex) { + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_R, LINEARTRANSFER_PROP_RED_DISABLE); + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_G, LINEARTRANSFER_PROP_GREEN_DISABLE); + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_B, LINEARTRANSFER_PROP_BLUE_DISABLE); + CONVERT_PROP(LINEAR_TRANSFER_DISABLE_A, LINEARTRANSFER_PROP_ALPHA_DISABLE); + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_R, LINEARTRANSFER_PROP_RED_Y_INTERCEPT); + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_G, LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT); + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_B, LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT); + CONVERT_PROP(LINEAR_TRANSFER_INTERCEPT_A, LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT); + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_R, LINEARTRANSFER_PROP_RED_SLOPE); + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_G, LINEARTRANSFER_PROP_GREEN_SLOPE); + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_B, LINEARTRANSFER_PROP_BLUE_SLOPE); + CONVERT_PROP(LINEAR_TRANSFER_SLOPE_A, LINEARTRANSFER_PROP_ALPHA_SLOPE); + } + break; + case FilterType::GAMMA_TRANSFER: + switch (aIndex) { + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_R, GAMMATRANSFER_PROP_RED_DISABLE); + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_G, GAMMATRANSFER_PROP_GREEN_DISABLE); + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_B, GAMMATRANSFER_PROP_BLUE_DISABLE); + CONVERT_PROP(GAMMA_TRANSFER_DISABLE_A, GAMMATRANSFER_PROP_ALPHA_DISABLE); + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_R, GAMMATRANSFER_PROP_RED_AMPLITUDE); + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_G, GAMMATRANSFER_PROP_GREEN_AMPLITUDE); + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_B, GAMMATRANSFER_PROP_BLUE_AMPLITUDE); + CONVERT_PROP(GAMMA_TRANSFER_AMPLITUDE_A, GAMMATRANSFER_PROP_ALPHA_AMPLITUDE); + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_R, GAMMATRANSFER_PROP_RED_EXPONENT); + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_G, GAMMATRANSFER_PROP_GREEN_EXPONENT); + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_B, GAMMATRANSFER_PROP_BLUE_EXPONENT); + CONVERT_PROP(GAMMA_TRANSFER_EXPONENT_A, GAMMATRANSFER_PROP_ALPHA_EXPONENT); + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_R, GAMMATRANSFER_PROP_RED_OFFSET); + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_G, GAMMATRANSFER_PROP_GREEN_OFFSET); + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_B, GAMMATRANSFER_PROP_BLUE_OFFSET); + CONVERT_PROP(GAMMA_TRANSFER_OFFSET_A, GAMMATRANSFER_PROP_ALPHA_OFFSET); + } + break; + case FilterType::CONVOLVE_MATRIX: + switch (aIndex) { + CONVERT_PROP(CONVOLVE_MATRIX_BIAS, CONVOLVEMATRIX_PROP_BIAS); + CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_MATRIX, CONVOLVEMATRIX_PROP_KERNEL_MATRIX); + CONVERT_PROP(CONVOLVE_MATRIX_DIVISOR, CONVOLVEMATRIX_PROP_DIVISOR); + CONVERT_PROP(CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH); + CONVERT_PROP(CONVOLVE_MATRIX_PRESERVE_ALPHA, CONVOLVEMATRIX_PROP_PRESERVE_ALPHA); + } + case FilterType::DISPLACEMENT_MAP: + switch (aIndex) { + CONVERT_PROP(DISPLACEMENT_MAP_SCALE, DISPLACEMENTMAP_PROP_SCALE); + CONVERT_PROP(DISPLACEMENT_MAP_X_CHANNEL, DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT); + CONVERT_PROP(DISPLACEMENT_MAP_Y_CHANNEL, DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT); + } + break; + case FilterType::TURBULENCE: + switch (aIndex) { + CONVERT_PROP(TURBULENCE_BASE_FREQUENCY, TURBULENCE_PROP_BASE_FREQUENCY); + CONVERT_PROP(TURBULENCE_NUM_OCTAVES, TURBULENCE_PROP_NUM_OCTAVES); + CONVERT_PROP(TURBULENCE_SEED, TURBULENCE_PROP_SEED); + CONVERT_PROP(TURBULENCE_STITCHABLE, TURBULENCE_PROP_STITCHABLE); + CONVERT_PROP(TURBULENCE_TYPE, TURBULENCE_PROP_NOISE); + } + break; + case FilterType::ARITHMETIC_COMBINE: + switch (aIndex) { + CONVERT_PROP(ARITHMETIC_COMBINE_COEFFICIENTS, ARITHMETICCOMPOSITE_PROP_COEFFICIENTS); + } + break; + case FilterType::COMPOSITE: + switch (aIndex) { + CONVERT_PROP(COMPOSITE_OPERATOR, COMPOSITE_PROP_MODE); + } + break; + case FilterType::GAUSSIAN_BLUR: + switch (aIndex) { + CONVERT_PROP(GAUSSIAN_BLUR_STD_DEVIATION, GAUSSIANBLUR_PROP_STANDARD_DEVIATION); + } + break; + case FilterType::DIRECTIONAL_BLUR: + switch (aIndex) { + CONVERT_PROP(DIRECTIONAL_BLUR_STD_DEVIATION, DIRECTIONALBLUR_PROP_STANDARD_DEVIATION); + CONVERT_PROP(DIRECTIONAL_BLUR_DIRECTION, DIRECTIONALBLUR_PROP_ANGLE); + } + break; + case FilterType::POINT_DIFFUSE: + switch (aIndex) { + CONVERT_PROP(POINT_DIFFUSE_DIFFUSE_CONSTANT, POINTDIFFUSE_PROP_DIFFUSE_CONSTANT); + CONVERT_PROP(POINT_DIFFUSE_POSITION, POINTDIFFUSE_PROP_LIGHT_POSITION); + CONVERT_PROP(POINT_DIFFUSE_COLOR, POINTDIFFUSE_PROP_COLOR); + CONVERT_PROP(POINT_DIFFUSE_SURFACE_SCALE, POINTDIFFUSE_PROP_SURFACE_SCALE); + CONVERT_PROP(POINT_DIFFUSE_KERNEL_UNIT_LENGTH, POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::SPOT_DIFFUSE: + switch (aIndex) { + CONVERT_PROP(SPOT_DIFFUSE_DIFFUSE_CONSTANT, SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT); + CONVERT_PROP(SPOT_DIFFUSE_POINTS_AT, SPOTDIFFUSE_PROP_POINTS_AT); + CONVERT_PROP(SPOT_DIFFUSE_FOCUS, SPOTDIFFUSE_PROP_FOCUS); + CONVERT_PROP(SPOT_DIFFUSE_LIMITING_CONE_ANGLE, SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE); + CONVERT_PROP(SPOT_DIFFUSE_POSITION, SPOTDIFFUSE_PROP_LIGHT_POSITION); + CONVERT_PROP(SPOT_DIFFUSE_COLOR, SPOTDIFFUSE_PROP_COLOR); + CONVERT_PROP(SPOT_DIFFUSE_SURFACE_SCALE, SPOTDIFFUSE_PROP_SURFACE_SCALE); + CONVERT_PROP(SPOT_DIFFUSE_KERNEL_UNIT_LENGTH, SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::DISTANT_DIFFUSE: + switch (aIndex) { + CONVERT_PROP(DISTANT_DIFFUSE_DIFFUSE_CONSTANT, DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT); + CONVERT_PROP(DISTANT_DIFFUSE_AZIMUTH, DISTANTDIFFUSE_PROP_AZIMUTH); + CONVERT_PROP(DISTANT_DIFFUSE_ELEVATION, DISTANTDIFFUSE_PROP_ELEVATION); + CONVERT_PROP(DISTANT_DIFFUSE_COLOR, DISTANTDIFFUSE_PROP_COLOR); + CONVERT_PROP(DISTANT_DIFFUSE_SURFACE_SCALE, DISTANTDIFFUSE_PROP_SURFACE_SCALE); + CONVERT_PROP(DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH, DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::POINT_SPECULAR: + switch (aIndex) { + CONVERT_PROP(POINT_SPECULAR_SPECULAR_CONSTANT, POINTSPECULAR_PROP_SPECULAR_CONSTANT); + CONVERT_PROP(POINT_SPECULAR_SPECULAR_EXPONENT, POINTSPECULAR_PROP_SPECULAR_EXPONENT); + CONVERT_PROP(POINT_SPECULAR_POSITION, POINTSPECULAR_PROP_LIGHT_POSITION); + CONVERT_PROP(POINT_SPECULAR_COLOR, POINTSPECULAR_PROP_COLOR); + CONVERT_PROP(POINT_SPECULAR_SURFACE_SCALE, POINTSPECULAR_PROP_SURFACE_SCALE); + CONVERT_PROP(POINT_SPECULAR_KERNEL_UNIT_LENGTH, POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::SPOT_SPECULAR: + switch (aIndex) { + CONVERT_PROP(SPOT_SPECULAR_SPECULAR_CONSTANT, SPOTSPECULAR_PROP_SPECULAR_CONSTANT); + CONVERT_PROP(SPOT_SPECULAR_SPECULAR_EXPONENT, SPOTSPECULAR_PROP_SPECULAR_EXPONENT); + CONVERT_PROP(SPOT_SPECULAR_POINTS_AT, SPOTSPECULAR_PROP_POINTS_AT); + CONVERT_PROP(SPOT_SPECULAR_FOCUS, SPOTSPECULAR_PROP_FOCUS); + CONVERT_PROP(SPOT_SPECULAR_LIMITING_CONE_ANGLE, SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE); + CONVERT_PROP(SPOT_SPECULAR_POSITION, SPOTSPECULAR_PROP_LIGHT_POSITION); + CONVERT_PROP(SPOT_SPECULAR_COLOR, SPOTSPECULAR_PROP_COLOR); + CONVERT_PROP(SPOT_SPECULAR_SURFACE_SCALE, SPOTSPECULAR_PROP_SURFACE_SCALE); + CONVERT_PROP(SPOT_SPECULAR_KERNEL_UNIT_LENGTH, SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::DISTANT_SPECULAR: + switch (aIndex) { + CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_CONSTANT, DISTANTSPECULAR_PROP_SPECULAR_CONSTANT); + CONVERT_PROP(DISTANT_SPECULAR_SPECULAR_EXPONENT, DISTANTSPECULAR_PROP_SPECULAR_EXPONENT); + CONVERT_PROP(DISTANT_SPECULAR_AZIMUTH, DISTANTSPECULAR_PROP_AZIMUTH); + CONVERT_PROP(DISTANT_SPECULAR_ELEVATION, DISTANTSPECULAR_PROP_ELEVATION); + CONVERT_PROP(DISTANT_SPECULAR_COLOR, DISTANTSPECULAR_PROP_COLOR); + CONVERT_PROP(DISTANT_SPECULAR_SURFACE_SCALE, DISTANTSPECULAR_PROP_SURFACE_SCALE); + CONVERT_PROP(DISTANT_SPECULAR_KERNEL_UNIT_LENGTH, DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH); + } + break; + case FilterType::CROP: + switch (aIndex) { + CONVERT_PROP(CROP_RECT, CROP_PROP_RECT); + } + break; + } + + return UINT32_MAX; +} + +bool +GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UINT32 *aPropHeight) +{ + switch (aType) { + case FilterType::MORPHOLOGY: + if (aIndex == ATT_MORPHOLOGY_RADII) { + *aPropWidth = D2D1_MORPHOLOGY_PROP_WIDTH; + *aPropHeight = D2D1_MORPHOLOGY_PROP_HEIGHT; + return true; + } + break; + } + return false; +} + +static inline REFCLSID GetCLDIDForFilterType(FilterType aType) +{ + switch (aType) { + case FilterType::COLOR_MATRIX: + return CLSID_D2D1ColorMatrix; + case FilterType::TRANSFORM: + return CLSID_D2D12DAffineTransform; + case FilterType::BLEND: + return CLSID_D2D1Blend; + case FilterType::MORPHOLOGY: + return CLSID_D2D1Morphology; + case FilterType::FLOOD: + return CLSID_D2D1Flood; + case FilterType::TILE: + return CLSID_D2D1Tile; + case FilterType::TABLE_TRANSFER: + return CLSID_D2D1TableTransfer; + case FilterType::LINEAR_TRANSFER: + return CLSID_D2D1LinearTransfer; + case FilterType::DISCRETE_TRANSFER: + return CLSID_D2D1DiscreteTransfer; + case FilterType::GAMMA_TRANSFER: + return CLSID_D2D1GammaTransfer; + case FilterType::DISPLACEMENT_MAP: + return CLSID_D2D1DisplacementMap; + case FilterType::TURBULENCE: + return CLSID_D2D1Turbulence; + case FilterType::ARITHMETIC_COMBINE: + return CLSID_D2D1ArithmeticComposite; + case FilterType::COMPOSITE: + return CLSID_D2D1Composite; + case FilterType::GAUSSIAN_BLUR: + return CLSID_D2D1GaussianBlur; + case FilterType::DIRECTIONAL_BLUR: + return CLSID_D2D1DirectionalBlur; + case FilterType::POINT_DIFFUSE: + return CLSID_D2D1PointDiffuse; + case FilterType::POINT_SPECULAR: + return CLSID_D2D1PointSpecular; + case FilterType::SPOT_DIFFUSE: + return CLSID_D2D1SpotDiffuse; + case FilterType::SPOT_SPECULAR: + return CLSID_D2D1SpotSpecular; + case FilterType::DISTANT_DIFFUSE: + return CLSID_D2D1DistantDiffuse; + case FilterType::DISTANT_SPECULAR: + return CLSID_D2D1DistantSpecular; + case FilterType::CROP: + return CLSID_D2D1Crop; + case FilterType::PREMULTIPLY: + return CLSID_D2D1Premultiply; + case FilterType::UNPREMULTIPLY: + return CLSID_D2D1UnPremultiply; + } + return GUID_NULL; +} + +/* static */ +TemporaryRef +FilterNodeD2D1::Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType) +{ + if (aType == FilterType::CONVOLVE_MATRIX) { + return new FilterNodeConvolveD2D1(aDT, aDC); + } + + RefPtr effect; + HRESULT hr; + + hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), byRef(effect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create effect for FilterType: " << hr; + return nullptr; + } + + switch (aType) { + case FilterType::LINEAR_TRANSFER: + case FilterType::GAMMA_TRANSFER: + case FilterType::TABLE_TRANSFER: + case FilterType::DISCRETE_TRANSFER: + return new FilterNodeComponentTransferD2D1(aDT, aDC, effect, aType); + default: + return new FilterNodeD2D1(aDT, effect, aType); + } +} + +void +FilterNodeD2D1::InitUnmappedProperties() +{ + switch (mType) { + case FilterType::TRANSFORM: + mEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD); + break; + default: + break; + } +} + +void +FilterNodeD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface) +{ + UINT32 input = GetD2D1InputForInput(mType, aIndex); + ID2D1Effect* effect = InputEffect(); + MOZ_ASSERT(input < effect->GetInputCount()); + + if (mType == FilterType::COMPOSITE) { + UINT32 inputCount = effect->GetInputCount(); + + if (aIndex == inputCount - 1 && aSurface == nullptr) { + effect->SetInputCount(inputCount - 1); + } else if (aIndex >= inputCount && aSurface) { + effect->SetInputCount(aIndex + 1); + } + } + + RefPtr image = GetImageForSourceSurface(mDT, aSurface); + effect->SetInput(input, image); +} + +void +FilterNodeD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter) +{ + UINT32 input = GetD2D1InputForInput(mType, aIndex); + ID2D1Effect* effect = InputEffect(); + + if (mType == FilterType::COMPOSITE) { + UINT32 inputCount = effect->GetInputCount(); + + if (aIndex == inputCount - 1 && aFilter == nullptr) { + effect->SetInputCount(inputCount - 1); + } else if (aIndex >= inputCount && aFilter) { + effect->SetInputCount(aIndex + 1); + } + } + + MOZ_ASSERT(input < effect->GetInputCount()); + + if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { + gfxWarning() << "Unknown input SourceSurface set on effect."; + MOZ_ASSERT(0); + return; + } + + effect->SetInputEffect(input, static_cast(aFilter)->OutputEffect()); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + if (mType == FilterType::TURBULENCE && aIndex == ATT_TURBULENCE_BASE_FREQUENCY) { + mEffect->SetValue(input, D2D1::Vector2F(FLOAT(aValue), FLOAT(aValue))); + return; + } else if (mType == FilterType::DIRECTIONAL_BLUR && aIndex == ATT_DIRECTIONAL_BLUR_DIRECTION) { + mEffect->SetValue(input, aValue == BLUR_DIRECTION_X ? 0 : 90.0f); + return; + } + + mEffect->SetValue(input, ConvertValue(mType, aIndex, aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, Float aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, aValue); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DPoint(aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DMatrix5x4(aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Point3D &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DVector3D(aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Size &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2D1::Vector2F(aValue.width, aValue.height)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue) +{ + UINT32 widthProp, heightProp; + + if (!GetD2D1PropsForIntSize(mType, aIndex, &widthProp, &heightProp)) { + return; + } + + IntSize value = aValue; + ConvertValue(mType, aIndex, value); + + mEffect->SetValue(widthProp, (UINT)value.width); + mEffect->SetValue(heightProp, (UINT)value.height); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Color &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + switch (mType) { + case FilterType::POINT_DIFFUSE: + case FilterType::SPOT_DIFFUSE: + case FilterType::DISTANT_DIFFUSE: + case FilterType::POINT_SPECULAR: + case FilterType::SPOT_SPECULAR: + case FilterType::DISTANT_SPECULAR: + mEffect->SetValue(input, D2D1::Vector3F(aValue.r, aValue.g, aValue.b)); + break; + default: + mEffect->SetValue(input, D2D1::Vector4F(aValue.r * aValue.a, aValue.g * aValue.a, aValue.b * aValue.a, aValue.a)); + } +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Rect &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DRect(aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue) +{ + if (mType == FilterType::TURBULENCE) { + MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT); + + mEffect->SetValue(D2D1_TURBULENCE_PROP_OFFSET, D2D1::Vector2F(Float(aValue.x), Float(aValue.y))); + mEffect->SetValue(D2D1_TURBULENCE_PROP_SIZE, D2D1::Vector2F(Float(aValue.width), Float(aValue.height))); + return; + } + + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2D1::RectF(Float(aValue.x), Float(aValue.y), + Float(aValue.XMost()), Float(aValue.YMost()))); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, bool aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, (BOOL)aValue); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, (BYTE*)aValues, sizeof(Float) * aSize); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DPoint(aValue)); +} + +void +FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix) +{ + UINT32 input = GetD2D1PropForAttribute(mType, aIndex); + MOZ_ASSERT(input < mEffect->GetPropertyCount()); + + mEffect->SetValue(input, D2DMatrix(aMatrix)); +} + +FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC) + : FilterNodeD2D1(aDT, nullptr, FilterType::CONVOLVE_MATRIX) + , mEdgeMode(EDGE_MODE_DUPLICATE) +{ + // Correctly handling the interaction of edge mode and source rect is a bit + // tricky with D2D1 effects. We want the edge mode to only apply outside of + // the source rect (as specified by the ATT_CONVOLVE_MATRIX_SOURCE_RECT + // attribute). So if our input surface or filter is smaller than the source + // rect, we need to add transparency around it until we reach the edges of + // the source rect, and only then do any repeating or edge duplicating. + // Unfortunately, D2D1 does not have any "extend with transparency" effect. + // (The crop effect can only cut off parts, it can't make the output rect + // bigger.) And the border effect does not have a source rect attribute - + // it only looks at the output rect of its input filter or surface. + // So we use the following trick to extend the input size to the source rect: + // Instead of feeding the input directly into the border effect, we first + // composite it with a transparent flood effect (which is infinite-sized) and + // use a crop effect on the result in order to get the right size. Then we + // feed the cropped composition into the border effect, which then finally + // feeds into the convolve matrix effect. + // All of this is only necessary when our edge mode is not EDGE_MODE_NONE, so + // we update the filter chain dynamically in UpdateChain(). + + HRESULT hr; + + hr = aDC->CreateEffect(CLSID_D2D1ConvolveMatrix, byRef(mEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ConvolveMatrix filter!"; + return; + } + + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT); + + hr = aDC->CreateEffect(CLSID_D2D1Flood, byRef(mFloodEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ConvolveMatrix filter!"; + return; + } + + mFloodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(0.0f, 0.0f, 0.0f, 0.0f)); + + hr = aDC->CreateEffect(CLSID_D2D1Composite, byRef(mCompositeEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ConvolveMatrix filter!"; + return; + } + + mCompositeEffect->SetInputEffect(1, mFloodEffect.get()); + + hr = aDC->CreateEffect(CLSID_D2D1Crop, byRef(mCropEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ConvolveMatrix filter!"; + return; + } + + mCropEffect->SetInputEffect(0, mCompositeEffect.get()); + + hr = aDC->CreateEffect(CLSID_D2D1Border, byRef(mBorderEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ConvolveMatrix filter!"; + return; + } + + mBorderEffect->SetInputEffect(0, mCropEffect.get()); + + UpdateChain(); + UpdateSourceRect(); +} + +void +FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, SourceSurface *aSurface) +{ + MOZ_ASSERT(aIndex == 0); + + mInput = GetImageForSourceSurface(mDT, aSurface); + + mInputEffect = nullptr; + + UpdateChain(); +} + +void +FilterNodeConvolveD2D1::SetInput(uint32_t aIndex, FilterNode *aFilter) +{ + MOZ_ASSERT(aIndex == 0); + + if (aFilter->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { + gfxWarning() << "Unknown input SourceSurface set on effect."; + MOZ_ASSERT(0); + return; + } + + mInput = nullptr; + mInputEffect = static_cast(aFilter)->mEffect; + + UpdateChain(); +} + +void +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, uint32_t aValue) +{ + if (aIndex != ATT_CONVOLVE_MATRIX_EDGE_MODE) { + return FilterNodeD2D1::SetAttribute(aIndex, aValue); + } + + mEdgeMode = (ConvolveMatrixEdgeMode)aValue; + + UpdateChain(); +} + +void +FilterNodeConvolveD2D1::UpdateChain() +{ + // The shape of the filter graph: + // + // EDGE_MODE_NONE: + // input --> convolvematrix + // + // EDGE_MODE_DUPLICATE or EDGE_MODE_WRAP: + // input -------v + // flood --> composite --> crop --> border --> convolvematrix + + ID2D1Effect *firstEffect = mCompositeEffect; + if (mEdgeMode == EDGE_MODE_NONE) { + firstEffect = mEffect; + } else { + mEffect->SetInputEffect(0, mBorderEffect.get()); + } + + if (mInputEffect) { + firstEffect->SetInputEffect(0, mInputEffect); + } else { + firstEffect->SetInput(0, mInput); + } + + if (mEdgeMode == EDGE_MODE_DUPLICATE) { + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_CLAMP); + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_CLAMP); + } else if (mEdgeMode == EDGE_MODE_WRAP) { + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_X, D2D1_BORDER_EDGE_MODE_WRAP); + mBorderEffect->SetValue(D2D1_BORDER_PROP_EDGE_MODE_Y, D2D1_BORDER_EDGE_MODE_WRAP); + } +} + +void +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntSize &aValue) +{ + if (aIndex != ATT_CONVOLVE_MATRIX_KERNEL_SIZE) { + MOZ_ASSERT(false); + return; + } + + mKernelSize = aValue; + + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X, aValue.width); + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y, aValue.height); + + UpdateOffset(); +} + +void +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue) +{ + if (aIndex != ATT_CONVOLVE_MATRIX_TARGET) { + MOZ_ASSERT(false); + return; + } + + mTarget = aValue; + + UpdateOffset(); +} + +void +FilterNodeConvolveD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue) +{ + if (aIndex != ATT_CONVOLVE_MATRIX_SOURCE_RECT) { + MOZ_ASSERT(false); + return; + } + + mSourceRect = aValue; + + UpdateSourceRect(); +} + +void +FilterNodeConvolveD2D1::UpdateOffset() +{ + D2D1_VECTOR_2F vector = + D2D1::Vector2F((Float(mKernelSize.width) - 1.0f) / 2.0f - Float(mTarget.x), + (Float(mKernelSize.height) - 1.0f) / 2.0f - Float(mTarget.y)); + + mEffect->SetValue(D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET, vector); +} + +void +FilterNodeConvolveD2D1::UpdateSourceRect() +{ + mCropEffect->SetValue(D2D1_CROP_PROP_RECT, + D2D1::RectF(Float(mSourceRect.x), Float(mSourceRect.y), + Float(mSourceRect.XMost()), Float(mSourceRect.YMost()))); +} + +FilterNodeComponentTransferD2D1::FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC, + ID2D1Effect *aEffect, FilterType aType) + : FilterNodeD2D1(aDT, aEffect, aType) +{ + // D2D1 component transfer effects do strange things when it comes to + // premultiplication. + // For our purposes we only need the transfer filters to apply straight to + // unpremultiplied source channels and output unpremultiplied results. + // However, the D2D1 effects are designed differently: They can apply to both + // premultiplied and unpremultiplied inputs, and they always premultiply + // their result - at least in those color channels that have not been + // disabled. + // In order to determine whether the input needs to be unpremultiplied as + // part of the transfer, the effect consults the alpha mode metadata of the + // input surface or the input effect. We don't have such a concept in Moz2D, + // and giving Moz2D users different results based on something that cannot be + // influenced through Moz2D APIs seems like a bad idea. + // We solve this by applying a premultiply effect to the input before feeding + // it into the transfer effect. The premultiply effect always premultiplies + // regardless of any alpha mode metadata on inputs, and it always marks its + // output as premultiplied so that the transfer effect will unpremultiply + // consistently. Feeding always-premultiplied input into the transfer effect + // also avoids another problem that would appear when individual color + // channels disable the transfer: In that case, the disabled channels would + // pass through unchanged in their unpremultiplied form and the other + // channels would be premultiplied, giving a mixed result. + // But since we now ensure that the input is premultiplied, disabled channels + // will pass premultiplied values through to the result, which is consistent + // with the enabled channels. + // We also add an unpremultiply effect that postprocesses the result of the + // transfer effect because getting unpremultiplied results from the transfer + // filters is part of the FilterNode API. + HRESULT hr; + + hr = aDC->CreateEffect(CLSID_D2D1Premultiply, byRef(mPrePremultiplyEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ComponentTransfer filter!"; + return; + } + + hr = aDC->CreateEffect(CLSID_D2D1UnPremultiply, byRef(mPostUnpremultiplyEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ComponentTransfer filter!"; + return; + } + + mEffect->SetInputEffect(0, mPrePremultiplyEffect.get()); + mPostUnpremultiplyEffect->SetInputEffect(0, mEffect.get()); +} + +} +} diff --git a/libazure/FilterNodeD2D1.h b/libazure/FilterNodeD2D1.h new file mode 100644 index 0000000..c225f51 --- /dev/null +++ b/libazure/FilterNodeD2D1.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_FILTERNODED2D1_H_ +#define MOZILLA_GFX_FILTERNODED2D1_H_ + +#include "2D.h" +#include "Filters.h" +#include +#include + +namespace mozilla { +namespace gfx { + +class FilterNodeD2D1 : public FilterNode +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeD2D1) + static TemporaryRef Create(DrawTarget* aDT, ID2D1DeviceContext *aDC, FilterType aType); + + FilterNodeD2D1(DrawTarget* aDT, ID2D1Effect *aEffect, FilterType aType) + : mDT(aDT) + , mEffect(aEffect) + , mType(aType) + { + InitUnmappedProperties(); + } + + virtual FilterBackend GetBackendType() { return FILTER_BACKEND_DIRECT2D1_1; } + + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface); + virtual void SetInput(uint32_t aIndex, FilterNode *aFilter); + + virtual void SetAttribute(uint32_t aIndex, uint32_t aValue); + virtual void SetAttribute(uint32_t aIndex, Float aValue); + virtual void SetAttribute(uint32_t aIndex, const Point &aValue); + virtual void SetAttribute(uint32_t aIndex, const Matrix5x4 &aValue); + virtual void SetAttribute(uint32_t aIndex, const Point3D &aValue); + virtual void SetAttribute(uint32_t aIndex, const Size &aValue); + virtual void SetAttribute(uint32_t aIndex, const IntSize &aValue); + virtual void SetAttribute(uint32_t aIndex, const Color &aValue); + virtual void SetAttribute(uint32_t aIndex, const Rect &aValue); + virtual void SetAttribute(uint32_t aIndex, const IntRect &aValue); + virtual void SetAttribute(uint32_t aIndex, bool aValue); + virtual void SetAttribute(uint32_t aIndex, const Float *aValues, uint32_t aSize); + virtual void SetAttribute(uint32_t aIndex, const IntPoint &aValue); + virtual void SetAttribute(uint32_t aIndex, const Matrix &aValue); + +protected: + friend class DrawTargetD2D1; + friend class DrawTargetD2D; + friend class FilterNodeConvolveD2D1; + + virtual ID2D1Effect* InputEffect() { return mEffect.get(); } + virtual ID2D1Effect* OutputEffect() { return mEffect.get(); } + + void InitUnmappedProperties(); + + RefPtr mDT; + RefPtr mEffect; + FilterType mType; +}; + +class FilterNodeConvolveD2D1 : public FilterNodeD2D1 +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeConvolveD2D1) + FilterNodeConvolveD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC); + + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface); + virtual void SetInput(uint32_t aIndex, FilterNode *aFilter); + + virtual void SetAttribute(uint32_t aIndex, uint32_t aValue); + virtual void SetAttribute(uint32_t aIndex, const IntSize &aValue); + virtual void SetAttribute(uint32_t aIndex, const IntPoint &aValue); + virtual void SetAttribute(uint32_t aIndex, const IntRect &aValue); + +private: + void UpdateChain(); + void UpdateOffset(); + void UpdateSourceRect(); + + RefPtr mInput; + RefPtr mInputEffect; + RefPtr mFloodEffect; + RefPtr mCompositeEffect; + RefPtr mCropEffect; + RefPtr mBorderEffect; + ConvolveMatrixEdgeMode mEdgeMode; + IntPoint mTarget; + IntSize mKernelSize; + IntRect mSourceRect; +}; + +class FilterNodeComponentTransferD2D1 : public FilterNodeD2D1 +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeComponentTransferD2D1) + FilterNodeComponentTransferD2D1(DrawTarget *aDT, ID2D1DeviceContext *aDC, ID2D1Effect *aEffect, FilterType aType); + +protected: + virtual ID2D1Effect* InputEffect() MOZ_OVERRIDE { return mPrePremultiplyEffect.get(); } + virtual ID2D1Effect* OutputEffect() MOZ_OVERRIDE { return mPostUnpremultiplyEffect.get(); } + +private: + RefPtr mPrePremultiplyEffect; + RefPtr mPostUnpremultiplyEffect; +}; + +} +} + +#endif diff --git a/libazure/FilterNodeSoftware.cpp b/libazure/FilterNodeSoftware.cpp new file mode 100644 index 0000000..734c7c9 --- /dev/null +++ b/libazure/FilterNodeSoftware.cpp @@ -0,0 +1,3588 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define _USE_MATH_DEFINES + +#include +#include "DataSurfaceHelpers.h" +#include "FilterNodeSoftware.h" +#include "2D.h" +#include "Tools.h" +#include "Blur.h" +#include +#include "FilterProcessing.h" +#include "Logging.h" +#include "mozilla/PodOperations.h" +#include "mozilla/DebugOnly.h" +#include + +// #define DEBUG_DUMP_SURFACES + +#ifdef DEBUG_DUMP_SURFACES +#include "gfxUtils.h" // not part of Moz2D +#endif + +namespace mozilla { +namespace gfx { + +namespace { + +/** + * This class provides a way to get a pow() results in constant-time. It works + * by caching 256 values for bases between 0 and 1 and a fixed exponent. + **/ +class PowCache +{ +public: + PowCache() + { + CacheForExponent(0.0f); + } + + void CacheForExponent(Float aExponent) + { + mExponent = aExponent; + int numPreSquares = 0; + while (numPreSquares < 5 && mExponent > (1 << (numPreSquares + 2))) { + numPreSquares++; + } + mNumPowTablePreSquares = numPreSquares; + for (size_t i = 0; i < sCacheSize; i++) { + // sCacheSize is chosen in such a way that a takes values + // from 0.0 to 1.0 inclusive. + Float a = i / Float(1 << sCacheIndexPrecisionBits); + MOZ_ASSERT(0.0f <= a && a <= 1.0f, "We only want to cache for bases between 0 and 1."); + + for (int j = 0; j < mNumPowTablePreSquares; j++) { + a = sqrt(a); + } + uint32_t cachedInt = pow(a, mExponent) * (1 << sOutputIntPrecisionBits); + MOZ_ASSERT(cachedInt < (1 << (sizeof(mPowTable[i]) * 8)), "mPowCache integer type too small"); + + mPowTable[i] = cachedInt; + } + } + + uint16_t Pow(uint16_t aBase) + { + // Results should be similar to what the following code would produce: + // Float x = Float(aBase) / (1 << sInputIntPrecisionBits); + // return uint16_t(pow(x, mExponent) * (1 << sOutputIntPrecisionBits)); + + MOZ_ASSERT(aBase <= (1 << sInputIntPrecisionBits), "aBase needs to be between 0 and 1!"); + + uint32_t a = aBase; + for (int j = 0; j < mNumPowTablePreSquares; j++) { + a = a * a >> sInputIntPrecisionBits; + } + uint32_t i = a >> (sInputIntPrecisionBits - sCacheIndexPrecisionBits); + MOZ_ASSERT(i < sCacheSize, "out-of-bounds mPowTable access"); + return mPowTable[i]; + } + + static const int sInputIntPrecisionBits = 15; + static const int sOutputIntPrecisionBits = 15; + static const int sCacheIndexPrecisionBits = 7; + +private: + static const size_t sCacheSize = (1 << sCacheIndexPrecisionBits) + 1; + + Float mExponent; + int mNumPowTablePreSquares; + uint16_t mPowTable[sCacheSize]; +}; + +class PointLightSoftware +{ +public: + bool SetAttribute(uint32_t aIndex, Float) { return false; } + bool SetAttribute(uint32_t aIndex, const Point3D &); + void Prepare() {} + Point3D GetVectorToLight(const Point3D &aTargetPoint); + uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight); + +private: + Point3D mPosition; +}; + +class SpotLightSoftware +{ +public: + SpotLightSoftware(); + bool SetAttribute(uint32_t aIndex, Float); + bool SetAttribute(uint32_t aIndex, const Point3D &); + void Prepare(); + Point3D GetVectorToLight(const Point3D &aTargetPoint); + uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight); + +private: + Point3D mPosition; + Point3D mPointsAt; + Point3D mVectorFromFocusPointToLight; + Float mSpecularFocus; + Float mLimitingConeAngle; + Float mLimitingConeCos; + PowCache mPowCache; +}; + +class DistantLightSoftware +{ +public: + DistantLightSoftware(); + bool SetAttribute(uint32_t aIndex, Float); + bool SetAttribute(uint32_t aIndex, const Point3D &) { return false; } + void Prepare(); + Point3D GetVectorToLight(const Point3D &aTargetPoint); + uint32_t GetColor(uint32_t aLightColor, const Point3D &aVectorToLight); + +private: + Float mAzimuth; + Float mElevation; + Point3D mVectorToLight; +}; + +class DiffuseLightingSoftware +{ +public: + DiffuseLightingSoftware(); + bool SetAttribute(uint32_t aIndex, Float); + void Prepare() {} + uint32_t LightPixel(const Point3D &aNormal, const Point3D &aVectorToLight, + uint32_t aColor); + +private: + Float mDiffuseConstant; +}; + +class SpecularLightingSoftware +{ +public: + SpecularLightingSoftware(); + bool SetAttribute(uint32_t aIndex, Float); + void Prepare(); + uint32_t LightPixel(const Point3D &aNormal, const Point3D &aVectorToLight, + uint32_t aColor); + +private: + Float mSpecularConstant; + Float mSpecularExponent; + uint32_t mSpecularConstantInt; + PowCache mPowCache; +}; + +} // unnamed namespace + +// from xpcom/ds/nsMathUtils.h +static int32_t +NS_lround(double x) +{ + return x >= 0.0 ? int32_t(x + 0.5) : int32_t(x - 0.5); +} + +// This check is safe against integer overflow. +static bool +SurfaceContainsPoint(SourceSurface* aSurface, const IntPoint& aPoint) +{ + IntSize size = aSurface->GetSize(); + return aPoint.x >= 0 && aPoint.x < size.width && + aPoint.y >= 0 && aPoint.y < size.height; +} + +static uint8_t* +DataAtOffset(DataSourceSurface* aSurface, IntPoint aPoint) +{ + if (!SurfaceContainsPoint(aSurface, aPoint)) { + MOZ_CRASH("sample position needs to be inside surface!"); + } + + MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()), + "surface size overflows - this should have been prevented when the surface was created"); + + uint8_t* data = aSurface->GetData() + aPoint.y * aSurface->Stride() + + aPoint.x * BytesPerPixel(aSurface->GetFormat()); + + if (data < aSurface->GetData()) { + MOZ_CRASH("out-of-range data access"); + } + + return data; +} + +static bool +IntRectOverflows(const IntRect& aRect) +{ + CheckedInt xMost = aRect.x; + xMost += aRect.width; + CheckedInt yMost = aRect.y; + yMost += aRect.height; + return !xMost.isValid() || !yMost.isValid(); +} + +/** + * aSrcRect: Rect relative to the aSrc surface + * aDestPoint: Point inside aDest surface + */ +static void +CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest, + IntRect aSrcRect, IntPoint aDestPoint) +{ + if (IntRectOverflows(aSrcRect) || + IntRectOverflows(IntRect(aDestPoint, aSrcRect.Size()))) { + MOZ_CRASH("we should never be getting invalid rects at this point"); + } + + MOZ_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "different surface formats"); + MOZ_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "source rect too big for source surface"); + MOZ_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(aSrcRect - aSrcRect.TopLeft() + aDestPoint), "dest surface too small"); + + if (aSrcRect.IsEmpty()) { + return; + } + + uint8_t* sourceData = DataAtOffset(aSrc, aSrcRect.TopLeft()); + uint32_t sourceStride = aSrc->Stride(); + uint8_t* destData = DataAtOffset(aDest, aDestPoint); + uint32_t destStride = aDest->Stride(); + + if (BytesPerPixel(aSrc->GetFormat()) == 4) { + for (int32_t y = 0; y < aSrcRect.height; y++) { + PodCopy((int32_t*)destData, (int32_t*)sourceData, aSrcRect.width); + sourceData += sourceStride; + destData += destStride; + } + } else if (BytesPerPixel(aSrc->GetFormat()) == 1) { + for (int32_t y = 0; y < aSrcRect.height; y++) { + PodCopy(destData, sourceData, aSrcRect.width); + sourceData += sourceStride; + destData += destStride; + } + } +} + +TemporaryRef +CloneAligned(DataSourceSurface* aSource) +{ + RefPtr copy = + Factory::CreateDataSourceSurface(aSource->GetSize(), aSource->GetFormat()); + if (copy) { + CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint()); + } + return copy.forget(); +} + +static void +FillRectWithPixel(DataSourceSurface *aSurface, const IntRect &aFillRect, IntPoint aPixelPos) +{ + MOZ_ASSERT(!IntRectOverflows(aFillRect)); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect), + "aFillRect needs to be completely inside the surface"); + MOZ_ASSERT(SurfaceContainsPoint(aSurface, aPixelPos), + "aPixelPos needs to be inside the surface"); + + int32_t stride = aSurface->Stride(); + uint8_t* sourcePixelData = DataAtOffset(aSurface, aPixelPos); + uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft()); + int bpp = BytesPerPixel(aSurface->GetFormat()); + + // Fill the first row by hand. + if (bpp == 4) { + uint32_t sourcePixel = *(uint32_t*)sourcePixelData; + for (int32_t x = 0; x < aFillRect.width; x++) { + *((uint32_t*)data + x) = sourcePixel; + } + } else if (BytesPerPixel(aSurface->GetFormat()) == 1) { + uint8_t sourcePixel = *sourcePixelData; + memset(data, sourcePixel, aFillRect.width); + } + + // Copy the first row into the other rows. + for (int32_t y = 1; y < aFillRect.height; y++) { + PodCopy(data + y * stride, data, aFillRect.width * bpp); + } +} + +static void +FillRectWithVerticallyRepeatingHorizontalStrip(DataSourceSurface *aSurface, + const IntRect &aFillRect, + const IntRect &aSampleRect) +{ + MOZ_ASSERT(!IntRectOverflows(aFillRect)); + MOZ_ASSERT(!IntRectOverflows(aSampleRect)); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect), + "aFillRect needs to be completely inside the surface"); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect), + "aSampleRect needs to be completely inside the surface"); + + int32_t stride = aSurface->Stride(); + uint8_t* sampleData = DataAtOffset(aSurface, aSampleRect.TopLeft()); + uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft()); + if (BytesPerPixel(aSurface->GetFormat()) == 4) { + for (int32_t y = 0; y < aFillRect.height; y++) { + PodCopy((uint32_t*)data, (uint32_t*)sampleData, aFillRect.width); + data += stride; + } + } else if (BytesPerPixel(aSurface->GetFormat()) == 1) { + for (int32_t y = 0; y < aFillRect.height; y++) { + PodCopy(data, sampleData, aFillRect.width); + data += stride; + } + } +} + +static void +FillRectWithHorizontallyRepeatingVerticalStrip(DataSourceSurface *aSurface, + const IntRect &aFillRect, + const IntRect &aSampleRect) +{ + MOZ_ASSERT(!IntRectOverflows(aFillRect)); + MOZ_ASSERT(!IntRectOverflows(aSampleRect)); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFillRect), + "aFillRect needs to be completely inside the surface"); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aSampleRect), + "aSampleRect needs to be completely inside the surface"); + + int32_t stride = aSurface->Stride(); + uint8_t* sampleData = DataAtOffset(aSurface, aSampleRect.TopLeft()); + uint8_t* data = DataAtOffset(aSurface, aFillRect.TopLeft()); + if (BytesPerPixel(aSurface->GetFormat()) == 4) { + for (int32_t y = 0; y < aFillRect.height; y++) { + int32_t sampleColor = *((uint32_t*)sampleData); + for (int32_t x = 0; x < aFillRect.width; x++) { + *((uint32_t*)data + x) = sampleColor; + } + data += stride; + sampleData += stride; + } + } else if (BytesPerPixel(aSurface->GetFormat()) == 1) { + for (int32_t y = 0; y < aFillRect.height; y++) { + uint8_t sampleColor = *sampleData; + memset(data, sampleColor, aFillRect.width); + data += stride; + sampleData += stride; + } + } +} + +static void +DuplicateEdges(DataSourceSurface* aSurface, const IntRect &aFromRect) +{ + MOZ_ASSERT(!IntRectOverflows(aFromRect)); + MOZ_ASSERT(IntRect(IntPoint(), aSurface->GetSize()).Contains(aFromRect), + "aFromRect needs to be completely inside the surface"); + + IntSize size = aSurface->GetSize(); + IntRect fill; + IntRect sampleRect; + for (int32_t ix = 0; ix < 3; ix++) { + switch (ix) { + case 0: + fill.x = 0; + fill.width = aFromRect.x; + sampleRect.x = fill.XMost(); + sampleRect.width = 1; + break; + case 1: + fill.x = aFromRect.x; + fill.width = aFromRect.width; + sampleRect.x = fill.x; + sampleRect.width = fill.width; + break; + case 2: + fill.x = aFromRect.XMost(); + fill.width = size.width - fill.x; + sampleRect.x = fill.x - 1; + sampleRect.width = 1; + break; + } + if (fill.width <= 0) { + continue; + } + bool xIsMiddle = (ix == 1); + for (int32_t iy = 0; iy < 3; iy++) { + switch (iy) { + case 0: + fill.y = 0; + fill.height = aFromRect.y; + sampleRect.y = fill.YMost(); + sampleRect.height = 1; + break; + case 1: + fill.y = aFromRect.y; + fill.height = aFromRect.height; + sampleRect.y = fill.y; + sampleRect.height = fill.height; + break; + case 2: + fill.y = aFromRect.YMost(); + fill.height = size.height - fill.y; + sampleRect.y = fill.y - 1; + sampleRect.height = 1; + break; + } + if (fill.height <= 0) { + continue; + } + bool yIsMiddle = (iy == 1); + if (!xIsMiddle && !yIsMiddle) { + // Corner + FillRectWithPixel(aSurface, fill, sampleRect.TopLeft()); + } + if (xIsMiddle && !yIsMiddle) { + // Top middle or bottom middle + FillRectWithVerticallyRepeatingHorizontalStrip(aSurface, fill, sampleRect); + } + if (!xIsMiddle && yIsMiddle) { + // Left middle or right middle + FillRectWithHorizontallyRepeatingVerticalStrip(aSurface, fill, sampleRect); + } + } + } +} + +static IntPoint +TileIndex(const IntRect &aFirstTileRect, const IntPoint &aPoint) +{ + return IntPoint(int32_t(floor(double(aPoint.x - aFirstTileRect.x) / aFirstTileRect.width)), + int32_t(floor(double(aPoint.y - aFirstTileRect.y) / aFirstTileRect.height))); +} + +static void +TileSurface(DataSourceSurface* aSource, DataSourceSurface* aTarget, const IntPoint &aOffset) +{ + IntRect sourceRect(aOffset, aSource->GetSize()); + IntRect targetRect(IntPoint(0, 0), aTarget->GetSize()); + IntPoint startIndex = TileIndex(sourceRect, targetRect.TopLeft()); + IntPoint endIndex = TileIndex(sourceRect, targetRect.BottomRight()); + + for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) { + for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) { + IntPoint destPoint(sourceRect.x + ix * sourceRect.width, + sourceRect.y + iy * sourceRect.height); + IntRect destRect(destPoint, sourceRect.Size()); + destRect = destRect.Intersect(targetRect); + IntRect srcRect = destRect - destPoint; + CopyRect(aSource, aTarget, srcRect, destRect.TopLeft()); + } + } +} + +static TemporaryRef +GetDataSurfaceInRect(SourceSurface *aSurface, + const IntRect &aSurfaceRect, + const IntRect &aDestRect, + ConvolveMatrixEdgeMode aEdgeMode) +{ + MOZ_ASSERT(aSurface ? aSurfaceRect.Size() == aSurface->GetSize() : aSurfaceRect.IsEmpty()); + + if (IntRectOverflows(aSurfaceRect) || IntRectOverflows(aDestRect)) { + // We can't rely on the intersection calculations below to make sense when + // XMost() or YMost() overflow. Bail out. + return nullptr; + } + + IntRect sourceRect = aSurfaceRect; + + if (sourceRect.IsEqualEdges(aDestRect)) { + return aSurface ? aSurface->GetDataSurface() : nullptr; + } + + IntRect intersect = sourceRect.Intersect(aDestRect); + IntRect intersectInSourceSpace = intersect - sourceRect.TopLeft(); + IntRect intersectInDestSpace = intersect - aDestRect.TopLeft(); + SurfaceFormat format = aSurface ? aSurface->GetFormat() : SurfaceFormat(SurfaceFormat::B8G8R8A8); + + bool clear = aEdgeMode == EDGE_MODE_NONE && !aSurfaceRect.Contains(aDestRect); + RefPtr target = + Factory::CreateDataSourceSurface(aDestRect.Size(), format, clear); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + if (!aSurface) { + return target.forget(); + } + + RefPtr dataSource = aSurface->GetDataSurface(); + MOZ_ASSERT(dataSource); + + if (aEdgeMode == EDGE_MODE_WRAP) { + TileSurface(dataSource, target, intersectInDestSpace.TopLeft()); + return target.forget(); + } + + CopyRect(dataSource, target, intersectInSourceSpace, + intersectInDestSpace.TopLeft()); + + if (aEdgeMode == EDGE_MODE_DUPLICATE) { + DuplicateEdges(target, intersectInDestSpace); + } + + return target.forget(); +} + +/* static */ TemporaryRef +FilterNodeSoftware::Create(FilterType aType) +{ + RefPtr filter; + switch (aType) { + case FilterType::BLEND: + filter = new FilterNodeBlendSoftware(); + break; + case FilterType::TRANSFORM: + filter = new FilterNodeTransformSoftware(); + break; + case FilterType::MORPHOLOGY: + filter = new FilterNodeMorphologySoftware(); + break; + case FilterType::COLOR_MATRIX: + filter = new FilterNodeColorMatrixSoftware(); + break; + case FilterType::FLOOD: + filter = new FilterNodeFloodSoftware(); + break; + case FilterType::TILE: + filter = new FilterNodeTileSoftware(); + break; + case FilterType::TABLE_TRANSFER: + filter = new FilterNodeTableTransferSoftware(); + break; + case FilterType::DISCRETE_TRANSFER: + filter = new FilterNodeDiscreteTransferSoftware(); + break; + case FilterType::LINEAR_TRANSFER: + filter = new FilterNodeLinearTransferSoftware(); + break; + case FilterType::GAMMA_TRANSFER: + filter = new FilterNodeGammaTransferSoftware(); + break; + case FilterType::CONVOLVE_MATRIX: + filter = new FilterNodeConvolveMatrixSoftware(); + break; + case FilterType::DISPLACEMENT_MAP: + filter = new FilterNodeDisplacementMapSoftware(); + break; + case FilterType::TURBULENCE: + filter = new FilterNodeTurbulenceSoftware(); + break; + case FilterType::ARITHMETIC_COMBINE: + filter = new FilterNodeArithmeticCombineSoftware(); + break; + case FilterType::COMPOSITE: + filter = new FilterNodeCompositeSoftware(); + break; + case FilterType::GAUSSIAN_BLUR: + filter = new FilterNodeGaussianBlurSoftware(); + break; + case FilterType::DIRECTIONAL_BLUR: + filter = new FilterNodeDirectionalBlurSoftware(); + break; + case FilterType::CROP: + filter = new FilterNodeCropSoftware(); + break; + case FilterType::PREMULTIPLY: + filter = new FilterNodePremultiplySoftware(); + break; + case FilterType::UNPREMULTIPLY: + filter = new FilterNodeUnpremultiplySoftware(); + break; + case FilterType::POINT_DIFFUSE: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + case FilterType::POINT_SPECULAR: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + case FilterType::SPOT_DIFFUSE: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + case FilterType::SPOT_SPECULAR: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + case FilterType::DISTANT_DIFFUSE: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + case FilterType::DISTANT_SPECULAR: + filter = new FilterNodeLightingSoftware("FilterNodeLightingSoftware"); + break; + } + return filter.forget(); +} + +void +FilterNodeSoftware::Draw(DrawTarget* aDrawTarget, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ +#ifdef DEBUG_DUMP_SURFACES + printf("
\nRendering filter %s...\n", GetName());
+#endif
+
+  Rect renderRect = aSourceRect;
+  renderRect.RoundOut();
+  IntRect renderIntRect;
+  if (!renderRect.ToIntRect(&renderIntRect)) {
+#ifdef DEBUG_DUMP_SURFACES
+    printf("render rect overflowed, not painting anything\n");
+    printf("
\n"); +#endif + return; + } + + IntRect outputRect = GetOutputRectInRect(renderIntRect); + if (IntRectOverflows(outputRect)) { +#ifdef DEBUG_DUMP_SURFACES + printf("output rect overflowed, not painting anything\n"); + printf("\n"); +#endif + return; + } + + RefPtr result; + if (!outputRect.IsEmpty()) { + result = GetOutput(outputRect); + } + + if (!result) { + // Null results are allowed and treated as transparent. Don't draw anything. +#ifdef DEBUG_DUMP_SURFACES + printf("output returned null\n"); + printf("\n"); +#endif + return; + } + +#ifdef DEBUG_DUMP_SURFACES + printf("output from %s:\n", GetName()); + printf("\n"); + printf("\n"); +#endif + + Point sourceToDestOffset = aDestPoint - aSourceRect.TopLeft(); + Rect renderedSourceRect = Rect(outputRect).Intersect(aSourceRect); + Rect renderedDestRect = renderedSourceRect + sourceToDestOffset; + if (result->GetFormat() == SurfaceFormat::A8) { + // Interpret the result as having implicitly black color channels. + aDrawTarget->PushClipRect(renderedDestRect); + aDrawTarget->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), + result, + Point(outputRect.TopLeft()) + sourceToDestOffset, + aOptions); + aDrawTarget->PopClip(); + } else { + aDrawTarget->DrawSurface(result, renderedDestRect, + renderedSourceRect - Point(outputRect.TopLeft()), + DrawSurfaceOptions(), aOptions); + } +} + +TemporaryRef +FilterNodeSoftware::GetOutput(const IntRect &aRect) +{ + MOZ_ASSERT(GetOutputRectInRect(aRect).Contains(aRect)); + + if (IntRectOverflows(aRect)) { + return nullptr; + } + + if (!mCachedRect.Contains(aRect)) { + RequestRect(aRect); + mCachedOutput = Render(mRequestedRect); + if (!mCachedOutput) { + mCachedRect = IntRect(); + mRequestedRect = IntRect(); + return nullptr; + } + mCachedRect = mRequestedRect; + mRequestedRect = IntRect(); + } else { + MOZ_ASSERT(mCachedOutput, "cached rect but no cached output?"); + } + return GetDataSurfaceInRect(mCachedOutput, mCachedRect, aRect, EDGE_MODE_NONE); +} + +void +FilterNodeSoftware::RequestRect(const IntRect &aRect) +{ + mRequestedRect = mRequestedRect.Union(aRect); + RequestFromInputsForRect(aRect); +} + +void +FilterNodeSoftware::RequestInputRect(uint32_t aInputEnumIndex, const IntRect &aRect) +{ + if (IntRectOverflows(aRect)) { + return; + } + + int32_t inputIndex = InputIndex(aInputEnumIndex); + if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) { + MOZ_CRASH(); + } + if (mInputSurfaces[inputIndex]) { + return; + } + RefPtr filter = mInputFilters[inputIndex]; + MOZ_ASSERT(filter, "missing input"); + filter->RequestRect(filter->GetOutputRectInRect(aRect)); +} + +SurfaceFormat +FilterNodeSoftware::DesiredFormat(SurfaceFormat aCurrentFormat, + FormatHint aFormatHint) +{ + if (aCurrentFormat == SurfaceFormat::A8 && aFormatHint == CAN_HANDLE_A8) { + return SurfaceFormat::A8; + } + return SurfaceFormat::B8G8R8A8; +} + +TemporaryRef +FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex, + const IntRect& aRect, + FormatHint aFormatHint, + ConvolveMatrixEdgeMode aEdgeMode, + const IntRect *aTransparencyPaddedSourceRect) +{ + if (IntRectOverflows(aRect)) { + return nullptr; + } + +#ifdef DEBUG_DUMP_SURFACES + printf("

GetInputDataSourceSurface with aRect: %d, %d, %d, %d

\n", + aRect.x, aRect.y, aRect.width, aRect.height); +#endif + int32_t inputIndex = InputIndex(aInputEnumIndex); + if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) { + MOZ_CRASH(); + return nullptr; + } + + if (aRect.IsEmpty()) { + return nullptr; + } + + RefPtr surface; + IntRect surfaceRect; + + if (mInputSurfaces[inputIndex]) { + // Input from input surface + surface = mInputSurfaces[inputIndex]; +#ifdef DEBUG_DUMP_SURFACES + printf("input from input surface:\n"); +#endif + surfaceRect = IntRect(IntPoint(0, 0), surface->GetSize()); + } else { + // Input from input filter +#ifdef DEBUG_DUMP_SURFACES + printf("getting input from input filter %s...\n", mInputFilters[inputIndex]->GetName()); +#endif + RefPtr filter = mInputFilters[inputIndex]; + MOZ_ASSERT(filter, "missing input"); + IntRect inputFilterOutput = filter->GetOutputRectInRect(aRect); + if (!inputFilterOutput.IsEmpty()) { + surface = filter->GetOutput(inputFilterOutput); + } +#ifdef DEBUG_DUMP_SURFACES + printf("input from input filter %s:\n", mInputFilters[inputIndex]->GetName()); +#endif + surfaceRect = inputFilterOutput; + MOZ_ASSERT(!surface || surfaceRect.Size() == surface->GetSize()); + } + + if (surface && surface->GetFormat() == SurfaceFormat::UNKNOWN) { +#ifdef DEBUG_DUMP_SURFACES + printf("wrong input format
\n\n"); +#endif + return nullptr; + } + + if (!surfaceRect.IsEmpty() && !surface) { +#ifdef DEBUG_DUMP_SURFACES + printf(" -- no input --\n\n"); +#endif + return nullptr; + } + + if (aTransparencyPaddedSourceRect && !aTransparencyPaddedSourceRect->IsEmpty()) { + IntRect srcRect = aTransparencyPaddedSourceRect->Intersect(aRect); + surface = GetDataSurfaceInRect(surface, surfaceRect, srcRect, EDGE_MODE_NONE); + surfaceRect = srcRect; + } + + RefPtr result = + GetDataSurfaceInRect(surface, surfaceRect, aRect, aEdgeMode); + + if (result) { + // TODO: This isn't safe since we don't have a guarantee + // that future Maps will have the same stride + DataSourceSurface::MappedSurface map; + if (result->Map(DataSourceSurface::READ, &map)) { + // Unmap immediately since CloneAligned hasn't been updated + // to use the Map API yet. We can still read the stride/data + // values as long as we don't try to dereference them. + result->Unmap(); + if (map.mStride != GetAlignedStride<16>(map.mStride) || + reinterpret_cast(map.mData) % 16 != 0) { + // Align unaligned surface. + result = CloneAligned(result); + } + } else { + result = nullptr; + } + } + + + if (!result) { +#ifdef DEBUG_DUMP_SURFACES + printf(" -- no input --\n\n"); +#endif + return nullptr; + } + + SurfaceFormat currentFormat = result->GetFormat(); + if (DesiredFormat(currentFormat, aFormatHint) == SurfaceFormat::B8G8R8A8 && + currentFormat != SurfaceFormat::B8G8R8A8) { + result = FilterProcessing::ConvertToB8G8R8A8(result); + } + +#ifdef DEBUG_DUMP_SURFACES + printf(""); +#endif + + MOZ_ASSERT(!result || result->GetSize() == aRect.Size(), "wrong surface size"); + + return result.forget(); +} + +IntRect +FilterNodeSoftware::GetInputRectInRect(uint32_t aInputEnumIndex, + const IntRect &aInRect) +{ + if (IntRectOverflows(aInRect)) { + return IntRect(); + } + + int32_t inputIndex = InputIndex(aInputEnumIndex); + if (inputIndex < 0 || (uint32_t)inputIndex >= NumberOfSetInputs()) { + MOZ_CRASH(); + return IntRect(); + } + if (mInputSurfaces[inputIndex]) { + return aInRect.Intersect(IntRect(IntPoint(0, 0), + mInputSurfaces[inputIndex]->GetSize())); + } + RefPtr filter = mInputFilters[inputIndex]; + MOZ_ASSERT(filter, "missing input"); + return filter->GetOutputRectInRect(aInRect); +} + +size_t +FilterNodeSoftware::NumberOfSetInputs() +{ + return std::max(mInputSurfaces.size(), mInputFilters.size()); +} + +void +FilterNodeSoftware::AddInvalidationListener(FilterInvalidationListener* aListener) +{ + MOZ_ASSERT(aListener, "null listener"); + mInvalidationListeners.push_back(aListener); +} + +void +FilterNodeSoftware::RemoveInvalidationListener(FilterInvalidationListener* aListener) +{ + MOZ_ASSERT(aListener, "null listener"); + std::vector::iterator it = + std::find(mInvalidationListeners.begin(), mInvalidationListeners.end(), aListener); + mInvalidationListeners.erase(it); +} + +void +FilterNodeSoftware::FilterInvalidated(FilterNodeSoftware* aFilter) +{ + Invalidate(); +} + +void +FilterNodeSoftware::Invalidate() +{ + mCachedOutput = nullptr; + mCachedRect = IntRect(); + for (std::vector::iterator it = mInvalidationListeners.begin(); + it != mInvalidationListeners.end(); it++) { + (*it)->FilterInvalidated(this); + } +} + +FilterNodeSoftware::~FilterNodeSoftware() +{ + MOZ_ASSERT(!mInvalidationListeners.size(), + "All invalidation listeners should have unsubscribed themselves by now!"); + + for (std::vector >::iterator it = mInputFilters.begin(); + it != mInputFilters.end(); it++) { + if (*it) { + (*it)->RemoveInvalidationListener(this); + } + } +} + +void +FilterNodeSoftware::SetInput(uint32_t aIndex, FilterNode *aFilter) +{ + if (aFilter->GetBackendType() != FILTER_BACKEND_SOFTWARE) { + MOZ_ASSERT(false, "can only take software filters as inputs"); + return; + } + SetInput(aIndex, nullptr, static_cast(aFilter)); +} + +void +FilterNodeSoftware::SetInput(uint32_t aIndex, SourceSurface *aSurface) +{ + SetInput(aIndex, aSurface, nullptr); +} + +void +FilterNodeSoftware::SetInput(uint32_t aInputEnumIndex, + SourceSurface *aSurface, + FilterNodeSoftware *aFilter) +{ + int32_t inputIndex = InputIndex(aInputEnumIndex); + if (inputIndex < 0) { + MOZ_CRASH(); + return; + } + if ((uint32_t)inputIndex >= mInputSurfaces.size()) { + mInputSurfaces.resize(inputIndex + 1); + } + if ((uint32_t)inputIndex >= mInputFilters.size()) { + mInputFilters.resize(inputIndex + 1); + } + mInputSurfaces[inputIndex] = aSurface; + if (mInputFilters[inputIndex]) { + mInputFilters[inputIndex]->RemoveInvalidationListener(this); + } + if (aFilter) { + aFilter->AddInvalidationListener(this); + } + mInputFilters[inputIndex] = aFilter; + Invalidate(); +} + +FilterNodeBlendSoftware::FilterNodeBlendSoftware() + : mBlendMode(BLEND_MODE_MULTIPLY) +{} + +int32_t +FilterNodeBlendSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_BLEND_IN: return 0; + case IN_BLEND_IN2: return 1; + default: return -1; + } +} + +void +FilterNodeBlendSoftware::SetAttribute(uint32_t aIndex, uint32_t aBlendMode) +{ + MOZ_ASSERT(aIndex == ATT_BLEND_BLENDMODE); + mBlendMode = static_cast(aBlendMode); + Invalidate(); +} + +static CompositionOp ToBlendOp(BlendMode aOp) +{ + switch (aOp) { + case BLEND_MODE_MULTIPLY: + return CompositionOp::OP_MULTIPLY; + case BLEND_MODE_SCREEN: + return CompositionOp::OP_SCREEN; + case BLEND_MODE_OVERLAY: + return CompositionOp::OP_OVERLAY; + case BLEND_MODE_DARKEN: + return CompositionOp::OP_DARKEN; + case BLEND_MODE_LIGHTEN: + return CompositionOp::OP_LIGHTEN; + case BLEND_MODE_COLOR_DODGE: + return CompositionOp::OP_COLOR_DODGE; + case BLEND_MODE_COLOR_BURN: + return CompositionOp::OP_COLOR_BURN; + case BLEND_MODE_HARD_LIGHT: + return CompositionOp::OP_HARD_LIGHT; + case BLEND_MODE_SOFT_LIGHT: + return CompositionOp::OP_SOFT_LIGHT; + case BLEND_MODE_DIFFERENCE: + return CompositionOp::OP_DIFFERENCE; + case BLEND_MODE_EXCLUSION: + return CompositionOp::OP_EXCLUSION; + case BLEND_MODE_HUE: + return CompositionOp::OP_HUE; + case BLEND_MODE_SATURATION: + return CompositionOp::OP_SATURATION; + case BLEND_MODE_COLOR: + return CompositionOp::OP_COLOR; + case BLEND_MODE_LUMINOSITY: + return CompositionOp::OP_LUMINOSITY; + default: + return CompositionOp::OP_OVER; + } + + return CompositionOp::OP_OVER; +} + +TemporaryRef +FilterNodeBlendSoftware::Render(const IntRect& aRect) +{ + RefPtr input1 = + GetInputDataSourceSurface(IN_BLEND_IN, aRect, NEED_COLOR_CHANNELS); + RefPtr input2 = + GetInputDataSourceSurface(IN_BLEND_IN2, aRect, NEED_COLOR_CHANNELS); + + // Null inputs need to be treated as transparent. + + // First case: both are transparent. + if (!input1 && !input2) { + // Then the result is transparent, too. + return nullptr; + } + + // Second case: one of them is transparent. Return the non-transparent one. + if (!input1 || !input2) { + return input1 ? input1.forget() : input2.forget(); + } + + // Third case: both are non-transparent. + // Apply normal filtering. + RefPtr target = FilterProcessing::ApplyBlending(input1, input2, mBlendMode); + if (target != nullptr) { + return target.forget(); + } + + IntSize size = input1->GetSize(); + target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + CopyRect(input1, target, IntRect(IntPoint(), size), IntPoint()); + + RefPtr dt = + Factory::CreateDrawTargetForData(BackendType::CAIRO, + target->GetData(), + target->GetSize(), + target->Stride(), + target->GetFormat()); + + Rect r(0, 0, size.width, size.height); + dt->DrawSurface(input2, r, r, DrawSurfaceOptions(), DrawOptions(1.0f, ToBlendOp(mBlendMode))); + dt->Flush(); + return target.forget(); +} + +void +FilterNodeBlendSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_BLEND_IN, aRect); + RequestInputRect(IN_BLEND_IN2, aRect); +} + +IntRect +FilterNodeBlendSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_BLEND_IN, aRect).Union( + GetInputRectInRect(IN_BLEND_IN2, aRect)).Intersect(aRect); +} + +FilterNodeTransformSoftware::FilterNodeTransformSoftware() + : mFilter(Filter::GOOD) +{} + +int32_t +FilterNodeTransformSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_TRANSFORM_IN: return 0; + default: return -1; + } +} + +void +FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex, uint32_t aFilter) +{ + MOZ_ASSERT(aIndex == ATT_TRANSFORM_FILTER); + mFilter = static_cast(aFilter); + Invalidate(); +} + +void +FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex, const Matrix &aMatrix) +{ + MOZ_ASSERT(aIndex == ATT_TRANSFORM_MATRIX); + mMatrix = aMatrix; + Invalidate(); +} + +IntRect +FilterNodeTransformSoftware::SourceRectForOutputRect(const IntRect &aRect) +{ + if (aRect.IsEmpty()) { + return IntRect(); + } + + Matrix inverted(mMatrix); + if (!inverted.Invert()) { + return IntRect(); + } + + Rect neededRect = inverted.TransformBounds(Rect(aRect)); + neededRect.RoundOut(); + IntRect neededIntRect; + if (!neededRect.ToIntRect(&neededIntRect)) { + return IntRect(); + } + return GetInputRectInRect(IN_TRANSFORM_IN, neededIntRect); +} + +TemporaryRef +FilterNodeTransformSoftware::Render(const IntRect& aRect) +{ + IntRect srcRect = SourceRectForOutputRect(aRect); + + RefPtr input = + GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect, NEED_COLOR_CHANNELS); + + if (!input) { + return nullptr; + } + + Matrix transform = Matrix::Translation(srcRect.x, srcRect.y) * mMatrix * + Matrix::Translation(-aRect.x, -aRect.y); + if (transform.IsIdentity() && srcRect.Size() == aRect.Size()) { + return input.forget(); + } + + RefPtr dt = + Factory::CreateDrawTarget(BackendType::CAIRO, aRect.Size(), input->GetFormat()); + if (!dt) { + return nullptr; + } + + Rect r(0, 0, srcRect.width, srcRect.height); + dt->SetTransform(transform); + dt->DrawSurface(input, r, r, DrawSurfaceOptions(mFilter)); + + RefPtr result = dt->Snapshot(); + RefPtr resultData = result->GetDataSurface(); + return resultData.forget(); +} + +void +FilterNodeTransformSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_TRANSFORM_IN, SourceRectForOutputRect(aRect)); +} + +IntRect +FilterNodeTransformSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect srcRect = SourceRectForOutputRect(aRect); + if (srcRect.IsEmpty()) { + return IntRect(); + } + + Rect outRect = mMatrix.TransformBounds(Rect(srcRect)); + outRect.RoundOut(); + IntRect outIntRect; + if (!outRect.ToIntRect(&outIntRect)) { + return IntRect(); + } + return outIntRect.Intersect(aRect); +} + +FilterNodeMorphologySoftware::FilterNodeMorphologySoftware() + : mOperator(MORPHOLOGY_OPERATOR_ERODE) +{} + +int32_t +FilterNodeMorphologySoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_MORPHOLOGY_IN: return 0; + default: return -1; + } +} + +void +FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex, + const IntSize &aRadii) +{ + MOZ_ASSERT(aIndex == ATT_MORPHOLOGY_RADII); + mRadii.width = std::min(std::max(aRadii.width, 0), 100000); + mRadii.height = std::min(std::max(aRadii.height, 0), 100000); + Invalidate(); +} + +void +FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex, + uint32_t aOperator) +{ + MOZ_ASSERT(aIndex == ATT_MORPHOLOGY_OPERATOR); + mOperator = static_cast(aOperator); + Invalidate(); +} + +static TemporaryRef +ApplyMorphology(const IntRect& aSourceRect, DataSourceSurface* aInput, + const IntRect& aDestRect, int32_t rx, int32_t ry, + MorphologyOperator aOperator) +{ + IntRect srcRect = aSourceRect - aDestRect.TopLeft(); + IntRect destRect = aDestRect - aDestRect.TopLeft(); + IntRect tmpRect(destRect.x, srcRect.y, destRect.width, srcRect.height); +#ifdef DEBUG + IntMargin margin = srcRect - destRect; + MOZ_ASSERT(margin.top >= ry && margin.right >= rx && + margin.bottom >= ry && margin.left >= rx, "insufficient margin"); +#endif + + RefPtr tmp; + if (rx == 0) { + tmp = aInput; + } else { + tmp = Factory::CreateDataSourceSurface(tmpRect.Size(), SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!tmp)) { + return nullptr; + } + + int32_t sourceStride = aInput->Stride(); + uint8_t* sourceData = DataAtOffset(aInput, destRect.TopLeft() - srcRect.TopLeft()); + + int32_t tmpStride = tmp->Stride(); + uint8_t* tmpData = DataAtOffset(tmp, destRect.TopLeft() - tmpRect.TopLeft()); + + FilterProcessing::ApplyMorphologyHorizontal( + sourceData, sourceStride, tmpData, tmpStride, tmpRect, rx, aOperator); + } + + RefPtr dest; + if (ry == 0) { + dest = tmp; + } else { + dest = Factory::CreateDataSourceSurface(destRect.Size(), SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!dest)) { + return nullptr; + } + + int32_t tmpStride = tmp->Stride(); + uint8_t* tmpData = DataAtOffset(tmp, destRect.TopLeft() - tmpRect.TopLeft()); + + int32_t destStride = dest->Stride(); + uint8_t* destData = dest->GetData(); + + FilterProcessing::ApplyMorphologyVertical( + tmpData, tmpStride, destData, destStride, destRect, ry, aOperator); + } + + return dest.forget(); +} + +TemporaryRef +FilterNodeMorphologySoftware::Render(const IntRect& aRect) +{ + IntRect srcRect = aRect; + srcRect.Inflate(mRadii); + + RefPtr input = + GetInputDataSourceSurface(IN_MORPHOLOGY_IN, srcRect, NEED_COLOR_CHANNELS); + if (!input) { + return nullptr; + } + + int32_t rx = mRadii.width; + int32_t ry = mRadii.height; + + if (rx == 0 && ry == 0) { + return input.forget(); + } + + return ApplyMorphology(srcRect, input, aRect, rx, ry, mOperator); +} + +void +FilterNodeMorphologySoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + IntRect srcRect = aRect; + srcRect.Inflate(mRadii); + RequestInputRect(IN_MORPHOLOGY_IN, srcRect); +} + +IntRect +FilterNodeMorphologySoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect inflatedSourceRect = aRect; + inflatedSourceRect.Inflate(mRadii); + IntRect inputRect = GetInputRectInRect(IN_MORPHOLOGY_IN, inflatedSourceRect); + if (mOperator == MORPHOLOGY_OPERATOR_ERODE) { + inputRect.Deflate(mRadii); + } else { + inputRect.Inflate(mRadii); + } + return inputRect.Intersect(aRect); +} + +int32_t +FilterNodeColorMatrixSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_COLOR_MATRIX_IN: return 0; + default: return -1; + } +} + +void +FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex, + const Matrix5x4 &aMatrix) +{ + MOZ_ASSERT(aIndex == ATT_COLOR_MATRIX_MATRIX); + mMatrix = aMatrix; + Invalidate(); +} + +void +FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex, + uint32_t aAlphaMode) +{ + MOZ_ASSERT(aIndex == ATT_COLOR_MATRIX_ALPHA_MODE); + mAlphaMode = (AlphaMode)aAlphaMode; + Invalidate(); +} + +static TemporaryRef +Premultiply(DataSourceSurface* aSurface) +{ + if (aSurface->GetFormat() == SurfaceFormat::A8) { + return aSurface; + } + + IntSize size = aSurface->GetSize(); + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + uint8_t* inputData = aSurface->GetData(); + int32_t inputStride = aSurface->Stride(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + + FilterProcessing::DoPremultiplicationCalculation( + size, targetData, targetStride, inputData, inputStride); + + return target.forget(); +} + +static TemporaryRef +Unpremultiply(DataSourceSurface* aSurface) +{ + if (aSurface->GetFormat() == SurfaceFormat::A8) { + return aSurface; + } + + IntSize size = aSurface->GetSize(); + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + uint8_t* inputData = aSurface->GetData(); + int32_t inputStride = aSurface->Stride(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + + FilterProcessing::DoUnpremultiplicationCalculation( + size, targetData, targetStride, inputData, inputStride); + + return target.forget(); +} + +TemporaryRef +FilterNodeColorMatrixSoftware::Render(const IntRect& aRect) +{ + RefPtr input = + GetInputDataSourceSurface(IN_COLOR_MATRIX_IN, aRect, NEED_COLOR_CHANNELS); + if (!input) { + return nullptr; + } + + if (mAlphaMode == ALPHA_MODE_PREMULTIPLIED) { + input = Unpremultiply(input); + } + + RefPtr result = + FilterProcessing::ApplyColorMatrix(input, mMatrix); + + if (mAlphaMode == ALPHA_MODE_PREMULTIPLIED) { + result = Premultiply(result); + } + + return result.forget(); +} + +void +FilterNodeColorMatrixSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_COLOR_MATRIX_IN, aRect); +} + +IntRect +FilterNodeColorMatrixSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_COLOR_MATRIX_IN, aRect); +} + +void +FilterNodeFloodSoftware::SetAttribute(uint32_t aIndex, const Color &aColor) +{ + MOZ_ASSERT(aIndex == ATT_FLOOD_COLOR); + mColor = aColor; + Invalidate(); +} + +static uint32_t +ColorToBGRA(const Color& aColor) +{ + union { + uint32_t color; + uint8_t components[4]; + }; + components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = NS_lround(aColor.r * aColor.a * 255.0f); + components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = NS_lround(aColor.g * aColor.a * 255.0f); + components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = NS_lround(aColor.b * aColor.a * 255.0f); + components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = NS_lround(aColor.a * 255.0f); + return color; +} + +static SurfaceFormat +FormatForColor(Color aColor) +{ + if (aColor.r == 0 && aColor.g == 0 && aColor.b == 0) { + return SurfaceFormat::A8; + } + return SurfaceFormat::B8G8R8A8; +} + +TemporaryRef +FilterNodeFloodSoftware::Render(const IntRect& aRect) +{ + SurfaceFormat format = FormatForColor(mColor); + RefPtr target = + Factory::CreateDataSourceSurface(aRect.Size(), format); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + uint8_t* targetData = target->GetData(); + uint32_t stride = target->Stride(); + + if (format == SurfaceFormat::B8G8R8A8) { + uint32_t color = ColorToBGRA(mColor); + for (int32_t y = 0; y < aRect.height; y++) { + for (int32_t x = 0; x < aRect.width; x++) { + *((uint32_t*)targetData + x) = color; + } + targetData += stride; + } + } else if (format == SurfaceFormat::A8) { + uint8_t alpha = NS_lround(mColor.a * 255.0f); + for (int32_t y = 0; y < aRect.height; y++) { + for (int32_t x = 0; x < aRect.width; x++) { + targetData[x] = alpha; + } + targetData += stride; + } + } else { + MOZ_CRASH(); + } + + return target.forget(); +} + +// Override GetOutput to get around caching. Rendering simple floods is +// comparatively fast. +TemporaryRef +FilterNodeFloodSoftware::GetOutput(const IntRect& aRect) +{ + return Render(aRect); +} + +IntRect +FilterNodeFloodSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + if (mColor.a == 0.0f) { + return IntRect(); + } + return aRect; +} + +int32_t +FilterNodeTileSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_TILE_IN: return 0; + default: return -1; + } +} + +void +FilterNodeTileSoftware::SetAttribute(uint32_t aIndex, + const IntRect &aSourceRect) +{ + MOZ_ASSERT(aIndex == ATT_TILE_SOURCE_RECT); + mSourceRect = IntRect(int32_t(aSourceRect.x), int32_t(aSourceRect.y), + int32_t(aSourceRect.width), int32_t(aSourceRect.height)); + Invalidate(); +} + +namespace { +struct CompareIntRects +{ + bool operator()(const IntRect& a, const IntRect& b) const + { + if (a.x != b.x) { + return a.x < b.x; + } + if (a.y != b.y) { + return a.y < b.y; + } + if (a.width != b.width) { + return a.width < b.width; + } + return a.height < b.height; + } +}; +} + +TemporaryRef +FilterNodeTileSoftware::Render(const IntRect& aRect) +{ + if (mSourceRect.IsEmpty()) { + return nullptr; + } + + if (mSourceRect.Contains(aRect)) { + return GetInputDataSourceSurface(IN_TILE_IN, aRect); + } + + RefPtr target; + + typedef std::map, CompareIntRects> InputMap; + InputMap inputs; + + IntPoint startIndex = TileIndex(mSourceRect, aRect.TopLeft()); + IntPoint endIndex = TileIndex(mSourceRect, aRect.BottomRight()); + for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) { + for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) { + IntPoint sourceToDestOffset(ix * mSourceRect.width, + iy * mSourceRect.height); + IntRect destRect = aRect.Intersect(mSourceRect + sourceToDestOffset); + IntRect srcRect = destRect - sourceToDestOffset; + if (srcRect.IsEmpty()) { + continue; + } + + RefPtr input; + InputMap::iterator it = inputs.find(srcRect); + if (it == inputs.end()) { + input = GetInputDataSourceSurface(IN_TILE_IN, srcRect); + inputs[srcRect] = input; + } else { + input = it->second; + } + if (!input) { + return nullptr; + } + if (!target) { + // We delay creating the target until now because we want to use the + // same format as our input filter, and we do not actually know the + // input format before we call GetInputDataSourceSurface. + target = Factory::CreateDataSourceSurface(aRect.Size(), input->GetFormat()); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + } + MOZ_ASSERT(input->GetFormat() == target->GetFormat(), "different surface formats from the same input?"); + + CopyRect(input, target, srcRect - srcRect.TopLeft(), destRect.TopLeft() - aRect.TopLeft()); + } + } + + return target.forget(); +} + +void +FilterNodeTileSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + // Do not request anything. + // Source rects for the tile filter can be discontinuous with large gaps + // between them. Requesting those from our input filter might cause it to + // render the whole bounding box of all of them, which would be wasteful. +} + +IntRect +FilterNodeTileSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return aRect; +} + +FilterNodeComponentTransferSoftware::FilterNodeComponentTransferSoftware() + : mDisableR(true) + , mDisableG(true) + , mDisableB(true) + , mDisableA(true) +{} + +void +FilterNodeComponentTransferSoftware::SetAttribute(uint32_t aIndex, + bool aDisable) +{ + switch (aIndex) { + case ATT_TRANSFER_DISABLE_R: + mDisableR = aDisable; + break; + case ATT_TRANSFER_DISABLE_G: + mDisableG = aDisable; + break; + case ATT_TRANSFER_DISABLE_B: + mDisableB = aDisable; + break; + case ATT_TRANSFER_DISABLE_A: + mDisableA = aDisable; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeComponentTransferSoftware::GenerateLookupTable(ptrdiff_t aComponent, + uint8_t aTables[4][256], + bool aDisabled) +{ + if (aDisabled) { + static uint8_t sIdentityLookupTable[256]; + static bool sInitializedIdentityLookupTable = false; + if (!sInitializedIdentityLookupTable) { + for (int32_t i = 0; i < 256; i++) { + sIdentityLookupTable[i] = i; + } + sInitializedIdentityLookupTable = true; + } + memcpy(aTables[aComponent], sIdentityLookupTable, 256); + } else { + FillLookupTable(aComponent, aTables[aComponent]); + } +} + +template +static void TransferComponents(DataSourceSurface* aInput, + DataSourceSurface* aTarget, + const uint8_t aLookupTables[BytesPerPixel][256]) +{ + MOZ_ASSERT(aInput->GetFormat() == aTarget->GetFormat(), "different formats"); + IntSize size = aInput->GetSize(); + + uint8_t* sourceData = aInput->GetData(); + uint8_t* targetData = aTarget->GetData(); + uint32_t sourceStride = aInput->Stride(); + uint32_t targetStride = aTarget->Stride(); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + uint32_t sourceIndex = y * sourceStride + x * BytesPerPixel; + uint32_t targetIndex = y * targetStride + x * BytesPerPixel; + for (uint32_t i = 0; i < BytesPerPixel; i++) { + targetData[targetIndex + i] = aLookupTables[i][sourceData[sourceIndex + i]]; + } + } + } +} + +bool +IsAllZero(uint8_t aLookupTable[256]) +{ + for (int32_t i = 0; i < 256; i++) { + if (aLookupTable[i] != 0) { + return false; + } + } + return true; +} + +TemporaryRef +FilterNodeComponentTransferSoftware::Render(const IntRect& aRect) +{ + if (mDisableR && mDisableG && mDisableB && mDisableA) { + return GetInputDataSourceSurface(IN_TRANSFER_IN, aRect); + } + + uint8_t lookupTables[4][256]; + GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_R, lookupTables, mDisableR); + GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_G, lookupTables, mDisableG); + GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_B, lookupTables, mDisableB); + GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_A, lookupTables, mDisableA); + + bool needColorChannels = + lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_R][0] != 0 || + lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_G][0] != 0 || + lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_B][0] != 0; + + FormatHint pref = needColorChannels ? NEED_COLOR_CHANNELS : CAN_HANDLE_A8; + + RefPtr input = + GetInputDataSourceSurface(IN_TRANSFER_IN, aRect, pref); + if (!input) { + return nullptr; + } + + if (input->GetFormat() == SurfaceFormat::B8G8R8A8 && !needColorChannels) { + bool colorChannelsBecomeBlack = + IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_R]) && + IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_G]) && + IsAllZero(lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_B]); + + if (colorChannelsBecomeBlack) { + input = FilterProcessing::ExtractAlpha(input); + } + } + + SurfaceFormat format = input->GetFormat(); + if (format == SurfaceFormat::A8 && mDisableA) { + return input.forget(); + } + + RefPtr target = + Factory::CreateDataSourceSurface(aRect.Size(), format); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + if (format == SurfaceFormat::A8) { + TransferComponents<1>(input, target, &lookupTables[B8G8R8A8_COMPONENT_BYTEOFFSET_A]); + } else { + TransferComponents<4>(input, target, lookupTables); + } + + return target.forget(); +} + +void +FilterNodeComponentTransferSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_TRANSFER_IN, aRect); +} + +IntRect +FilterNodeComponentTransferSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_TRANSFER_IN, aRect); +} + +int32_t +FilterNodeComponentTransferSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_TRANSFER_IN: return 0; + default: return -1; + } +} + +void +FilterNodeTableTransferSoftware::SetAttribute(uint32_t aIndex, + const Float* aFloat, + uint32_t aSize) +{ + std::vector table(aFloat, aFloat + aSize); + switch (aIndex) { + case ATT_TABLE_TRANSFER_TABLE_R: + mTableR = table; + break; + case ATT_TABLE_TRANSFER_TABLE_G: + mTableG = table; + break; + case ATT_TABLE_TRANSFER_TABLE_B: + mTableB = table; + break; + case ATT_TABLE_TRANSFER_TABLE_A: + mTableA = table; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeTableTransferSoftware::FillLookupTable(ptrdiff_t aComponent, + uint8_t aTable[256]) +{ + switch (aComponent) { + case B8G8R8A8_COMPONENT_BYTEOFFSET_R: + FillLookupTableImpl(mTableR, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_G: + FillLookupTableImpl(mTableG, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_B: + FillLookupTableImpl(mTableB, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_A: + FillLookupTableImpl(mTableA, aTable); + break; + default: + MOZ_ASSERT(false, "unknown component"); + break; + } +} + +void +FilterNodeTableTransferSoftware::FillLookupTableImpl(std::vector& aTableValues, + uint8_t aTable[256]) +{ + uint32_t tvLength = aTableValues.size(); + if (tvLength < 2) { + return; + } + + for (size_t i = 0; i < 256; i++) { + uint32_t k = (i * (tvLength - 1)) / 255; + Float v1 = aTableValues[k]; + Float v2 = aTableValues[std::min(k + 1, tvLength - 1)]; + int32_t val = + int32_t(255 * (v1 + (i/255.0f - k/float(tvLength-1))*(tvLength - 1)*(v2 - v1))); + val = std::min(255, val); + val = std::max(0, val); + aTable[i] = val; + } +} + +void +FilterNodeDiscreteTransferSoftware::SetAttribute(uint32_t aIndex, + const Float* aFloat, + uint32_t aSize) +{ + std::vector discrete(aFloat, aFloat + aSize); + switch (aIndex) { + case ATT_DISCRETE_TRANSFER_TABLE_R: + mTableR = discrete; + break; + case ATT_DISCRETE_TRANSFER_TABLE_G: + mTableG = discrete; + break; + case ATT_DISCRETE_TRANSFER_TABLE_B: + mTableB = discrete; + break; + case ATT_DISCRETE_TRANSFER_TABLE_A: + mTableA = discrete; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeDiscreteTransferSoftware::FillLookupTable(ptrdiff_t aComponent, + uint8_t aTable[256]) +{ + switch (aComponent) { + case B8G8R8A8_COMPONENT_BYTEOFFSET_R: + FillLookupTableImpl(mTableR, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_G: + FillLookupTableImpl(mTableG, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_B: + FillLookupTableImpl(mTableB, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_A: + FillLookupTableImpl(mTableA, aTable); + break; + default: + MOZ_ASSERT(false, "unknown component"); + break; + } +} + +void +FilterNodeDiscreteTransferSoftware::FillLookupTableImpl(std::vector& aTableValues, + uint8_t aTable[256]) +{ + uint32_t tvLength = aTableValues.size(); + if (tvLength < 1) { + return; + } + + for (size_t i = 0; i < 256; i++) { + uint32_t k = (i * tvLength) / 255; + k = std::min(k, tvLength - 1); + Float v = aTableValues[k]; + int32_t val = NS_lround(255 * v); + val = std::min(255, val); + val = std::max(0, val); + aTable[i] = val; + } +} + +FilterNodeLinearTransferSoftware::FilterNodeLinearTransferSoftware() + : mSlopeR(0) + , mSlopeG(0) + , mSlopeB(0) + , mSlopeA(0) + , mInterceptR(0) + , mInterceptG(0) + , mInterceptB(0) + , mInterceptA(0) +{} + +void +FilterNodeLinearTransferSoftware::SetAttribute(uint32_t aIndex, + Float aValue) +{ + switch (aIndex) { + case ATT_LINEAR_TRANSFER_SLOPE_R: + mSlopeR = aValue; + break; + case ATT_LINEAR_TRANSFER_INTERCEPT_R: + mInterceptR = aValue; + break; + case ATT_LINEAR_TRANSFER_SLOPE_G: + mSlopeG = aValue; + break; + case ATT_LINEAR_TRANSFER_INTERCEPT_G: + mInterceptG = aValue; + break; + case ATT_LINEAR_TRANSFER_SLOPE_B: + mSlopeB = aValue; + break; + case ATT_LINEAR_TRANSFER_INTERCEPT_B: + mInterceptB = aValue; + break; + case ATT_LINEAR_TRANSFER_SLOPE_A: + mSlopeA = aValue; + break; + case ATT_LINEAR_TRANSFER_INTERCEPT_A: + mInterceptA = aValue; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeLinearTransferSoftware::FillLookupTable(ptrdiff_t aComponent, + uint8_t aTable[256]) +{ + switch (aComponent) { + case B8G8R8A8_COMPONENT_BYTEOFFSET_R: + FillLookupTableImpl(mSlopeR, mInterceptR, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_G: + FillLookupTableImpl(mSlopeG, mInterceptG, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_B: + FillLookupTableImpl(mSlopeB, mInterceptB, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_A: + FillLookupTableImpl(mSlopeA, mInterceptA, aTable); + break; + default: + MOZ_ASSERT(false, "unknown component"); + break; + } +} + +void +FilterNodeLinearTransferSoftware::FillLookupTableImpl(Float aSlope, + Float aIntercept, + uint8_t aTable[256]) +{ + for (size_t i = 0; i < 256; i++) { + int32_t val = NS_lround(aSlope * i + 255 * aIntercept); + val = std::min(255, val); + val = std::max(0, val); + aTable[i] = val; + } +} + +FilterNodeGammaTransferSoftware::FilterNodeGammaTransferSoftware() + : mAmplitudeR(0) + , mAmplitudeG(0) + , mAmplitudeB(0) + , mAmplitudeA(0) + , mExponentR(0) + , mExponentG(0) + , mExponentB(0) + , mExponentA(0) +{} + +void +FilterNodeGammaTransferSoftware::SetAttribute(uint32_t aIndex, + Float aValue) +{ + switch (aIndex) { + case ATT_GAMMA_TRANSFER_AMPLITUDE_R: + mAmplitudeR = aValue; + break; + case ATT_GAMMA_TRANSFER_EXPONENT_R: + mExponentR = aValue; + break; + case ATT_GAMMA_TRANSFER_OFFSET_R: + mOffsetR = aValue; + break; + case ATT_GAMMA_TRANSFER_AMPLITUDE_G: + mAmplitudeG = aValue; + break; + case ATT_GAMMA_TRANSFER_EXPONENT_G: + mExponentG = aValue; + break; + case ATT_GAMMA_TRANSFER_OFFSET_G: + mOffsetG = aValue; + break; + case ATT_GAMMA_TRANSFER_AMPLITUDE_B: + mAmplitudeB = aValue; + break; + case ATT_GAMMA_TRANSFER_EXPONENT_B: + mExponentB = aValue; + break; + case ATT_GAMMA_TRANSFER_OFFSET_B: + mOffsetB = aValue; + break; + case ATT_GAMMA_TRANSFER_AMPLITUDE_A: + mAmplitudeA = aValue; + break; + case ATT_GAMMA_TRANSFER_EXPONENT_A: + mExponentA = aValue; + break; + case ATT_GAMMA_TRANSFER_OFFSET_A: + mOffsetA = aValue; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeGammaTransferSoftware::FillLookupTable(ptrdiff_t aComponent, + uint8_t aTable[256]) +{ + switch (aComponent) { + case B8G8R8A8_COMPONENT_BYTEOFFSET_R: + FillLookupTableImpl(mAmplitudeR, mExponentR, mOffsetR, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_G: + FillLookupTableImpl(mAmplitudeG, mExponentG, mOffsetG, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_B: + FillLookupTableImpl(mAmplitudeB, mExponentB, mOffsetB, aTable); + break; + case B8G8R8A8_COMPONENT_BYTEOFFSET_A: + FillLookupTableImpl(mAmplitudeA, mExponentA, mOffsetA, aTable); + break; + default: + MOZ_ASSERT(false, "unknown component"); + break; + } +} + +void +FilterNodeGammaTransferSoftware::FillLookupTableImpl(Float aAmplitude, + Float aExponent, + Float aOffset, + uint8_t aTable[256]) +{ + for (size_t i = 0; i < 256; i++) { + int32_t val = NS_lround(255 * (aAmplitude * pow(i / 255.0f, aExponent) + aOffset)); + val = std::min(255, val); + val = std::max(0, val); + aTable[i] = val; + } +} + +FilterNodeConvolveMatrixSoftware::FilterNodeConvolveMatrixSoftware() + : mDivisor(0) + , mBias(0) + , mEdgeMode(EDGE_MODE_DUPLICATE) + , mPreserveAlpha(false) +{} + +int32_t +FilterNodeConvolveMatrixSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_CONVOLVE_MATRIX_IN: return 0; + default: return -1; + } +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + const IntSize &aKernelSize) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_KERNEL_SIZE); + mKernelSize = aKernelSize; + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + const Float *aMatrix, + uint32_t aSize) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_KERNEL_MATRIX); + mKernelMatrix = std::vector(aMatrix, aMatrix + aSize); + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + switch (aIndex) { + case ATT_CONVOLVE_MATRIX_DIVISOR: + mDivisor = aValue; + break; + case ATT_CONVOLVE_MATRIX_BIAS: + mBias = aValue; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, const Size &aKernelUnitLength) +{ + switch (aIndex) { + case ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH: + mKernelUnitLength = aKernelUnitLength; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + const IntPoint &aTarget) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_TARGET); + mTarget = aTarget; + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + const IntRect &aSourceRect) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_SOURCE_RECT); + mSourceRect = aSourceRect; + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + uint32_t aEdgeMode) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_EDGE_MODE); + mEdgeMode = static_cast(aEdgeMode); + Invalidate(); +} + +void +FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex, + bool aPreserveAlpha) +{ + MOZ_ASSERT(aIndex == ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA); + mPreserveAlpha = aPreserveAlpha; + Invalidate(); +} + +#ifdef DEBUG +static bool sColorSamplingAccessControlEnabled = false; +static uint8_t* sColorSamplingAccessControlStart = nullptr; +static uint8_t* sColorSamplingAccessControlEnd = nullptr; + +struct DebugOnlyAutoColorSamplingAccessControl +{ + explicit DebugOnlyAutoColorSamplingAccessControl(DataSourceSurface* aSurface) + { + sColorSamplingAccessControlStart = aSurface->GetData(); + sColorSamplingAccessControlEnd = sColorSamplingAccessControlStart + + aSurface->Stride() * aSurface->GetSize().height; + sColorSamplingAccessControlEnabled = true; + } + + ~DebugOnlyAutoColorSamplingAccessControl() + { + sColorSamplingAccessControlEnabled = false; + } +}; + +static inline void +DebugOnlyCheckColorSamplingAccess(const uint8_t* aSampleAddress) +{ + if (sColorSamplingAccessControlEnabled) { + MOZ_ASSERT(aSampleAddress >= sColorSamplingAccessControlStart, "accessing before start"); + MOZ_ASSERT(aSampleAddress < sColorSamplingAccessControlEnd, "accessing after end"); + } +} +#else +typedef DebugOnly DebugOnlyAutoColorSamplingAccessControl; +#define DebugOnlyCheckColorSamplingAccess(address) +#endif + +static inline uint8_t +ColorComponentAtPoint(const uint8_t *aData, int32_t aStride, int32_t x, int32_t y, size_t bpp, ptrdiff_t c) +{ + DebugOnlyCheckColorSamplingAccess(&aData[y * aStride + bpp * x + c]); + return aData[y * aStride + bpp * x + c]; +} + +static inline int32_t +ColorAtPoint(const uint8_t *aData, int32_t aStride, int32_t x, int32_t y) +{ + DebugOnlyCheckColorSamplingAccess(aData + y * aStride + 4 * x); + return *(uint32_t*)(aData + y * aStride + 4 * x); +} + +// Accepts fractional x & y and does bilinear interpolation. +// Only call this if the pixel (floor(x)+1, floor(y)+1) is accessible. +static inline uint8_t +ColorComponentAtPoint(const uint8_t *aData, int32_t aStride, Float x, Float y, size_t bpp, ptrdiff_t c) +{ + const uint32_t f = 256; + const int32_t lx = floor(x); + const int32_t ly = floor(y); + const int32_t tux = uint32_t((x - lx) * f); + const int32_t tlx = f - tux; + const int32_t tuy = uint32_t((y - ly) * f); + const int32_t tly = f - tuy; + const uint8_t &cll = ColorComponentAtPoint(aData, aStride, lx, ly, bpp, c); + const uint8_t &cul = ColorComponentAtPoint(aData, aStride, lx + 1, ly, bpp, c); + const uint8_t &clu = ColorComponentAtPoint(aData, aStride, lx, ly + 1, bpp, c); + const uint8_t &cuu = ColorComponentAtPoint(aData, aStride, lx + 1, ly + 1, bpp, c); + return ((cll * tlx + cul * tux) * tly + + (clu * tlx + cuu * tux) * tuy + f * f / 2) / (f * f); +} + +static int32_t +ClampToNonZero(int32_t a) +{ + return a * (a >= 0); +} + +template +static void +ConvolvePixel(const uint8_t *aSourceData, + uint8_t *aTargetData, + int32_t aWidth, int32_t aHeight, + int32_t aSourceStride, int32_t aTargetStride, + int32_t aX, int32_t aY, + const int32_t *aKernel, + int32_t aBias, int32_t shiftL, int32_t shiftR, + bool aPreserveAlpha, + int32_t aOrderX, int32_t aOrderY, + int32_t aTargetX, int32_t aTargetY, + CoordType aKernelUnitLengthX, + CoordType aKernelUnitLengthY) +{ + int32_t sum[4] = {0, 0, 0, 0}; + int32_t offsets[4] = { B8G8R8A8_COMPONENT_BYTEOFFSET_R, + B8G8R8A8_COMPONENT_BYTEOFFSET_G, + B8G8R8A8_COMPONENT_BYTEOFFSET_B, + B8G8R8A8_COMPONENT_BYTEOFFSET_A }; + int32_t channels = aPreserveAlpha ? 3 : 4; + int32_t roundingAddition = shiftL == 0 ? 0 : 1 << (shiftL - 1); + + for (int32_t y = 0; y < aOrderY; y++) { + CoordType sampleY = aY + (y - aTargetY) * aKernelUnitLengthY; + for (int32_t x = 0; x < aOrderX; x++) { + CoordType sampleX = aX + (x - aTargetX) * aKernelUnitLengthX; + for (int32_t i = 0; i < channels; i++) { + sum[i] += aKernel[aOrderX * y + x] * + ColorComponentAtPoint(aSourceData, aSourceStride, + sampleX, sampleY, 4, offsets[i]); + } + } + } + for (int32_t i = 0; i < channels; i++) { + int32_t clamped = umin(ClampToNonZero(sum[i] + aBias), 255 << shiftL >> shiftR); + aTargetData[aY * aTargetStride + 4 * aX + offsets[i]] = + (clamped + roundingAddition) << shiftR >> shiftL; + } + if (aPreserveAlpha) { + aTargetData[aY * aTargetStride + 4 * aX + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = + aSourceData[aY * aSourceStride + 4 * aX + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; + } +} + +TemporaryRef +FilterNodeConvolveMatrixSoftware::Render(const IntRect& aRect) +{ + if (mKernelUnitLength.width == floor(mKernelUnitLength.width) && + mKernelUnitLength.height == floor(mKernelUnitLength.height)) { + return DoRender(aRect, (int32_t)mKernelUnitLength.width, (int32_t)mKernelUnitLength.height); + } + return DoRender(aRect, mKernelUnitLength.width, mKernelUnitLength.height); +} + +static std::vector +ReversedVector(const std::vector &aVector) +{ + size_t length = aVector.size(); + std::vector result(length, 0); + for (size_t i = 0; i < length; i++) { + result[length - 1 - i] = aVector[i]; + } + return result; +} + +static std::vector +ScaledVector(const std::vector &aVector, Float aDivisor) +{ + size_t length = aVector.size(); + std::vector result(length, 0); + for (size_t i = 0; i < length; i++) { + result[i] = aVector[i] / aDivisor; + } + return result; +} + +static Float +MaxVectorSum(const std::vector &aVector) +{ + Float sum = 0; + size_t length = aVector.size(); + for (size_t i = 0; i < length; i++) { + if (aVector[i] > 0) { + sum += aVector[i]; + } + } + return sum; +} + +// Returns shiftL and shiftR in such a way that +// a << shiftL >> shiftR is roughly a * aFloat. +static void +TranslateDoubleToShifts(double aDouble, int32_t &aShiftL, int32_t &aShiftR) +{ + aShiftL = 0; + aShiftR = 0; + if (aDouble <= 0) { + MOZ_CRASH(); + } + if (aDouble < 1) { + while (1 << (aShiftR + 1) < 1 / aDouble) { + aShiftR++; + } + } else { + while (1 << (aShiftL + 1) < aDouble) { + aShiftL++; + } + } +} + +template +TemporaryRef +FilterNodeConvolveMatrixSoftware::DoRender(const IntRect& aRect, + CoordType aKernelUnitLengthX, + CoordType aKernelUnitLengthY) +{ + if (mKernelSize.width <= 0 || mKernelSize.height <= 0 || + mKernelMatrix.size() != uint32_t(mKernelSize.width * mKernelSize.height) || + !IntRect(IntPoint(0, 0), mKernelSize).Contains(mTarget) || + mDivisor == 0) { + return Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8); + } + + IntRect srcRect = InflatedSourceRect(aRect); + RefPtr input = + GetInputDataSourceSurface(IN_CONVOLVE_MATRIX_IN, srcRect, NEED_COLOR_CHANNELS, mEdgeMode, &mSourceRect); + + if (!input) { + return nullptr; + } + + DebugOnlyAutoColorSamplingAccessControl accessControl(input); + + RefPtr target = + Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, true); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + IntPoint offset = aRect.TopLeft() - srcRect.TopLeft(); + + uint8_t* sourceData = DataAtOffset(input, offset); + int32_t sourceStride = input->Stride(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + + // Why exactly are we reversing the kernel? + std::vector kernel = ReversedVector(mKernelMatrix); + kernel = ScaledVector(kernel, mDivisor); + Float maxResultAbs = std::max(MaxVectorSum(kernel) + mBias, + MaxVectorSum(ScaledVector(kernel, -1)) - mBias); + maxResultAbs = std::max(maxResultAbs, 1.0f); + + double idealFactor = std::numeric_limits::max() / 2.0 / maxResultAbs / 255.0 * 0.999; + MOZ_ASSERT(255.0 * maxResultAbs * idealFactor <= std::numeric_limits::max() / 2.0, "badly chosen float-to-int scale"); + int32_t shiftL, shiftR; + TranslateDoubleToShifts(idealFactor, shiftL, shiftR); + double factorFromShifts = Float(1 << shiftL) / Float(1 << shiftR); + MOZ_ASSERT(255.0 * maxResultAbs * factorFromShifts <= std::numeric_limits::max() / 2.0, "badly chosen float-to-int scale"); + + int32_t* intKernel = new int32_t[kernel.size()]; + for (size_t i = 0; i < kernel.size(); i++) { + intKernel[i] = NS_lround(kernel[i] * factorFromShifts); + } + int32_t bias = NS_lround(mBias * 255 * factorFromShifts); + + for (int32_t y = 0; y < aRect.height; y++) { + for (int32_t x = 0; x < aRect.width; x++) { + ConvolvePixel(sourceData, targetData, + aRect.width, aRect.height, sourceStride, targetStride, + x, y, intKernel, bias, shiftL, shiftR, mPreserveAlpha, + mKernelSize.width, mKernelSize.height, mTarget.x, mTarget.y, + aKernelUnitLengthX, aKernelUnitLengthY); + } + } + delete[] intKernel; + + return target.forget(); +} + +void +FilterNodeConvolveMatrixSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_CONVOLVE_MATRIX_IN, InflatedSourceRect(aRect)); +} + +IntRect +FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect &aDestRect) +{ + if (aDestRect.IsEmpty()) { + return IntRect(); + } + + IntMargin margin; + margin.left = ceil(mTarget.x * mKernelUnitLength.width); + margin.top = ceil(mTarget.y * mKernelUnitLength.height); + margin.right = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width); + margin.bottom = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height); + + IntRect srcRect = aDestRect; + srcRect.Inflate(margin); + return srcRect; +} + +IntRect +FilterNodeConvolveMatrixSoftware::InflatedDestRect(const IntRect &aSourceRect) +{ + if (aSourceRect.IsEmpty()) { + return IntRect(); + } + + IntMargin margin; + margin.left = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width); + margin.top = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height); + margin.right = ceil(mTarget.x * mKernelUnitLength.width); + margin.bottom = ceil(mTarget.y * mKernelUnitLength.height); + + IntRect destRect = aSourceRect; + destRect.Inflate(margin); + return destRect; +} + +IntRect +FilterNodeConvolveMatrixSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect srcRequest = InflatedSourceRect(aRect); + IntRect srcOutput = GetInputRectInRect(IN_COLOR_MATRIX_IN, srcRequest); + return InflatedDestRect(srcOutput).Intersect(aRect); +} + +FilterNodeDisplacementMapSoftware::FilterNodeDisplacementMapSoftware() + : mScale(0.0f) + , mChannelX(COLOR_CHANNEL_R) + , mChannelY(COLOR_CHANNEL_G) +{} + +int32_t +FilterNodeDisplacementMapSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_DISPLACEMENT_MAP_IN: return 0; + case IN_DISPLACEMENT_MAP_IN2: return 1; + default: return -1; + } +} + +void +FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex, + Float aScale) +{ + MOZ_ASSERT(aIndex == ATT_DISPLACEMENT_MAP_SCALE); + mScale = aScale; + Invalidate(); +} + +void +FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex, uint32_t aValue) +{ + switch (aIndex) { + case ATT_DISPLACEMENT_MAP_X_CHANNEL: + mChannelX = static_cast(aValue); + break; + case ATT_DISPLACEMENT_MAP_Y_CHANNEL: + mChannelY = static_cast(aValue); + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +TemporaryRef +FilterNodeDisplacementMapSoftware::Render(const IntRect& aRect) +{ + IntRect srcRect = InflatedSourceOrDestRect(aRect); + RefPtr input = + GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN, srcRect, NEED_COLOR_CHANNELS); + RefPtr map = + GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN2, aRect, NEED_COLOR_CHANNELS); + RefPtr target = + Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!(input && map && target))) { + return nullptr; + } + + IntPoint offset = aRect.TopLeft() - srcRect.TopLeft(); + + uint8_t* sourceData = DataAtOffset(input, offset); + int32_t sourceStride = input->Stride(); + uint8_t* mapData = map->GetData(); + int32_t mapStride = map->Stride(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + + static const ptrdiff_t channelMap[4] = { + B8G8R8A8_COMPONENT_BYTEOFFSET_R, + B8G8R8A8_COMPONENT_BYTEOFFSET_G, + B8G8R8A8_COMPONENT_BYTEOFFSET_B, + B8G8R8A8_COMPONENT_BYTEOFFSET_A }; + uint16_t xChannel = channelMap[mChannelX]; + uint16_t yChannel = channelMap[mChannelY]; + + float scaleOver255 = mScale / 255.0f; + float scaleAdjustment = -0.5f * mScale; + + for (int32_t y = 0; y < aRect.height; y++) { + for (int32_t x = 0; x < aRect.width; x++) { + uint32_t mapIndex = y * mapStride + 4 * x; + uint32_t targIndex = y * targetStride + 4 * x; + int32_t sourceX = x + + scaleOver255 * mapData[mapIndex + xChannel] + scaleAdjustment; + int32_t sourceY = y + + scaleOver255 * mapData[mapIndex + yChannel] + scaleAdjustment; + *(uint32_t*)(targetData + targIndex) = + ColorAtPoint(sourceData, sourceStride, sourceX, sourceY); + } + } + + return target.forget(); +} + +void +FilterNodeDisplacementMapSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_DISPLACEMENT_MAP_IN, InflatedSourceOrDestRect(aRect)); + RequestInputRect(IN_DISPLACEMENT_MAP_IN2, aRect); +} + +IntRect +FilterNodeDisplacementMapSoftware::InflatedSourceOrDestRect(const IntRect &aDestOrSourceRect) +{ + IntRect sourceOrDestRect = aDestOrSourceRect; + sourceOrDestRect.Inflate(ceil(fabs(mScale) / 2)); + return sourceOrDestRect; +} + +IntRect +FilterNodeDisplacementMapSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect srcRequest = InflatedSourceOrDestRect(aRect); + IntRect srcOutput = GetInputRectInRect(IN_DISPLACEMENT_MAP_IN, srcRequest); + return InflatedSourceOrDestRect(srcOutput).Intersect(aRect); +} + +FilterNodeTurbulenceSoftware::FilterNodeTurbulenceSoftware() + : mNumOctaves(0) + , mSeed(0) + , mStitchable(false) + , mType(TURBULENCE_TYPE_TURBULENCE) +{} + +int32_t +FilterNodeTurbulenceSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + return -1; +} + +void +FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, const Size &aBaseFrequency) +{ + switch (aIndex) { + case ATT_TURBULENCE_BASE_FREQUENCY: + mBaseFrequency = aBaseFrequency; + break; + default: + MOZ_CRASH(); + break; + } + Invalidate(); +} + +void +FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, const IntRect &aRect) +{ + switch (aIndex) { + case ATT_TURBULENCE_RECT: + mRenderRect = aRect; + break; + default: + MOZ_CRASH(); + break; + } + Invalidate(); +} + +void +FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, bool aStitchable) +{ + MOZ_ASSERT(aIndex == ATT_TURBULENCE_STITCHABLE); + mStitchable = aStitchable; + Invalidate(); +} + +void +FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex, uint32_t aValue) +{ + switch (aIndex) { + case ATT_TURBULENCE_NUM_OCTAVES: + mNumOctaves = aValue; + break; + case ATT_TURBULENCE_SEED: + mSeed = aValue; + break; + case ATT_TURBULENCE_TYPE: + mType = static_cast(aValue); + break; + default: + MOZ_CRASH(); + break; + } + Invalidate(); +} + +TemporaryRef +FilterNodeTurbulenceSoftware::Render(const IntRect& aRect) +{ + return FilterProcessing::RenderTurbulence( + aRect.Size(), aRect.TopLeft(), mBaseFrequency, + mSeed, mNumOctaves, mType, mStitchable, Rect(mRenderRect)); +} + +IntRect +FilterNodeTurbulenceSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return aRect.Intersect(mRenderRect); +} + +FilterNodeArithmeticCombineSoftware::FilterNodeArithmeticCombineSoftware() + : mK1(0), mK2(0), mK3(0), mK4(0) +{ +} + +int32_t +FilterNodeArithmeticCombineSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_ARITHMETIC_COMBINE_IN: return 0; + case IN_ARITHMETIC_COMBINE_IN2: return 1; + default: return -1; + } +} + +void +FilterNodeArithmeticCombineSoftware::SetAttribute(uint32_t aIndex, + const Float* aFloat, + uint32_t aSize) +{ + MOZ_ASSERT(aIndex == ATT_ARITHMETIC_COMBINE_COEFFICIENTS); + MOZ_ASSERT(aSize == 4); + + mK1 = aFloat[0]; + mK2 = aFloat[1]; + mK3 = aFloat[2]; + mK4 = aFloat[3]; + + Invalidate(); +} + +TemporaryRef +FilterNodeArithmeticCombineSoftware::Render(const IntRect& aRect) +{ + RefPtr input1 = + GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN, aRect, NEED_COLOR_CHANNELS); + RefPtr input2 = + GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN2, aRect, NEED_COLOR_CHANNELS); + if (!input1 && !input2) { + return nullptr; + } + + // If one input is null, treat it as transparent by adjusting the factors. + Float k1 = mK1, k2 = mK2, k3 = mK3, k4 = mK4; + if (!input1) { + k1 = 0.0f; + k2 = 0.0f; + input1 = input2; + } + + if (!input2) { + k1 = 0.0f; + k3 = 0.0f; + input2 = input1; + } + + return FilterProcessing::ApplyArithmeticCombine(input1, input2, k1, k2, k3, k4); +} + +void +FilterNodeArithmeticCombineSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_ARITHMETIC_COMBINE_IN, aRect); + RequestInputRect(IN_ARITHMETIC_COMBINE_IN2, aRect); +} + +IntRect +FilterNodeArithmeticCombineSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + if (mK4 > 0.0f) { + return aRect; + } + IntRect rectFrom1 = GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN, aRect).Intersect(aRect); + IntRect rectFrom2 = GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN2, aRect).Intersect(aRect); + IntRect result; + if (mK1 > 0.0f) { + result = rectFrom1.Intersect(rectFrom2); + } + if (mK2 > 0.0f) { + result = result.Union(rectFrom1); + } + if (mK3 > 0.0f) { + result = result.Union(rectFrom2); + } + return result; +} + +FilterNodeCompositeSoftware::FilterNodeCompositeSoftware() + : mOperator(COMPOSITE_OPERATOR_OVER) +{} + +int32_t +FilterNodeCompositeSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + return aInputEnumIndex - IN_COMPOSITE_IN_START; +} + +void +FilterNodeCompositeSoftware::SetAttribute(uint32_t aIndex, uint32_t aCompositeOperator) +{ + MOZ_ASSERT(aIndex == ATT_COMPOSITE_OPERATOR); + mOperator = static_cast(aCompositeOperator); + Invalidate(); +} + +TemporaryRef +FilterNodeCompositeSoftware::Render(const IntRect& aRect) +{ + RefPtr start = + GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS); + RefPtr dest = + Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::B8G8R8A8, !start); + if (MOZ2D_WARN_IF(!dest)) { + return nullptr; + } + + if (start) { + CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint()); + } + + for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) { + RefPtr input = + GetInputDataSourceSurface(IN_COMPOSITE_IN_START + inputIndex, aRect, NEED_COLOR_CHANNELS); + if (input) { + FilterProcessing::ApplyComposition(input, dest, mOperator); + } else { + // We need to treat input as transparent. Depending on the composite + // operator, different things happen to dest. + switch (mOperator) { + case COMPOSITE_OPERATOR_OVER: + case COMPOSITE_OPERATOR_ATOP: + case COMPOSITE_OPERATOR_XOR: + // dest is unchanged. + break; + case COMPOSITE_OPERATOR_OUT: + // dest is now transparent, but it can become non-transparent again + // when compositing additional inputs. + ClearDataSourceSurface(dest); + break; + case COMPOSITE_OPERATOR_IN: + // Transparency always wins. We're completely transparent now and + // no additional input can get rid of that transparency. + return nullptr; + } + } + } + return dest.forget(); +} + +void +FilterNodeCompositeSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + for (size_t inputIndex = 0; inputIndex < NumberOfSetInputs(); inputIndex++) { + RequestInputRect(IN_COMPOSITE_IN_START + inputIndex, aRect); + } +} + +IntRect +FilterNodeCompositeSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect rect; + for (size_t inputIndex = 0; inputIndex < NumberOfSetInputs(); inputIndex++) { + IntRect inputRect = GetInputRectInRect(IN_COMPOSITE_IN_START + inputIndex, aRect); + if (mOperator == COMPOSITE_OPERATOR_IN && inputIndex > 0) { + rect = rect.Intersect(inputRect); + } else { + rect = rect.Union(inputRect); + } + } + return rect; +} + +int32_t +FilterNodeBlurXYSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_GAUSSIAN_BLUR_IN: return 0; + default: return -1; + } +} + +TemporaryRef +FilterNodeBlurXYSoftware::Render(const IntRect& aRect) +{ + Size sigmaXY = StdDeviationXY(); + IntSize d = AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY.width, sigmaXY.height)); + + if (d.width == 0 && d.height == 0) { + return GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN, aRect); + } + + IntRect srcRect = InflatedSourceOrDestRect(aRect); + RefPtr input = + GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN, srcRect); + if (!input) { + return nullptr; + } + + RefPtr target; + Rect r(0, 0, srcRect.width, srcRect.height); + + if (input->GetFormat() == SurfaceFormat::A8) { + target = Factory::CreateDataSourceSurface(srcRect.Size(), SurfaceFormat::A8); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + CopyRect(input, target, IntRect(IntPoint(), input->GetSize()), IntPoint()); + AlphaBoxBlur blur(r, target->Stride(), sigmaXY.width, sigmaXY.height); + blur.Blur(target->GetData()); + } else { + RefPtr channel0, channel1, channel2, channel3; + FilterProcessing::SeparateColorChannels(input, channel0, channel1, channel2, channel3); + if (MOZ2D_WARN_IF(!(channel0 && channel1 && channel2))) { + return nullptr; + } + AlphaBoxBlur blur(r, channel0->Stride(), sigmaXY.width, sigmaXY.height); + blur.Blur(channel0->GetData()); + blur.Blur(channel1->GetData()); + blur.Blur(channel2->GetData()); + blur.Blur(channel3->GetData()); + target = FilterProcessing::CombineColorChannels(channel0, channel1, channel2, channel3); + } + + return GetDataSurfaceInRect(target, srcRect, aRect, EDGE_MODE_NONE); +} + +void +FilterNodeBlurXYSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_GAUSSIAN_BLUR_IN, InflatedSourceOrDestRect(aRect)); +} + +IntRect +FilterNodeBlurXYSoftware::InflatedSourceOrDestRect(const IntRect &aDestRect) +{ + Size sigmaXY = StdDeviationXY(); + IntSize d = AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY.width, sigmaXY.height)); + IntRect srcRect = aDestRect; + srcRect.Inflate(d); + return srcRect; +} + +IntRect +FilterNodeBlurXYSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + IntRect srcRequest = InflatedSourceOrDestRect(aRect); + IntRect srcOutput = GetInputRectInRect(IN_GAUSSIAN_BLUR_IN, srcRequest); + return InflatedSourceOrDestRect(srcOutput).Intersect(aRect); +} + +FilterNodeGaussianBlurSoftware::FilterNodeGaussianBlurSoftware() + : mStdDeviation(0) +{} + +static float +ClampStdDeviation(float aStdDeviation) +{ + // Cap software blur radius for performance reasons. + return std::min(std::max(0.0f, aStdDeviation), 100.0f); +} + +void +FilterNodeGaussianBlurSoftware::SetAttribute(uint32_t aIndex, + float aStdDeviation) +{ + switch (aIndex) { + case ATT_GAUSSIAN_BLUR_STD_DEVIATION: + mStdDeviation = ClampStdDeviation(aStdDeviation); + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +Size +FilterNodeGaussianBlurSoftware::StdDeviationXY() +{ + return Size(mStdDeviation, mStdDeviation); +} + +FilterNodeDirectionalBlurSoftware::FilterNodeDirectionalBlurSoftware() + : mBlurDirection(BLUR_DIRECTION_X) +{} + +void +FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex, + Float aStdDeviation) +{ + switch (aIndex) { + case ATT_DIRECTIONAL_BLUR_STD_DEVIATION: + mStdDeviation = ClampStdDeviation(aStdDeviation); + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +void +FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex, + uint32_t aBlurDirection) +{ + switch (aIndex) { + case ATT_DIRECTIONAL_BLUR_DIRECTION: + mBlurDirection = (BlurDirection)aBlurDirection; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +Size +FilterNodeDirectionalBlurSoftware::StdDeviationXY() +{ + float sigmaX = mBlurDirection == BLUR_DIRECTION_X ? mStdDeviation : 0; + float sigmaY = mBlurDirection == BLUR_DIRECTION_Y ? mStdDeviation : 0; + return Size(sigmaX, sigmaY); +} + +int32_t +FilterNodeCropSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_CROP_IN: return 0; + default: return -1; + } +} + +void +FilterNodeCropSoftware::SetAttribute(uint32_t aIndex, + const Rect &aSourceRect) +{ + MOZ_ASSERT(aIndex == ATT_CROP_RECT); + Rect srcRect = aSourceRect; + srcRect.Round(); + if (!srcRect.ToIntRect(&mCropRect)) { + mCropRect = IntRect(); + } + Invalidate(); +} + +TemporaryRef +FilterNodeCropSoftware::Render(const IntRect& aRect) +{ + return GetInputDataSourceSurface(IN_CROP_IN, aRect.Intersect(mCropRect)); +} + +void +FilterNodeCropSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_CROP_IN, aRect.Intersect(mCropRect)); +} + +IntRect +FilterNodeCropSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_CROP_IN, aRect).Intersect(mCropRect); +} + +int32_t +FilterNodePremultiplySoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_PREMULTIPLY_IN: return 0; + default: return -1; + } +} + +TemporaryRef +FilterNodePremultiplySoftware::Render(const IntRect& aRect) +{ + RefPtr input = + GetInputDataSourceSurface(IN_PREMULTIPLY_IN, aRect); + return input ? Premultiply(input) : nullptr; +} + +void +FilterNodePremultiplySoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_PREMULTIPLY_IN, aRect); +} + +IntRect +FilterNodePremultiplySoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_PREMULTIPLY_IN, aRect); +} + +int32_t +FilterNodeUnpremultiplySoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_UNPREMULTIPLY_IN: return 0; + default: return -1; + } +} + +TemporaryRef +FilterNodeUnpremultiplySoftware::Render(const IntRect& aRect) +{ + RefPtr input = + GetInputDataSourceSurface(IN_UNPREMULTIPLY_IN, aRect); + return input ? Unpremultiply(input) : nullptr; +} + +void +FilterNodeUnpremultiplySoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + RequestInputRect(IN_UNPREMULTIPLY_IN, aRect); +} + +IntRect +FilterNodeUnpremultiplySoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_UNPREMULTIPLY_IN, aRect); +} + +bool +PointLightSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint) +{ + switch (aIndex) { + case ATT_POINT_LIGHT_POSITION: + mPosition = aPoint; + break; + default: + return false; + } + return true; +} + +SpotLightSoftware::SpotLightSoftware() + : mSpecularFocus(0) + , mLimitingConeAngle(0) + , mLimitingConeCos(1) +{ +} + +bool +SpotLightSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint) +{ + switch (aIndex) { + case ATT_SPOT_LIGHT_POSITION: + mPosition = aPoint; + break; + case ATT_SPOT_LIGHT_POINTS_AT: + mPointsAt = aPoint; + break; + default: + return false; + } + return true; +} + +bool +SpotLightSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + switch (aIndex) { + case ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE: + mLimitingConeAngle = aValue; + break; + case ATT_SPOT_LIGHT_FOCUS: + mSpecularFocus = aValue; + break; + default: + return false; + } + return true; +} + +DistantLightSoftware::DistantLightSoftware() + : mAzimuth(0) + , mElevation(0) +{ +} + +bool +DistantLightSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + switch (aIndex) { + case ATT_DISTANT_LIGHT_AZIMUTH: + mAzimuth = aValue; + break; + case ATT_DISTANT_LIGHT_ELEVATION: + mElevation = aValue; + break; + default: + return false; + } + return true; +} + +static inline Point3D Normalized(const Point3D &vec) { + Point3D copy(vec); + copy.Normalize(); + return copy; +} + +template +FilterNodeLightingSoftware::FilterNodeLightingSoftware(const char* aTypeName) + : mSurfaceScale(0) +#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) + , mTypeName(aTypeName) +#endif +{} + +template +int32_t +FilterNodeLightingSoftware::InputIndex(uint32_t aInputEnumIndex) +{ + switch (aInputEnumIndex) { + case IN_LIGHTING_IN: return 0; + default: return -1; + } +} + +template +void +FilterNodeLightingSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint) +{ + if (mLight.SetAttribute(aIndex, aPoint)) { + Invalidate(); + return; + } + MOZ_CRASH(); +} + +template +void +FilterNodeLightingSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + if (mLight.SetAttribute(aIndex, aValue) || + mLighting.SetAttribute(aIndex, aValue)) { + Invalidate(); + return; + } + switch (aIndex) { + case ATT_LIGHTING_SURFACE_SCALE: + mSurfaceScale = aValue; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +template +void +FilterNodeLightingSoftware::SetAttribute(uint32_t aIndex, const Size &aKernelUnitLength) +{ + switch (aIndex) { + case ATT_LIGHTING_KERNEL_UNIT_LENGTH: + mKernelUnitLength = aKernelUnitLength; + break; + default: + MOZ_CRASH(); + } + Invalidate(); +} + +template +void +FilterNodeLightingSoftware::SetAttribute(uint32_t aIndex, const Color &aColor) +{ + MOZ_ASSERT(aIndex == ATT_LIGHTING_COLOR); + mColor = aColor; + Invalidate(); +} + +template +IntRect +FilterNodeLightingSoftware::GetOutputRectInRect(const IntRect& aRect) +{ + return GetInputRectInRect(IN_LIGHTING_IN, aRect); +} + +Point3D +PointLightSoftware::GetVectorToLight(const Point3D &aTargetPoint) +{ + return Normalized(mPosition - aTargetPoint); +} + +uint32_t +PointLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight) +{ + return aLightColor; +} + +void +SpotLightSoftware::Prepare() +{ + mVectorFromFocusPointToLight = Normalized(mPointsAt - mPosition); + mLimitingConeCos = std::max(cos(mLimitingConeAngle * M_PI/180.0), 0.0); + mPowCache.CacheForExponent(mSpecularFocus); +} + +Point3D +SpotLightSoftware::GetVectorToLight(const Point3D &aTargetPoint) +{ + return Normalized(mPosition - aTargetPoint); +} + +uint32_t +SpotLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight) +{ + union { + uint32_t color; + uint8_t colorC[4]; + }; + color = aLightColor; + Float dot = -aVectorToLight.DotProduct(mVectorFromFocusPointToLight); + uint16_t doti = dot * (dot >= 0) * (1 << PowCache::sInputIntPrecisionBits); + uint32_t tmp = mPowCache.Pow(doti) * (dot >= mLimitingConeCos); + MOZ_ASSERT(tmp <= (1 << PowCache::sOutputIntPrecisionBits), "pow() result must not exceed 1.0"); + colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_R] * tmp) >> PowCache::sOutputIntPrecisionBits); + colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_G] * tmp) >> PowCache::sOutputIntPrecisionBits); + colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = uint8_t((colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_B] * tmp) >> PowCache::sOutputIntPrecisionBits); + colorC[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = 255; + return color; +} + +void +DistantLightSoftware::Prepare() +{ + const double radPerDeg = M_PI / 180.0; + mVectorToLight.x = cos(mAzimuth * radPerDeg) * cos(mElevation * radPerDeg); + mVectorToLight.y = sin(mAzimuth * radPerDeg) * cos(mElevation * radPerDeg); + mVectorToLight.z = sin(mElevation * radPerDeg); +} + +Point3D +DistantLightSoftware::GetVectorToLight(const Point3D &aTargetPoint) +{ + return mVectorToLight; +} + +uint32_t +DistantLightSoftware::GetColor(uint32_t aLightColor, const Point3D &aVectorToLight) +{ + return aLightColor; +} + +template +static Point3D +GenerateNormal(const uint8_t *data, int32_t stride, + int32_t x, int32_t y, float surfaceScale, + CoordType dx, CoordType dy) +{ + const uint8_t *index = data + y * stride + x; + + CoordType zero = 0; + + // See this for source of constants: + // http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement + int16_t normalX = + -1 * ColorComponentAtPoint(index, stride, -dx, -dy, 1, 0) + + 1 * ColorComponentAtPoint(index, stride, dx, -dy, 1, 0) + + -2 * ColorComponentAtPoint(index, stride, -dx, zero, 1, 0) + + 2 * ColorComponentAtPoint(index, stride, dx, zero, 1, 0) + + -1 * ColorComponentAtPoint(index, stride, -dx, dy, 1, 0) + + 1 * ColorComponentAtPoint(index, stride, dx, dy, 1, 0); + + int16_t normalY = + -1 * ColorComponentAtPoint(index, stride, -dx, -dy, 1, 0) + + -2 * ColorComponentAtPoint(index, stride, zero, -dy, 1, 0) + + -1 * ColorComponentAtPoint(index, stride, dx, -dy, 1, 0) + + 1 * ColorComponentAtPoint(index, stride, -dx, dy, 1, 0) + + 2 * ColorComponentAtPoint(index, stride, zero, dy, 1, 0) + + 1 * ColorComponentAtPoint(index, stride, dx, dy, 1, 0); + + Point3D normal; + normal.x = -surfaceScale * normalX / 4.0f; + normal.y = -surfaceScale * normalY / 4.0f; + normal.z = 255; + return Normalized(normal); +} + +template +TemporaryRef +FilterNodeLightingSoftware::Render(const IntRect& aRect) +{ + if (mKernelUnitLength.width == floor(mKernelUnitLength.width) && + mKernelUnitLength.height == floor(mKernelUnitLength.height)) { + return DoRender(aRect, (int32_t)mKernelUnitLength.width, (int32_t)mKernelUnitLength.height); + } + return DoRender(aRect, mKernelUnitLength.width, mKernelUnitLength.height); +} + +template +void +FilterNodeLightingSoftware::RequestFromInputsForRect(const IntRect &aRect) +{ + IntRect srcRect = aRect; + srcRect.Inflate(ceil(mKernelUnitLength.width), + ceil(mKernelUnitLength.height)); + RequestInputRect(IN_LIGHTING_IN, srcRect); +} + +template template +TemporaryRef +FilterNodeLightingSoftware::DoRender(const IntRect& aRect, + CoordType aKernelUnitLengthX, + CoordType aKernelUnitLengthY) +{ + IntRect srcRect = aRect; + IntSize size = aRect.Size(); + srcRect.Inflate(ceil(float(aKernelUnitLengthX)), + ceil(float(aKernelUnitLengthY))); + RefPtr input = + GetInputDataSourceSurface(IN_LIGHTING_IN, srcRect, CAN_HANDLE_A8, + EDGE_MODE_DUPLICATE); + + if (!input) { + return nullptr; + } + + if (input->GetFormat() != SurfaceFormat::A8) { + input = FilterProcessing::ExtractAlpha(input); + } + + DebugOnlyAutoColorSamplingAccessControl accessControl(input); + + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!target)) { + return nullptr; + } + + IntPoint offset = aRect.TopLeft() - srcRect.TopLeft(); + + uint8_t* sourceData = DataAtOffset(input, offset); + int32_t sourceStride = input->Stride(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + + uint32_t lightColor = ColorToBGRA(mColor); + mLight.Prepare(); + mLighting.Prepare(); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t sourceIndex = y * sourceStride + x; + int32_t targetIndex = y * targetStride + 4 * x; + + Point3D normal = GenerateNormal(sourceData, sourceStride, + x, y, mSurfaceScale, + aKernelUnitLengthX, aKernelUnitLengthY); + + IntPoint pointInFilterSpace(aRect.x + x, aRect.y + y); + Float Z = mSurfaceScale * sourceData[sourceIndex] / 255.0f; + Point3D pt(pointInFilterSpace.x, pointInFilterSpace.y, Z); + Point3D rayDir = mLight.GetVectorToLight(pt); + uint32_t color = mLight.GetColor(lightColor, rayDir); + + *(uint32_t*)(targetData + targetIndex) = mLighting.LightPixel(normal, rayDir, color); + } + } + + return target.forget(); +} + +DiffuseLightingSoftware::DiffuseLightingSoftware() + : mDiffuseConstant(0) +{ +} + +bool +DiffuseLightingSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + switch (aIndex) { + case ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT: + mDiffuseConstant = aValue; + break; + default: + return false; + } + return true; +} + +uint32_t +DiffuseLightingSoftware::LightPixel(const Point3D &aNormal, + const Point3D &aVectorToLight, + uint32_t aColor) +{ + Float dotNL = std::max(0.0f, aNormal.DotProduct(aVectorToLight)); + Float diffuseNL = mDiffuseConstant * dotNL; + + union { + uint32_t bgra; + uint8_t components[4]; + } color = { aColor }; + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = + umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B]), 255U); + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = + umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G]), 255U); + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = + umin(uint32_t(diffuseNL * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R]), 255U); + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = 255; + return color.bgra; +} + +SpecularLightingSoftware::SpecularLightingSoftware() + : mSpecularConstant(0) + , mSpecularExponent(0) +{ +} + +bool +SpecularLightingSoftware::SetAttribute(uint32_t aIndex, Float aValue) +{ + switch (aIndex) { + case ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT: + mSpecularConstant = std::min(std::max(aValue, 0.0f), 255.0f); + break; + case ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT: + mSpecularExponent = std::min(std::max(aValue, 1.0f), 128.0f); + break; + default: + return false; + } + return true; +} + +void +SpecularLightingSoftware::Prepare() +{ + mPowCache.CacheForExponent(mSpecularExponent); + mSpecularConstantInt = uint32_t(mSpecularConstant * (1 << 8)); +} + +uint32_t +SpecularLightingSoftware::LightPixel(const Point3D &aNormal, + const Point3D &aVectorToLight, + uint32_t aColor) +{ + Point3D vectorToEye(0, 0, 1); + Point3D halfwayVector = Normalized(aVectorToLight + vectorToEye); + Float dotNH = aNormal.DotProduct(halfwayVector); + uint16_t dotNHi = uint16_t(dotNH * (dotNH >= 0) * (1 << PowCache::sInputIntPrecisionBits)); + uint32_t specularNHi = uint32_t(mSpecularConstantInt) * mPowCache.Pow(dotNHi) >> 8; + + union { + uint32_t bgra; + uint8_t components[4]; + } color = { aColor }; + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B] = + umin( + (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B]) >> PowCache::sOutputIntPrecisionBits, 255U); + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G] = + umin( + (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G]) >> PowCache::sOutputIntPrecisionBits, 255U); + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R] = + umin( + (specularNHi * color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R]) >> PowCache::sOutputIntPrecisionBits, 255U); + + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_A] = + umax(color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_B], + umax(color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_G], + color.components[B8G8R8A8_COMPONENT_BYTEOFFSET_R])); + return color.bgra; +} + +} // namespace gfx +} // namespace mozilla diff --git a/libazure/FilterNodeSoftware.h b/libazure/FilterNodeSoftware.h new file mode 100644 index 0000000..73b5417 --- /dev/null +++ b/libazure/FilterNodeSoftware.h @@ -0,0 +1,724 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_FILTERNODESOFTWARE_H_ +#define _MOZILLA_GFX_FILTERNODESOFTWARE_H_ + +#include "Filters.h" +#include + +namespace mozilla { +namespace gfx { + +class DataSourceSurface; +class DrawTarget; +struct DrawOptions; +class FilterNodeSoftware; + +/** + * Can be attached to FilterNodeSoftware instances using + * AddInvalidationListener. FilterInvalidated is called whenever the output of + * the observed filter may have changed; that is, whenever cached GetOutput() + * results (and results derived from them) need to discarded. + */ +class FilterInvalidationListener +{ +public: + virtual void FilterInvalidated(FilterNodeSoftware* aFilter) = 0; +}; + +/** + * This is the base class for the software (i.e. pure CPU, non-accelerated) + * FilterNode implementation. The software implementation is backend-agnostic, + * so it can be used as a fallback for all DrawTarget implementations. + */ +class FilterNodeSoftware : public FilterNode, + public FilterInvalidationListener +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeSoftware) + virtual ~FilterNodeSoftware(); + + // Factory method, intended to be called from DrawTarget*::CreateFilter. + static TemporaryRef Create(FilterType aType); + + // Draw the filter, intended to be called by DrawTarget*::DrawFilter. + void Draw(DrawTarget* aDrawTarget, const Rect &aSourceRect, + const Point &aDestPoint, const DrawOptions &aOptions); + + virtual FilterBackend GetBackendType() MOZ_OVERRIDE { return FILTER_BACKEND_SOFTWARE; } + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) MOZ_OVERRIDE; + virtual void SetInput(uint32_t aIndex, FilterNode *aFilter) MOZ_OVERRIDE; + + virtual const char* GetName() { return "Unknown"; } + + virtual void AddInvalidationListener(FilterInvalidationListener* aListener); + virtual void RemoveInvalidationListener(FilterInvalidationListener* aListener); + + // FilterInvalidationListener implementation + virtual void FilterInvalidated(FilterNodeSoftware* aFilter); + +protected: + + // The following methods are intended to be overriden by subclasses. + + /** + * Translates a *FilterInputs enum value into an index for the + * mInputFilters / mInputSurfaces arrays. Returns -1 for invalid inputs. + * If somebody calls SetInput(enumValue, input) with an enumValue for which + * InputIndex(enumValue) is -1, we abort. + */ + virtual int32_t InputIndex(uint32_t aInputEnumIndex) { return -1; } + + /** + * Every filter node has an output rect, which can also be infinite. The + * output rect can depend on the values of any set attributes and on the + * output rects of any input filters or surfaces. + * This method returns the intersection of the filter's output rect with + * aInRect. Filters with unconstrained output always return aInRect. + */ + virtual IntRect GetOutputRectInRect(const IntRect& aInRect) = 0; + + /** + * Return a surface with the rendered output which is of size aRect.Size(). + * aRect is required to be a subrect of this filter's output rect; in other + * words, aRect == GetOutputRectInRect(aRect) must always be true. + * May return nullptr in error conditions or for an empty aRect. + * Implementations are not required to allocate a new surface and may even + * pass through input surfaces unchanged. + * Callers need to treat the returned surface as immutable. + */ + virtual TemporaryRef Render(const IntRect& aRect) = 0; + + /** + * Call RequestRect (see below) on any input filters with the desired input + * rect, so that the input filter knows what to cache the next time it + * renders. + */ + virtual void RequestFromInputsForRect(const IntRect &aRect) {} + + /** + * This method provides a caching default implementation but can be overriden + * by subclasses that don't want to cache their output. Those classes should + * call Render(aRect) directly from here. + */ + virtual TemporaryRef GetOutput(const IntRect &aRect); + + // The following methods are non-virtual helper methods. + + /** + * Format hints for GetInputDataSourceSurface. Some callers of + * GetInputDataSourceSurface can handle both B8G8R8A8 and A8 surfaces, these + * should pass CAN_HANDLE_A8 in order to avoid unnecessary conversions. + * Callers that can only handle B8G8R8A8 surfaces pass NEED_COLOR_CHANNELS. + */ + enum FormatHint { + CAN_HANDLE_A8, + NEED_COLOR_CHANNELS + }; + + /** + * Returns SurfaceFormat::B8G8R8A8 or SurfaceFormat::A8, depending on the current surface + * format and the format hint. + */ + SurfaceFormat DesiredFormat(SurfaceFormat aCurrentFormat, + FormatHint aFormatHint); + + /** + * Intended to be called by FilterNodeSoftware::Render implementations. + * Returns a surface of size aRect.Size() or nullptr in error conditions. The + * returned surface contains the output of the specified input filter or + * input surface in aRect. If aRect extends beyond the input filter's output + * rect (or the input surface's dimensions), the remaining area is filled + * according to aEdgeMode: The default, EDGE_MODE_NONE, simply pads with + * transparent black. + * If non-null, the returned surface is guaranteed to be of SurfaceFormat::A8 or + * SurfaceFormat::B8G8R8A8. If aFormatHint is NEED_COLOR_CHANNELS, the returned + * surface is guaranteed to be of SurfaceFormat::B8G8R8A8 always. + * Each pixel row of the returned surface is guaranteed to be 16-byte aligned. + */ + TemporaryRef + GetInputDataSourceSurface(uint32_t aInputEnumIndex, const IntRect& aRect, + FormatHint aFormatHint = CAN_HANDLE_A8, + ConvolveMatrixEdgeMode aEdgeMode = EDGE_MODE_NONE, + const IntRect *aTransparencyPaddedSourceRect = nullptr); + + /** + * Returns the intersection of the input filter's or surface's output rect + * with aInRect. + */ + IntRect GetInputRectInRect(uint32_t aInputEnumIndex, const IntRect& aInRect); + + /** + * Calls RequestRect on the specified input, if it's a filter. + */ + void RequestInputRect(uint32_t aInputEnumIndex, const IntRect& aRect); + + /** + * Returns the number of set input filters or surfaces. Needed for filters + * which can have an arbitrary number of inputs. + */ + size_t NumberOfSetInputs(); + + /** + * Discard the cached surface that was stored in the GetOutput default + * implementation. Needs to be called whenever attributes or inputs are set + * that might change the result of a Render() call. + */ + void Invalidate(); + + /** + * Called in order to let this filter know what to cache during the next + * GetOutput call. Expected to call RequestRect on this filter's input + * filters. + */ + void RequestRect(const IntRect &aRect); + + /** + * Set input filter and clear input surface for this input index, or set + * input surface and clear input filter. One of aSurface and aFilter should + * be null. + */ + void SetInput(uint32_t aIndex, SourceSurface *aSurface, + FilterNodeSoftware *aFilter); + +protected: + /** + * mInputSurfaces / mInputFilters: For each input index, either a surface or + * a filter is set, and the other is null. + */ + std::vector > mInputSurfaces; + std::vector > mInputFilters; + + /** + * Weak pointers to our invalidation listeners, i.e. to those filters who + * have this filter as an input. Invalidation listeners are required to + * unsubscribe themselves from us when they let go of their reference to us. + * This ensures that the pointers in this array are never stale. + */ + std::vector mInvalidationListeners; + + /** + * Stores the rect which we want to render and cache on the next call to + * GetOutput. + */ + IntRect mRequestedRect; + + /** + * Stores our cached output. + */ + IntRect mCachedRect; + RefPtr mCachedOutput; +}; + +// Subclasses for specific filters. + +class FilterNodeTransformSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeTransformSoftware) + FilterNodeTransformSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "Transform"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, uint32_t aGraphicsFilter) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Matrix &aMatrix) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + IntRect SourceRectForOutputRect(const IntRect &aRect); + +private: + Matrix mMatrix; + Filter mFilter; +}; + +class FilterNodeBlendSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeBlendSoftware) + FilterNodeBlendSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "Blend"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, uint32_t aBlendMode) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + BlendMode mBlendMode; +}; + +class FilterNodeMorphologySoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeMorphologySoftware) + FilterNodeMorphologySoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "Morphology"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const IntSize &aRadii) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aOperator) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + IntSize mRadii; + MorphologyOperator mOperator; +}; + +class FilterNodeColorMatrixSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeColorMatrixSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "ColorMatrix"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Matrix5x4 &aMatrix) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aAlphaMode) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + Matrix5x4 mMatrix; + AlphaMode mAlphaMode; +}; + +class FilterNodeFloodSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeFloodSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "Flood"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Color &aColor) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef GetOutput(const IntRect &aRect) MOZ_OVERRIDE; + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + +private: + Color mColor; +}; + +class FilterNodeTileSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeTileSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "Tile"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const IntRect &aSourceRect) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + IntRect mSourceRect; +}; + +/** + * Baseclass for the four different component transfer filters. + */ +class FilterNodeComponentTransferSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeComponentTransferSoftware) + FilterNodeComponentTransferSoftware(); + + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, bool aDisable) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + virtual void GenerateLookupTable(ptrdiff_t aComponent, uint8_t aTables[4][256], + bool aDisabled); + virtual void FillLookupTable(ptrdiff_t aComponent, uint8_t aTable[256]) = 0; + + bool mDisableR; + bool mDisableG; + bool mDisableB; + bool mDisableA; +}; + +class FilterNodeTableTransferSoftware : public FilterNodeComponentTransferSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeTableTransferSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "TableTransfer"; } + using FilterNodeComponentTransferSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) MOZ_OVERRIDE; + +protected: + virtual void FillLookupTable(ptrdiff_t aComponent, uint8_t aTable[256]) MOZ_OVERRIDE; + +private: + void FillLookupTableImpl(std::vector& aTableValues, uint8_t aTable[256]); + + std::vector mTableR; + std::vector mTableG; + std::vector mTableB; + std::vector mTableA; +}; + +class FilterNodeDiscreteTransferSoftware : public FilterNodeComponentTransferSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeDiscreteTransferSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "DiscreteTransfer"; } + using FilterNodeComponentTransferSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) MOZ_OVERRIDE; + +protected: + virtual void FillLookupTable(ptrdiff_t aComponent, uint8_t aTable[256]) MOZ_OVERRIDE; + +private: + void FillLookupTableImpl(std::vector& aTableValues, uint8_t aTable[256]); + + std::vector mTableR; + std::vector mTableG; + std::vector mTableB; + std::vector mTableA; +}; + +class FilterNodeLinearTransferSoftware : public FilterNodeComponentTransferSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeLinearTransformSoftware) + FilterNodeLinearTransferSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "LinearTransfer"; } + using FilterNodeComponentTransferSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float aValue) MOZ_OVERRIDE; + +protected: + virtual void FillLookupTable(ptrdiff_t aComponent, uint8_t aTable[256]) MOZ_OVERRIDE; + +private: + void FillLookupTableImpl(Float aSlope, Float aIntercept, uint8_t aTable[256]); + + Float mSlopeR; + Float mSlopeG; + Float mSlopeB; + Float mSlopeA; + Float mInterceptR; + Float mInterceptG; + Float mInterceptB; + Float mInterceptA; +}; + +class FilterNodeGammaTransferSoftware : public FilterNodeComponentTransferSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeGammaTransferSoftware) + FilterNodeGammaTransferSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "GammaTransfer"; } + using FilterNodeComponentTransferSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float aValue) MOZ_OVERRIDE; + +protected: + virtual void FillLookupTable(ptrdiff_t aComponent, uint8_t aTable[256]) MOZ_OVERRIDE; + +private: + void FillLookupTableImpl(Float aAmplitude, Float aExponent, Float aOffset, uint8_t aTable[256]); + + Float mAmplitudeR; + Float mAmplitudeG; + Float mAmplitudeB; + Float mAmplitudeA; + Float mExponentR; + Float mExponentG; + Float mExponentB; + Float mExponentA; + Float mOffsetR; + Float mOffsetG; + Float mOffsetB; + Float mOffsetA; +}; + +class FilterNodeConvolveMatrixSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeConvolveMatrixSoftware) + FilterNodeConvolveMatrixSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "ConvolveMatrix"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const IntSize &aKernelSize) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Float* aMatrix, uint32_t aSize) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, Float aValue) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Size &aKernelUnitLength) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const IntRect &aSourceRect) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const IntPoint &aTarget) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aEdgeMode) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, bool aPreserveAlpha) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + template + TemporaryRef DoRender(const IntRect& aRect, + CoordType aKernelUnitLengthX, + CoordType aKernelUnitLengthY); + + IntRect InflatedSourceRect(const IntRect &aDestRect); + IntRect InflatedDestRect(const IntRect &aSourceRect); + + IntSize mKernelSize; + std::vector mKernelMatrix; + Float mDivisor; + Float mBias; + IntPoint mTarget; + IntRect mSourceRect; + ConvolveMatrixEdgeMode mEdgeMode; + Size mKernelUnitLength; + bool mPreserveAlpha; +}; + +class FilterNodeDisplacementMapSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeDisplacementMapSoftware) + FilterNodeDisplacementMapSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "DisplacementMap"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float aScale) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aValue) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + IntRect InflatedSourceOrDestRect(const IntRect &aDestOrSourceRect); + + Float mScale; + ColorChannel mChannelX; + ColorChannel mChannelY; +}; + +class FilterNodeTurbulenceSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeTurbulenceSoftware) + FilterNodeTurbulenceSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "Turbulence"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Size &aSize) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const IntRect &aRenderRect) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, bool aStitchable) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aValue) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + +private: + IntRect mRenderRect; + Size mBaseFrequency; + uint32_t mNumOctaves; + uint32_t mSeed; + bool mStitchable; + TurbulenceType mType; +}; + +class FilterNodeArithmeticCombineSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeArithmeticCombineSoftware) + FilterNodeArithmeticCombineSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "ArithmeticCombine"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + Float mK1; + Float mK2; + Float mK3; + Float mK4; +}; + +class FilterNodeCompositeSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeCompositeSoftware) + FilterNodeCompositeSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "Composite"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, uint32_t aOperator) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + CompositeOperator mOperator; +}; + +// Base class for FilterNodeGaussianBlurSoftware and +// FilterNodeDirectionalBlurSoftware. +class FilterNodeBlurXYSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeBlurXYSoftware) +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + IntRect InflatedSourceOrDestRect(const IntRect &aDestRect); + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + + // Implemented by subclasses. + virtual Size StdDeviationXY() = 0; +}; + +class FilterNodeGaussianBlurSoftware : public FilterNodeBlurXYSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeGaussianBlurSoftware) + FilterNodeGaussianBlurSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "GaussianBlur"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float aStdDeviation) MOZ_OVERRIDE; + +protected: + virtual Size StdDeviationXY() MOZ_OVERRIDE; + +private: + Float mStdDeviation; +}; + +class FilterNodeDirectionalBlurSoftware : public FilterNodeBlurXYSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeDirectionalBlurSoftware) + FilterNodeDirectionalBlurSoftware(); + virtual const char* GetName() MOZ_OVERRIDE { return "DirectionalBlur"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float aStdDeviation) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, uint32_t aBlurDirection) MOZ_OVERRIDE; + +protected: + virtual Size StdDeviationXY() MOZ_OVERRIDE; + +private: + Float mStdDeviation; + BlurDirection mBlurDirection; +}; + +class FilterNodeCropSoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeCropSoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "Crop"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, const Rect &aSourceRect) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + IntRect mCropRect; +}; + +class FilterNodePremultiplySoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodePremultiplySoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "Premultiply"; } +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; +}; + +class FilterNodeUnpremultiplySoftware : public FilterNodeSoftware +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeUnpremultiplySoftware) + virtual const char* GetName() MOZ_OVERRIDE { return "Unpremultiply"; } +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; +}; + +template +class FilterNodeLightingSoftware : public FilterNodeSoftware +{ +public: +#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) + // Helpers for refcounted + virtual const char* typeName() const MOZ_OVERRIDE { return mTypeName; } + virtual size_t typeSize() const MOZ_OVERRIDE { return sizeof(*this); } +#endif + explicit FilterNodeLightingSoftware(const char* aTypeName); + virtual const char* GetName() MOZ_OVERRIDE { return "Lighting"; } + using FilterNodeSoftware::SetAttribute; + virtual void SetAttribute(uint32_t aIndex, Float) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Size &) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Point3D &) MOZ_OVERRIDE; + virtual void SetAttribute(uint32_t aIndex, const Color &) MOZ_OVERRIDE; + +protected: + virtual TemporaryRef Render(const IntRect& aRect) MOZ_OVERRIDE; + virtual IntRect GetOutputRectInRect(const IntRect& aRect) MOZ_OVERRIDE; + virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE; + virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE; + +private: + template + TemporaryRef DoRender(const IntRect& aRect, + CoordType aKernelUnitLengthX, + CoordType aKernelUnitLengthY); + + LightType mLight; + LightingType mLighting; + Float mSurfaceScale; + Size mKernelUnitLength; + Color mColor; +#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) + const char* mTypeName; +#endif +}; + +} +} + +#endif // _MOZILLA_GFX_FILTERNODESOFTWARE_H_ diff --git a/libazure/FilterProcessing.cpp b/libazure/FilterProcessing.cpp new file mode 100644 index 0000000..084f947 --- /dev/null +++ b/libazure/FilterProcessing.cpp @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FilterProcessing.h" +#include "Logging.h" + +namespace mozilla { +namespace gfx { + +TemporaryRef +FilterProcessing::ExtractAlpha(DataSourceSurface* aSource) +{ + IntSize size = aSource->GetSize(); + RefPtr alpha = Factory::CreateDataSourceSurface(size, SurfaceFormat::A8); + if (MOZ2D_WARN_IF(!alpha)) { + return nullptr; + } + uint8_t* sourceData = aSource->GetData(); + int32_t sourceStride = aSource->Stride(); + uint8_t* alphaData = alpha->GetData(); + int32_t alphaStride = alpha->Stride(); + + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + ExtractAlpha_SSE2(size, sourceData, sourceStride, alphaData, alphaStride); +#endif + } else { + ExtractAlpha_Scalar(size, sourceData, sourceStride, alphaData, alphaStride); + } + + return alpha.forget(); +} + +TemporaryRef +FilterProcessing::ConvertToB8G8R8A8(SourceSurface* aSurface) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + return ConvertToB8G8R8A8_SSE2(aSurface); +#endif + } + return ConvertToB8G8R8A8_Scalar(aSurface); +} + +TemporaryRef +FilterProcessing::ApplyBlending(DataSourceSurface* aInput1, DataSourceSurface* aInput2, + BlendMode aBlendMode) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + return ApplyBlending_SSE2(aInput1, aInput2, aBlendMode); +#endif + } + return nullptr; +} + +void +FilterProcessing::ApplyMorphologyHorizontal(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + ApplyMorphologyHorizontal_SSE2( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); +#endif + } else { + ApplyMorphologyHorizontal_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); + } +} + +void +FilterProcessing::ApplyMorphologyVertical(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + ApplyMorphologyVertical_SSE2( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); +#endif + } else { + ApplyMorphologyVertical_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); + } +} + +TemporaryRef +FilterProcessing::ApplyColorMatrix(DataSourceSurface* aInput, const Matrix5x4 &aMatrix) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + return ApplyColorMatrix_SSE2(aInput, aMatrix); +#endif + } + return ApplyColorMatrix_Scalar(aInput, aMatrix); +} + +void +FilterProcessing::ApplyComposition(DataSourceSurface* aSource, DataSourceSurface* aDest, + CompositeOperator aOperator) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + ApplyComposition_SSE2(aSource, aDest, aOperator); +#endif + } else { + ApplyComposition_Scalar(aSource, aDest, aOperator); + } +} + +void +FilterProcessing::SeparateColorChannels(DataSourceSurface* aSource, + RefPtr& aChannel0, + RefPtr& aChannel1, + RefPtr& aChannel2, + RefPtr& aChannel3) +{ + IntSize size = aSource->GetSize(); + aChannel0 = Factory::CreateDataSourceSurface(size, SurfaceFormat::A8); + aChannel1 = Factory::CreateDataSourceSurface(size, SurfaceFormat::A8); + aChannel2 = Factory::CreateDataSourceSurface(size, SurfaceFormat::A8); + aChannel3 = Factory::CreateDataSourceSurface(size, SurfaceFormat::A8); + if (MOZ2D_WARN_IF(!(aChannel0 && aChannel1 && aChannel2 && aChannel3))) { + return; + } + + uint8_t* sourceData = aSource->GetData(); + int32_t sourceStride = aSource->Stride(); + uint8_t* channel0Data = aChannel0->GetData(); + uint8_t* channel1Data = aChannel1->GetData(); + uint8_t* channel2Data = aChannel2->GetData(); + uint8_t* channel3Data = aChannel3->GetData(); + int32_t channelStride = aChannel0->Stride(); + + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + SeparateColorChannels_SSE2(size, sourceData, sourceStride, channel0Data, channel1Data, channel2Data, channel3Data, channelStride); +#endif + } else { + SeparateColorChannels_Scalar(size, sourceData, sourceStride, channel0Data, channel1Data, channel2Data, channel3Data, channelStride); + } +} + +TemporaryRef +FilterProcessing::CombineColorChannels(DataSourceSurface* aChannel0, DataSourceSurface* aChannel1, + DataSourceSurface* aChannel2, DataSourceSurface* aChannel3) +{ + IntSize size = aChannel0->GetSize(); + RefPtr result = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (MOZ2D_WARN_IF(!result)) { + return nullptr; + } + int32_t resultStride = result->Stride(); + uint8_t* resultData = result->GetData(); + int32_t channelStride = aChannel0->Stride(); + uint8_t* channel0Data = aChannel0->GetData(); + uint8_t* channel1Data = aChannel1->GetData(); + uint8_t* channel2Data = aChannel2->GetData(); + uint8_t* channel3Data = aChannel3->GetData(); + + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + CombineColorChannels_SSE2(size, resultStride, resultData, channelStride, channel0Data, channel1Data, channel2Data, channel3Data); +#endif + } else { + CombineColorChannels_Scalar(size, resultStride, resultData, channelStride, channel0Data, channel1Data, channel2Data, channel3Data); + } + + return result.forget(); +} + +void +FilterProcessing::DoPremultiplicationCalculation(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + DoPremultiplicationCalculation_SSE2( + aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); +#endif + } else { + DoPremultiplicationCalculation_Scalar( + aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); + } +} + +void +FilterProcessing::DoUnpremultiplicationCalculation(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + DoUnpremultiplicationCalculation_SSE2( + aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); +#endif + } else { + DoUnpremultiplicationCalculation_Scalar( + aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); + } +} + +TemporaryRef +FilterProcessing::RenderTurbulence(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + return RenderTurbulence_SSE2(aSize, aOffset, aBaseFrequency, aSeed, aNumOctaves, aType, aStitch, aTileRect); +#endif + } + return RenderTurbulence_Scalar(aSize, aOffset, aBaseFrequency, aSeed, aNumOctaves, aType, aStitch, aTileRect); +} + +TemporaryRef +FilterProcessing::ApplyArithmeticCombine(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4) +{ + if (Factory::HasSSE2()) { +#ifdef USE_SSE2 + return ApplyArithmeticCombine_SSE2(aInput1, aInput2, aK1, aK2, aK3, aK4); +#endif + } + return ApplyArithmeticCombine_Scalar(aInput1, aInput2, aK1, aK2, aK3, aK4); +} + +} // namespace gfx +} // namespace mozilla diff --git a/libazure/FilterProcessing.h b/libazure/FilterProcessing.h new file mode 100644 index 0000000..253d165 --- /dev/null +++ b/libazure/FilterProcessing.h @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_FILTERPROCESSING_H_ +#define _MOZILLA_GFX_FILTERPROCESSING_H_ + +#include "2D.h" +#include "Filters.h" + +namespace mozilla { +namespace gfx { + +const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_B = 0; +const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_G = 1; +const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_R = 2; +const ptrdiff_t B8G8R8A8_COMPONENT_BYTEOFFSET_A = 3; + +class FilterProcessing +{ +public: + + // Fast approximate division by 255. It has the property that + // for all 0 <= v <= 255*255, FastDivideBy255(v) == v/255. + // But it only uses two adds and two shifts instead of an + // integer division (which is expensive on many processors). + template + static B FastDivideBy255(A v) + { + return ((v << 8) + v + 255) >> 16; + } + + static TemporaryRef ExtractAlpha(DataSourceSurface* aSource); + static TemporaryRef ConvertToB8G8R8A8(SourceSurface* aSurface); + static TemporaryRef ApplyBlending(DataSourceSurface* aInput1, DataSourceSurface* aInput2, BlendMode aBlendMode); + static void ApplyMorphologyHorizontal(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static void ApplyMorphologyVertical(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static TemporaryRef ApplyColorMatrix(DataSourceSurface* aInput, const Matrix5x4 &aMatrix); + static void ApplyComposition(DataSourceSurface* aSource, DataSourceSurface* aDest, CompositeOperator aOperator); + static void SeparateColorChannels(DataSourceSurface* aSource, + RefPtr& aChannel0, + RefPtr& aChannel1, + RefPtr& aChannel2, + RefPtr& aChannel3); + static TemporaryRef + CombineColorChannels(DataSourceSurface* aChannel0, DataSourceSurface* aChannel1, + DataSourceSurface* aChannel2, DataSourceSurface* aChannel3); + static void DoPremultiplicationCalculation(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static void DoUnpremultiplicationCalculation(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static TemporaryRef + RenderTurbulence(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect); + static TemporaryRef + ApplyArithmeticCombine(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4); + +protected: + static void ExtractAlpha_Scalar(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride); + static TemporaryRef ConvertToB8G8R8A8_Scalar(SourceSurface* aSurface); + static void ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static void ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static TemporaryRef ApplyColorMatrix_Scalar(DataSourceSurface* aInput, const Matrix5x4 &aMatrix); + static void ApplyComposition_Scalar(DataSourceSurface* aSource, DataSourceSurface* aDest, CompositeOperator aOperator); + + static void SeparateColorChannels_Scalar(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data, int32_t channelStride); + static void CombineColorChannels_Scalar(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data); + static void DoPremultiplicationCalculation_Scalar(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static void DoUnpremultiplicationCalculation_Scalar(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static TemporaryRef + RenderTurbulence_Scalar(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect); + static TemporaryRef + ApplyArithmeticCombine_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4); + +#ifdef USE_SSE2 + static void ExtractAlpha_SSE2(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride); + static TemporaryRef ConvertToB8G8R8A8_SSE2(SourceSurface* aSurface); + static TemporaryRef ApplyBlending_SSE2(DataSourceSurface* aInput1, DataSourceSurface* aInput2, BlendMode aBlendMode); + static void ApplyMorphologyHorizontal_SSE2(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static void ApplyMorphologyVertical_SSE2(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOperator); + static TemporaryRef ApplyColorMatrix_SSE2(DataSourceSurface* aInput, const Matrix5x4 &aMatrix); + static void ApplyComposition_SSE2(DataSourceSurface* aSource, DataSourceSurface* aDest, CompositeOperator aOperator); + static void SeparateColorChannels_SSE2(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data, int32_t channelStride); + static void CombineColorChannels_SSE2(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data); + static void DoPremultiplicationCalculation_SSE2(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static void DoUnpremultiplicationCalculation_SSE2(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride); + static TemporaryRef + RenderTurbulence_SSE2(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect); + static TemporaryRef + ApplyArithmeticCombine_SSE2(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4); +#endif +}; + +// Constant-time max and min functions for unsigned arguments +static inline unsigned +umax(unsigned a, unsigned b) +{ + return a - ((a - b) & -(a < b)); +} + +static inline unsigned +umin(unsigned a, unsigned b) +{ + return a - ((a - b) & -(a > b)); +} + +} // namespace gfx +} // namespace mozilla + +#endif // _MOZILLA_GFX_FILTERPROCESSING_H_ diff --git a/libazure/FilterProcessingSIMD-inl.h b/libazure/FilterProcessingSIMD-inl.h new file mode 100644 index 0000000..8f58809 --- /dev/null +++ b/libazure/FilterProcessingSIMD-inl.h @@ -0,0 +1,1081 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FilterProcessing.h" + +#include "SIMD.h" +#include "SVGTurbulenceRenderer-inl.h" + +namespace mozilla { +namespace gfx { + +template +inline TemporaryRef +ConvertToB8G8R8A8_SIMD(SourceSurface* aSurface) +{ + IntSize size = aSurface->GetSize(); + RefPtr input = aSurface->GetDataSurface(); + RefPtr output = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + uint8_t *inputData = input->GetData(); + uint8_t *outputData = output->GetData(); + int32_t inputStride = input->Stride(); + int32_t outputStride = output->Stride(); + switch (input->GetFormat()) { + case SurfaceFormat::B8G8R8A8: + output = input; + break; + case SurfaceFormat::B8G8R8X8: + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t inputIndex = y * inputStride + 4 * x; + int32_t outputIndex = y * outputStride + 4 * x; + outputData[outputIndex + 0] = inputData[inputIndex + 0]; + outputData[outputIndex + 1] = inputData[inputIndex + 1]; + outputData[outputIndex + 2] = inputData[inputIndex + 2]; + outputData[outputIndex + 3] = 255; + } + } + break; + case SurfaceFormat::R8G8B8A8: + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t inputIndex = y * inputStride + 4 * x; + int32_t outputIndex = y * outputStride + 4 * x; + outputData[outputIndex + 2] = inputData[inputIndex + 0]; + outputData[outputIndex + 1] = inputData[inputIndex + 1]; + outputData[outputIndex + 0] = inputData[inputIndex + 2]; + outputData[outputIndex + 3] = inputData[inputIndex + 3]; + } + } + break; + case SurfaceFormat::R8G8B8X8: + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t inputIndex = y * inputStride + 4 * x; + int32_t outputIndex = y * outputStride + 4 * x; + outputData[outputIndex + 2] = inputData[inputIndex + 0]; + outputData[outputIndex + 1] = inputData[inputIndex + 1]; + outputData[outputIndex + 0] = inputData[inputIndex + 2]; + outputData[outputIndex + 3] = 255; + } + } + break; + case SurfaceFormat::A8: + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 16) { + int32_t inputIndex = y * inputStride + x; + int32_t outputIndex = y * outputStride + 4 * x; + u8x16_t p1To16 = simd::Load8(&inputData[inputIndex]); + // Turn AAAAAAAAAAAAAAAA into four chunks of 000A000A000A000A by + // interleaving with 0000000000000000 twice. + u8x16_t zero = simd::FromZero8(); + u8x16_t p1To8 = simd::InterleaveLo8(zero, p1To16); + u8x16_t p9To16 = simd::InterleaveHi8(zero, p1To16); + u8x16_t p1To4 = simd::InterleaveLo8(zero, p1To8); + u8x16_t p5To8 = simd::InterleaveHi8(zero, p1To8); + u8x16_t p9To12 = simd::InterleaveLo8(zero, p9To16); + u8x16_t p13To16 = simd::InterleaveHi8(zero, p9To16); + simd::Store8(&outputData[outputIndex], p1To4); + if ((x + 4) * 4 < outputStride) { + simd::Store8(&outputData[outputIndex + 4 * 4], p5To8); + } + if ((x + 8) * 4 < outputStride) { + simd::Store8(&outputData[outputIndex + 4 * 8], p9To12); + } + if ((x + 12) * 4 < outputStride) { + simd::Store8(&outputData[outputIndex + 4 * 12], p13To16); + } + } + } + break; + default: + output = nullptr; + break; + } + return output; +} + +template +inline void +ExtractAlpha_SIMD(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 16) { + // Process 16 pixels at a time. + // Turn up to four chunks of BGRABGRABGRABGRA into one chunk of AAAAAAAAAAAAAAAA. + int32_t sourceIndex = y * sourceStride + 4 * x; + int32_t targetIndex = y * alphaStride + x; + + u8x16_t bgrabgrabgrabgra1 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra2 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra3 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra4 = simd::FromZero8(); + + bgrabgrabgrabgra1 = simd::Load8(&sourceData[sourceIndex]); + if (4 * (x + 4) < sourceStride) { + bgrabgrabgrabgra2 = simd::Load8(&sourceData[sourceIndex + 4 * 4]); + } + if (4 * (x + 8) < sourceStride) { + bgrabgrabgrabgra3 = simd::Load8(&sourceData[sourceIndex + 4 * 8]); + } + if (4 * (x + 12) < sourceStride) { + bgrabgrabgrabgra4 = simd::Load8(&sourceData[sourceIndex + 4 * 12]); + } + + u8x16_t bbggrraabbggrraa1 = simd::InterleaveLo8(bgrabgrabgrabgra1, bgrabgrabgrabgra3); + u8x16_t bbggrraabbggrraa2 = simd::InterleaveHi8(bgrabgrabgrabgra1, bgrabgrabgrabgra3); + u8x16_t bbggrraabbggrraa3 = simd::InterleaveLo8(bgrabgrabgrabgra2, bgrabgrabgrabgra4); + u8x16_t bbggrraabbggrraa4 = simd::InterleaveHi8(bgrabgrabgrabgra2, bgrabgrabgrabgra4); + u8x16_t bbbbggggrrrraaaa1 = simd::InterleaveLo8(bbggrraabbggrraa1, bbggrraabbggrraa3); + u8x16_t bbbbggggrrrraaaa2 = simd::InterleaveHi8(bbggrraabbggrraa1, bbggrraabbggrraa3); + u8x16_t bbbbggggrrrraaaa3 = simd::InterleaveLo8(bbggrraabbggrraa2, bbggrraabbggrraa4); + u8x16_t bbbbggggrrrraaaa4 = simd::InterleaveHi8(bbggrraabbggrraa2, bbggrraabbggrraa4); + u8x16_t rrrrrrrraaaaaaaa1 = simd::InterleaveHi8(bbbbggggrrrraaaa1, bbbbggggrrrraaaa3); + u8x16_t rrrrrrrraaaaaaaa2 = simd::InterleaveHi8(bbbbggggrrrraaaa2, bbbbggggrrrraaaa4); + u8x16_t aaaaaaaaaaaaaaaa = simd::InterleaveHi8(rrrrrrrraaaaaaaa1, rrrrrrrraaaaaaaa2); + + simd::Store8(&alphaData[targetIndex], aaaaaaaaaaaaaaaa); + } + } +} + +// This function calculates the result color values for four pixels, but for +// only two color channels - either b & r or g & a. However, the a result will +// not be used. +// source and dest each contain 8 values, either bbbb gggg or rrrr aaaa. +// sourceAlpha and destAlpha are of the form aaaa aaaa, where each aaaa is the +// alpha of all four pixels (and both aaaa's are the same). +// blendendComponent1 and blendedComponent2 are the out parameters. +template +inline void +BlendTwoComponentsOfFourPixels(i16x8_t source, i16x8_t sourceAlpha, + i16x8_t dest, const i16x8_t& destAlpha, + i32x4_t& blendedComponent1, i32x4_t& blendedComponent2) +{ + i16x8_t x255 = simd::FromI16(255); + + switch (aBlendMode) { + + case BLEND_MODE_MULTIPLY: + { + // val = ((255 - destAlpha) * source + (255 - sourceAlpha + source) * dest); + i16x8_t twoFiftyFiveMinusDestAlpha = simd::Sub16(x255, destAlpha); + i16x8_t twoFiftyFiveMinusSourceAlpha = simd::Sub16(x255, sourceAlpha); + i16x8_t twoFiftyFiveMinusSourceAlphaPlusSource = simd::Add16(twoFiftyFiveMinusSourceAlpha, source); + + i16x8_t sourceInterleavedWithDest1 = simd::InterleaveLo16(source, dest); + i16x8_t leftFactor1 = simd::InterleaveLo16(twoFiftyFiveMinusDestAlpha, twoFiftyFiveMinusSourceAlphaPlusSource); + blendedComponent1 = simd::MulAdd16x8x2To32x4(sourceInterleavedWithDest1, leftFactor1); + blendedComponent1 = simd::FastDivideBy255(blendedComponent1); + + i16x8_t sourceInterleavedWithDest2 = simd::InterleaveHi16(source, dest); + i16x8_t leftFactor2 = simd::InterleaveHi16(twoFiftyFiveMinusDestAlpha, twoFiftyFiveMinusSourceAlphaPlusSource); + blendedComponent2 = simd::MulAdd16x8x2To32x4(sourceInterleavedWithDest2, leftFactor2); + blendedComponent2 = simd::FastDivideBy255(blendedComponent2); + + break; + } + + case BLEND_MODE_SCREEN: + { + // val = 255 * (source + dest) + (0 - dest) * source; + i16x8_t sourcePlusDest = simd::Add16(source, dest); + i16x8_t zeroMinusDest = simd::Sub16(simd::FromI16(0), dest); + + i16x8_t twoFiftyFiveInterleavedWithZeroMinusDest1 = simd::InterleaveLo16(x255, zeroMinusDest); + i16x8_t sourcePlusDestInterleavedWithSource1 = simd::InterleaveLo16(sourcePlusDest, source); + blendedComponent1 = simd::MulAdd16x8x2To32x4(twoFiftyFiveInterleavedWithZeroMinusDest1, sourcePlusDestInterleavedWithSource1); + blendedComponent1 = simd::FastDivideBy255(blendedComponent1); + + i16x8_t twoFiftyFiveInterleavedWithZeroMinusDest2 = simd::InterleaveHi16(x255, zeroMinusDest); + i16x8_t sourcePlusDestInterleavedWithSource2 = simd::InterleaveHi16(sourcePlusDest, source); + blendedComponent2 = simd::MulAdd16x8x2To32x4(twoFiftyFiveInterleavedWithZeroMinusDest2, sourcePlusDestInterleavedWithSource2); + blendedComponent2 = simd::FastDivideBy255(blendedComponent2); + + break; + } + + case BLEND_MODE_DARKEN: + case BLEND_MODE_LIGHTEN: + { + // Darken: + // val = min((255 - destAlpha) * source + 255 * dest, + // 255 * source + (255 - sourceAlpha) * dest); + // + // Lighten: + // val = max((255 - destAlpha) * source + 255 * dest, + // 255 * source + (255 - sourceAlpha) * dest); + + i16x8_t twoFiftyFiveMinusDestAlpha = simd::Sub16(x255, destAlpha); + i16x8_t twoFiftyFiveMinusSourceAlpha = simd::Sub16(x255, sourceAlpha); + + i16x8_t twoFiftyFiveMinusDestAlphaInterleavedWithTwoFiftyFive1 = simd::InterleaveLo16(twoFiftyFiveMinusDestAlpha, x255); + i16x8_t twoFiftyFiveInterleavedWithTwoFiftyFiveMinusSourceAlpha1 = simd::InterleaveLo16(x255, twoFiftyFiveMinusSourceAlpha); + i16x8_t sourceInterleavedWithDest1 = simd::InterleaveLo16(source, dest); + i32x4_t product1_1 = simd::MulAdd16x8x2To32x4(twoFiftyFiveMinusDestAlphaInterleavedWithTwoFiftyFive1, sourceInterleavedWithDest1); + i32x4_t product1_2 = simd::MulAdd16x8x2To32x4(twoFiftyFiveInterleavedWithTwoFiftyFiveMinusSourceAlpha1, sourceInterleavedWithDest1); + blendedComponent1 = aBlendMode == BLEND_MODE_DARKEN ? simd::Min32(product1_1, product1_2) : simd::Max32(product1_1, product1_2); + blendedComponent1 = simd::FastDivideBy255(blendedComponent1); + + i16x8_t twoFiftyFiveMinusDestAlphaInterleavedWithTwoFiftyFive2 = simd::InterleaveHi16(twoFiftyFiveMinusDestAlpha, x255); + i16x8_t twoFiftyFiveInterleavedWithTwoFiftyFiveMinusSourceAlpha2 = simd::InterleaveHi16(x255, twoFiftyFiveMinusSourceAlpha); + i16x8_t sourceInterleavedWithDest2 = simd::InterleaveHi16(source, dest); + i32x4_t product2_1 = simd::MulAdd16x8x2To32x4(twoFiftyFiveMinusDestAlphaInterleavedWithTwoFiftyFive2, sourceInterleavedWithDest2); + i32x4_t product2_2 = simd::MulAdd16x8x2To32x4(twoFiftyFiveInterleavedWithTwoFiftyFiveMinusSourceAlpha2, sourceInterleavedWithDest2); + blendedComponent2 = aBlendMode == BLEND_MODE_DARKEN ? simd::Min32(product2_1, product2_2) : simd::Max32(product2_1, product2_2); + blendedComponent2 = simd::FastDivideBy255(blendedComponent2); + + break; + } + + } +} + +// The alpha channel is subject to a different calculation than the RGB +// channels, and this calculation is the same for all blend modes: +// resultAlpha * 255 = 255 * 255 - (255 - sourceAlpha) * (255 - destAlpha) +template +inline i32x4_t +BlendAlphaOfFourPixels(i16x8_t s_rrrraaaa1234, i16x8_t d_rrrraaaa1234) +{ + // We're using MulAdd16x8x2To32x4, so we need to interleave our factors + // appropriately. The calculation is rewritten as follows: + // resultAlpha[0] * 255 = 255 * 255 - (255 - sourceAlpha[0]) * (255 - destAlpha[0]) + // = 255 * 255 + (255 - sourceAlpha[0]) * (destAlpha[0] - 255) + // = (255 - 0) * (510 - 255) + (255 - sourceAlpha[0]) * (destAlpha[0] - 255) + // = MulAdd(255 - IntLv(0, sourceAlpha), IntLv(510, destAlpha) - 255)[0] + i16x8_t zeroInterleavedWithSourceAlpha = simd::InterleaveHi16(simd::FromI16(0), s_rrrraaaa1234); + i16x8_t fiveTenInterleavedWithDestAlpha = simd::InterleaveHi16(simd::FromI16(510), d_rrrraaaa1234); + i16x8_t f1 = simd::Sub16(simd::FromI16(255), zeroInterleavedWithSourceAlpha); + i16x8_t f2 = simd::Sub16(fiveTenInterleavedWithDestAlpha, simd::FromI16(255)); + return simd::FastDivideBy255(simd::MulAdd16x8x2To32x4(f1, f2)); +} + +template +inline void +UnpackAndShuffleComponents(u8x16_t bgrabgrabgrabgra1234, + i16x8_t& bbbbgggg1234, i16x8_t& rrrraaaa1234) +{ + // bgrabgrabgrabgra1234 -> bbbbgggg1234, rrrraaaa1234 + i16x8_t bgrabgra12 = simd::UnpackLo8x8ToI16x8(bgrabgrabgrabgra1234); + i16x8_t bgrabgra34 = simd::UnpackHi8x8ToI16x8(bgrabgrabgrabgra1234); + i16x8_t bbggrraa13 = simd::InterleaveLo16(bgrabgra12, bgrabgra34); + i16x8_t bbggrraa24 = simd::InterleaveHi16(bgrabgra12, bgrabgra34); + bbbbgggg1234 = simd::InterleaveLo16(bbggrraa13, bbggrraa24); + rrrraaaa1234 = simd::InterleaveHi16(bbggrraa13, bbggrraa24); +} + +template +inline u8x16_t +ShuffleAndPackComponents(i32x4_t bbbb1234, i32x4_t gggg1234, + i32x4_t rrrr1234, const i32x4_t& aaaa1234) +{ + // bbbb1234, gggg1234, rrrr1234, aaaa1234 -> bgrabgrabgrabgra1234 + i16x8_t bbbbgggg1234 = simd::PackAndSaturate32To16(bbbb1234, gggg1234); + i16x8_t rrrraaaa1234 = simd::PackAndSaturate32To16(rrrr1234, aaaa1234); + i16x8_t brbrbrbr1234 = simd::InterleaveLo16(bbbbgggg1234, rrrraaaa1234); + i16x8_t gagagaga1234 = simd::InterleaveHi16(bbbbgggg1234, rrrraaaa1234); + i16x8_t bgrabgra12 = simd::InterleaveLo16(brbrbrbr1234, gagagaga1234); + i16x8_t bgrabgra34 = simd::InterleaveHi16(brbrbrbr1234, gagagaga1234); + return simd::PackAndSaturate16To8(bgrabgra12, bgrabgra34); +} + +template +inline TemporaryRef +ApplyBlending_SIMD(DataSourceSurface* aInput1, DataSourceSurface* aInput2) +{ + IntSize size = aInput1->GetSize(); + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (!target) { + return nullptr; + } + + uint8_t* source1Data = aInput1->GetData(); + uint8_t* source2Data = aInput2->GetData(); + uint8_t* targetData = target->GetData(); + int32_t targetStride = target->Stride(); + int32_t source1Stride = aInput1->Stride(); + int32_t source2Stride = aInput2->Stride(); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 4) { + int32_t targetIndex = y * targetStride + 4 * x; + int32_t source1Index = y * source1Stride + 4 * x; + int32_t source2Index = y * source2Stride + 4 * x; + + u8x16_t s1234 = simd::Load8(&source2Data[source2Index]); + u8x16_t d1234 = simd::Load8(&source1Data[source1Index]); + + // The blending calculation for the RGB channels all need access to the + // alpha channel of their pixel, and the alpha calculation is different, + // so it makes sense to separate by channel. + + i16x8_t s_bbbbgggg1234, s_rrrraaaa1234; + i16x8_t d_bbbbgggg1234, d_rrrraaaa1234; + UnpackAndShuffleComponents(s1234, s_bbbbgggg1234, s_rrrraaaa1234); + UnpackAndShuffleComponents(d1234, d_bbbbgggg1234, d_rrrraaaa1234); + i16x8_t s_aaaaaaaa1234 = simd::Shuffle32<3,2,3,2>(s_rrrraaaa1234); + i16x8_t d_aaaaaaaa1234 = simd::Shuffle32<3,2,3,2>(d_rrrraaaa1234); + + // We only use blendedB, blendedG and blendedR. + i32x4_t blendedB, blendedG, blendedR, blendedA; + BlendTwoComponentsOfFourPixels(s_bbbbgggg1234, s_aaaaaaaa1234, d_bbbbgggg1234, d_aaaaaaaa1234, blendedB, blendedG); + BlendTwoComponentsOfFourPixels(s_rrrraaaa1234, s_aaaaaaaa1234, d_rrrraaaa1234, d_aaaaaaaa1234, blendedR, blendedA); + + // Throw away blendedA and overwrite it with the correct blended alpha. + blendedA = BlendAlphaOfFourPixels(s_rrrraaaa1234, d_rrrraaaa1234); + + u8x16_t result1234 = ShuffleAndPackComponents(blendedB, blendedG, blendedR, blendedA); + simd::Store8(&targetData[targetIndex], result1234); + } + } + + return target; +} + +template +static TemporaryRef +ApplyBlending_SIMD(DataSourceSurface* aInput1, DataSourceSurface* aInput2, + BlendMode aBlendMode) +{ + switch (aBlendMode) { + case BLEND_MODE_MULTIPLY: + return ApplyBlending_SIMD(aInput1, aInput2); + case BLEND_MODE_SCREEN: + return ApplyBlending_SIMD(aInput1, aInput2); + case BLEND_MODE_DARKEN: + return ApplyBlending_SIMD(aInput1, aInput2); + case BLEND_MODE_LIGHTEN: + return ApplyBlending_SIMD(aInput1, aInput2); + default: + return nullptr; + } +} + +template +static u8x16_t +Morph8(u8x16_t a, u8x16_t b) +{ + return Operator == MORPHOLOGY_OPERATOR_ERODE ? + simd::Min8(a, b) : simd::Max8(a, b); +} + +// Set every pixel to the per-component minimum or maximum of the pixels around +// it that are up to aRadius pixels away from it (horizontally). +template +inline void ApplyMorphologyHorizontal_SIMD(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius) +{ + static_assert(op == MORPHOLOGY_OPERATOR_ERODE || + op == MORPHOLOGY_OPERATOR_DILATE, + "unexpected morphology operator"); + + int32_t kernelSize = aRadius + 1 + aRadius; + MOZ_ASSERT(kernelSize >= 3, "don't call this with aRadius <= 0"); + MOZ_ASSERT(kernelSize % 4 == 1 || kernelSize % 4 == 3); + int32_t completeKernelSizeForFourPixels = kernelSize + 3; + MOZ_ASSERT(completeKernelSizeForFourPixels % 4 == 0 || + completeKernelSizeForFourPixels % 4 == 2); + + // aSourceData[-aRadius] and aDestData[0] are both aligned to 16 bytes, just + // the way we need them to be. + + IntRect sourceRect = aDestRect; + sourceRect.Inflate(aRadius, 0); + + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++) { + int32_t kernelStartX = aDestRect.x - aRadius; + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x += 4, kernelStartX += 4) { + // We process four pixels (16 color values) at a time. + // aSourceData[0] points to the pixel located at aDestRect.TopLeft(); + // source values can be read beyond that because the source is extended + // by aRadius pixels. + + int32_t sourceIndex = y * aSourceStride + 4 * kernelStartX; + u8x16_t p1234 = simd::Load8(&aSourceData[sourceIndex]); + u8x16_t m1234 = p1234; + + for (int32_t i = 4; i < completeKernelSizeForFourPixels; i += 4) { + u8x16_t p5678 = (kernelStartX + i < sourceRect.XMost()) ? + simd::Load8(&aSourceData[sourceIndex + 4 * i]) : + simd::FromZero8(); + u8x16_t p2345 = simd::Rotate8<4>(p1234, p5678); + u8x16_t p3456 = simd::Rotate8<8>(p1234, p5678); + m1234 = Morph8(m1234, p2345); + m1234 = Morph8(m1234, p3456); + if (i + 2 < completeKernelSizeForFourPixels) { + u8x16_t p4567 = simd::Rotate8<12>(p1234, p5678); + m1234 = Morph8(m1234, p4567); + m1234 = Morph8(m1234, p5678); + } + p1234 = p5678; + } + + int32_t destIndex = y * aDestStride + 4 * x; + simd::Store8(&aDestData[destIndex], m1234); + } + } +} + +template +inline void ApplyMorphologyHorizontal_SIMD(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { + ApplyMorphologyHorizontal_SIMD( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } else { + ApplyMorphologyHorizontal_SIMD( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } +} + +// Set every pixel to the per-component minimum or maximum of the pixels around +// it that are up to aRadius pixels away from it (vertically). +template +static void ApplyMorphologyVertical_SIMD(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius) +{ + static_assert(op == MORPHOLOGY_OPERATOR_ERODE || + op == MORPHOLOGY_OPERATOR_DILATE, + "unexpected morphology operator"); + + int32_t startY = aDestRect.y - aRadius; + int32_t endY = aDestRect.y + aRadius; + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++, startY++, endY++) { + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x += 4) { + int32_t sourceIndex = startY * aSourceStride + 4 * x; + u8x16_t u = simd::Load8(&aSourceData[sourceIndex]); + sourceIndex += aSourceStride; + for (int32_t iy = startY + 1; iy <= endY; iy++, sourceIndex += aSourceStride) { + u8x16_t u2 = simd::Load8(&aSourceData[sourceIndex]); + u = Morph8(u, u2); + } + + int32_t destIndex = y * aDestStride + 4 * x; + simd::Store8(&aDestData[destIndex], u); + } + } +} + +template +inline void ApplyMorphologyVertical_SIMD(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { + ApplyMorphologyVertical_SIMD( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } else { + ApplyMorphologyVertical_SIMD( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } +} + +template +static i32x4_t +ColorMatrixMultiply(i16x8_t p, i16x8_t rows_bg, i16x8_t rows_ra, const i32x4_t& bias) +{ + // int16_t p[8] == { b, g, r, a, b, g, r, a }. + // int16_t rows_bg[8] == { bB, bG, bR, bA, gB, gG, gR, gA }. + // int16_t rows_ra[8] == { rB, rG, rR, rA, aB, aG, aR, aA }. + // int32_t bias[4] == { _B, _G, _R, _A }. + + i32x4_t sum = bias; + + // int16_t bg[8] = { b, g, b, g, b, g, b, g }; + i16x8_t bg = simd::ShuffleHi16<1,0,1,0>(simd::ShuffleLo16<1,0,1,0>(p)); + // int32_t prodsum_bg[4] = { b * bB + g * gB, b * bG + g * gG, b * bR + g * gR, b * bA + g * gA } + i32x4_t prodsum_bg = simd::MulAdd16x8x2To32x4(bg, rows_bg); + sum = simd::Add32(sum, prodsum_bg); + + // uint16_t ra[8] = { r, a, r, a, r, a, r, a }; + i16x8_t ra = simd::ShuffleHi16<3,2,3,2>(simd::ShuffleLo16<3,2,3,2>(p)); + // int32_t prodsum_ra[4] = { r * rB + a * aB, r * rG + a * aG, r * rR + a * aR, r * rA + a * aA } + i32x4_t prodsum_ra = simd::MulAdd16x8x2To32x4(ra, rows_ra); + sum = simd::Add32(sum, prodsum_ra); + + // int32_t sum[4] == { b * bB + g * gB + r * rB + a * aB + _B, ... }. + return sum; +} + +template +static TemporaryRef +ApplyColorMatrix_SIMD(DataSourceSurface* aInput, const Matrix5x4 &aMatrix) +{ + IntSize size = aInput->GetSize(); + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (!target) { + return nullptr; + } + + uint8_t* sourceData = aInput->GetData(); + uint8_t* targetData = target->GetData(); + int32_t sourceStride = aInput->Stride(); + int32_t targetStride = target->Stride(); + + const int16_t factor = 128; + const Float floatElementMax = INT16_MAX / factor; // 255 + MOZ_ASSERT((floatElementMax * factor) <= INT16_MAX, "badly chosen float-to-int scale"); + + const Float *floats = &aMatrix._11; + + ptrdiff_t componentOffsets[4] = { + B8G8R8A8_COMPONENT_BYTEOFFSET_R, + B8G8R8A8_COMPONENT_BYTEOFFSET_G, + B8G8R8A8_COMPONENT_BYTEOFFSET_B, + B8G8R8A8_COMPONENT_BYTEOFFSET_A + }; + + // We store the color matrix in rows_bgra in the following format: + // { bB, bG, bR, bA, gB, gG, gR, gA }. + // { bB, gB, bG, gG, bR, gR, bA, gA } + // The way this is interleaved allows us to use the intrinsic _mm_madd_epi16 + // which works especially well for our use case. + int16_t rows_bgra[2][8]; + for (size_t rowIndex = 0; rowIndex < 4; rowIndex++) { + for (size_t colIndex = 0; colIndex < 4; colIndex++) { + const Float& floatMatrixElement = floats[rowIndex * 4 + colIndex]; + Float clampedFloatMatrixElement = std::min(std::max(floatMatrixElement, -floatElementMax), floatElementMax); + int16_t scaledIntMatrixElement = int16_t(clampedFloatMatrixElement * factor + 0.5); + int8_t bg_or_ra = componentOffsets[rowIndex] / 2; + int8_t g_or_a = componentOffsets[rowIndex] % 2; + int8_t B_or_G_or_R_or_A = componentOffsets[colIndex]; + rows_bgra[bg_or_ra][B_or_G_or_R_or_A * 2 + g_or_a] = scaledIntMatrixElement; + } + } + + int32_t rowBias[4]; + Float biasMax = (INT32_MAX - 4 * 255 * INT16_MAX) / (factor * 255); + for (size_t colIndex = 0; colIndex < 4; colIndex++) { + size_t rowIndex = 4; + const Float& floatMatrixElement = floats[rowIndex * 4 + colIndex]; + Float clampedFloatMatrixElement = std::min(std::max(floatMatrixElement, -biasMax), biasMax); + int32_t scaledIntMatrixElement = int32_t(clampedFloatMatrixElement * factor * 255 + 0.5); + rowBias[componentOffsets[colIndex]] = scaledIntMatrixElement; + } + + i16x8_t row_bg_v = simd::FromI16( + rows_bgra[0][0], rows_bgra[0][1], rows_bgra[0][2], rows_bgra[0][3], + rows_bgra[0][4], rows_bgra[0][5], rows_bgra[0][6], rows_bgra[0][7]); + + i16x8_t row_ra_v = simd::FromI16( + rows_bgra[1][0], rows_bgra[1][1], rows_bgra[1][2], rows_bgra[1][3], + rows_bgra[1][4], rows_bgra[1][5], rows_bgra[1][6], rows_bgra[1][7]); + + i32x4_t rowsBias_v = + simd::From32(rowBias[0], rowBias[1], rowBias[2], rowBias[3]); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 4) { + MOZ_ASSERT(sourceStride >= 4 * (x + 4), "need to be able to read 4 pixels at this position"); + MOZ_ASSERT(targetStride >= 4 * (x + 4), "need to be able to write 4 pixels at this position"); + int32_t sourceIndex = y * sourceStride + 4 * x; + int32_t targetIndex = y * targetStride + 4 * x; + + // We load 4 pixels, unpack them, process them 1 pixel at a time, and + // finally pack and store the 4 result pixels. + + u8x16_t p1234 = simd::Load8(&sourceData[sourceIndex]); + + // Splat needed to get each pixel twice into i16x8 + i16x8_t p11 = simd::UnpackLo8x8ToI16x8(simd::Splat32On8<0>(p1234)); + i16x8_t p22 = simd::UnpackLo8x8ToI16x8(simd::Splat32On8<1>(p1234)); + i16x8_t p33 = simd::UnpackLo8x8ToI16x8(simd::Splat32On8<2>(p1234)); + i16x8_t p44 = simd::UnpackLo8x8ToI16x8(simd::Splat32On8<3>(p1234)); + + i32x4_t result_p1 = ColorMatrixMultiply(p11, row_bg_v, row_ra_v, rowsBias_v); + i32x4_t result_p2 = ColorMatrixMultiply(p22, row_bg_v, row_ra_v, rowsBias_v); + i32x4_t result_p3 = ColorMatrixMultiply(p33, row_bg_v, row_ra_v, rowsBias_v); + i32x4_t result_p4 = ColorMatrixMultiply(p44, row_bg_v, row_ra_v, rowsBias_v); + + static_assert(factor == 1 << 7, "Please adapt the calculation in the lines below for a different factor."); + u8x16_t result_p1234 = simd::PackAndSaturate32To8(simd::ShiftRight32<7>(result_p1), + simd::ShiftRight32<7>(result_p2), + simd::ShiftRight32<7>(result_p3), + simd::ShiftRight32<7>(result_p4)); + simd::Store8(&targetData[targetIndex], result_p1234); + } + } + + return target; +} + +// source / dest: bgra bgra +// sourceAlpha / destAlpha: aaaa aaaa +// result: bgra bgra +template +static inline u16x8_t +CompositeTwoPixels(u16x8_t source, u16x8_t sourceAlpha, u16x8_t dest, const u16x8_t& destAlpha) +{ + u16x8_t x255 = simd::FromU16(255); + + switch (aCompositeOperator) { + + case COMPOSITE_OPERATOR_OVER: + { + // val = dest * (255 - sourceAlpha) + source * 255; + u16x8_t twoFiftyFiveMinusSourceAlpha = simd::Sub16(x255, sourceAlpha); + + u16x8_t destSourceInterleaved1 = simd::InterleaveLo16(dest, source); + u16x8_t rightFactor1 = simd::InterleaveLo16(twoFiftyFiveMinusSourceAlpha, x255); + i32x4_t result1 = simd::MulAdd16x8x2To32x4(destSourceInterleaved1, rightFactor1); + + u16x8_t destSourceInterleaved2 = simd::InterleaveHi16(dest, source); + u16x8_t rightFactor2 = simd::InterleaveHi16(twoFiftyFiveMinusSourceAlpha, x255); + i32x4_t result2 = simd::MulAdd16x8x2To32x4(destSourceInterleaved2, rightFactor2); + + return simd::PackAndSaturate32ToU16(simd::FastDivideBy255(result1), + simd::FastDivideBy255(result2)); + } + + case COMPOSITE_OPERATOR_IN: + { + // val = source * destAlpha; + return simd::FastDivideBy255_16(simd::Mul16(source, destAlpha)); + } + + case COMPOSITE_OPERATOR_OUT: + { + // val = source * (255 - destAlpha); + u16x8_t prod = simd::Mul16(source, simd::Sub16(x255, destAlpha)); + return simd::FastDivideBy255_16(prod); + } + + case COMPOSITE_OPERATOR_ATOP: + { + // val = dest * (255 - sourceAlpha) + source * destAlpha; + u16x8_t twoFiftyFiveMinusSourceAlpha = simd::Sub16(x255, sourceAlpha); + + u16x8_t destSourceInterleaved1 = simd::InterleaveLo16(dest, source); + u16x8_t rightFactor1 = simd::InterleaveLo16(twoFiftyFiveMinusSourceAlpha, destAlpha); + i32x4_t result1 = simd::MulAdd16x8x2To32x4(destSourceInterleaved1, rightFactor1); + + u16x8_t destSourceInterleaved2 = simd::InterleaveHi16(dest, source); + u16x8_t rightFactor2 = simd::InterleaveHi16(twoFiftyFiveMinusSourceAlpha, destAlpha); + i32x4_t result2 = simd::MulAdd16x8x2To32x4(destSourceInterleaved2, rightFactor2); + + return simd::PackAndSaturate32ToU16(simd::FastDivideBy255(result1), + simd::FastDivideBy255(result2)); + } + + case COMPOSITE_OPERATOR_XOR: + { + // val = dest * (255 - sourceAlpha) + source * (255 - destAlpha); + u16x8_t twoFiftyFiveMinusSourceAlpha = simd::Sub16(x255, sourceAlpha); + u16x8_t twoFiftyFiveMinusDestAlpha = simd::Sub16(x255, destAlpha); + + u16x8_t destSourceInterleaved1 = simd::InterleaveLo16(dest, source); + u16x8_t rightFactor1 = simd::InterleaveLo16(twoFiftyFiveMinusSourceAlpha, + twoFiftyFiveMinusDestAlpha); + i32x4_t result1 = simd::MulAdd16x8x2To32x4(destSourceInterleaved1, rightFactor1); + + u16x8_t destSourceInterleaved2 = simd::InterleaveHi16(dest, source); + u16x8_t rightFactor2 = simd::InterleaveHi16(twoFiftyFiveMinusSourceAlpha, + twoFiftyFiveMinusDestAlpha); + i32x4_t result2 = simd::MulAdd16x8x2To32x4(destSourceInterleaved2, rightFactor2); + + return simd::PackAndSaturate32ToU16(simd::FastDivideBy255(result1), + simd::FastDivideBy255(result2)); + } + + default: + return simd::FromU16(0); + + } +} + +template +static void +ApplyComposition(DataSourceSurface* aSource, DataSourceSurface* aDest) +{ + IntSize size = aDest->GetSize(); + + uint8_t* sourceData = aSource->GetData(); + uint8_t* destData = aDest->GetData(); + uint32_t sourceStride = aSource->Stride(); + uint32_t destStride = aDest->Stride(); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 4) { + uint32_t sourceIndex = y * sourceStride + 4 * x; + uint32_t destIndex = y * destStride + 4 * x; + + u8x16_t s1234 = simd::Load8(&sourceData[sourceIndex]); + u8x16_t d1234 = simd::Load8(&destData[destIndex]); + + u16x8_t s12 = simd::UnpackLo8x8ToU16x8(s1234); + u16x8_t d12 = simd::UnpackLo8x8ToU16x8(d1234); + u16x8_t sa12 = simd::Splat16<3,3>(s12); + u16x8_t da12 = simd::Splat16<3,3>(d12); + u16x8_t result12 = CompositeTwoPixels(s12, sa12, d12, da12); + + u16x8_t s34 = simd::UnpackHi8x8ToU16x8(s1234); + u16x8_t d34 = simd::UnpackHi8x8ToU16x8(d1234); + u16x8_t sa34 = simd::Splat16<3,3>(s34); + u16x8_t da34 = simd::Splat16<3,3>(d34); + u16x8_t result34 = CompositeTwoPixels(s34, sa34, d34, da34); + + u8x16_t result1234 = simd::PackAndSaturate16To8(result12, result34); + simd::Store8(&destData[destIndex], result1234); + } + } +} + +template +static void +ApplyComposition_SIMD(DataSourceSurface* aSource, DataSourceSurface* aDest, + CompositeOperator aOperator) +{ + switch (aOperator) { + case COMPOSITE_OPERATOR_OVER: + ApplyComposition(aSource, aDest); + break; + case COMPOSITE_OPERATOR_IN: + ApplyComposition(aSource, aDest); + break; + case COMPOSITE_OPERATOR_OUT: + ApplyComposition(aSource, aDest); + break; + case COMPOSITE_OPERATOR_ATOP: + ApplyComposition(aSource, aDest); + break; + case COMPOSITE_OPERATOR_XOR: + ApplyComposition(aSource, aDest); + break; + default: + MOZ_CRASH(); + } +} + +template +static void +SeparateColorChannels_SIMD(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, + uint8_t* channel0Data, uint8_t* channel1Data, + uint8_t* channel2Data, uint8_t* channel3Data, + int32_t channelStride) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 16) { + // Process 16 pixels at a time. + int32_t sourceIndex = y * sourceStride + 4 * x; + int32_t targetIndex = y * channelStride + x; + + u8x16_t bgrabgrabgrabgra1 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra2 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra3 = simd::FromZero8(); + u8x16_t bgrabgrabgrabgra4 = simd::FromZero8(); + + bgrabgrabgrabgra1 = simd::Load8(&sourceData[sourceIndex]); + if (4 * (x + 4) < sourceStride) { + bgrabgrabgrabgra2 = simd::Load8(&sourceData[sourceIndex + 4 * 4]); + } + if (4 * (x + 8) < sourceStride) { + bgrabgrabgrabgra3 = simd::Load8(&sourceData[sourceIndex + 4 * 8]); + } + if (4 * (x + 12) < sourceStride) { + bgrabgrabgrabgra4 = simd::Load8(&sourceData[sourceIndex + 4 * 12]); + } + + u8x16_t bbggrraabbggrraa1 = simd::InterleaveLo8(bgrabgrabgrabgra1, bgrabgrabgrabgra3); + u8x16_t bbggrraabbggrraa2 = simd::InterleaveHi8(bgrabgrabgrabgra1, bgrabgrabgrabgra3); + u8x16_t bbggrraabbggrraa3 = simd::InterleaveLo8(bgrabgrabgrabgra2, bgrabgrabgrabgra4); + u8x16_t bbggrraabbggrraa4 = simd::InterleaveHi8(bgrabgrabgrabgra2, bgrabgrabgrabgra4); + u8x16_t bbbbggggrrrraaaa1 = simd::InterleaveLo8(bbggrraabbggrraa1, bbggrraabbggrraa3); + u8x16_t bbbbggggrrrraaaa2 = simd::InterleaveHi8(bbggrraabbggrraa1, bbggrraabbggrraa3); + u8x16_t bbbbggggrrrraaaa3 = simd::InterleaveLo8(bbggrraabbggrraa2, bbggrraabbggrraa4); + u8x16_t bbbbggggrrrraaaa4 = simd::InterleaveHi8(bbggrraabbggrraa2, bbggrraabbggrraa4); + u8x16_t bbbbbbbbgggggggg1 = simd::InterleaveLo8(bbbbggggrrrraaaa1, bbbbggggrrrraaaa3); + u8x16_t rrrrrrrraaaaaaaa1 = simd::InterleaveHi8(bbbbggggrrrraaaa1, bbbbggggrrrraaaa3); + u8x16_t bbbbbbbbgggggggg2 = simd::InterleaveLo8(bbbbggggrrrraaaa2, bbbbggggrrrraaaa4); + u8x16_t rrrrrrrraaaaaaaa2 = simd::InterleaveHi8(bbbbggggrrrraaaa2, bbbbggggrrrraaaa4); + u8x16_t bbbbbbbbbbbbbbbb = simd::InterleaveLo8(bbbbbbbbgggggggg1, bbbbbbbbgggggggg2); + u8x16_t gggggggggggggggg = simd::InterleaveHi8(bbbbbbbbgggggggg1, bbbbbbbbgggggggg2); + u8x16_t rrrrrrrrrrrrrrrr = simd::InterleaveLo8(rrrrrrrraaaaaaaa1, rrrrrrrraaaaaaaa2); + u8x16_t aaaaaaaaaaaaaaaa = simd::InterleaveHi8(rrrrrrrraaaaaaaa1, rrrrrrrraaaaaaaa2); + + simd::Store8(&channel0Data[targetIndex], bbbbbbbbbbbbbbbb); + simd::Store8(&channel1Data[targetIndex], gggggggggggggggg); + simd::Store8(&channel2Data[targetIndex], rrrrrrrrrrrrrrrr); + simd::Store8(&channel3Data[targetIndex], aaaaaaaaaaaaaaaa); + } + } +} + +template +static void +CombineColorChannels_SIMD(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 16) { + // Process 16 pixels at a time. + int32_t resultIndex = y * resultStride + 4 * x; + int32_t channelIndex = y * channelStride + x; + + u8x16_t bbbbbbbbbbbbbbbb = simd::Load8(&channel0Data[channelIndex]); + u8x16_t gggggggggggggggg = simd::Load8(&channel1Data[channelIndex]); + u8x16_t rrrrrrrrrrrrrrrr = simd::Load8(&channel2Data[channelIndex]); + u8x16_t aaaaaaaaaaaaaaaa = simd::Load8(&channel3Data[channelIndex]); + + u8x16_t brbrbrbrbrbrbrbr1 = simd::InterleaveLo8(bbbbbbbbbbbbbbbb, rrrrrrrrrrrrrrrr); + u8x16_t brbrbrbrbrbrbrbr2 = simd::InterleaveHi8(bbbbbbbbbbbbbbbb, rrrrrrrrrrrrrrrr); + u8x16_t gagagagagagagaga1 = simd::InterleaveLo8(gggggggggggggggg, aaaaaaaaaaaaaaaa); + u8x16_t gagagagagagagaga2 = simd::InterleaveHi8(gggggggggggggggg, aaaaaaaaaaaaaaaa); + + u8x16_t bgrabgrabgrabgra1 = simd::InterleaveLo8(brbrbrbrbrbrbrbr1, gagagagagagagaga1); + u8x16_t bgrabgrabgrabgra2 = simd::InterleaveHi8(brbrbrbrbrbrbrbr1, gagagagagagagaga1); + u8x16_t bgrabgrabgrabgra3 = simd::InterleaveLo8(brbrbrbrbrbrbrbr2, gagagagagagagaga2); + u8x16_t bgrabgrabgrabgra4 = simd::InterleaveHi8(brbrbrbrbrbrbrbr2, gagagagagagagaga2); + + simd::Store8(&resultData[resultIndex], bgrabgrabgrabgra1); + if (4 * (x + 4) < resultStride) { + simd::Store8(&resultData[resultIndex + 4 * 4], bgrabgrabgrabgra2); + } + if (4 * (x + 8) < resultStride) { + simd::Store8(&resultData[resultIndex + 8 * 4], bgrabgrabgrabgra3); + } + if (4 * (x + 12) < resultStride) { + simd::Store8(&resultData[resultIndex + 12 * 4], bgrabgrabgrabgra4); + } + } + } +} + + +template +static void +DoPremultiplicationCalculation_SIMD(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + const u8x16_t alphaMask = simd::From8(0, 0, 0, 0xff, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0, 0, 0, 0xff); + for (int32_t y = 0; y < aSize.height; y++) { + for (int32_t x = 0; x < aSize.width; x += 4) { + int32_t inputIndex = y * aSourceStride + 4 * x; + int32_t targetIndex = y * aTargetStride + 4 * x; + + u8x16_t p1234 = simd::Load8(&aSourceData[inputIndex]); + u16x8_t p12 = simd::UnpackLo8x8ToU16x8(p1234); + u16x8_t p34 = simd::UnpackHi8x8ToU16x8(p1234); + + // Multiply all components with alpha. + p12 = simd::Mul16(p12, simd::Splat16<3,3>(p12)); + p34 = simd::Mul16(p34, simd::Splat16<3,3>(p34)); + + // Divide by 255 and pack. + u8x16_t result = simd::PackAndSaturate16To8(simd::FastDivideBy255_16(p12), + simd::FastDivideBy255_16(p34)); + + // Get the original alpha channel value back from p1234. + result = simd::Pick(alphaMask, result, p1234); + + simd::Store8(&aTargetData[targetIndex], result); + } + } +} + +// We use a table of precomputed factors for unpremultiplying. +// We want to compute round(r / (alpha / 255.0f)) for arbitrary values of +// r and alpha in constant time. This table of factors has the property that +// (r * sAlphaFactors[alpha] + 128) >> 8 roughly gives the result we want (with +// a maximum deviation of 1). +// +// sAlphaFactors[alpha] == round(255.0 * (1 << 8) / alpha) +// +// This table has been created using the python code +// ", ".join("%d" % (round(255.0 * 256 / alpha) if alpha > 0 else 0) for alpha in range(256)) +static const uint16_t sAlphaFactors[256] = { + 0, 65280, 32640, 21760, 16320, 13056, 10880, 9326, 8160, 7253, 6528, 5935, + 5440, 5022, 4663, 4352, 4080, 3840, 3627, 3436, 3264, 3109, 2967, 2838, 2720, + 2611, 2511, 2418, 2331, 2251, 2176, 2106, 2040, 1978, 1920, 1865, 1813, 1764, + 1718, 1674, 1632, 1592, 1554, 1518, 1484, 1451, 1419, 1389, 1360, 1332, 1306, + 1280, 1255, 1232, 1209, 1187, 1166, 1145, 1126, 1106, 1088, 1070, 1053, 1036, + 1020, 1004, 989, 974, 960, 946, 933, 919, 907, 894, 882, 870, 859, 848, 837, + 826, 816, 806, 796, 787, 777, 768, 759, 750, 742, 733, 725, 717, 710, 702, + 694, 687, 680, 673, 666, 659, 653, 646, 640, 634, 628, 622, 616, 610, 604, + 599, 593, 588, 583, 578, 573, 568, 563, 558, 553, 549, 544, 540, 535, 531, + 526, 522, 518, 514, 510, 506, 502, 498, 495, 491, 487, 484, 480, 476, 473, + 470, 466, 463, 460, 457, 453, 450, 447, 444, 441, 438, 435, 432, 429, 427, + 424, 421, 418, 416, 413, 411, 408, 405, 403, 400, 398, 396, 393, 391, 389, + 386, 384, 382, 380, 377, 375, 373, 371, 369, 367, 365, 363, 361, 359, 357, + 355, 353, 351, 349, 347, 345, 344, 342, 340, 338, 336, 335, 333, 331, 330, + 328, 326, 325, 323, 322, 320, 318, 317, 315, 314, 312, 311, 309, 308, 306, + 305, 304, 302, 301, 299, 298, 297, 295, 294, 293, 291, 290, 289, 288, 286, + 285, 284, 283, 281, 280, 279, 278, 277, 275, 274, 273, 272, 271, 270, 269, + 268, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256 +}; + +template +static void +DoUnpremultiplicationCalculation_SIMD(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + for (int32_t y = 0; y < aSize.height; y++) { + for (int32_t x = 0; x < aSize.width; x += 4) { + int32_t inputIndex = y * aSourceStride + 4 * x; + int32_t targetIndex = y * aTargetStride + 4 * x; + union { + u8x16_t p1234; + uint8_t u8[4][4]; + }; + p1234 = simd::Load8(&aSourceData[inputIndex]); + + // Prepare the alpha factors. + uint16_t aF1 = sAlphaFactors[u8[0][B8G8R8A8_COMPONENT_BYTEOFFSET_A]]; + uint16_t aF2 = sAlphaFactors[u8[1][B8G8R8A8_COMPONENT_BYTEOFFSET_A]]; + uint16_t aF3 = sAlphaFactors[u8[2][B8G8R8A8_COMPONENT_BYTEOFFSET_A]]; + uint16_t aF4 = sAlphaFactors[u8[3][B8G8R8A8_COMPONENT_BYTEOFFSET_A]]; + u16x8_t aF12 = simd::FromU16(aF1, aF1, aF1, 1 << 8, aF2, aF2, aF2, 1 << 8); + u16x8_t aF34 = simd::FromU16(aF3, aF3, aF3, 1 << 8, aF4, aF4, aF4, 1 << 8); + + u16x8_t p12 = simd::UnpackLo8x8ToU16x8(p1234); + u16x8_t p34 = simd::UnpackHi8x8ToU16x8(p1234); + + // Multiply with the alpha factors, add 128 for rounding, and shift right by 8 bits. + p12 = simd::ShiftRight16<8>(simd::Add16(simd::Mul16(p12, aF12), simd::FromU16(128))); + p34 = simd::ShiftRight16<8>(simd::Add16(simd::Mul16(p34, aF34), simd::FromU16(128))); + + u8x16_t result = simd::PackAndSaturate16To8(p12, p34); + simd::Store8(&aTargetData[targetIndex], result); + } + } +} + +template +static TemporaryRef +RenderTurbulence_SIMD(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect) +{ +#define RETURN_TURBULENCE(Type, Stitch) \ + SVGTurbulenceRenderer \ + renderer(aBaseFrequency, aSeed, aNumOctaves, aTileRect); \ + return renderer.Render(aSize, aOffset); + + switch (aType) { + case TURBULENCE_TYPE_TURBULENCE: + { + if (aStitch) { + RETURN_TURBULENCE(TURBULENCE_TYPE_TURBULENCE, true); + } + RETURN_TURBULENCE(TURBULENCE_TYPE_TURBULENCE, false); + } + case TURBULENCE_TYPE_FRACTAL_NOISE: + { + if (aStitch) { + RETURN_TURBULENCE(TURBULENCE_TYPE_FRACTAL_NOISE, true); + } + RETURN_TURBULENCE(TURBULENCE_TYPE_FRACTAL_NOISE, false); + } + } + return nullptr; +#undef RETURN_TURBULENCE +} + +// k1 * in1 * in2 + k2 * in1 + k3 * in2 + k4 +template +static MOZ_ALWAYS_INLINE i16x8_t +ArithmeticCombineTwoPixels(i16x8_t in1, i16x8_t in2, + const i16x8_t &k1And4, const i16x8_t &k2And3) +{ + // Calculate input product: inProd = (in1 * in2) / 255. + i32x4_t inProd_1, inProd_2; + simd::Mul16x4x2x2To32x4x2(in1, in2, inProd_1, inProd_2); + i16x8_t inProd = simd::PackAndSaturate32To16(simd::FastDivideBy255(inProd_1), simd::FastDivideBy255(inProd_2)); + + // Calculate k1 * ((in1 * in2) / 255) + (k4/128) * 128 + i16x8_t oneTwentyEight = simd::FromI16(128); + i16x8_t inProd1AndOneTwentyEight = simd::InterleaveLo16(inProd, oneTwentyEight); + i16x8_t inProd2AndOneTwentyEight = simd::InterleaveHi16(inProd, oneTwentyEight); + i32x4_t inProdTimesK1PlusK4_1 = simd::MulAdd16x8x2To32x4(k1And4, inProd1AndOneTwentyEight); + i32x4_t inProdTimesK1PlusK4_2 = simd::MulAdd16x8x2To32x4(k1And4, inProd2AndOneTwentyEight); + + // Calculate k2 * in1 + k3 * in2 + i16x8_t in12_1 = simd::InterleaveLo16(in1, in2); + i16x8_t in12_2 = simd::InterleaveHi16(in1, in2); + i32x4_t inTimesK2K3_1 = simd::MulAdd16x8x2To32x4(k2And3, in12_1); + i32x4_t inTimesK2K3_2 = simd::MulAdd16x8x2To32x4(k2And3, in12_2); + + // Sum everything up and truncate the fractional part. + i32x4_t result_1 = simd::ShiftRight32<7>(simd::Add32(inProdTimesK1PlusK4_1, inTimesK2K3_1)); + i32x4_t result_2 = simd::ShiftRight32<7>(simd::Add32(inProdTimesK1PlusK4_2, inTimesK2K3_2)); + return simd::PackAndSaturate32To16(result_1, result_2); +} + +template +static TemporaryRef +ApplyArithmeticCombine_SIMD(DataSourceSurface* aInput1, DataSourceSurface* aInput2, + Float aK1, Float aK2, Float aK3, Float aK4) +{ + IntSize size = aInput1->GetSize(); + RefPtr target = + Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); + if (!target) { + return nullptr; + } + + uint8_t* source1Data = aInput1->GetData(); + uint8_t* source2Data = aInput2->GetData(); + uint8_t* targetData = target->GetData(); + uint32_t source1Stride = aInput1->Stride(); + uint32_t source2Stride = aInput2->Stride(); + uint32_t targetStride = target->Stride(); + + // The arithmetic combine filter does the following calculation: + // result = k1 * in1 * in2 + k2 * in1 + k3 * in2 + k4 + // + // Or, with in1/2 integers between 0 and 255: + // result = (k1 * in1 * in2) / 255 + k2 * in1 + k3 * in2 + k4 * 255 + // + // We want the whole calculation to happen in integer, with 16-bit factors. + // So we convert our factors to fixed-point with precision 1.8.7. + // K4 is premultiplied with 255, and it will be multiplied with 128 later + // during the actual calculation, because premultiplying it with 255 * 128 + // would overflow int16. + + i16x8_t k1 = simd::FromI16(int16_t(floorf(std::min(std::max(aK1, -255.0f), 255.0f) * 128 + 0.5f))); + i16x8_t k2 = simd::FromI16(int16_t(floorf(std::min(std::max(aK2, -255.0f), 255.0f) * 128 + 0.5f))); + i16x8_t k3 = simd::FromI16(int16_t(floorf(std::min(std::max(aK3, -255.0f), 255.0f) * 128 + 0.5f))); + i16x8_t k4 = simd::FromI16(int16_t(floorf(std::min(std::max(aK4, -128.0f), 128.0f) * 255 + 0.5f))); + + i16x8_t k1And4 = simd::InterleaveLo16(k1, k4); + i16x8_t k2And3 = simd::InterleaveLo16(k2, k3); + + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x += 4) { + uint32_t source1Index = y * source1Stride + 4 * x; + uint32_t source2Index = y * source2Stride + 4 * x; + uint32_t targetIndex = y * targetStride + 4 * x; + + // Load and unpack. + u8x16_t in1 = simd::Load8(&source1Data[source1Index]); + u8x16_t in2 = simd::Load8(&source2Data[source2Index]); + i16x8_t in1_12 = simd::UnpackLo8x8ToI16x8(in1); + i16x8_t in1_34 = simd::UnpackHi8x8ToI16x8(in1); + i16x8_t in2_12 = simd::UnpackLo8x8ToI16x8(in2); + i16x8_t in2_34 = simd::UnpackHi8x8ToI16x8(in2); + + // Multiply and add. + i16x8_t result_12 = ArithmeticCombineTwoPixels(in1_12, in2_12, k1And4, k2And3); + i16x8_t result_34 = ArithmeticCombineTwoPixels(in1_34, in2_34, k1And4, k2And3); + + // Pack and store. + simd::Store8(&targetData[targetIndex], simd::PackAndSaturate16To8(result_12, result_34)); + } + } + + return target; +} + +} // namespace mozilla +} // namespace gfx diff --git a/libazure/FilterProcessingSSE2.cpp b/libazure/FilterProcessingSSE2.cpp new file mode 100644 index 0000000..ca1d2db --- /dev/null +++ b/libazure/FilterProcessingSSE2.cpp @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define SIMD_COMPILE_SSE2 + +#include "FilterProcessingSIMD-inl.h" + +#ifndef USE_SSE2 +static_assert(false, "If this file is built, FilterProcessing.h should know about it!"); +#endif + +namespace mozilla { +namespace gfx { + +void +FilterProcessing::ExtractAlpha_SSE2(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride) +{ + ExtractAlpha_SIMD<__m128i>(size, sourceData, sourceStride, alphaData, alphaStride); +} + +TemporaryRef +FilterProcessing::ConvertToB8G8R8A8_SSE2(SourceSurface* aSurface) +{ + return ConvertToB8G8R8A8_SIMD<__m128i>(aSurface); +} + +TemporaryRef +FilterProcessing::ApplyBlending_SSE2(DataSourceSurface* aInput1, DataSourceSurface* aInput2, + BlendMode aBlendMode) +{ + return ApplyBlending_SIMD<__m128i,__m128i,__m128i>(aInput1, aInput2, aBlendMode); +} + +void +FilterProcessing::ApplyMorphologyHorizontal_SSE2(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + ApplyMorphologyHorizontal_SIMD<__m128i,__m128i>( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); +} + +void +FilterProcessing::ApplyMorphologyVertical_SSE2(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + ApplyMorphologyVertical_SIMD<__m128i,__m128i>( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius, aOp); +} + +TemporaryRef +FilterProcessing::ApplyColorMatrix_SSE2(DataSourceSurface* aInput, const Matrix5x4 &aMatrix) +{ + return ApplyColorMatrix_SIMD<__m128i,__m128i,__m128i>(aInput, aMatrix); +} + +void +FilterProcessing::ApplyComposition_SSE2(DataSourceSurface* aSource, DataSourceSurface* aDest, + CompositeOperator aOperator) +{ + return ApplyComposition_SIMD<__m128i,__m128i,__m128i>(aSource, aDest, aOperator); +} + +void +FilterProcessing::SeparateColorChannels_SSE2(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data, int32_t channelStride) +{ + SeparateColorChannels_SIMD<__m128i>(size, sourceData, sourceStride, channel0Data, channel1Data, channel2Data, channel3Data, channelStride); +} + +void +FilterProcessing::CombineColorChannels_SSE2(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data) +{ + CombineColorChannels_SIMD<__m128i>(size, resultStride, resultData, channelStride, channel0Data, channel1Data, channel2Data, channel3Data); +} + +void +FilterProcessing::DoPremultiplicationCalculation_SSE2(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + DoPremultiplicationCalculation_SIMD<__m128i,__m128i,__m128i>(aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); +} + +void +FilterProcessing::DoUnpremultiplicationCalculation_SSE2( + const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + DoUnpremultiplicationCalculation_SIMD<__m128i,__m128i>(aSize, aTargetData, aTargetStride, aSourceData, aSourceStride); +} + +TemporaryRef +FilterProcessing::RenderTurbulence_SSE2(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect) +{ + return RenderTurbulence_SIMD<__m128,__m128i,__m128i>(aSize, aOffset, aBaseFrequency, aSeed, aNumOctaves, aType, aStitch, aTileRect); +} + +TemporaryRef +FilterProcessing::ApplyArithmeticCombine_SSE2(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4) +{ + return ApplyArithmeticCombine_SIMD<__m128i,__m128i,__m128i>(aInput1, aInput2, aK1, aK2, aK3, aK4); +} + +} // namespace mozilla +} // namespace gfx diff --git a/libazure/FilterProcessingScalar.cpp b/libazure/FilterProcessingScalar.cpp new file mode 100644 index 0000000..3a38118 --- /dev/null +++ b/libazure/FilterProcessingScalar.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define FILTER_PROCESSING_SCALAR + +#include "FilterProcessingSIMD-inl.h" +#include "Logging.h" + +namespace mozilla { +namespace gfx { + +void +FilterProcessing::ExtractAlpha_Scalar(const IntSize& size, uint8_t* sourceData, int32_t sourceStride, uint8_t* alphaData, int32_t alphaStride) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t sourceIndex = y * sourceStride + 4 * x; + int32_t targetIndex = y * alphaStride + x; + alphaData[targetIndex] = sourceData[sourceIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; + } + } +} + +TemporaryRef +FilterProcessing::ConvertToB8G8R8A8_Scalar(SourceSurface* aSurface) +{ + return ConvertToB8G8R8A8_SIMD(aSurface); +} + +template +static void +ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius) +{ + static_assert(Operator == MORPHOLOGY_OPERATOR_ERODE || + Operator == MORPHOLOGY_OPERATOR_DILATE, + "unexpected morphology operator"); + + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++) { + int32_t startX = aDestRect.x - aRadius; + int32_t endX = aDestRect.x + aRadius; + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x++, startX++, endX++) { + int32_t sourceIndex = y * aSourceStride + 4 * startX; + uint8_t u[4]; + for (size_t i = 0; i < 4; i++) { + u[i] = aSourceData[sourceIndex + i]; + } + sourceIndex += 4; + for (int32_t ix = startX + 1; ix <= endX; ix++, sourceIndex += 4) { + for (size_t i = 0; i < 4; i++) { + if (Operator == MORPHOLOGY_OPERATOR_ERODE) { + u[i] = umin(u[i], aSourceData[sourceIndex + i]); + } else { + u[i] = umax(u[i], aSourceData[sourceIndex + i]); + } + } + } + + int32_t destIndex = y * aDestStride + 4 * x; + for (size_t i = 0; i < 4; i++) { + aDestData[destIndex+i] = u[i]; + } + } + } +} + +void +FilterProcessing::ApplyMorphologyHorizontal_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { + gfx::ApplyMorphologyHorizontal_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } else { + gfx::ApplyMorphologyHorizontal_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } +} + +template +static void ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius) +{ + static_assert(Operator == MORPHOLOGY_OPERATOR_ERODE || + Operator == MORPHOLOGY_OPERATOR_DILATE, + "unexpected morphology operator"); + + int32_t startY = aDestRect.y - aRadius; + int32_t endY = aDestRect.y + aRadius; + for (int32_t y = aDestRect.y; y < aDestRect.YMost(); y++, startY++, endY++) { + for (int32_t x = aDestRect.x; x < aDestRect.XMost(); x++) { + int32_t sourceIndex = startY * aSourceStride + 4 * x; + uint8_t u[4]; + for (size_t i = 0; i < 4; i++) { + u[i] = aSourceData[sourceIndex + i]; + } + sourceIndex += aSourceStride; + for (int32_t iy = startY + 1; iy <= endY; iy++, sourceIndex += aSourceStride) { + for (size_t i = 0; i < 4; i++) { + if (Operator == MORPHOLOGY_OPERATOR_ERODE) { + u[i] = umin(u[i], aSourceData[sourceIndex + i]); + } else { + u[i] = umax(u[i], aSourceData[sourceIndex + i]); + } + } + } + + int32_t destIndex = y * aDestStride + 4 * x; + for (size_t i = 0; i < 4; i++) { + aDestData[destIndex+i] = u[i]; + } + } + } +} + +void +FilterProcessing::ApplyMorphologyVertical_Scalar(uint8_t* aSourceData, int32_t aSourceStride, + uint8_t* aDestData, int32_t aDestStride, + const IntRect& aDestRect, int32_t aRadius, + MorphologyOperator aOp) +{ + if (aOp == MORPHOLOGY_OPERATOR_ERODE) { + gfx::ApplyMorphologyVertical_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } else { + gfx::ApplyMorphologyVertical_Scalar( + aSourceData, aSourceStride, aDestData, aDestStride, aDestRect, aRadius); + } +} + +TemporaryRef +FilterProcessing::ApplyColorMatrix_Scalar(DataSourceSurface* aInput, const Matrix5x4 &aMatrix) +{ + return ApplyColorMatrix_SIMD(aInput, aMatrix); +} + +void +FilterProcessing::ApplyComposition_Scalar(DataSourceSurface* aSource, DataSourceSurface* aDest, + CompositeOperator aOperator) +{ + return ApplyComposition_SIMD(aSource, aDest, aOperator); +} + +void +FilterProcessing::SeparateColorChannels_Scalar(const IntSize &size, uint8_t* sourceData, int32_t sourceStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data, int32_t channelStride) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t sourceIndex = y * sourceStride + 4 * x; + int32_t targetIndex = y * channelStride + x; + channel0Data[targetIndex] = sourceData[sourceIndex]; + channel1Data[targetIndex] = sourceData[sourceIndex+1]; + channel2Data[targetIndex] = sourceData[sourceIndex+2]; + channel3Data[targetIndex] = sourceData[sourceIndex+3]; + } + } +} + +void +FilterProcessing::CombineColorChannels_Scalar(const IntSize &size, int32_t resultStride, uint8_t* resultData, int32_t channelStride, uint8_t* channel0Data, uint8_t* channel1Data, uint8_t* channel2Data, uint8_t* channel3Data) +{ + for (int32_t y = 0; y < size.height; y++) { + for (int32_t x = 0; x < size.width; x++) { + int32_t resultIndex = y * resultStride + 4 * x; + int32_t channelIndex = y * channelStride + x; + resultData[resultIndex] = channel0Data[channelIndex]; + resultData[resultIndex+1] = channel1Data[channelIndex]; + resultData[resultIndex+2] = channel2Data[channelIndex]; + resultData[resultIndex+3] = channel3Data[channelIndex]; + } + } +} + +void +FilterProcessing::DoPremultiplicationCalculation_Scalar(const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + for (int32_t y = 0; y < aSize.height; y++) { + for (int32_t x = 0; x < aSize.width; x++) { + int32_t inputIndex = y * aSourceStride + 4 * x; + int32_t targetIndex = y * aTargetStride + 4 * x; + uint8_t alpha = aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] = + FastDivideBy255(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] * alpha); + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] = + FastDivideBy255(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] * alpha); + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] = + FastDivideBy255(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] * alpha); + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = alpha; + } + } +} + +void +FilterProcessing::DoUnpremultiplicationCalculation_Scalar( + const IntSize& aSize, + uint8_t* aTargetData, int32_t aTargetStride, + uint8_t* aSourceData, int32_t aSourceStride) +{ + for (int32_t y = 0; y < aSize.height; y++) { + for (int32_t x = 0; x < aSize.width; x++) { + int32_t inputIndex = y * aSourceStride + 4 * x; + int32_t targetIndex = y * aTargetStride + 4 * x; + uint8_t alpha = aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A]; + uint16_t alphaFactor = sAlphaFactors[alpha]; + // inputColor * alphaFactor + 128 is guaranteed to fit into uint16_t + // because the input is premultiplied and thus inputColor <= inputAlpha. + // The maximum value this can attain is 65520 (which is less than 65535) + // for color == alpha == 244: + // 244 * sAlphaFactors[244] + 128 == 244 * 268 + 128 == 65520 + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] = + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] * alphaFactor + 128) >> 8; + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] = + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] * alphaFactor + 128) >> 8; + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] = + (aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] * alphaFactor + 128) >> 8; + aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] = alpha; + } + } +} + +TemporaryRef +FilterProcessing::RenderTurbulence_Scalar(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency, + int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect) +{ + return RenderTurbulence_SIMD( + aSize, aOffset, aBaseFrequency, aSeed, aNumOctaves, aType, aStitch, aTileRect); +} + +TemporaryRef +FilterProcessing::ApplyArithmeticCombine_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2, Float aK1, Float aK2, Float aK3, Float aK4) +{ + return ApplyArithmeticCombine_SIMD(aInput1, aInput2, aK1, aK2, aK3, aK4); +} + +} // namespace mozilla +} // namespace gfx diff --git a/libazure/Filters.h b/libazure/Filters.h new file mode 100644 index 0000000..31c3e83 --- /dev/null +++ b/libazure/Filters.h @@ -0,0 +1,512 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_FILTERS_H_ +#define MOZILLA_GFX_FILTERS_H_ + +#include "Types.h" +#include "mozilla/RefPtr.h" + +#include "Point.h" +#include "Matrix.h" +#include + +namespace mozilla { +namespace gfx { + +class SourceSurface; + +enum FilterBackend { + FILTER_BACKEND_SOFTWARE = 0, + FILTER_BACKEND_DIRECT2D1_1, + FILTER_BACKEND_RECORDING +}; + +enum TransformFilterAtts +{ + ATT_TRANSFORM_MATRIX = 0, // Matrix + ATT_TRANSFORM_FILTER // Filter +}; + +enum TransformFilterInputs +{ + IN_TRANSFORM_IN = 0 +}; + +enum BlendFilterAtts +{ + ATT_BLEND_BLENDMODE = 0 // uint32_t +}; + +enum BlendMode +{ + BLEND_MODE_MULTIPLY = 0, + BLEND_MODE_SCREEN, + BLEND_MODE_DARKEN, + BLEND_MODE_LIGHTEN, + BLEND_MODE_OVERLAY, + BLEND_MODE_COLOR_DODGE, + BLEND_MODE_COLOR_BURN, + BLEND_MODE_HARD_LIGHT, + BLEND_MODE_SOFT_LIGHT, + BLEND_MODE_DIFFERENCE, + BLEND_MODE_EXCLUSION, + BLEND_MODE_HUE, + BLEND_MODE_SATURATION, + BLEND_MODE_COLOR, + BLEND_MODE_LUMINOSITY +}; + +enum BlendFilterInputs +{ + IN_BLEND_IN = 0, + IN_BLEND_IN2 +}; + +enum MorphologyFilterAtts +{ + ATT_MORPHOLOGY_RADII = 0, // IntSize + ATT_MORPHOLOGY_OPERATOR // MorphologyOperator +}; + +enum MorphologyOperator +{ + MORPHOLOGY_OPERATOR_ERODE = 0, + MORPHOLOGY_OPERATOR_DILATE +}; + +enum MorphologyFilterInputs +{ + IN_MORPHOLOGY_IN = 0 +}; + +enum AlphaMode +{ + ALPHA_MODE_PREMULTIPLIED = 0, + ALPHA_MODE_STRAIGHT +}; + +enum ColorMatrixFilterAtts +{ + ATT_COLOR_MATRIX_MATRIX = 0, // Matrix5x4 + ATT_COLOR_MATRIX_ALPHA_MODE // AlphaMode +}; + +enum ColorMatrixFilterInputs +{ + IN_COLOR_MATRIX_IN = 0 +}; + +enum FloodFilterAtts +{ + ATT_FLOOD_COLOR = 0 // Color +}; + +enum FloodFilterInputs +{ + IN_FLOOD_IN = 0 +}; + +enum TileFilterAtts +{ + ATT_TILE_SOURCE_RECT = 0 // IntRect +}; + +enum TileFilterInputs +{ + IN_TILE_IN = 0 +}; + +enum TransferAtts +{ + ATT_TRANSFER_DISABLE_R = 0, // bool + ATT_TRANSFER_DISABLE_G, // bool + ATT_TRANSFER_DISABLE_B, // bool + ATT_TRANSFER_DISABLE_A // bool +}; + +enum TransferInputs +{ + IN_TRANSFER_IN = 0 +}; + +enum TableTransferAtts +{ + ATT_TABLE_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R, + ATT_TABLE_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G, + ATT_TABLE_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B, + ATT_TABLE_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A, + ATT_TABLE_TRANSFER_TABLE_R, // Float[] + ATT_TABLE_TRANSFER_TABLE_G, // Float[] + ATT_TABLE_TRANSFER_TABLE_B, // Float[] + ATT_TABLE_TRANSFER_TABLE_A // Float[] +}; + +enum TableTransferInputs +{ + IN_TABLE_TRANSFER_IN = IN_TRANSFER_IN +}; + +enum DiscreteTransferAtts +{ + ATT_DISCRETE_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R, + ATT_DISCRETE_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G, + ATT_DISCRETE_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B, + ATT_DISCRETE_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A, + ATT_DISCRETE_TRANSFER_TABLE_R, // Float[] + ATT_DISCRETE_TRANSFER_TABLE_G, // Float[] + ATT_DISCRETE_TRANSFER_TABLE_B, // Float[] + ATT_DISCRETE_TRANSFER_TABLE_A // Float[] +}; + +enum DiscreteTransferInputs +{ + IN_DISCRETE_TRANSFER_IN = IN_TRANSFER_IN +}; + +enum LinearTransferAtts +{ + ATT_LINEAR_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R, + ATT_LINEAR_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G, + ATT_LINEAR_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B, + ATT_LINEAR_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A, + ATT_LINEAR_TRANSFER_SLOPE_R, // Float + ATT_LINEAR_TRANSFER_SLOPE_G, // Float + ATT_LINEAR_TRANSFER_SLOPE_B, // Float + ATT_LINEAR_TRANSFER_SLOPE_A, // Float + ATT_LINEAR_TRANSFER_INTERCEPT_R, // Float + ATT_LINEAR_TRANSFER_INTERCEPT_G, // Float + ATT_LINEAR_TRANSFER_INTERCEPT_B, // Float + ATT_LINEAR_TRANSFER_INTERCEPT_A // Float +}; + +enum LinearTransferInputs +{ + IN_LINEAR_TRANSFER_IN = IN_TRANSFER_IN +}; + +enum GammaTransferAtts +{ + ATT_GAMMA_TRANSFER_DISABLE_R = ATT_TRANSFER_DISABLE_R, + ATT_GAMMA_TRANSFER_DISABLE_G = ATT_TRANSFER_DISABLE_G, + ATT_GAMMA_TRANSFER_DISABLE_B = ATT_TRANSFER_DISABLE_B, + ATT_GAMMA_TRANSFER_DISABLE_A = ATT_TRANSFER_DISABLE_A, + ATT_GAMMA_TRANSFER_AMPLITUDE_R, // Float + ATT_GAMMA_TRANSFER_AMPLITUDE_G, // Float + ATT_GAMMA_TRANSFER_AMPLITUDE_B, // Float + ATT_GAMMA_TRANSFER_AMPLITUDE_A, // Float + ATT_GAMMA_TRANSFER_EXPONENT_R, // Float + ATT_GAMMA_TRANSFER_EXPONENT_G, // Float + ATT_GAMMA_TRANSFER_EXPONENT_B, // Float + ATT_GAMMA_TRANSFER_EXPONENT_A, // Float + ATT_GAMMA_TRANSFER_OFFSET_R, // Float + ATT_GAMMA_TRANSFER_OFFSET_G, // Float + ATT_GAMMA_TRANSFER_OFFSET_B, // Float + ATT_GAMMA_TRANSFER_OFFSET_A // Float +}; + +enum GammaTransferInputs +{ + IN_GAMMA_TRANSFER_IN = IN_TRANSFER_IN +}; + +enum ConvolveMatrixAtts +{ + ATT_CONVOLVE_MATRIX_KERNEL_SIZE = 0, // IntSize + ATT_CONVOLVE_MATRIX_KERNEL_MATRIX, // Float[] + ATT_CONVOLVE_MATRIX_DIVISOR, // Float + ATT_CONVOLVE_MATRIX_BIAS, // Float + ATT_CONVOLVE_MATRIX_TARGET, // IntPoint + ATT_CONVOLVE_MATRIX_SOURCE_RECT, // IntRect + ATT_CONVOLVE_MATRIX_EDGE_MODE, // ConvolveMatrixEdgeMode + ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, // Size + ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA, // bool +}; + +enum ConvolveMatrixEdgeMode +{ + EDGE_MODE_DUPLICATE = 0, + EDGE_MODE_WRAP, + EDGE_MODE_NONE +}; + +enum ConvolveMatrixInputs +{ + IN_CONVOLVE_MATRIX_IN = 0 +}; + +enum DisplacementMapAtts +{ + ATT_DISPLACEMENT_MAP_SCALE = 0, // Float + ATT_DISPLACEMENT_MAP_X_CHANNEL, // ColorChannel + ATT_DISPLACEMENT_MAP_Y_CHANNEL // ColorChannel +}; + +enum ColorChannel +{ + COLOR_CHANNEL_R = 0, + COLOR_CHANNEL_G, + COLOR_CHANNEL_B, + COLOR_CHANNEL_A +}; + +enum DisplacementMapInputs +{ + IN_DISPLACEMENT_MAP_IN = 0, + IN_DISPLACEMENT_MAP_IN2 +}; + +enum TurbulenceAtts +{ + ATT_TURBULENCE_BASE_FREQUENCY = 0, // Size + ATT_TURBULENCE_NUM_OCTAVES, // uint32_t + ATT_TURBULENCE_SEED, // uint32_t + ATT_TURBULENCE_STITCHABLE, // bool + ATT_TURBULENCE_TYPE, // TurbulenceType + ATT_TURBULENCE_RECT // IntRect +}; + +enum TurbulenceType +{ + TURBULENCE_TYPE_TURBULENCE = 0, + TURBULENCE_TYPE_FRACTAL_NOISE +}; + +enum ArithmeticCombineAtts +{ + ATT_ARITHMETIC_COMBINE_COEFFICIENTS = 0 // Float[4] +}; + +enum ArithmeticCombineInputs +{ + IN_ARITHMETIC_COMBINE_IN = 0, + IN_ARITHMETIC_COMBINE_IN2 +}; + +enum CompositeAtts +{ + ATT_COMPOSITE_OPERATOR = 0 // CompositeOperator +}; + +enum CompositeOperator +{ + COMPOSITE_OPERATOR_OVER = 0, + COMPOSITE_OPERATOR_IN, + COMPOSITE_OPERATOR_OUT, + COMPOSITE_OPERATOR_ATOP, + COMPOSITE_OPERATOR_XOR +}; + +enum CompositeInputs +{ + // arbitrary number of inputs + IN_COMPOSITE_IN_START = 0 +}; + +enum GaussianBlurAtts +{ + ATT_GAUSSIAN_BLUR_STD_DEVIATION = 0 // Float +}; + +enum GaussianBlurInputs +{ + IN_GAUSSIAN_BLUR_IN = 0 +}; + +enum DirectionalBlurAtts +{ + ATT_DIRECTIONAL_BLUR_STD_DEVIATION = 0, // Float + ATT_DIRECTIONAL_BLUR_DIRECTION // BlurDirection +}; + +enum BlurDirection +{ + BLUR_DIRECTION_X = 0, + BLUR_DIRECTION_Y +}; + +enum DirectionalBlurInputs +{ + IN_DIRECTIONAL_BLUR_IN = 0 +}; + +enum LightingAtts +{ + ATT_POINT_LIGHT_POSITION = 0, // Point3D + + ATT_SPOT_LIGHT_POSITION, // Point3D + ATT_SPOT_LIGHT_POINTS_AT, // Point3D + ATT_SPOT_LIGHT_FOCUS, // Float + ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE, // Float + + ATT_DISTANT_LIGHT_AZIMUTH, // Float + ATT_DISTANT_LIGHT_ELEVATION, // Float + + ATT_LIGHTING_COLOR, // Color + ATT_LIGHTING_SURFACE_SCALE, // Float + ATT_LIGHTING_KERNEL_UNIT_LENGTH, // Size + + ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT, // Float + + ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT, // Float + ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT // Float +}; + +enum LightingInputs +{ + IN_LIGHTING_IN = 0 +}; + +enum PointDiffuseAtts +{ + ATT_POINT_DIFFUSE_POSITION = ATT_POINT_LIGHT_POSITION, + ATT_POINT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR, + ATT_POINT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_POINT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_POINT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT +}; + +enum PointDiffuseInputs +{ + IN_POINT_DIFFUSE_IN = IN_LIGHTING_IN +}; + +enum SpotDiffuseAtts +{ + ATT_SPOT_DIFFUSE_POSITION = ATT_SPOT_LIGHT_POSITION, + ATT_SPOT_DIFFUSE_POINTS_AT = ATT_SPOT_LIGHT_POINTS_AT, + ATT_SPOT_DIFFUSE_FOCUS = ATT_SPOT_LIGHT_FOCUS, + ATT_SPOT_DIFFUSE_LIMITING_CONE_ANGLE = ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE, + ATT_SPOT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR, + ATT_SPOT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_SPOT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_SPOT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT +}; + +enum SpotDiffuseInputs +{ + IN_SPOT_DIFFUSE_IN = IN_LIGHTING_IN +}; + +enum DistantDiffuseAtts +{ + ATT_DISTANT_DIFFUSE_AZIMUTH = ATT_DISTANT_LIGHT_AZIMUTH, + ATT_DISTANT_DIFFUSE_ELEVATION = ATT_DISTANT_LIGHT_ELEVATION, + ATT_DISTANT_DIFFUSE_COLOR = ATT_LIGHTING_COLOR, + ATT_DISTANT_DIFFUSE_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_DISTANT_DIFFUSE_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_DISTANT_DIFFUSE_DIFFUSE_CONSTANT = ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT +}; + +enum DistantDiffuseInputs +{ + IN_DISTANT_DIFFUSE_IN = IN_LIGHTING_IN +}; + +enum PointSpecularAtts +{ + ATT_POINT_SPECULAR_POSITION = ATT_POINT_LIGHT_POSITION, + ATT_POINT_SPECULAR_COLOR = ATT_LIGHTING_COLOR, + ATT_POINT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_POINT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_POINT_SPECULAR_SPECULAR_CONSTANT = ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT, + ATT_POINT_SPECULAR_SPECULAR_EXPONENT = ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT +}; + +enum PointSpecularInputs +{ + IN_POINT_SPECULAR_IN = IN_LIGHTING_IN +}; + +enum SpotSpecularAtts +{ + ATT_SPOT_SPECULAR_POSITION = ATT_SPOT_LIGHT_POSITION, + ATT_SPOT_SPECULAR_POINTS_AT = ATT_SPOT_LIGHT_POINTS_AT, + ATT_SPOT_SPECULAR_FOCUS = ATT_SPOT_LIGHT_FOCUS, + ATT_SPOT_SPECULAR_LIMITING_CONE_ANGLE = ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE, + ATT_SPOT_SPECULAR_COLOR = ATT_LIGHTING_COLOR, + ATT_SPOT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_SPOT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_SPOT_SPECULAR_SPECULAR_CONSTANT = ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT, + ATT_SPOT_SPECULAR_SPECULAR_EXPONENT = ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT +}; + +enum SpotSpecularInputs +{ + IN_SPOT_SPECULAR_IN = IN_LIGHTING_IN +}; + +enum DistantSpecularAtts +{ + ATT_DISTANT_SPECULAR_AZIMUTH = ATT_DISTANT_LIGHT_AZIMUTH, + ATT_DISTANT_SPECULAR_ELEVATION = ATT_DISTANT_LIGHT_ELEVATION, + ATT_DISTANT_SPECULAR_COLOR = ATT_LIGHTING_COLOR, + ATT_DISTANT_SPECULAR_SURFACE_SCALE = ATT_LIGHTING_SURFACE_SCALE, + ATT_DISTANT_SPECULAR_KERNEL_UNIT_LENGTH = ATT_LIGHTING_KERNEL_UNIT_LENGTH, + ATT_DISTANT_SPECULAR_SPECULAR_CONSTANT = ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT, + ATT_DISTANT_SPECULAR_SPECULAR_EXPONENT = ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT +}; + +enum DistantSpecularInputs +{ + IN_DISTANT_SPECULAR_IN = IN_LIGHTING_IN +}; + +enum CropAtts +{ + ATT_CROP_RECT = 0 // Rect +}; + +enum CropInputs +{ + IN_CROP_IN = 0 +}; + +enum PremultiplyInputs +{ + IN_PREMULTIPLY_IN = 0 +}; + +enum UnpremultiplyInputs +{ + IN_UNPREMULTIPLY_IN = 0 +}; + +class FilterNode : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNode) + virtual ~FilterNode() {} + + virtual FilterBackend GetBackendType() = 0; + + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) { MOZ_CRASH(); } + virtual void SetInput(uint32_t aIndex, FilterNode *aFilter) { MOZ_CRASH(); } + + virtual void SetAttribute(uint32_t aIndex, bool) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, uint32_t) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, Float) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Size &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const IntSize &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const IntPoint &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Rect &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const IntRect &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Point &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Matrix &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Matrix5x4 &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Point3D &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Color &) { MOZ_CRASH(); } + virtual void SetAttribute(uint32_t aIndex, const Float* aFloat, uint32_t aSize) { MOZ_CRASH(); } + +protected: + friend class Factory; + + FilterNode() {} +}; + +} +} + +#endif diff --git a/libazure/GenericRefCounted.h b/libazure/GenericRefCounted.h new file mode 100644 index 0000000..5642169 --- /dev/null +++ b/libazure/GenericRefCounted.h @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This header provides virtual, non-templated alternatives to MFBT's RefCounted. +// It intentionally uses MFBT coding style with the intention of moving there +// should there be other use cases for it. + +#ifndef MOZILLA_GENERICREFCOUNTED_H_ +#define MOZILLA_GENERICREFCOUNTED_H_ + +#include "mozilla/RefPtr.h" + +namespace mozilla { + +/** + * Common base class for GenericRefCounted and GenericAtomicRefCounted. + * + * Having this shared base class, common to both the atomic and non-atomic + * cases, allows to have RefPtr's that don't care about whether the + * objects they're managing have atomic refcounts or not. + */ +class GenericRefCountedBase +{ + protected: + virtual ~GenericRefCountedBase() {}; + + public: + // AddRef() and Release() method names are for compatibility with nsRefPtr. + virtual void AddRef() = 0; + + virtual void Release() = 0; + + // ref() and deref() method names are for compatibility with wtf::RefPtr. + // No virtual keywords here: if a subclass wants to override the refcounting + // mechanism, it is welcome to do so by overriding AddRef() and Release(). + void ref() { AddRef(); } + void deref() { Release(); } + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING + virtual const char* typeName() const = 0; + virtual size_t typeSize() const = 0; +#endif +}; + +namespace detail { + +template +class GenericRefCounted : public GenericRefCountedBase +{ + protected: + GenericRefCounted() : refCnt(0) { } + + virtual ~GenericRefCounted() { + MOZ_ASSERT(refCnt == detail::DEAD); + } + + public: + virtual void AddRef() { + // Note: this method must be thread safe for GenericAtomicRefCounted. + MOZ_ASSERT(int32_t(refCnt) >= 0); +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING + ++refCnt; +#else + const char* type = typeName(); + uint32_t size = typeSize(); + const void* ptr = this; + MozRefCountType cnt = ++refCnt; + detail::RefCountLogger::logAddRef(ptr, cnt, type, size); +#endif + } + + virtual void Release() { + // Note: this method must be thread safe for GenericAtomicRefCounted. + MOZ_ASSERT(int32_t(refCnt) > 0); +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING + MozRefCountType cnt = --refCnt; +#else + const char* type = typeName(); + const void* ptr = this; + MozRefCountType cnt = --refCnt; + // Note: it's not safe to touch |this| after decrementing the refcount, + // except for below. + detail::RefCountLogger::logRelease(ptr, cnt, type); +#endif + if (0 == cnt) { + // Because we have atomically decremented the refcount above, only + // one thread can get a 0 count here, so as long as we can assume that + // everything else in the system is accessing this object through + // RefPtrs, it's safe to access |this| here. +#ifdef DEBUG + refCnt = detail::DEAD; +#endif + delete this; + } + } + + MozRefCountType refCount() const { return refCnt; } + bool hasOneRef() const { + MOZ_ASSERT(refCnt > 0); + return refCnt == 1; + } + + private: + typename Conditional, MozRefCountType>::Type refCnt; +}; + +} // namespace detail + +/** + * This reference-counting base class is virtual instead of + * being templated, which is useful in cases where one needs + * genericity at binary code level, but comes at the cost + * of a moderate performance and size overhead, like anything virtual. + */ +class GenericRefCounted : public detail::GenericRefCounted +{ +}; + +/** + * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated + * reference counter. + */ +class GenericAtomicRefCounted : public detail::GenericRefCounted +{ +}; + +} // namespace mozilla + +#endif diff --git a/libazure/src/gfx/2d/GradientStopsD2D.h b/libazure/GradientStopsD2D.h similarity index 81% rename from libazure/src/gfx/2d/GradientStopsD2D.h rename to libazure/GradientStopsD2D.h index fe5b4e2..e06bfa0 100644 --- a/libazure/src/gfx/2d/GradientStopsD2D.h +++ b/libazure/GradientStopsD2D.h @@ -16,14 +16,16 @@ namespace gfx { class GradientStopsD2D : public GradientStops { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsD2D) GradientStopsD2D(ID2D1GradientStopCollection *aStopCollection) : mStopCollection(aStopCollection) {} - virtual BackendType GetBackendType() const { return BACKEND_DIRECT2D; } + virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; } private: friend class DrawTargetD2D; + friend class DrawTargetD2D1; mutable RefPtr mStopCollection; }; diff --git a/libazure/GradientStopsNVpr.cpp b/libazure/GradientStopsNVpr.cpp new file mode 100644 index 0000000..7fb5f74 --- /dev/null +++ b/libazure/GradientStopsNVpr.cpp @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GradientStopsNVpr.h" +#include +#include + +static const int sMaxColorRampSize = 4096; +static const size_t sMaxRampTexturePoolSize = 32; + +using namespace mozilla::gfx::nvpr; +using namespace std; + +struct TextureColor { + TextureColor() {} + TextureColor(const mozilla::gfx::Color& color) + : r(static_cast(color.a * color.r * 255)) + , g(static_cast(color.a * color.g * 255)) + , b(static_cast(color.a * color.b * 255)) + , a(static_cast(color.a * 255)) + {} + void Lerp(TextureColor aColor1, TextureColor aColor2, uint8_t aWeight) + { + r = (aColor1.r * (256 - aWeight) + aColor2.r * aWeight) >> 8; + g = (aColor1.g * (256 - aWeight) + aColor2.g * aWeight) >> 8; + b = (aColor1.b * (256 - aWeight) + aColor2.b * aWeight) >> 8; + a = (aColor1.a * (256 - aWeight) + aColor2.a * aWeight) >> 8; + } + void Average(TextureColor aColor1, TextureColor aColor2) + { + r = (aColor1.r + aColor2.r) >> 1; + g = (aColor1.g + aColor2.g) >> 1; + b = (aColor1.b + aColor2.b) >> 1; + a = (aColor1.a + aColor2.a) >> 1; + } + GLubyte r, g, b, a; +}; + +struct ColorRampData : public mozilla::gfx::nvpr::UserData::Object { + vector mRampBuffer; + size_t mNumLevels; + deque mTexturePool; +}; + +namespace mozilla { +namespace gfx { + +GradientStopsNVpr::GradientStopsNVpr(GradientStop* aRawStops, uint32_t aNumStops, + ExtendMode aExtendMode) + : mRampTextureId(0) + , mInitialColor(1, 1, 1, 1) + , mFinalColor(1, 1, 1, 1) +{ + if (!aRawStops || !aNumStops) { + return; + } + + if (aNumStops == 1) { + mInitialColor = mFinalColor = aRawStops[0].color; + return; + } + + vector sortedStops(aNumStops); + memcpy(sortedStops.data(), aRawStops, aNumStops * sizeof(GradientStop)); + sort(sortedStops.begin(), sortedStops.end()); + + mInitialColor = sortedStops.front().color; + mFinalColor = sortedStops.back().color; + + gl->MakeCurrent(); + + // Draw the color stops into a linear color ramp buffer. + // TODO: Optimize this with SSE/NEON. + ColorRampData& rampData = + gl->GetUserObject(&nvpr::UserData::mColorRampData); + vector& ramp = rampData.mRampBuffer; + + if (ramp.empty()) { + ramp.resize(min(sMaxColorRampSize, gl->MaxTextureSize())); + rampData.mNumLevels = 0; + for (size_t width = ramp.size(); width; width >>= 1) { + rampData.mNumLevels++; + } + } + + TextureColor startColor(mInitialColor); + MOZ_ASSERT(sortedStops[0].offset >= 0 && sortedStops[0].offset <= 1); + size_t startIndex = sortedStops[0].offset * (ramp.size() - 1); + for (size_t i = 0; i < startIndex; i++) { + ramp[i] = startColor; + } + + for (size_t i = 1; i < sortedStops.size(); i++) { + MOZ_ASSERT(sortedStops[i].offset >= 0 && sortedStops[i].offset <= 1); + const TextureColor endColor(sortedStops[i].color); + const size_t endIndex = sortedStops[i].offset * (ramp.size() - 1); + + if (endIndex == startIndex) { + startColor = endColor; + continue; + } + + const uint16_t weightStep = (1 << 16) / (endIndex - startIndex); + uint16_t weight = 0; + for (size_t i = startIndex; i < endIndex; i++) { + ramp[i].Lerp(startColor, endColor, weight >> 8); + weight += weightStep; + } + + startColor = endColor; + startIndex = endIndex; + } + + const TextureColor endColor(mFinalColor); + for (size_t i = startIndex; i < ramp.size(); i++) { + ramp[i] = endColor; + } + + // Create a texture from the color ramp buffer. + if (!rampData.mTexturePool.empty()) { + mRampTextureId = rampData.mTexturePool.front(); + rampData.mTexturePool.pop_front(); + } else { + gl->GenTextures(1, &mRampTextureId); + gl->TextureStorage1DEXT(mRampTextureId, GL_TEXTURE_1D, + rampData.mNumLevels, GL_RGBA8, ramp.size()); + } + + gl->TextureSubImage1DEXT(mRampTextureId, GL_TEXTURE_1D, 0, 0, ramp.size(), + GL_RGBA, GL_UNSIGNED_BYTE, ramp.data()); + + size_t previousWidth = ramp.size(); + for (size_t level = 1; level < rampData.mNumLevels - 1; level++) { + // Generate a mipmap image where the begin and end texels are the same + // colors as the begin and end stops, to ensure proper clamping. + const size_t width = previousWidth >> 1; + for (size_t i = 1; i < width - 1; i++) { + ramp[i].Average(ramp[2 * i], ramp[2 * i + 1]); + } + ramp[width - 1] = ramp[previousWidth - 1]; + + gl->TextureSubImage1DEXT(mRampTextureId, GL_TEXTURE_1D, level, 0, width, + GL_RGBA, GL_UNSIGNED_BYTE, ramp.data()); + + previousWidth = width; + } + + // Configure texturing parameters. + gl->TextureParameteriEXT(mRampTextureId, GL_TEXTURE_1D, + //GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TextureParameteriEXT(mRampTextureId, GL_TEXTURE_1D, + GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (aExtendMode == ExtendMode::CLAMP) { + gl->TextureParameteriEXT(mRampTextureId, GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, + rampData.mNumLevels - 2); + } else { + gl->TextureParameteriEXT(mRampTextureId, GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, + rampData.mNumLevels - 1); + ramp[0].Average(ramp[0], ramp[1]); + gl->TextureSubImage1DEXT(mRampTextureId, GL_TEXTURE_1D, + rampData.mNumLevels - 1, 0, 1, GL_RGBA, + GL_UNSIGNED_BYTE, ramp.data()); + } + + GLenum wrapMode; + switch (aExtendMode) { + default: + MOZ_ASSERT(!"Invalid gradient extend mode"); + case ExtendMode::CLAMP: + wrapMode = GL_CLAMP_TO_EDGE; + break; + case ExtendMode::REPEAT: + wrapMode = GL_REPEAT; + break; + case ExtendMode::REFLECT: + wrapMode = GL_MIRRORED_REPEAT; + break; + } + gl->TextureParameteriEXT(mRampTextureId, GL_TEXTURE_1D, + GL_TEXTURE_WRAP_S, wrapMode); +} + +GradientStopsNVpr::~GradientStopsNVpr() +{ + ColorRampData& rampData = + gl->GetUserObject(&nvpr::UserData::mColorRampData); + + if (rampData.mTexturePool.size() < sMaxRampTexturePoolSize) { + rampData.mTexturePool.push_back(mRampTextureId); + return; + } + + gl->MakeCurrent(); + gl->DeleteTexture(mRampTextureId); +} + +} +} diff --git a/libazure/GradientStopsNVpr.h b/libazure/GradientStopsNVpr.h new file mode 100644 index 0000000..5d3acdf --- /dev/null +++ b/libazure/GradientStopsNVpr.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_GRADIENTSTOPSNVPR_H_ +#define MOZILLA_GFX_GRADIENTSTOPSNVPR_H_ + +#include "2D.h" +#include "nvpr/GL.h" +#include + +namespace mozilla { +namespace gfx { + +class GradientStopsNVpr : public GradientStops { +public: + static TemporaryRef + create(GradientStop* aRawStops, uint32_t aNumStops, ExtendMode aExtendMode) + { + return new GradientStopsNVpr(aRawStops, aNumStops, aExtendMode); + } + + ~GradientStopsNVpr(); + + virtual BackendType GetBackendType() const { return BackendType::NVPR; } + + const Color& FinalColor() const { return mFinalColor; } + operator GLuint() const { return mRampTextureId; } + +private: + GradientStopsNVpr(GradientStop* aRawStops, uint32_t aNumStops, + ExtendMode aExtendMode); + + GLuint mRampTextureId; + Color mInitialColor; + Color mFinalColor; +}; + +} +} + +#endif /* MOZILLA_GFX_GRADIENTSTOPSNVPR_H_ */ diff --git a/libazure/src/gfx/2d/Helpers.h b/libazure/Helpers.h similarity index 100% rename from libazure/src/gfx/2d/Helpers.h rename to libazure/Helpers.h diff --git a/libazure/src/gfx/2d/HelpersCairo.h b/libazure/HelpersCairo.h similarity index 69% rename from libazure/src/gfx/2d/HelpersCairo.h rename to libazure/HelpersCairo.h index 5dfcee2..a0f52b3 100644 --- a/libazure/src/gfx/2d/HelpersCairo.h +++ b/libazure/HelpersCairo.h @@ -18,73 +18,92 @@ GfxOpToCairoOp(CompositionOp op) { switch (op) { - case OP_OVER: + case CompositionOp::OP_OVER: return CAIRO_OPERATOR_OVER; - case OP_ADD: + case CompositionOp::OP_ADD: return CAIRO_OPERATOR_ADD; - case OP_ATOP: + case CompositionOp::OP_ATOP: return CAIRO_OPERATOR_ATOP; - case OP_OUT: + case CompositionOp::OP_OUT: return CAIRO_OPERATOR_OUT; - case OP_IN: + case CompositionOp::OP_IN: return CAIRO_OPERATOR_IN; - case OP_SOURCE: + case CompositionOp::OP_SOURCE: return CAIRO_OPERATOR_SOURCE; - case OP_DEST_IN: + case CompositionOp::OP_DEST_IN: return CAIRO_OPERATOR_DEST_IN; - case OP_DEST_OUT: + case CompositionOp::OP_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT; - case OP_DEST_OVER: + case CompositionOp::OP_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER; - case OP_DEST_ATOP: + case CompositionOp::OP_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP; - case OP_XOR: + case CompositionOp::OP_XOR: return CAIRO_OPERATOR_XOR; - case OP_MULTIPLY: + case CompositionOp::OP_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY; - case OP_SCREEN: + case CompositionOp::OP_SCREEN: return CAIRO_OPERATOR_SCREEN; - case OP_OVERLAY: + case CompositionOp::OP_OVERLAY: return CAIRO_OPERATOR_OVERLAY; - case OP_DARKEN: + case CompositionOp::OP_DARKEN: return CAIRO_OPERATOR_DARKEN; - case OP_LIGHTEN: + case CompositionOp::OP_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN; - case OP_COLOR_DODGE: + case CompositionOp::OP_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE; - case OP_COLOR_BURN: + case CompositionOp::OP_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN; - case OP_HARD_LIGHT: + case CompositionOp::OP_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT; - case OP_SOFT_LIGHT: + case CompositionOp::OP_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT; - case OP_DIFFERENCE: + case CompositionOp::OP_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE; - case OP_EXCLUSION: + case CompositionOp::OP_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION; - case OP_HUE: + case CompositionOp::OP_HUE: return CAIRO_OPERATOR_HSL_HUE; - case OP_SATURATION: + case CompositionOp::OP_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION; - case OP_COLOR: + case CompositionOp::OP_COLOR: return CAIRO_OPERATOR_HSL_COLOR; - case OP_LUMINOSITY: + case CompositionOp::OP_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY; - case OP_COUNT: + case CompositionOp::OP_COUNT: break; } return CAIRO_OPERATOR_OVER; } +static inline cairo_antialias_t +GfxAntialiasToCairoAntialias(AntialiasMode antialias) +{ + switch (antialias) + { + case AntialiasMode::NONE: + return CAIRO_ANTIALIAS_NONE; + case AntialiasMode::GRAY: + return CAIRO_ANTIALIAS_GRAY; + case AntialiasMode::SUBPIXEL: + return CAIRO_ANTIALIAS_SUBPIXEL; + case AntialiasMode::DEFAULT: + return CAIRO_ANTIALIAS_DEFAULT; + } + return CAIRO_ANTIALIAS_DEFAULT; +} + static inline cairo_filter_t GfxFilterToCairoFilter(Filter filter) { switch (filter) { - case FILTER_LINEAR: + case Filter::GOOD: + return CAIRO_FILTER_GOOD; + case Filter::LINEAR: return CAIRO_FILTER_BILINEAR; - case FILTER_POINT: + case Filter::POINT: return CAIRO_FILTER_NEAREST; } @@ -96,11 +115,11 @@ GfxExtendToCairoExtend(ExtendMode extend) { switch (extend) { - case EXTEND_CLAMP: + case ExtendMode::CLAMP: return CAIRO_EXTEND_PAD; - case EXTEND_REPEAT: + case ExtendMode::REPEAT: return CAIRO_EXTEND_REPEAT; - case EXTEND_REFLECT: + case ExtendMode::REFLECT: return CAIRO_EXTEND_REFLECT; } @@ -112,13 +131,13 @@ GfxFormatToCairoFormat(SurfaceFormat format) { switch (format) { - case FORMAT_B8G8R8A8: + case SurfaceFormat::B8G8R8A8: return CAIRO_FORMAT_ARGB32; - case FORMAT_B8G8R8X8: + case SurfaceFormat::B8G8R8X8: return CAIRO_FORMAT_RGB24; - case FORMAT_A8: + case SurfaceFormat::A8: return CAIRO_FORMAT_A8; - case FORMAT_R5G6B5: + case SurfaceFormat::R5G6B5: return CAIRO_FORMAT_RGB16_565; default: gfxWarning() << "Unknown image format"; @@ -131,12 +150,12 @@ GfxFormatToCairoContent(SurfaceFormat format) { switch (format) { - case FORMAT_B8G8R8A8: + case SurfaceFormat::B8G8R8A8: return CAIRO_CONTENT_COLOR_ALPHA; - case FORMAT_B8G8R8X8: - case FORMAT_R5G6B5: //fall through + case SurfaceFormat::B8G8R8X8: + case SurfaceFormat::R5G6B5: //fall through return CAIRO_CONTENT_COLOR; - case FORMAT_A8: + case SurfaceFormat::A8: return CAIRO_CONTENT_ALPHA; default: gfxWarning() << "Unknown image format"; @@ -149,13 +168,13 @@ GfxLineJoinToCairoLineJoin(JoinStyle style) { switch (style) { - case JOIN_BEVEL: + case JoinStyle::BEVEL: return CAIRO_LINE_JOIN_BEVEL; - case JOIN_ROUND: + case JoinStyle::ROUND: return CAIRO_LINE_JOIN_ROUND; - case JOIN_MITER: + case JoinStyle::MITER: return CAIRO_LINE_JOIN_MITER; - case JOIN_MITER_OR_BEVEL: + case JoinStyle::MITER_OR_BEVEL: return CAIRO_LINE_JOIN_MITER; } @@ -167,11 +186,11 @@ GfxLineCapToCairoLineCap(CapStyle style) { switch (style) { - case CAP_BUTT: + case CapStyle::BUTT: return CAIRO_LINE_CAP_BUTT; - case CAP_ROUND: + case CapStyle::ROUND: return CAIRO_LINE_CAP_ROUND; - case CAP_SQUARE: + case CapStyle::SQUARE: return CAIRO_LINE_CAP_SQUARE; } @@ -184,15 +203,15 @@ CairoContentToGfxFormat(cairo_content_t content) switch (content) { case CAIRO_CONTENT_COLOR_ALPHA: - return FORMAT_B8G8R8A8; + return SurfaceFormat::B8G8R8A8; case CAIRO_CONTENT_COLOR: // BEWARE! format may be 565 - return FORMAT_B8G8R8X8; + return SurfaceFormat::B8G8R8X8; case CAIRO_CONTENT_ALPHA: - return FORMAT_A8; + return SurfaceFormat::A8; } - return FORMAT_B8G8R8A8; + return SurfaceFormat::B8G8R8A8; } static inline void @@ -228,9 +247,9 @@ GfxFillRuleToCairoFillRule(FillRule rule) { switch (rule) { - case FILL_WINDING: + case FillRule::FILL_WINDING: return CAIRO_FILL_RULE_WINDING; - case FILL_EVEN_ODD: + case FillRule::FILL_EVEN_ODD: return CAIRO_FILL_RULE_EVEN_ODD; } diff --git a/libazure/HelpersD2D.h b/libazure/HelpersD2D.h new file mode 100644 index 0000000..d941cb2 --- /dev/null +++ b/libazure/HelpersD2D.h @@ -0,0 +1,640 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_HELPERSD2D_H_ +#define MOZILLA_GFX_HELPERSD2D_H_ + +#ifndef USE_D2D1_1 +#include "moz-d2d1-1.h" +#else +#include +#endif + +#include + +#include +#include "2D.h" +#include "Logging.h" +#include "Tools.h" +#include "ImageScaling.h" + +#include "ScaledFontDWrite.h" + +#undef min +#undef max + +namespace mozilla { +namespace gfx { + +ID2D1Factory* D2DFactory(); + +#ifdef USE_D2D1_1 +ID2D1Factory1* D2DFactory1(); +#endif + +static inline D2D1_POINT_2F D2DPoint(const Point &aPoint) +{ + return D2D1::Point2F(aPoint.x, aPoint.y); +} + +static inline D2D1_SIZE_U D2DIntSize(const IntSize &aSize) +{ + return D2D1::SizeU(aSize.width, aSize.height); +} + +template +static inline D2D1_RECT_F D2DRect(const T &aRect) +{ + return D2D1::RectF(aRect.x, aRect.y, aRect.XMost(), aRect.YMost()); +} + +static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode) +{ + D2D1_EXTEND_MODE extend; + switch (aExtendMode) { + case ExtendMode::REPEAT: + extend = D2D1_EXTEND_MODE_WRAP; + break; + case ExtendMode::REFLECT: + extend = D2D1_EXTEND_MODE_MIRROR; + break; + default: + extend = D2D1_EXTEND_MODE_CLAMP; + } + + return extend; +} + +static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter) +{ + switch (aFilter) { + case Filter::POINT: + return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + default: + return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR; + } +} + +#ifdef USE_D2D1_1 +static inline D2D1_INTERPOLATION_MODE D2DInterpolationMode(const Filter &aFilter) +{ + switch (aFilter) { + case Filter::POINT: + return D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + default: + return D2D1_INTERPOLATION_MODE_LINEAR; + } +} + +static inline D2D1_MATRIX_5X4_F D2DMatrix5x4(const Matrix5x4 &aMatrix) +{ + return D2D1::Matrix5x4F(aMatrix._11, aMatrix._12, aMatrix._13, aMatrix._14, + aMatrix._21, aMatrix._22, aMatrix._23, aMatrix._24, + aMatrix._31, aMatrix._32, aMatrix._33, aMatrix._34, + aMatrix._41, aMatrix._42, aMatrix._43, aMatrix._44, + aMatrix._51, aMatrix._52, aMatrix._53, aMatrix._54); +} + +static inline D2D1_VECTOR_3F D2DVector3D(const Point3D &aPoint) +{ + return D2D1::Vector3F(aPoint.x, aPoint.y, aPoint.z); +} + +#endif + +static inline D2D1_ANTIALIAS_MODE D2DAAMode(AntialiasMode aMode) +{ + switch (aMode) { + case AntialiasMode::NONE: + return D2D1_ANTIALIAS_MODE_ALIASED; + default: + return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; + } +} + +static inline D2D1_MATRIX_3X2_F D2DMatrix(const Matrix &aTransform) +{ + return D2D1::Matrix3x2F(aTransform._11, aTransform._12, + aTransform._21, aTransform._22, + aTransform._31, aTransform._32); +} + +static inline D2D1_COLOR_F D2DColor(const Color &aColor) +{ + return D2D1::ColorF(aColor.r, aColor.g, aColor.b, aColor.a); +} + +static inline IntSize ToIntSize(const D2D1_SIZE_U &aSize) +{ + return IntSize(aSize.width, aSize.height); +} + +static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat) +{ + switch(aFormat.format) { + case DXGI_FORMAT_A8_UNORM: + return SurfaceFormat::A8; + case DXGI_FORMAT_B8G8R8A8_UNORM: + if (aFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE) { + return SurfaceFormat::B8G8R8X8; + } else { + return SurfaceFormat::B8G8R8A8; + } + default: + return SurfaceFormat::B8G8R8A8; + } +} + +static inline Rect ToRect(const D2D1_RECT_F &aRect) +{ + return Rect(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top); +} + +static inline Matrix ToMatrix(const D2D1_MATRIX_3X2_F &aTransform) +{ + return Matrix(aTransform._11, aTransform._12, + aTransform._21, aTransform._22, + aTransform._31, aTransform._32); +} + +static inline Point ToPoint(const D2D1_POINT_2F &aPoint) +{ + return Point(aPoint.x, aPoint.y); +} + +static inline DXGI_FORMAT DXGIFormat(SurfaceFormat aFormat) +{ + switch (aFormat) { + case SurfaceFormat::B8G8R8A8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case SurfaceFormat::B8G8R8X8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case SurfaceFormat::A8: + return DXGI_FORMAT_A8_UNORM; + default: + return DXGI_FORMAT_UNKNOWN; + } +} + +static inline D2D1_ALPHA_MODE D2DAlphaModeForFormat(SurfaceFormat aFormat) +{ + switch (aFormat) { + case SurfaceFormat::B8G8R8X8: + return D2D1_ALPHA_MODE_IGNORE; + default: + return D2D1_ALPHA_MODE_PREMULTIPLIED; + } +} + +static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat) +{ + return D2D1::PixelFormat(DXGIFormat(aFormat), D2DAlphaModeForFormat(aFormat)); +} + +#ifdef USE_D2D1_1 +static inline bool D2DSupportsCompositeMode(CompositionOp aOp) +{ + switch(aOp) { + case CompositionOp::OP_OVER: + case CompositionOp::OP_ADD: + case CompositionOp::OP_ATOP: + case CompositionOp::OP_OUT: + case CompositionOp::OP_IN: + case CompositionOp::OP_SOURCE: + case CompositionOp::OP_DEST_IN: + case CompositionOp::OP_DEST_OUT: + case CompositionOp::OP_DEST_OVER: + case CompositionOp::OP_DEST_ATOP: + case CompositionOp::OP_XOR: + return true; + default: + return false; + } +} + +static inline D2D1_COMPOSITE_MODE D2DCompositionMode(CompositionOp aOp) +{ + switch(aOp) { + case CompositionOp::OP_OVER: + return D2D1_COMPOSITE_MODE_SOURCE_OVER; + case CompositionOp::OP_ADD: + return D2D1_COMPOSITE_MODE_PLUS; + case CompositionOp::OP_ATOP: + return D2D1_COMPOSITE_MODE_SOURCE_ATOP; + case CompositionOp::OP_OUT: + return D2D1_COMPOSITE_MODE_SOURCE_OUT; + case CompositionOp::OP_IN: + return D2D1_COMPOSITE_MODE_SOURCE_IN; + case CompositionOp::OP_SOURCE: + return D2D1_COMPOSITE_MODE_SOURCE_COPY; + case CompositionOp::OP_DEST_IN: + return D2D1_COMPOSITE_MODE_DESTINATION_IN; + case CompositionOp::OP_DEST_OUT: + return D2D1_COMPOSITE_MODE_DESTINATION_OUT; + case CompositionOp::OP_DEST_OVER: + return D2D1_COMPOSITE_MODE_DESTINATION_OVER; + case CompositionOp::OP_DEST_ATOP: + return D2D1_COMPOSITE_MODE_DESTINATION_ATOP; + case CompositionOp::OP_XOR: + return D2D1_COMPOSITE_MODE_XOR; + default: + return D2D1_COMPOSITE_MODE_SOURCE_OVER; + } +} + +static inline D2D1_BLEND_MODE D2DBlendMode(CompositionOp aOp) +{ + switch (aOp) { + case CompositionOp::OP_MULTIPLY: + return D2D1_BLEND_MODE_MULTIPLY; + case CompositionOp::OP_SCREEN: + return D2D1_BLEND_MODE_SCREEN; + case CompositionOp::OP_OVERLAY: + return D2D1_BLEND_MODE_OVERLAY; + case CompositionOp::OP_DARKEN: + return D2D1_BLEND_MODE_DARKEN; + case CompositionOp::OP_LIGHTEN: + return D2D1_BLEND_MODE_LIGHTEN; + case CompositionOp::OP_COLOR_DODGE: + return D2D1_BLEND_MODE_COLOR_DODGE; + case CompositionOp::OP_COLOR_BURN: + return D2D1_BLEND_MODE_COLOR_BURN; + case CompositionOp::OP_HARD_LIGHT: + return D2D1_BLEND_MODE_HARD_LIGHT; + case CompositionOp::OP_SOFT_LIGHT: + return D2D1_BLEND_MODE_SOFT_LIGHT; + case CompositionOp::OP_DIFFERENCE: + return D2D1_BLEND_MODE_DIFFERENCE; + case CompositionOp::OP_EXCLUSION: + return D2D1_BLEND_MODE_EXCLUSION; + case CompositionOp::OP_HUE: + return D2D1_BLEND_MODE_HUE; + case CompositionOp::OP_SATURATION: + return D2D1_BLEND_MODE_SATURATION; + case CompositionOp::OP_COLOR: + return D2D1_BLEND_MODE_COLOR; + case CompositionOp::OP_LUMINOSITY: + return D2D1_BLEND_MODE_LUMINOSITY; + default: + return D2D1_BLEND_MODE_MULTIPLY; + } +} +#endif + +static inline bool IsPatternSupportedByD2D(const Pattern &aPattern) +{ + if (aPattern.GetType() != PatternType::RADIAL_GRADIENT) { + return true; + } + + const RadialGradientPattern *pat = + static_cast(&aPattern); + + if (pat->mRadius1 != 0) { + return false; + } + + Point diff = pat->mCenter2 - pat->mCenter1; + + if (sqrt(diff.x * diff.x + diff.y * diff.y) >= pat->mRadius2) { + // Inner point lies outside the circle. + return false; + } + + return true; +} + +/** + * This structure is used to pass rectangles to our shader constant. We can use + * this for passing rectangular areas to SetVertexShaderConstant. In the format + * of a 4 component float(x,y,width,height). Our vertex shader can then use + * this to construct rectangular positions from the 0,0-1,1 quad that we source + * it with. + */ +struct ShaderConstantRectD3D10 +{ + float mX, mY, mWidth, mHeight; + ShaderConstantRectD3D10(float aX, float aY, float aWidth, float aHeight) + : mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight) + { } + + // For easy passing to SetVertexShaderConstantF. + operator float* () { return &mX; } +}; + +static inline DWRITE_MATRIX +DWriteMatrixFromMatrix(Matrix &aMatrix) +{ + DWRITE_MATRIX mat; + mat.m11 = aMatrix._11; + mat.m12 = aMatrix._12; + mat.m21 = aMatrix._21; + mat.m22 = aMatrix._22; + mat.dx = aMatrix._31; + mat.dy = aMatrix._32; + return mat; +} + +class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN +{ + static const unsigned kNumAutoGlyphs = 256; + +public: + AutoDWriteGlyphRun() { + glyphCount = 0; + } + + ~AutoDWriteGlyphRun() { + if (glyphCount > kNumAutoGlyphs) { + delete[] glyphIndices; + delete[] glyphAdvances; + delete[] glyphOffsets; + } + } + + void allocate(unsigned aNumGlyphs) { + glyphCount = aNumGlyphs; + if (aNumGlyphs <= kNumAutoGlyphs) { + glyphIndices = &mAutoIndices[0]; + glyphAdvances = &mAutoAdvances[0]; + glyphOffsets = &mAutoOffsets[0]; + } else { + glyphIndices = new UINT16[aNumGlyphs]; + glyphAdvances = new FLOAT[aNumGlyphs]; + glyphOffsets = new DWRITE_GLYPH_OFFSET[aNumGlyphs]; + } + } + +private: + DWRITE_GLYPH_OFFSET mAutoOffsets[kNumAutoGlyphs]; + FLOAT mAutoAdvances[kNumAutoGlyphs]; + UINT16 mAutoIndices[kNumAutoGlyphs]; +}; + +static inline void +DWriteGlyphRunFromGlyphs(const GlyphBuffer &aGlyphs, ScaledFontDWrite *aFont, AutoDWriteGlyphRun *run) +{ + run->allocate(aGlyphs.mNumGlyphs); + + FLOAT *advances = const_cast(run->glyphAdvances); + UINT16 *indices = const_cast(run->glyphIndices); + DWRITE_GLYPH_OFFSET *offsets = const_cast(run->glyphOffsets); + + memset(advances, 0, sizeof(FLOAT) * aGlyphs.mNumGlyphs); + for (unsigned int i = 0; i < aGlyphs.mNumGlyphs; i++) { + indices[i] = aGlyphs.mGlyphs[i].mIndex; + offsets[i].advanceOffset = aGlyphs.mGlyphs[i].mPosition.x; + offsets[i].ascenderOffset = -aGlyphs.mGlyphs[i].mPosition.y; + } + + run->bidiLevel = 0; + run->fontFace = aFont->mFontFace; + run->fontEmSize = aFont->GetSize(); + run->glyphCount = aGlyphs.mNumGlyphs; + run->isSideways = FALSE; +} + +static TemporaryRef +ConvertRectToGeometry(const D2D1_RECT_F& aRect) +{ + RefPtr rectGeom; + D2DFactory()->CreateRectangleGeometry(&aRect, byRef(rectGeom)); + return rectGeom.forget(); +} + +static TemporaryRef +GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform) +{ + RefPtr tmpGeometry; + D2DFactory()->CreatePathGeometry(byRef(tmpGeometry)); + RefPtr currentSink; + tmpGeometry->Open(byRef(currentSink)); + aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + aTransform, currentSink); + currentSink->Close(); + return tmpGeometry.forget(); +} + +static TemporaryRef +IntersectGeometry(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB) +{ + RefPtr pathGeom; + D2DFactory()->CreatePathGeometry(byRef(pathGeom)); + RefPtr sink; + pathGeom->Open(byRef(sink)); + aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink); + sink->Close(); + + return pathGeom.forget(); +} + +static TemporaryRef +CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions) +{ + RefPtr style; + + D2D1_CAP_STYLE capStyle; + D2D1_LINE_JOIN joinStyle; + + switch (aStrokeOptions.mLineCap) { + case CapStyle::BUTT: + capStyle = D2D1_CAP_STYLE_FLAT; + break; + case CapStyle::ROUND: + capStyle = D2D1_CAP_STYLE_ROUND; + break; + case CapStyle::SQUARE: + capStyle = D2D1_CAP_STYLE_SQUARE; + break; + } + + switch (aStrokeOptions.mLineJoin) { + case JoinStyle::MITER: + joinStyle = D2D1_LINE_JOIN_MITER; + break; + case JoinStyle::MITER_OR_BEVEL: + joinStyle = D2D1_LINE_JOIN_MITER_OR_BEVEL; + break; + case JoinStyle::ROUND: + joinStyle = D2D1_LINE_JOIN_ROUND; + break; + case JoinStyle::BEVEL: + joinStyle = D2D1_LINE_JOIN_BEVEL; + break; + } + + + HRESULT hr; + if (aStrokeOptions.mDashPattern) { + typedef std::vector FloatVector; + // D2D "helpfully" multiplies the dash pattern by the line width. + // That's not what cairo does, or is what 's dash wants. + // So fix the multiplication in advance. + Float lineWidth = aStrokeOptions.mLineWidth; + FloatVector dash(aStrokeOptions.mDashPattern, + aStrokeOptions.mDashPattern + aStrokeOptions.mDashLength); + for (FloatVector::iterator it = dash.begin(); it != dash.end(); ++it) { + *it /= lineWidth; + } + + hr = D2DFactory()->CreateStrokeStyle( + D2D1::StrokeStyleProperties(capStyle, capStyle, + capStyle, joinStyle, + aStrokeOptions.mMiterLimit, + D2D1_DASH_STYLE_CUSTOM, + aStrokeOptions.mDashOffset), + &dash[0], // data() is not C++98, although it's in recent gcc + // and VC10's STL + dash.size(), + byRef(style)); + } else { + hr = D2DFactory()->CreateStrokeStyle( + D2D1::StrokeStyleProperties(capStyle, capStyle, + capStyle, joinStyle, + aStrokeOptions.mMiterLimit), + nullptr, 0, byRef(style)); + } + + if (FAILED(hr)) { + gfxWarning() << "Failed to create Direct2D stroke style."; + } + + return style.forget(); +} + +// This creates a (partially) uploaded bitmap for a DataSourceSurface. It +// uploads the minimum requirement and possibly downscales. It adjusts the +// input Matrix to compensate. +static TemporaryRef +CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestinationTransform, + const IntSize &aDestinationSize, ExtendMode aExtendMode, + Matrix &aSourceTransform, ID2D1RenderTarget *aRT) +{ + RefPtr bitmap; + + // This is where things get complicated. The source surface was + // created for a surface that was too large to fit in a texture. + // We'll need to figure out if we can work with a partial upload + // or downsample in software. + + Matrix transform = aDestinationTransform; + Matrix invTransform = transform = aSourceTransform * transform; + if (!invTransform.Invert()) { + // Singular transform, nothing to be drawn. + return nullptr; + } + + Rect rect(0, 0, Float(aDestinationSize.width), Float(aDestinationSize.height)); + + // Calculate the rectangle of the source mapped to our surface. + rect = invTransform.TransformBounds(rect); + rect.RoundOut(); + + IntSize size = aSurface->GetSize(); + + Rect uploadRect(0, 0, Float(size.width), Float(size.height)); + + // Limit the uploadRect as much as possible without supporting discontiguous uploads + // + // region we will paint from + // uploadRect + // .---------------. .---------------. resulting uploadRect + // | |rect | | + // | .---------. .----. .----. .---------------. + // | | | ----> | | | | ----> | | + // | '---------' '----' '----' '---------------' + // '---------------' '---------------' + // + // + + if (uploadRect.Contains(rect)) { + // Extend mode is irrelevant, the displayed rect is completely contained + // by the source bitmap. + uploadRect = rect; + } else if (aExtendMode == ExtendMode::CLAMP && uploadRect.Intersects(rect)) { + // Calculate the rectangle on the source bitmap that touches our + // surface, and upload that, for ExtendMode::CLAMP we can actually guarantee + // correct behaviour in this case. + uploadRect = uploadRect.Intersect(rect); + + // We now proceed to check if we can limit at least one dimension of the + // upload rect safely without looking at extend mode. + } else if (rect.x >= 0 && rect.XMost() < size.width) { + uploadRect.x = rect.x; + uploadRect.width = rect.width; + } else if (rect.y >= 0 && rect.YMost() < size.height) { + uploadRect.y = rect.y; + uploadRect.height = rect.height; + } + + + int stride = aSurface->Stride(); + + if (uploadRect.width <= aRT->GetMaximumBitmapSize() && + uploadRect.height <= aRT->GetMaximumBitmapSize()) { + + // A partial upload will suffice. + aRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)), + aSurface->GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * stride, + stride, + D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())), + byRef(bitmap)); + + aSourceTransform.PreTranslate(uploadRect.x, uploadRect.y); + + return bitmap.forget(); + } else { + int Bpp = BytesPerPixel(aSurface->GetFormat()); + + if (Bpp != 4) { + // This shouldn't actually happen in practice! + MOZ_ASSERT(false); + return nullptr; + } + + ImageHalfScaler scaler(aSurface->GetData(), stride, size); + + // Calculate the maximum width/height of the image post transform. + Point topRight = transform * Point(Float(size.width), 0); + Point topLeft = transform * Point(0, 0); + Point bottomRight = transform * Point(Float(size.width), Float(size.height)); + Point bottomLeft = transform * Point(0, Float(size.height)); + + IntSize scaleSize; + + scaleSize.width = int32_t(std::max(Distance(topRight, topLeft), + Distance(bottomRight, bottomLeft))); + scaleSize.height = int32_t(std::max(Distance(topRight, bottomRight), + Distance(topLeft, bottomLeft))); + + if (unsigned(scaleSize.width) > aRT->GetMaximumBitmapSize()) { + // Ok, in this case we'd really want a downscale of a part of the bitmap, + // perhaps we can do this later but for simplicity let's do something + // different here and assume it's good enough, this should be rare! + scaleSize.width = 4095; + } + if (unsigned(scaleSize.height) > aRT->GetMaximumBitmapSize()) { + scaleSize.height = 4095; + } + + scaler.ScaleForSize(scaleSize); + + IntSize newSize = scaler.GetSize(); + + aRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height), + scaler.GetScaledData(), scaler.GetStride(), + D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())), + byRef(bitmap)); + + aSourceTransform.PreScale(Float(size.width / newSize.width), + Float(size.height / newSize.height)); + return bitmap.forget(); + } +} + +} +} + +#endif /* MOZILLA_GFX_HELPERSD2D_H_ */ diff --git a/libazure/HelpersSkia.h b/libazure/HelpersSkia.h new file mode 100644 index 0000000..59c372b --- /dev/null +++ b/libazure/HelpersSkia.h @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_HELPERSSKIA_H_ +#define MOZILLA_GFX_HELPERSSKIA_H_ + +#include "2D.h" +#include "core/SkCanvas.h" +#include "effects/SkDashPathEffect.h" +#include "core/SkShader.h" +#include "gpu/GrTypes.h" +#include "mozilla/Assertions.h" +#include + +namespace mozilla { +namespace gfx { + +static inline SkColorType +GfxFormatToSkiaColorType(SurfaceFormat format) +{ + switch (format) + { + case SurfaceFormat::B8G8R8A8: + return kBGRA_8888_SkColorType; + case SurfaceFormat::B8G8R8X8: + // We probably need to do something here. + return kBGRA_8888_SkColorType; + case SurfaceFormat::R5G6B5: + return kRGB_565_SkColorType; + case SurfaceFormat::A8: + return kAlpha_8_SkColorType; + default: + return kRGBA_8888_SkColorType; + } +} + +static inline SurfaceFormat +SkiaColorTypeToGfxFormat(SkColorType type) +{ + switch (type) + { + case kBGRA_8888_SkColorType: + return SurfaceFormat::B8G8R8A8; + case kRGB_565_SkColorType: + return SurfaceFormat::R5G6B5; + case kAlpha_8_SkColorType: + return SurfaceFormat::A8; + default: + return SurfaceFormat::B8G8R8A8; + } +} + +#ifdef USE_SKIA_GPU +static inline GrPixelConfig +GfxFormatToGrConfig(SurfaceFormat format) +{ + switch (format) + { + case SurfaceFormat::B8G8R8A8: + return kBGRA_8888_GrPixelConfig; + case SurfaceFormat::B8G8R8X8: + // We probably need to do something here. + return kBGRA_8888_GrPixelConfig; + case SurfaceFormat::R5G6B5: + return kRGB_565_GrPixelConfig; + case SurfaceFormat::A8: + return kAlpha_8_GrPixelConfig; + default: + return kRGBA_8888_GrPixelConfig; + } + +} +#endif +static inline void +GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval) +{ + retval.setAll(SkFloatToScalar(mat._11), SkFloatToScalar(mat._21), SkFloatToScalar(mat._31), + SkFloatToScalar(mat._12), SkFloatToScalar(mat._22), SkFloatToScalar(mat._32), + 0, 0, SK_Scalar1); +} + +static inline SkPaint::Cap +CapStyleToSkiaCap(CapStyle aCap) +{ + switch (aCap) + { + case CapStyle::BUTT: + return SkPaint::kButt_Cap; + case CapStyle::ROUND: + return SkPaint::kRound_Cap; + case CapStyle::SQUARE: + return SkPaint::kSquare_Cap; + } + return SkPaint::kDefault_Cap; +} + +static inline SkPaint::Join +JoinStyleToSkiaJoin(JoinStyle aJoin) +{ + switch (aJoin) + { + case JoinStyle::BEVEL: + return SkPaint::kBevel_Join; + case JoinStyle::ROUND: + return SkPaint::kRound_Join; + case JoinStyle::MITER: + case JoinStyle::MITER_OR_BEVEL: + return SkPaint::kMiter_Join; + } + return SkPaint::kDefault_Join; +} + +static inline bool +StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions) +{ + // Skia renders 0 width strokes with a width of 1 (and in black), + // so we should just skip the draw call entirely. + if (!aOptions.mLineWidth) { + return false; + } + aPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth)); + aPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit)); + aPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap)); + aPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin)); + + if (aOptions.mDashLength > 0) { + // Skia only supports dash arrays that are multiples of 2. + uint32_t dashCount; + + if (aOptions.mDashLength % 2 == 0) { + dashCount = aOptions.mDashLength; + } else { + dashCount = aOptions.mDashLength * 2; + } + + std::vector pattern; + pattern.resize(dashCount); + + for (uint32_t i = 0; i < dashCount; i++) { + pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i % aOptions.mDashLength]); + } + + SkDashPathEffect* dash = SkDashPathEffect::Create(&pattern.front(), + dashCount, + SkFloatToScalar(aOptions.mDashOffset)); + SkSafeUnref(aPaint.setPathEffect(dash)); + } + + aPaint.setStyle(SkPaint::kStroke_Style); + return true; +} + +static inline SkXfermode::Mode +GfxOpToSkiaOp(CompositionOp op) +{ + switch (op) + { + case CompositionOp::OP_OVER: + return SkXfermode::kSrcOver_Mode; + case CompositionOp::OP_ADD: + return SkXfermode::kPlus_Mode; + case CompositionOp::OP_ATOP: + return SkXfermode::kSrcATop_Mode; + case CompositionOp::OP_OUT: + return SkXfermode::kSrcOut_Mode; + case CompositionOp::OP_IN: + return SkXfermode::kSrcIn_Mode; + case CompositionOp::OP_SOURCE: + return SkXfermode::kSrc_Mode; + case CompositionOp::OP_DEST_IN: + return SkXfermode::kDstIn_Mode; + case CompositionOp::OP_DEST_OUT: + return SkXfermode::kDstOut_Mode; + case CompositionOp::OP_DEST_OVER: + return SkXfermode::kDstOver_Mode; + case CompositionOp::OP_DEST_ATOP: + return SkXfermode::kDstATop_Mode; + case CompositionOp::OP_XOR: + return SkXfermode::kXor_Mode; + case CompositionOp::OP_MULTIPLY: + return SkXfermode::kMultiply_Mode; + case CompositionOp::OP_SCREEN: + return SkXfermode::kScreen_Mode; + case CompositionOp::OP_OVERLAY: + return SkXfermode::kOverlay_Mode; + case CompositionOp::OP_DARKEN: + return SkXfermode::kDarken_Mode; + case CompositionOp::OP_LIGHTEN: + return SkXfermode::kLighten_Mode; + case CompositionOp::OP_COLOR_DODGE: + return SkXfermode::kColorDodge_Mode; + case CompositionOp::OP_COLOR_BURN: + return SkXfermode::kColorBurn_Mode; + case CompositionOp::OP_HARD_LIGHT: + return SkXfermode::kHardLight_Mode; + case CompositionOp::OP_SOFT_LIGHT: + return SkXfermode::kSoftLight_Mode; + case CompositionOp::OP_DIFFERENCE: + return SkXfermode::kDifference_Mode; + case CompositionOp::OP_EXCLUSION: + return SkXfermode::kExclusion_Mode; + case CompositionOp::OP_HUE: + return SkXfermode::kHue_Mode; + case CompositionOp::OP_SATURATION: + return SkXfermode::kSaturation_Mode; + case CompositionOp::OP_COLOR: + return SkXfermode::kColor_Mode; + case CompositionOp::OP_LUMINOSITY: + return SkXfermode::kLuminosity_Mode; + default: + return SkXfermode::kSrcOver_Mode; + } +} + +/* There's quite a bit of inconsistency about + * whether float colors should be rounded with .5f. + * We choose to do it to match cairo which also + * happens to match the Direct3D specs */ +static inline U8CPU ColorFloatToByte(Float color) +{ + //XXX: do a better job converting to int + return U8CPU(color*255.f + .5f); +}; + +static inline SkColor ColorToSkColor(const Color &color, Float aAlpha) +{ + return SkColorSetARGB(ColorFloatToByte(color.a*aAlpha), ColorFloatToByte(color.r), + ColorFloatToByte(color.g), ColorFloatToByte(color.b)); +} + +static inline SkRect +RectToSkRect(const Rect& aRect) +{ + return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y), + SkFloatToScalar(aRect.width), SkFloatToScalar(aRect.height)); +} + +static inline SkRect +IntRectToSkRect(const IntRect& aRect) +{ + return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y), + SkIntToScalar(aRect.width), SkIntToScalar(aRect.height)); +} + +static inline SkIRect +RectToSkIRect(const Rect& aRect) +{ + return SkIRect::MakeXYWH(int32_t(aRect.x), int32_t(aRect.y), + int32_t(aRect.width), int32_t(aRect.height)); +} + +static inline SkIRect +IntRectToSkIRect(const IntRect& aRect) +{ + return SkIRect::MakeXYWH(aRect.x, aRect.y, aRect.width, aRect.height); +} + +static inline Point +SkPointToPoint(const SkPoint &aPoint) +{ + return Point(SkScalarToFloat(aPoint.x()), SkScalarToFloat(aPoint.y())); +} + +static inline Rect +SkRectToRect(const SkRect &aRect) +{ + return Rect(SkScalarToFloat(aRect.x()), SkScalarToFloat(aRect.y()), + SkScalarToFloat(aRect.width()), SkScalarToFloat(aRect.height())); +} + +static inline SkShader::TileMode +ExtendModeToTileMode(ExtendMode aMode) +{ + switch (aMode) + { + case ExtendMode::CLAMP: + return SkShader::kClamp_TileMode; + case ExtendMode::REPEAT: + return SkShader::kRepeat_TileMode; + case ExtendMode::REFLECT: + return SkShader::kMirror_TileMode; + } + return SkShader::kClamp_TileMode; +} + +// The following class was imported from Skia, which is under the +// following licence: +// +// Copyright (c) 2011 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +template class RefPtrSkia { +public: + RefPtrSkia() : fObj(NULL) {} + explicit RefPtrSkia(T* obj) : fObj(obj) { SkSafeRef(fObj); } + RefPtrSkia(const RefPtrSkia& o) : fObj(o.fObj) { SkSafeRef(fObj); } + ~RefPtrSkia() { SkSafeUnref(fObj); } + + RefPtrSkia& operator=(const RefPtrSkia& rp) { + SkRefCnt_SafeAssign(fObj, rp.fObj); + return *this; + } + RefPtrSkia& operator=(T* obj) { + SkRefCnt_SafeAssign(fObj, obj); + return *this; + } + + T* get() const { return fObj; } + T& operator*() const { return *fObj; } + T* operator->() const { return fObj; } + + RefPtrSkia& adopt(T* obj) { + SkSafeUnref(fObj); + fObj = obj; + return *this; + } + + typedef T* RefPtrSkia::*unspecified_bool_type; + operator unspecified_bool_type() const { + return fObj ? &RefPtrSkia::fObj : NULL; + } + +private: + T* fObj; +}; + +// End of code imported from Skia. + +} +} + +#endif /* MOZILLA_GFX_HELPERSSKIA_H_ */ diff --git a/libazure/src/gfx/2d/ImageScaling.cpp b/libazure/ImageScaling.cpp similarity index 96% rename from libazure/src/gfx/2d/ImageScaling.cpp rename to libazure/ImageScaling.cpp index 313782e..62d08d0 100644 --- a/libazure/src/gfx/2d/ImageScaling.cpp +++ b/libazure/ImageScaling.cpp @@ -5,6 +5,7 @@ #include "ImageScaling.h" #include "2D.h" +#include "DataSurfaceHelpers.h" #include #include @@ -77,7 +78,13 @@ ImageHalfScaler::ScaleForSize(const IntSize &aSize) delete [] mDataStorage; // Allocate 15 bytes extra to make sure we can get 16 byte alignment. We // should add tools for this, see bug 751696. - mDataStorage = new uint8_t[internalSurfSize.height * mStride + 15]; + size_t bufLen = BufferSizeFromStrideAndHeight(mStride, internalSurfSize.height, 15); + if (bufLen == 0) { + mSize.SizeTo(0, 0); + mDataStorage = nullptr; + return; + } + mDataStorage = new uint8_t[bufLen]; if (uintptr_t(mDataStorage) % 16) { // Our storage does not start at a 16-byte boundary. Make sure mData does! diff --git a/libazure/src/gfx/2d/ImageScaling.h b/libazure/ImageScaling.h similarity index 100% rename from libazure/src/gfx/2d/ImageScaling.h rename to libazure/ImageScaling.h diff --git a/libazure/src/gfx/2d/ImageScalingSSE2.cpp b/libazure/ImageScalingSSE2.cpp similarity index 99% rename from libazure/src/gfx/2d/ImageScalingSSE2.cpp rename to libazure/ImageScalingSSE2.cpp index f87653b..92bad43 100644 --- a/libazure/src/gfx/2d/ImageScalingSSE2.cpp +++ b/libazure/ImageScalingSSE2.cpp @@ -248,7 +248,7 @@ ImageHalfScaler::HalfImageVertical_SSE2(uint8_t *aSource, int32_t aSourceStride, *storage++ = avg_sse2_4x2_4x1(a, b); } - } else if (!(uintptr_t(aSource + (y * aSourceStride)) % 16)) { + } else if (!(uintptr_t(aSource + ((y + 1) * aSourceStride)) % 16)) { for (; x < (aSourceSize.width - 3); x += 4) { uint8_t *upperRow = aSource + (y * aSourceStride + x * 4); uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4); diff --git a/libazure/Line.h b/libazure/Line.h new file mode 100644 index 0000000..bc65d33 --- /dev/null +++ b/libazure/Line.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_LINE_H_ +#define MOZILLA_GFX_LINE_H_ + +#include "Types.h" +#include "Point.h" + +namespace mozilla { +namespace gfx { + +/** + * This struct defines a line in standard form: + * + * Ax + By = C + */ +struct Line { + Float A, B, C; + + // Constructors + Line() : A(0), B(0), C(0) {} + Line(Float aA, Float aB, Float aC) : A(aA), B(aB), C(aC) {} + Line(const Point& aPt1, const Point& aPt2) + : A(aPt1.y - aPt2.y) + , B(aPt2.x - aPt1.x) + , C(A * aPt1.x + B * aPt1.y) + {} + + Line operator -() + { + return Line(-A, -B, -C); + } +}; + +} +} + +#endif /* MOZILLA_GFX_LINE_H_ */ diff --git a/libazure/Logging.h b/libazure/Logging.h new file mode 100644 index 0000000..30b78a3 --- /dev/null +++ b/libazure/Logging.h @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_LOGGING_H_ +#define MOZILLA_GFX_LOGGING_H_ + +#include +#include +#include + +#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID) +#include "nsDebug.h" +#endif +#include "Point.h" +#include "BaseRect.h" +#include "Matrix.h" +#include "mozilla/TypedEnum.h" + +#ifdef WIN32 +// This file gets included from nsGlobalWindow.cpp, which doesn't like +// having windows.h included in it. Since OutputDebugStringA is the only +// thing we need from windows.h, we just declare it here directly. +// Note: the function's documented signature is +// WINBASEAPI void WINAPI OutputDebugStringA(LPCSTR lpOutputString) +// but if we don't include windows.h, the macros WINBASEAPI, WINAPI, and +// LPCSTR are not defined, so we need to replace them with their expansions. +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString); +#endif + +#if defined(DEBUG) || defined(PR_LOGGING) +#include + +extern GFX2D_API PRLogModuleInfo *GetGFX2DLog(); +#endif + +namespace mozilla { +namespace gfx { + +const int LOG_DEBUG = 1; +const int LOG_WARNING = 2; +const int LOG_CRITICAL = 3; + +#if defined(DEBUG) || defined(PR_LOGGING) + +inline PRLogModuleLevel PRLogLevelForLevel(int aLevel) { + switch (aLevel) { + case LOG_DEBUG: + return PR_LOG_DEBUG; + case LOG_WARNING: + return PR_LOG_WARNING; + } + return PR_LOG_DEBUG; +} + +#endif + +extern GFX2D_API int sGfxLogLevel; + +struct BasicLogger +{ + static void OutputMessage(const std::string &aString, int aLevel) { +#if defined(WIN32) && !defined(PR_LOGGING) + if (aLevel >= sGfxLogLevel) { + ::OutputDebugStringA(aString.c_str()); + } +#elif defined(PR_LOGGING) && !(defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)) + if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) { + PR_LogPrint(aString.c_str()); + } +#else + if (aLevel >= sGfxLogLevel) { +#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID) + printf_stderr("%s", aString.c_str()); +#else + printf("%s", aString.c_str()); +#endif + } +#endif + } +}; + +struct CriticalLogger { + static void OutputMessage(const std::string &aString, int aLevel); +}; + +// Implement this interface and init the Factory with an instance to +// forward critical logs. +class LogForwarder { +public: + virtual ~LogForwarder() {} + virtual void Log(const std::string &aString) = 0; +}; + +class NoLog +{ +public: + NoLog() {} + ~NoLog() {} + + template + NoLog &operator <<(const T &aLogText) { return *this; } +}; + +MOZ_BEGIN_ENUM_CLASS(LogOptions, int) + NoNewline = 0x01 +MOZ_END_ENUM_CLASS(LogOptions) + +template +class Log +{ +public: + explicit Log(LogOptions aOptions = LogOptions(0)) : mOptions(aOptions) {} + ~Log() { + Flush(); + } + + void Flush() { + if (!(int(mOptions) & int(LogOptions::NoNewline))) { + mMessage << '\n'; + } + std::string str = mMessage.str(); + if (!str.empty()) { + WriteLog(str); + } + mMessage.str(""); + mMessage.clear(); + } + + Log &operator <<(char aChar) { mMessage << aChar; return *this; } + Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; } + Log &operator <<(const char aStr[]) { mMessage << static_cast(aStr); return *this; } + Log &operator <<(bool aBool) { mMessage << (aBool ? "true" : "false"); return *this; } + Log &operator <<(int aInt) { mMessage << aInt; return *this; } + Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; } + Log &operator <<(long aLong) { mMessage << aLong; return *this; } + Log &operator <<(unsigned long aLong) { mMessage << aLong; return *this; } + Log &operator <<(long long aLong) { mMessage << aLong; return *this; } + Log &operator <<(unsigned long long aLong) { mMessage << aLong; return *this; } + Log &operator <<(Float aFloat) { mMessage << aFloat; return *this; } + Log &operator <<(double aDouble) { mMessage << aDouble; return *this; } + template + Log &operator <<(const BasePoint& aPoint) + { mMessage << "Point" << aPoint; return *this; } + template + Log &operator <<(const BaseSize& aSize) + { mMessage << "Size(" << aSize.width << "," << aSize.height << ")"; return *this; } + template + Log &operator <<(const BaseRect& aRect) + { mMessage << "Rect" << aRect; return *this; } + Log &operator<<(const Matrix& aMatrix) + { mMessage << "Matrix(" << aMatrix._11 << " " << aMatrix._12 << " ; " << aMatrix._21 << " " << aMatrix._22 << " ; " << aMatrix._31 << " " << aMatrix._32 << ")"; return *this; } + + +private: + + void WriteLog(const std::string &aString) { + Logger::OutputMessage(aString, L); + } + + std::stringstream mMessage; + LogOptions mOptions; +}; + +typedef Log DebugLog; +typedef Log WarningLog; +typedef Log CriticalLog; + +#ifdef GFX_LOG_DEBUG +#define gfxDebug DebugLog +#else +#define gfxDebug if (1) ; else NoLog +#endif +#ifdef GFX_LOG_WARNING +#define gfxWarning WarningLog +#else +#define gfxWarning if (1) ; else NoLog +#endif + +// This log goes into crash reports, use with care. +#define gfxCriticalError CriticalLog + +// See nsDebug.h and the NS_WARN_IF macro + +#ifdef __cplusplus +#ifdef DEBUG +inline bool MOZ2D_warn_if_impl(bool aCondition, const char* aExpr, + const char* aFile, int32_t aLine) +{ + if (MOZ_UNLIKELY(aCondition)) { + gfxWarning() << aExpr << " at " << aFile << ":" << aLine; + } + return aCondition; +} +#define MOZ2D_WARN_IF(condition) \ + MOZ2D_warn_if_impl(condition, #condition, __FILE__, __LINE__) +#else +#define MOZ2D_WARN_IF(condition) (bool)(condition) +#endif +#endif + +const int INDENT_PER_LEVEL = 2; + +class TreeLog +{ +public: + explicit TreeLog(const std::string& aPrefix = "") + : mLog(LogOptions::NoNewline), + mPrefix(aPrefix), + mDepth(0), + mStartOfLine(true), + mConditionedOnPref(false), + mPrefFunction(nullptr) {} + + template + TreeLog& operator<<(const T& aObject) { + if (mConditionedOnPref && !mPrefFunction()) { + return *this; + } + if (mStartOfLine) { + mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' '); + mStartOfLine = false; + } + mLog << aObject; + if (EndsInNewline(aObject)) { + // Don't indent right here as the user may change the indent + // between now and the first output to the next line. + mLog.Flush(); + mStartOfLine = true; + } + return *this; + } + + void IncreaseIndent() { ++mDepth; } + void DecreaseIndent() { --mDepth; } + + void ConditionOnPrefFunction(bool(*aPrefFunction)()) { + mConditionedOnPref = true; + mPrefFunction = aPrefFunction; + } +private: + Log mLog; + std::string mPrefix; + uint32_t mDepth; + bool mStartOfLine; + bool mConditionedOnPref; + bool (*mPrefFunction)(); + + template + static bool EndsInNewline(const T& aObject) { + return false; + } + + static bool EndsInNewline(const std::string& aString) { + return !aString.empty() && aString[aString.length() - 1] == '\n'; + } + + static bool EndsInNewline(char aChar) { + return aChar == '\n'; + } + + static bool EndsInNewline(const char* aString) { + return EndsInNewline(std::string(aString)); + } +}; + +class TreeAutoIndent +{ +public: + explicit TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) { + mTreeLog.IncreaseIndent(); + } + ~TreeAutoIndent() { + mTreeLog.DecreaseIndent(); + } +private: + TreeLog& mTreeLog; +}; + +} +} + +#endif /* MOZILLA_GFX_LOGGING_H_ */ diff --git a/libazure/MacIOSurface.cpp b/libazure/MacIOSurface.cpp new file mode 100644 index 0000000..b31db7c --- /dev/null +++ b/libazure/MacIOSurface.cpp @@ -0,0 +1,532 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MacIOSurface.h" +#include +#include +#include +#include "mozilla/RefPtr.h" +#include "mozilla/Assertions.h" + +using namespace mozilla; +// IOSurface signatures +#define IOSURFACE_FRAMEWORK_PATH \ + "/System/Library/Frameworks/IOSurface.framework/IOSurface" +#define OPENGL_FRAMEWORK_PATH \ + "/System/Library/Frameworks/OpenGL.framework/OpenGL" +#define COREGRAPHICS_FRAMEWORK_PATH \ + "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/" \ + "CoreGraphics.framework/CoreGraphics" +#define COREVIDEO_FRAMEWORK_PATH \ + "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/" \ + "CoreVideo.framework/CoreVideo" + +#define GET_CONST(const_name) \ + ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name)) +#define GET_IOSYM(dest,sym_name) \ + (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name) +#define GET_CGLSYM(dest,sym_name) \ + (typeof(dest)) dlsym(sOpenGLFramework, sym_name) +#define GET_CGSYM(dest,sym_name) \ + (typeof(dest)) dlsym(sCoreGraphicsFramework, sym_name) +#define GET_CVSYM(dest, sym_name) \ + (typeof(dest)) dlsym(sCoreVideoFramework, sym_name) + +MacIOSurfaceLib::LibraryUnloader MacIOSurfaceLib::sLibraryUnloader; +bool MacIOSurfaceLib::isLoaded = false; +void* MacIOSurfaceLib::sIOSurfaceFramework; +void* MacIOSurfaceLib::sOpenGLFramework; +void* MacIOSurfaceLib::sCoreGraphicsFramework; +void* MacIOSurfaceLib::sCoreVideoFramework; +IOSurfaceCreateFunc MacIOSurfaceLib::sCreate; +IOSurfaceGetIDFunc MacIOSurfaceLib::sGetID; +IOSurfaceLookupFunc MacIOSurfaceLib::sLookup; +IOSurfaceGetBaseAddressFunc MacIOSurfaceLib::sGetBaseAddress; +IOSurfaceGetBaseAddressOfPlaneFunc MacIOSurfaceLib::sGetBaseAddressOfPlane; +IOSurfaceSizeTFunc MacIOSurfaceLib::sWidth; +IOSurfaceSizeTFunc MacIOSurfaceLib::sHeight; +IOSurfaceSizeTFunc MacIOSurfaceLib::sPlaneCount; +IOSurfaceSizeTFunc MacIOSurfaceLib::sBytesPerRow; +IOSurfaceGetPropertyMaximumFunc MacIOSurfaceLib::sGetPropertyMaximum; +IOSurfaceVoidFunc MacIOSurfaceLib::sIncrementUseCount; +IOSurfaceVoidFunc MacIOSurfaceLib::sDecrementUseCount; +IOSurfaceLockFunc MacIOSurfaceLib::sLock; +IOSurfaceUnlockFunc MacIOSurfaceLib::sUnlock; +CGLTexImageIOSurface2DFunc MacIOSurfaceLib::sTexImage; +IOSurfaceContextCreateFunc MacIOSurfaceLib::sIOSurfaceContextCreate; +IOSurfaceContextCreateImageFunc MacIOSurfaceLib::sIOSurfaceContextCreateImage; +IOSurfaceContextGetSurfaceFunc MacIOSurfaceLib::sIOSurfaceContextGetSurface; +CVPixelBufferGetIOSurfaceFunc MacIOSurfaceLib::sCVPixelBufferGetIOSurface; +unsigned int (*MacIOSurfaceLib::sCGContextGetTypePtr) (CGContextRef) = nullptr; + +CFStringRef MacIOSurfaceLib::kPropWidth; +CFStringRef MacIOSurfaceLib::kPropHeight; +CFStringRef MacIOSurfaceLib::kPropBytesPerElem; +CFStringRef MacIOSurfaceLib::kPropBytesPerRow; +CFStringRef MacIOSurfaceLib::kPropIsGlobal; + +bool MacIOSurfaceLib::isInit() { + // Guard against trying to reload the library + // if it is not available. + if (!isLoaded) + LoadLibrary(); + MOZ_ASSERT(sIOSurfaceFramework); + return sIOSurfaceFramework; +} + +IOSurfacePtr MacIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) { + return sCreate(properties); +} + +IOSurfacePtr MacIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) { + return sLookup(aIOSurfaceID); +} + +IOSurfaceID MacIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) { + return sGetID(aIOSurfacePtr); +} + +void* MacIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) { + return sGetBaseAddress(aIOSurfacePtr); +} + +void* MacIOSurfaceLib::IOSurfaceGetBaseAddressOfPlane(IOSurfacePtr aIOSurfacePtr, + size_t planeIndex) { + return sGetBaseAddressOfPlane(aIOSurfacePtr, planeIndex); +} + +size_t MacIOSurfaceLib::IOSurfaceGetPlaneCount(IOSurfacePtr aIOSurfacePtr) { + return sPlaneCount(aIOSurfacePtr); +} + +size_t MacIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) { + return sWidth(aIOSurfacePtr); +} + +size_t MacIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) { + return sHeight(aIOSurfacePtr); +} + +size_t MacIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) { + return sBytesPerRow(aIOSurfacePtr); +} + +size_t MacIOSurfaceLib::IOSurfaceGetPropertyMaximum(CFStringRef property) { + return sGetPropertyMaximum(property); +} + +IOReturn MacIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, + uint32_t options, uint32_t* seed) { + return sLock(aIOSurfacePtr, options, seed); +} + +IOReturn MacIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, + uint32_t options, uint32_t *seed) { + return sUnlock(aIOSurfacePtr, options, seed); +} + +void MacIOSurfaceLib::IOSurfaceIncrementUseCount(IOSurfacePtr aIOSurfacePtr) { + sIncrementUseCount(aIOSurfacePtr); +} + +void MacIOSurfaceLib::IOSurfaceDecrementUseCount(IOSurfacePtr aIOSurfacePtr) { + sDecrementUseCount(aIOSurfacePtr); +} + +CGLError MacIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt, + GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + IOSurfacePtr ioSurface, GLuint plane) { + return sTexImage(ctxt, target, internalFormat, width, height, + format, type, ioSurface, plane); +} + +IOSurfacePtr MacIOSurfaceLib::CVPixelBufferGetIOSurface(CVPixelBufferRef aPixelBuffer) { + return sCVPixelBufferGetIOSurface(aPixelBuffer); +} + +CGContextRef MacIOSurfaceLib::IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr, + unsigned aWidth, unsigned aHeight, + unsigned aBitsPerComponent, unsigned aBytes, + CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo) { + if (!sIOSurfaceContextCreate) + return nullptr; + return sIOSurfaceContextCreate(aIOSurfacePtr, aWidth, aHeight, aBitsPerComponent, aBytes, aColorSpace, bitmapInfo); +} + +CGImageRef MacIOSurfaceLib::IOSurfaceContextCreateImage(CGContextRef aContext) { + if (!sIOSurfaceContextCreateImage) + return nullptr; + return sIOSurfaceContextCreateImage(aContext); +} + +IOSurfacePtr MacIOSurfaceLib::IOSurfaceContextGetSurface(CGContextRef aContext) { + if (!sIOSurfaceContextGetSurface) + return nullptr; + return sIOSurfaceContextGetSurface(aContext); +} + +CFStringRef MacIOSurfaceLib::GetIOConst(const char* symbole) { + CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole); + if (!address) + return nullptr; + + return *address; +} + +void MacIOSurfaceLib::LoadLibrary() { + if (isLoaded) { + return; + } + isLoaded = true; + sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH, + RTLD_LAZY | RTLD_LOCAL); + sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH, + RTLD_LAZY | RTLD_LOCAL); + + sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH, + RTLD_LAZY | RTLD_LOCAL); + + sCoreVideoFramework = dlopen(COREVIDEO_FRAMEWORK_PATH, + RTLD_LAZY | RTLD_LOCAL); + + if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework || + !sCoreVideoFramework) { + if (sIOSurfaceFramework) + dlclose(sIOSurfaceFramework); + if (sOpenGLFramework) + dlclose(sOpenGLFramework); + if (sCoreGraphicsFramework) + dlclose(sCoreGraphicsFramework); + if (sCoreVideoFramework) + dlclose(sCoreVideoFramework); + sIOSurfaceFramework = nullptr; + sOpenGLFramework = nullptr; + sCoreGraphicsFramework = nullptr; + sCoreVideoFramework = nullptr; + return; + } + + kPropWidth = GetIOConst("kIOSurfaceWidth"); + kPropHeight = GetIOConst("kIOSurfaceHeight"); + kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement"); + kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow"); + kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal"); + sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate"); + sGetID = GET_IOSYM(sGetID, "IOSurfaceGetID"); + sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth"); + sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight"); + sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow"); + sGetPropertyMaximum = GET_IOSYM(sGetPropertyMaximum, "IOSurfaceGetPropertyMaximum"); + sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup"); + sLock = GET_IOSYM(sLock, "IOSurfaceLock"); + sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock"); + sIncrementUseCount = + GET_IOSYM(sIncrementUseCount, "IOSurfaceIncrementUseCount"); + sDecrementUseCount = + GET_IOSYM(sDecrementUseCount, "IOSurfaceDecrementUseCount"); + sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress"); + sGetBaseAddressOfPlane = + GET_IOSYM(sGetBaseAddressOfPlane, "IOSurfaceGetBaseAddressOfPlane"); + sPlaneCount = GET_IOSYM(sPlaneCount, "IOSurfaceGetPlaneCount"); + + sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D"); + sCGContextGetTypePtr = (unsigned int (*)(CGContext*))dlsym(RTLD_DEFAULT, "CGContextGetType"); + + sCVPixelBufferGetIOSurface = + GET_CVSYM(sCVPixelBufferGetIOSurface, "CVPixelBufferGetIOSurface"); + + // Optional symbols + sIOSurfaceContextCreate = GET_CGSYM(sIOSurfaceContextCreate, "CGIOSurfaceContextCreate"); + sIOSurfaceContextCreateImage = GET_CGSYM(sIOSurfaceContextCreateImage, "CGIOSurfaceContextCreateImage"); + sIOSurfaceContextGetSurface = GET_CGSYM(sIOSurfaceContextGetSurface, "CGIOSurfaceContextGetSurface"); + + if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress || + !sGetBaseAddressOfPlane || !sPlaneCount || + !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal || + !sLock || !sUnlock || !sIncrementUseCount || !sDecrementUseCount || + !sWidth || !sHeight || !kPropBytesPerRow || + !sBytesPerRow || !sGetPropertyMaximum || !sCVPixelBufferGetIOSurface) { + CloseLibrary(); + } +} + +void MacIOSurfaceLib::CloseLibrary() { + if (sIOSurfaceFramework) { + dlclose(sIOSurfaceFramework); + } + if (sOpenGLFramework) { + dlclose(sOpenGLFramework); + } + if (sCoreVideoFramework) { + dlclose(sCoreVideoFramework); + } + sIOSurfaceFramework = nullptr; + sOpenGLFramework = nullptr; + sCoreVideoFramework = nullptr; +} + +MacIOSurface::MacIOSurface(const void* aIOSurfacePtr, + double aContentsScaleFactor, bool aHasAlpha) + : mIOSurfacePtr(aIOSurfacePtr) + , mContentsScaleFactor(aContentsScaleFactor) + , mHasAlpha(aHasAlpha) +{ + CFRetain(mIOSurfacePtr); + IncrementUseCount(); +} + +MacIOSurface::~MacIOSurface() { + DecrementUseCount(); + CFRelease(mIOSurfacePtr); +} + +TemporaryRef MacIOSurface::CreateIOSurface(int aWidth, int aHeight, + double aContentsScaleFactor, + bool aHasAlpha) { + if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) + return nullptr; + + CFMutableDictionaryRef props = ::CFDictionaryCreateMutable( + kCFAllocatorDefault, 4, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!props) + return nullptr; + + MOZ_ASSERT((size_t)aWidth <= GetMaxWidth()); + MOZ_ASSERT((size_t)aHeight <= GetMaxHeight()); + + int32_t bytesPerElem = 4; + size_t intScaleFactor = ceil(aContentsScaleFactor); + aWidth *= intScaleFactor; + aHeight *= intScaleFactor; + CFNumberRef cfWidth = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aWidth); + CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight); + CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem); + ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth, + cfWidth); + ::CFRelease(cfWidth); + ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight, + cfHeight); + ::CFRelease(cfHeight); + ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, + cfBytesPerElem); + ::CFRelease(cfBytesPerElem); + ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, + kCFBooleanTrue); + + IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props); + ::CFRelease(props); + + if (!surfaceRef) + return nullptr; + + RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); + if (!ioSurface) { + ::CFRelease(surfaceRef); + return nullptr; + } + + // Release the IOSurface because MacIOSurface retained it + CFRelease(surfaceRef); + + return ioSurface.forget(); +} + +TemporaryRef MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID, + double aContentsScaleFactor, + bool aHasAlpha) { + if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) + return nullptr; + + IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID); + if (!surfaceRef) + return nullptr; + + RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); + if (!ioSurface) { + ::CFRelease(surfaceRef); + return nullptr; + } + + // Release the IOSurface because MacIOSurface retained it + CFRelease(surfaceRef); + + return ioSurface.forget(); +} + +IOSurfaceID MacIOSurface::GetIOSurfaceID() { + return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr); +} + +void* MacIOSurface::GetBaseAddress() { + return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr); +} + +void* MacIOSurface::GetBaseAddressOfPlane(size_t aPlaneIndex) +{ + return MacIOSurfaceLib::IOSurfaceGetBaseAddressOfPlane(mIOSurfacePtr, + aPlaneIndex); +} + +size_t MacIOSurface::GetWidth() { + size_t intScaleFactor = ceil(mContentsScaleFactor); + return GetDevicePixelWidth() / intScaleFactor; +} + +size_t MacIOSurface::GetHeight() { + size_t intScaleFactor = ceil(mContentsScaleFactor); + return GetDevicePixelHeight() / intScaleFactor; +} + +size_t MacIOSurface::GetPlaneCount() { + return MacIOSurfaceLib::IOSurfaceGetPlaneCount(mIOSurfacePtr); +} + +/*static*/ size_t MacIOSurface::GetMaxWidth() { + return MacIOSurfaceLib::IOSurfaceGetPropertyMaximum(MacIOSurfaceLib::kPropWidth); +} + +/*static*/ size_t MacIOSurface::GetMaxHeight() { + return MacIOSurfaceLib::IOSurfaceGetPropertyMaximum(MacIOSurfaceLib::kPropHeight); +} + +size_t MacIOSurface::GetDevicePixelWidth() { + return MacIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr); +} + +size_t MacIOSurface::GetDevicePixelHeight() { + return MacIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr); +} + +size_t MacIOSurface::GetBytesPerRow() { + return MacIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr); +} + +void MacIOSurface::IncrementUseCount() { + MacIOSurfaceLib::IOSurfaceIncrementUseCount(mIOSurfacePtr); +} + +void MacIOSurface::DecrementUseCount() { + MacIOSurfaceLib::IOSurfaceDecrementUseCount(mIOSurfacePtr); +} + +#define READ_ONLY 0x1 +void MacIOSurface::Lock() { + MacIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, nullptr); +} + +void MacIOSurface::Unlock() { + MacIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, nullptr); +} + +#include "SourceSurfaceRawData.h" +using mozilla::gfx::SourceSurface; +using mozilla::gfx::SourceSurfaceRawData; +using mozilla::gfx::IntSize; +using mozilla::gfx::SurfaceFormat; + +TemporaryRef +MacIOSurface::GetAsSurface() { + Lock(); + size_t bytesPerRow = GetBytesPerRow(); + size_t ioWidth = GetDevicePixelWidth(); + size_t ioHeight = GetDevicePixelHeight(); + + unsigned char* ioData = (unsigned char*)GetBaseAddress(); + unsigned char* dataCpy = (unsigned char*)malloc(bytesPerRow*ioHeight); + for (size_t i = 0; i < ioHeight; i++) { + memcpy(dataCpy + i * bytesPerRow, + ioData + i * bytesPerRow, ioWidth * 4); + } + + Unlock(); + + SurfaceFormat format = HasAlpha() ? mozilla::gfx::SurfaceFormat::B8G8R8A8 : + mozilla::gfx::SurfaceFormat::B8G8R8X8; + + RefPtr surf = new SourceSurfaceRawData(); + surf->InitWrappingData(dataCpy, IntSize(ioWidth, ioHeight), bytesPerRow, format, true); + + return surf.forget(); +} + +CGLError +MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx) +{ + return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx, + GL_TEXTURE_RECTANGLE_ARB, + HasAlpha() ? GL_RGBA : GL_RGB, + GetDevicePixelWidth(), + GetDevicePixelHeight(), + GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, + mIOSurfacePtr, 0); +} + +static +CGColorSpaceRef CreateSystemColorSpace() { + CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID()); + if (!cspace) { + cspace = ::CGColorSpaceCreateDeviceRGB(); + } + return cspace; +} + +CGContextRef MacIOSurface::CreateIOSurfaceContext() { + CGColorSpaceRef cspace = CreateSystemColorSpace(); + CGContextRef ref = MacIOSurfaceLib::IOSurfaceContextCreate(mIOSurfacePtr, + GetDevicePixelWidth(), + GetDevicePixelHeight(), + 8, 32, cspace, 0x2002); + ::CGColorSpaceRelease(cspace); + return ref; +} + +CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) { + if (!MacIOSurfaceLib::isInit()) + return nullptr; + + return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext); +} + +TemporaryRef MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext, + double aContentsScaleFactor, + bool aHasAlpha) { + if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0) + return nullptr; + + IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext); + if (!surfaceRef) + return nullptr; + + RefPtr ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha); + if (!ioSurface) { + ::CFRelease(surfaceRef); + return nullptr; + } + return ioSurface.forget(); +} + + +CGContextType GetContextType(CGContextRef ref) +{ + if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr) + return CG_CONTEXT_TYPE_UNKNOWN; + + unsigned int type = MacIOSurfaceLib::sCGContextGetTypePtr(ref); + if (type == CG_CONTEXT_TYPE_BITMAP) { + return CG_CONTEXT_TYPE_BITMAP; + } else if (type == CG_CONTEXT_TYPE_IOSURFACE) { + return CG_CONTEXT_TYPE_IOSURFACE; + } else { + return CG_CONTEXT_TYPE_UNKNOWN; + } +} + + diff --git a/libazure/MacIOSurface.h b/libazure/MacIOSurface.h new file mode 100644 index 0000000..62ddcd7 --- /dev/null +++ b/libazure/MacIOSurface.h @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MacIOSurface_h__ +#define MacIOSurface_h__ +#ifdef XP_MACOSX +#include +#include +#include "mozilla/RefPtr.h" + +typedef CFTypeRef IOSurfacePtr; +typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties); +typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id); +typedef IOSurfaceID (*IOSurfaceGetIDFunc)(IOSurfacePtr io_surface); +typedef void (*IOSurfaceVoidFunc)(IOSurfacePtr io_surface); +typedef IOReturn (*IOSurfaceLockFunc)(IOSurfacePtr io_surface, uint32_t options, + uint32_t *seed); +typedef IOReturn (*IOSurfaceUnlockFunc)(IOSurfacePtr io_surface, + uint32_t options, uint32_t *seed); +typedef void* (*IOSurfaceGetBaseAddressFunc)(IOSurfacePtr io_surface); +typedef void* (*IOSurfaceGetBaseAddressOfPlaneFunc)(IOSurfacePtr io_surface, + size_t planeIndex); +typedef size_t (*IOSurfaceSizeTFunc)(IOSurfacePtr io_surface); +typedef size_t (*IOSurfaceGetPropertyMaximumFunc) (CFStringRef property); +typedef CGLError (*CGLTexImageIOSurface2DFunc) (CGLContextObj ctxt, + GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + IOSurfacePtr ioSurface, GLuint plane); +typedef CGContextRef (*IOSurfaceContextCreateFunc)(CFTypeRef io_surface, + unsigned width, unsigned height, + unsigned bitsPerComponent, unsigned bytes, + CGColorSpaceRef colorSpace, CGBitmapInfo bitmapInfo); +typedef CGImageRef (*IOSurfaceContextCreateImageFunc)(CGContextRef ref); +typedef IOSurfacePtr (*IOSurfaceContextGetSurfaceFunc)(CGContextRef ref); + +typedef IOSurfacePtr (*CVPixelBufferGetIOSurfaceFunc)( + CVPixelBufferRef pixelBuffer); + +#import +#include "2D.h" +#include "mozilla/RefPtr.h" + +struct _CGLContextObject; + +typedef _CGLContextObject* CGLContextObj; +typedef struct CGContext* CGContextRef; +typedef struct CGImage* CGImageRef; +typedef uint32_t IOSurfaceID; + +enum CGContextType { + CG_CONTEXT_TYPE_UNKNOWN = 0, + // These are found by inspection, it's possible they could be changed + CG_CONTEXT_TYPE_BITMAP = 4, + CG_CONTEXT_TYPE_IOSURFACE = 8 +}; + +CGContextType GetContextType(CGContextRef ref); + +class MacIOSurface : public mozilla::RefCounted { +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(MacIOSurface) + typedef mozilla::gfx::SourceSurface SourceSurface; + + // The usage count of the IOSurface is increased by 1 during the lifetime + // of the MacIOSurface instance. + // MacIOSurface holds a reference to the corresponding IOSurface. + + static mozilla::TemporaryRef CreateIOSurface(int aWidth, int aHeight, + double aContentsScaleFactor = 1.0, + bool aHasAlpha = true); + static void ReleaseIOSurface(MacIOSurface *aIOSurface); + static mozilla::TemporaryRef LookupSurface(IOSurfaceID aSurfaceID, + double aContentsScaleFactor = 1.0, + bool aHasAlpha = true); + + explicit MacIOSurface(const void *aIOSurfacePtr, + double aContentsScaleFactor = 1.0, + bool aHasAlpha = true); + virtual ~MacIOSurface(); + IOSurfaceID GetIOSurfaceID(); + void *GetBaseAddress(); + void *GetBaseAddressOfPlane(size_t planeIndex); + size_t GetPlaneCount(); + // GetWidth() and GetHeight() return values in "display pixels". A + // "display pixel" is the smallest fully addressable part of a display. + // But in HiDPI modes each "display pixel" corresponds to more than one + // device pixel. Use GetDevicePixel**() to get device pixels. + size_t GetWidth(); + size_t GetHeight(); + double GetContentsScaleFactor() { return mContentsScaleFactor; } + size_t GetDevicePixelWidth(); + size_t GetDevicePixelHeight(); + size_t GetBytesPerRow(); + void Lock(); + void Unlock(); + void IncrementUseCount(); + void DecrementUseCount(); + bool HasAlpha() { return mHasAlpha; } + // We would like to forward declare NSOpenGLContext, but it is an @interface + // and this file is also used from c++, so we use a void *. + CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt); + mozilla::TemporaryRef GetAsSurface(); + CGContextRef CreateIOSurfaceContext(); + + // FIXME This doesn't really belong here + static CGImageRef CreateImageFromIOSurfaceContext(CGContextRef aContext); + static mozilla::TemporaryRef IOSurfaceContextGetSurface(CGContextRef aContext, + double aContentsScaleFactor = 1.0, + bool aHasAlpha = true); + static size_t GetMaxWidth(); + static size_t GetMaxHeight(); + +private: + friend class nsCARenderer; + const void* mIOSurfacePtr; + double mContentsScaleFactor; + bool mHasAlpha; +}; + +class MacIOSurfaceLib: public MacIOSurface { +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(MacIOSurfaceLib) + static void *sIOSurfaceFramework; + static void *sOpenGLFramework; + static void *sCoreGraphicsFramework; + static void *sCoreVideoFramework; + static bool isLoaded; + static IOSurfaceCreateFunc sCreate; + static IOSurfaceGetIDFunc sGetID; + static IOSurfaceLookupFunc sLookup; + static IOSurfaceGetBaseAddressFunc sGetBaseAddress; + static IOSurfaceGetBaseAddressOfPlaneFunc sGetBaseAddressOfPlane; + static IOSurfaceSizeTFunc sPlaneCount; + static IOSurfaceLockFunc sLock; + static IOSurfaceUnlockFunc sUnlock; + static IOSurfaceVoidFunc sIncrementUseCount; + static IOSurfaceVoidFunc sDecrementUseCount; + static IOSurfaceSizeTFunc sWidth; + static IOSurfaceSizeTFunc sHeight; + static IOSurfaceSizeTFunc sBytesPerRow; + static IOSurfaceGetPropertyMaximumFunc sGetPropertyMaximum; + static CGLTexImageIOSurface2DFunc sTexImage; + static IOSurfaceContextCreateFunc sIOSurfaceContextCreate; + static IOSurfaceContextCreateImageFunc sIOSurfaceContextCreateImage; + static IOSurfaceContextGetSurfaceFunc sIOSurfaceContextGetSurface; + static CVPixelBufferGetIOSurfaceFunc sCVPixelBufferGetIOSurface; + static CFStringRef kPropWidth; + static CFStringRef kPropHeight; + static CFStringRef kPropBytesPerElem; + static CFStringRef kPropBytesPerRow; + static CFStringRef kPropIsGlobal; + + static bool isInit(); + static CFStringRef GetIOConst(const char* symbole); + static IOSurfacePtr IOSurfaceCreate(CFDictionaryRef properties); + static IOSurfacePtr IOSurfaceLookup(IOSurfaceID aIOSurfaceID); + static IOSurfaceID IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr); + static void* IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr); + static void* IOSurfaceGetBaseAddressOfPlane(IOSurfacePtr aIOSurfacePtr, + size_t aPlaneIndex); + static size_t IOSurfaceGetPlaneCount(IOSurfacePtr aIOSurfacePtr); + static size_t IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr); + static size_t IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr); + static size_t IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr); + static size_t IOSurfaceGetPropertyMaximum(CFStringRef property); + static IOReturn IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, + uint32_t options, uint32_t *seed); + static IOReturn IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, + uint32_t options, uint32_t *seed); + static void IOSurfaceIncrementUseCount(IOSurfacePtr aIOSurfacePtr); + static void IOSurfaceDecrementUseCount(IOSurfacePtr aIOSurfacePtr); + static CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt, + GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + IOSurfacePtr ioSurface, GLuint plane); + static CGContextRef IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr, + unsigned aWidth, unsigned aHeight, + unsigned aBitsPerCompoent, unsigned aBytes, + CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo); + static CGImageRef IOSurfaceContextCreateImage(CGContextRef ref); + static IOSurfacePtr IOSurfaceContextGetSurface(CGContextRef ref); + static IOSurfacePtr CVPixelBufferGetIOSurface(CVPixelBufferRef apixelBuffer); + static unsigned int (*sCGContextGetTypePtr) (CGContextRef); + static void LoadLibrary(); + static void CloseLibrary(); + + // Static deconstructor + static class LibraryUnloader { + public: + ~LibraryUnloader() { + CloseLibrary(); + } + } sLibraryUnloader; +}; + +#endif +#endif diff --git a/libazure/Makefile b/libazure/Makefile new file mode 100644 index 0000000..714f8e4 --- /dev/null +++ b/libazure/Makefile @@ -0,0 +1,228 @@ +# High level targets +.PHONY: release debug player2d check clean + +OBJDIR_RELEASE=release +OBJDIR_DEBUG=debug +INCLUDES=. +CXXFLAGS=-std=gnu++0x -Wall +DEBUGFLAGS=-g -DDEBUG +RELEASEFLAGS=-O3 +DEFINES=USE_SSE2 + +MOZ2D_CAIRO=true + +ifeq ($(QMAKE_BIN),) +QMAKE_BIN=qmake +else +endif + +# Mark these targets as phony because we don't know all the dependencies for +# player2d at this level, so invoke the player2d Makefiles every time and let +# the submake deal with it. +.PHONY: $(OBJDIR_RELEASE)/player2d/player2d $(OBJDIR_DEBUG)/player2d/player2d + +# ================ OS FEATURES ================ +UNAME = $(shell uname) +ifeq ($(UNAME),Darwin) +LIBS += -framework CoreFoundation -framework ApplicationServices +endif + +# TODO: Files that depends on mozilla: +#convolver.cpp +#image_operations.cpp + +MOZ2D_CPPSRCS_ALLPLATFORMS = \ + Blur.cpp \ + BlurSSE2.cpp \ + DataSourceSurface.cpp \ + DrawEventRecorder.cpp \ + DrawTargetDual.cpp \ + DrawTargetRecording.cpp \ + Factory.cpp \ + FilterNodeSoftware.cpp \ + FilterProcessing.cpp \ + FilterProcessingScalar.cpp \ + FilterProcessingSSE2.cpp \ + ImageScaling.cpp \ + ImageScalingSSE2.cpp \ + Matrix.cpp \ + Path.cpp \ + PathRecording.cpp \ + RecordedEvent.cpp \ + Scale.cpp \ + ScaledFontBase.cpp \ + SourceSurfaceRawData.cpp \ + $(NULL) + +PERFTEST_CPPSRCS_ALLPLATFORMS = \ + perftest/Main.cpp \ + perftest/SanityChecks.cpp \ + perftest/TestBase.cpp \ + perftest/TestDrawTargetBase.cpp \ + $(NULL) + +RECORDBENCH_CPPSRCS_ALLPLATFORMS = \ + recordbench/Main.cpp \ + recordbench/RawTranslator.cpp \ + $(NULL) + +UNITTEST_CPPSRCS_ALLPLATFORMS = \ + unittest/SanityChecks.cpp \ + unittest/TestBase.cpp \ + unittest/TestPoint.cpp \ + unittest/TestRect.cpp \ + unittest/TestMatrix.cpp \ + unittest/TestScaling.cpp \ + unittest/Main.cpp \ + unittest/TestDrawTarget.cpp \ + unittest/TestPath.cpp \ + unittest/TestBugs.cpp \ + $(NULL) + +ifeq ($(UNAME),Darwin) +LIBS += -framework CoreFoundation +endif + +MOZ2D_CPPSRCS = $(MOZ2D_CPPSRCS_ALLPLATFORMS) +UNITTEST_CPPSRCS = $(UNITTEST_CPPSRCS_ALLPLATFORMS) +PERFTEST_CPPSRCS = $(PERFTEST_CPPSRCS_ALLPLATFORMS) +RECORDBENCH_CPPSRCS = $(RECORDBENCH_CPPSRCS_ALLPLATFORMS) + +ifeq ($(UNAME),Linux) +DEFINES += MOZ_ENABLE_FREETYPE +INCLUDES += /usr/include/freetype2 +LIBS += -lfreetype +MOZ2D_PLAYER2D_LIBS += -lfreetype +endif +ifeq ($(UNAME),Darwin) +DEFINES += MOZ_ENABLE_FREETYPE +CXXFLAGS += $(shell freetype-config --cflags) +LIBS += $(shell freetype-config --libs) +MOZ2D_PLAYER2D_LIBS += $(LIBS) +endif + +# ================ INCLUDE FEATURE SPECIFIC MAKEFILES ================= +# These will modify the following variables: +# TESTING_CPPSRCS +# MOZ2D_CPPSRCS +# DEFINES +# +ifdef MOZ2D_D2D + -include Makefile.d2d +endif +ifdef MOZ2D_CG + -include Makefile.cg +endif +ifdef MOZ2D_CAIRO + -include Makefile.cairo + QMAKE_PARAMS += "MOZ2D_CAIRO=1" +endif +ifdef MOZ2D_SKIA + -include Makefile.skia + QMAKE_PARAMS += "MOZ2D_SKIA=$(MOZ2D_SKIA)" +endif +ifdef MOZ2D_NVPR + -include Makefile.nvpr + QMAKE_PARAMS += "MOZ2D_NVPR=$(MOZ2D_NVPR)" +endif + +QMAKE_PARAMS += "MOZ2D_PATH=$(PWD)" + +CXXFLAGS += $(addprefix -I,$(INCLUDES)) + +CPPSRCS = $(MOZ2D_CPPSRCS) $(UNITTEST_CPPSRCS) $(PERFTEST_CPPSRCS) $(RECORDBENCH_CPPSRCS) +PRE_PERFTEST_CPPSRCS = $(MOZ2D_CPPSRCS) $(PERFTEST_CPPSRCS) +PRE_UNITTEST_CPPSRCS = $(MOZ2D_CPPSRCS) $(UNITTEST_CPPSRCS) +PRE_RECORDBENCH_CPPSRCS = $(MOZ2D_CPPSRCS) $(RECORDBENCH_CPPSRCS) + +RELEASE_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(CPPSRCS)) +DEBUG_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(CPPSRCS)) +RELEASE_PERFTEST_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_PERFTEST_CPPSRCS)) +DEBUG_PERFTEST_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_PERFTEST_CPPSRCS)) +RELEASE_UNITTEST_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_UNITTEST_CPPSRCS)) +DEBUG_UNITTEST_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_UNITTEST_CPPSRCS)) +RELEASE_RECORDBENCH_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_RECORDBENCH_CPPSRCS)) +DEBUG_RECORDBENCH_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_RECORDBENCH_CPPSRCS)) +COMPILER_DEFINES = $(addprefix -D,$(DEFINES)) + +-include $(RELEASE_CPPSRCS:.cpp=.d) +-include $(DEBUG_CPPSRCS:.cpp=.d) + +release: \ + $(OBJDIR_RELEASE)/libmoz2d.a \ + $(OBJDIR_RELEASE)/unittest/unittest \ + $(OBJDIR_RELEASE)/perftest/perftest \ + $(OBJDIR_RELEASE)/recordbench/recordbench \ + $(OBJDIR_RELEASE)/.mkdir.done \ + $(NULL) + +debug: \ + $(OBJDIR_DEBUG)/libmoz2d.a \ + $(OBJDIR_DEBUG)/unittest/unittest \ + $(OBJDIR_DEBUG)/perftest/perftest \ + $(OBJDIR_DEBUG)/recordbench/recordbench \ + $(OBJDIR_DEBUG)/.mkdir.done \ + $(NULL) + +player2d: $(OBJDIR_RELEASE)/player2d/player2d $(OBJDIR_DEBUG)/player2d/player2d + +$(OBJDIR_RELEASE)/unittest/unittest: $(RELEASE_UNITTEST_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_UNITTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/unittest/unittest + +$(OBJDIR_DEBUG)/unittest/unittest: $(DEBUG_UNITTEST_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_UNITTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/unittest/unittest + +$(OBJDIR_RELEASE)/perftest/perftest: $(RELEASE_PERFTEST_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_PERFTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/perftest/perftest + +$(OBJDIR_DEBUG)/perftest/perftest: $(DEBUG_PERFTEST_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_PERFTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/perftest/perftest + +$(OBJDIR_RELEASE)/recordbench/recordbench: $(RELEASE_RECORDBENCH_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_RECORDBENCH_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/recordbench/recordbench + +$(OBJDIR_DEBUG)/recordbench/recordbench: $(DEBUG_RECORDBENCH_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_RECORDBENCH_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/recordbench/recordbench + +$(OBJDIR_RELEASE)/libmoz2d.a: $(RELEASE_CPPSRCS:.cpp=.o) + ar rcs $(OBJDIR_RELEASE)/libmoz2d.a $(RELEASE_CPPSRCS:.cpp=.o) + +$(OBJDIR_DEBUG)/libmoz2d.a: $(DEBUG_CPPSRCS:.cpp=.o) + ar rcs $(OBJDIR_DEBUG)/libmoz2d.a $(DEBUG_CPPSRCS:.cpp=.o) + +$(OBJDIR_RELEASE)/player2d/player2d: $(OBJDIR_RELEASE)/.mkdir.done $(OBJDIR_RELEASE)/libmoz2d.a + @hash $(QMAKE_BIN) || "echo Please install Qt for your platform: http://qt-project.org/" + export MOZ2D_PLAYER2D_LIBS="$(MOZ2D_PLAYER2D_LIBS)" && cd $(OBJDIR_RELEASE)/player2d && $(QMAKE_BIN) ../../player2d $(QMAKE_PARAMS) && make + +$(OBJDIR_DEBUG)/player2d/player2d: $(OBJDIR_DEBUG)/.mkdir.done $(OBJDIR_DEBUG)/libmoz2d.a + @hash $(QMAKE_BIN) || "echo Please install Qt for your platform: http://qt-project.org/" + export MOZ2D_PLAYER2D_LIBS="$(MOZ2D_PLAYER2D_LIBS)" && cd $(OBJDIR_DEBUG)/player2d && $(QMAKE_BIN) ../../player2d $(QMAKE_PARAMS) MOZ2D_DEBUG=1 && make + +check: $(OBJDIR_RELEASE)/unittest/unittest $(OBJDIR_RELEASE)/perftest/perftest + $(OBJDIR_RELEASE)/unittest/unittest + $(OBJDIR_RELEASE)/perftest/perftest + +clean: + rm -rf $(OBJDIR_RELEASE) $(OBJDIR_DEBUG) + + + + +# ================== IMPLICIT RULES =========================== + +%/.mkdir.done: + mkdir -p $(dir $@)/perftest + mkdir -p $(dir $@)/unittest + mkdir -p $(dir $@)/recordbench + mkdir -p $(dir $@)/player2d + mkdir -p $(dir $@)/nvpr + mkdir -p $@ + +$(OBJDIR_RELEASE)/%.o: %.cpp $(OBJDIR_RELEASE)/.mkdir.done + $(CXX) -c $(COMPILER_DEFINES) $(RELEASEFLAGS) $(CXXFLAGS) -o $@ $< + $(CXX) -MM -MT $@ $(COMPILER_DEFINES) $(RELEASEFLAGS) $(CXXFLAGS) -o $(@:.o=.d) $< + +$(OBJDIR_DEBUG)/%.o: %.cpp $(OBJDIR_DEBUG)/.mkdir.done + $(CXX) $(COMPILER_DEFINES) $(DEBUGFLAGS) $(CXXFLAGS) -c -o $@ $< + $(CXX) -MM -MT $@ $(COMPILER_DEFINES) $(DEBUGFLAGS) $(CXXFLAGS) -o $(@:.o=.d) $< + diff --git a/libazure/Makefile.cairo b/libazure/Makefile.cairo new file mode 100644 index 0000000..9c77966 --- /dev/null +++ b/libazure/Makefile.cairo @@ -0,0 +1,22 @@ +# Simple checks +HAS_CAIRO=$(shell pkg-config cairo && echo YES) +ifneq ($(HAS_CAIRO),YES) +$(error Cairo package not found) +endif + +CXXFLAGS += `pkg-config --cflags cairo` +LIBS += `pkg-config --libs cairo` +MOZ2D_PLAYER2D_LIBS += $(shell pkg-config --libs cairo) +DEFINES += USE_CAIRO MOZ_ENABLE_FREETYPE USE_CAIRO_SCALED_FONT + +MOZ2D_CPPSRCS += \ + DrawTargetCairo.cpp \ + PathCairo.cpp \ + ScaledFontCairo.cpp \ + SourceSurfaceCairo.cpp \ + $(NULL) + +PERFTEST_CPPSRCS += \ + perftest/TestDrawTargetCairoImage.cpp \ + $(NULL) + diff --git a/libazure/Makefile.cg b/libazure/Makefile.cg new file mode 100644 index 0000000..67eefb3 --- /dev/null +++ b/libazure/Makefile.cg @@ -0,0 +1,11 @@ +# XP_MACOSX is analogous for CG +DEFINES += XP_MACOSX + +MOZ2D_CPPSRCS += \ + DrawTargetCG.cpp \ + SourceSurfaceCG.cpp \ + ScaledFontMac.cpp \ + PathCG.cpp \ + MacIOSurface.cpp \ + $(NULL) + diff --git a/libazure/Makefile.d2d b/libazure/Makefile.d2d new file mode 100644 index 0000000..f1a66da --- /dev/null +++ b/libazure/Makefile.d2d @@ -0,0 +1,16 @@ + +# TODO FontWin belong here? + +MOZ2D_CPPSRCS += \ + DrawTargetD2D.cpp \ + PathD2D.cpp \ + SourceSurfaceD2D.cpp \ + SourceSurfaceD2DTarget.cpp \ + ScaledFontDWrite.cpp \ + ScaledFontWin.cpp \ + $(NULL) + +UNITTEST_CPPSRS += \ + unittest/TestDrawTargetD2D.cpp \ + $(NULL) + diff --git a/libazure/src/gfx/2d/Makefile.in b/libazure/Makefile.in similarity index 99% rename from libazure/src/gfx/2d/Makefile.in rename to libazure/Makefile.in index 1862a48..704bbb2 100644 --- a/libazure/src/gfx/2d/Makefile.in +++ b/libazure/Makefile.in @@ -10,6 +10,7 @@ VPATH = $(srcdir) $(srcdir)/unittest include $(DEPTH)/config/autoconf.mk +MODULE = gfx2d LIBRARY_NAME = gfx2d LIBXUL_LIBRARY = 1 EXPORT_LIBRARY = 1 @@ -58,7 +59,6 @@ GTEST_CPPSRCS = \ TestBase.cpp \ TestPoint.cpp \ TestScaling.cpp \ - TestCairo.cpp \ $(NULL) ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) diff --git a/libazure/Makefile.nvpr b/libazure/Makefile.nvpr new file mode 100644 index 0000000..7f96371 --- /dev/null +++ b/libazure/Makefile.nvpr @@ -0,0 +1,25 @@ +DEFINES += USE_NVPR + +LIBS += -ldl -lX11 + +MOZ2D_CPPSRCS += \ + DrawTargetNVpr.cpp \ + PathNVpr.cpp \ + PathBuilderNVpr.cpp \ + SourceSurfaceNVpr.cpp \ + GradientStopsNVpr.cpp \ + ScaledFontNVpr.cpp \ + nvpr/Clip.cpp \ + nvpr/ConvexPolygon.cpp \ + nvpr/GL.cpp \ + nvpr/GLX.cpp \ + nvpr/ShaderProgram.cpp \ + nvpr/Paint.cpp \ + nvpr/ShadowShaders.cpp \ + $(NULL) + +UNITTEST_CPPSRCS += \ + $(NULL) + +PERFTEST_CPPSRCS += \ + $(NULL) diff --git a/libazure/Makefile.skia b/libazure/Makefile.skia new file mode 100644 index 0000000..364d5d8 --- /dev/null +++ b/libazure/Makefile.skia @@ -0,0 +1,25 @@ +DEFINES += USE_SKIA SK_RELEASE GR_RELEASE + +LIBS += -L$(MOZ2D_SKIA)/out/Release/ -Wl,--start-group -lskia_skgpu -lskia_core -lskia_ports -lskia_effects -lskia_sfnt -lskia_utils -lskia_core -lskia_opts -lskia_opts_ssse3 -lskia_ports -lskia_images -Wl,--end-group -lpthread -lGL + +ifeq ($(UNAME),Linux) +LIBS += -lfreetype -lfontconfig +endif + +MOZ2D_CPPSRCS += \ + DrawTargetSkia.cpp \ + PathSkia.cpp \ + ScaledFontSkia.cpp \ + SourceSurfaceSkia.cpp \ + $(NULL) + +INCLUDES += $(MOZ2D_SKIA)/include \ + $(MOZ2D_SKIA)/include/core \ + $(MOZ2D_SKIA)/include/config \ + $(MOZ2D_SKIA)/include/utils \ + $(MOZ2D_SKIA)/include/gpu \ + $(NULL) + +PERFTEST_CPPSRCS += \ + perftest/TestDrawTargetSkiaSoftware.cpp \ + $(NULL) diff --git a/libazure/Makefile.standalone b/libazure/Makefile.standalone new file mode 100644 index 0000000..3bde019 --- /dev/null +++ b/libazure/Makefile.standalone @@ -0,0 +1,232 @@ +# High level targets +.PHONY: release debug player2d check clean + +OBJDIR_RELEASE=release +OBJDIR_DEBUG=debug +INCLUDES=. +CXXFLAGS=-std=gnu++0x -Wall +DEBUGFLAGS=-g -DDEBUG +RELEASEFLAGS=-O3 +DEFINES=USE_SSE2 + +ifeq ($(QMAKE_BIN),) +QMAKE_BIN=qmake +else +endif + +# Mark these targets as phony because we don't know all the dependencies for +# player2d at this level, so invoke the player2d Makefiles every time and let +# the submake deal with it. +.PHONY: $(OBJDIR_RELEASE)/player2d/player2d $(OBJDIR_DEBUG)/player2d/player2d + +# ================ OS FEATURES ================ +UNAME = $(shell uname) +ifeq ($(UNAME),Darwin) +LIBS += -framework CoreFoundation -framework ApplicationServices +endif + +# TODO: Files that depends on mozilla: +#convolver.cpp +#image_operations.cpp + +MOZ2D_CPPSRCS_ALLPLATFORMS = \ + Blur.cpp \ + BlurSSE2.cpp \ + DataSourceSurface.cpp \ + DataSurfaceHelpers.cpp \ + DrawEventRecorder.cpp \ + DrawTargetDual.cpp \ + DrawTargetRecording.cpp \ + Factory.cpp \ + FilterNodeSoftware.cpp \ + FilterProcessing.cpp \ + FilterProcessingScalar.cpp \ + FilterProcessingSSE2.cpp \ + ImageScaling.cpp \ + ImageScalingSSE2.cpp \ + Matrix.cpp \ + Path.cpp \ + PathRecording.cpp \ + RecordedEvent.cpp \ + Scale.cpp \ + ScaledFontBase.cpp \ + SourceSurfaceRawData.cpp \ + PathHelpers.cpp \ + $(NULL) + +PERFTEST_CPPSRCS_ALLPLATFORMS = \ + perftest/Main.cpp \ + perftest/SanityChecks.cpp \ + perftest/TestBase.cpp \ + perftest/TestDrawTargetBase.cpp \ + $(NULL) + +RECORDBENCH_CPPSRCS_ALLPLATFORMS = \ + recordbench/Main.cpp \ + recordbench/RawTranslator.cpp \ + $(NULL) + +UNITTEST_CPPSRCS_ALLPLATFORMS = \ + unittest/SanityChecks.cpp \ + unittest/TestBase.cpp \ + unittest/TestPoint.cpp \ + unittest/TestRect.cpp \ + unittest/TestScaling.cpp \ + unittest/Main.cpp \ + unittest/TestBugs.cpp \ + unittest/TestDrawTarget.cpp \ + unittest/TestPath.cpp \ + $(NULL) + +ifeq ($(UNAME),Darwin) +LIBS += -framework CoreFoundation +endif + +MOZ2D_CPPSRCS = $(MOZ2D_CPPSRCS_ALLPLATFORMS) +UNITTEST_CPPSRCS = $(UNITTEST_CPPSRCS_ALLPLATFORMS) +PERFTEST_CPPSRCS = $(PERFTEST_CPPSRCS_ALLPLATFORMS) +RECORDBENCH_CPPSRCS = $(RECORDBENCH_CPPSRCS_ALLPLATFORMS) + +ifeq ($(UNAME),Linux) +DEFINES += MOZ_ENABLE_FREETYPE +INCLUDES += /usr/include/freetype2 +LIBS += -lfreetype +MOZ2D_PLAYER2D_LIBS += -lfreetype +endif +ifeq ($(UNAME),Darwin) +DEFINES += MOZ_ENABLE_FREETYPE +LIBS += -L/opt/local/lib -lfreetype +MOZ2D_PLAYER2D_LIBS += -L/opt/local/lib -lfreetype +endif + +# ================ INCLUDE FEATURE SPECIFIC MAKEFILES ================= +# These will modify the following variables: +# TESTING_CPPSRCS +# MOZ2D_CPPSRCS +# DEFINES +# +ifdef MOZ2D_D2D + -include Makefile.d2d +endif +ifdef MOZ2D_CG + -include Makefile.cg +endif +ifdef MOZ2D_CAIRO + -include Makefile.cairo + QMAKE_PARAMS += "MOZ2D_CAIRO=1" +endif +ifdef MOZ2D_SKIA + -include Makefile.skia + QMAKE_PARAMS += "MOZ2D_SKIA=$(MOZ2D_SKIA)" + DEFINES += SK_SUPPORT_LEGACY_LAYERRASTERIZER_API=1 + DEFINES += SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG=1 + DEFINES += SK_SUPPORT_LEGACY_GETTOTALCLIP=1 + DEFINES += SK_SUPPORT_LEGACY_DEVICE_CONFIG=1 + DEFINES += SK_IGNORE_ETC1_SUPPORT=1 + DEFINES += SK_ALLOW_STATIC_GLOBAL_INITIALIZERS=0 +endif +ifdef MOZ2D_NVPR + -include Makefile.nvpr + QMAKE_PARAMS += "MOZ2D_NVPR=$(MOZ2D_NVPR)" +endif + +QMAKE_PARAMS += "MOZ2D_PATH=$(PWD)" + +CXXFLAGS += $(addprefix -I,$(INCLUDES)) + +CPPSRCS = $(MOZ2D_CPPSRCS) $(UNITTEST_CPPSRCS) $(PERFTEST_CPPSRCS) $(RECORDBENCH_CPPSRCS) +PRE_PERFTEST_CPPSRCS = $(MOZ2D_CPPSRCS) $(PERFTEST_CPPSRCS) +PRE_UNITTEST_CPPSRCS = $(MOZ2D_CPPSRCS) $(UNITTEST_CPPSRCS) +PRE_RECORDBENCH_CPPSRCS = $(MOZ2D_CPPSRCS) $(RECORDBENCH_CPPSRCS) + +RELEASE_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(CPPSRCS)) +DEBUG_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(CPPSRCS)) +RELEASE_PERFTEST_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_PERFTEST_CPPSRCS)) +DEBUG_PERFTEST_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_PERFTEST_CPPSRCS)) +RELEASE_UNITTEST_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_UNITTEST_CPPSRCS)) +DEBUG_UNITTEST_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_UNITTEST_CPPSRCS)) +RELEASE_RECORDBENCH_CPPSRCS = $(addprefix $(OBJDIR_RELEASE)/,$(PRE_RECORDBENCH_CPPSRCS)) +DEBUG_RECORDBENCH_CPPSRCS = $(addprefix $(OBJDIR_DEBUG)/,$(PRE_RECORDBENCH_CPPSRCS)) +COMPILER_DEFINES = $(addprefix -D,$(DEFINES)) + +-include $(RELEASE_CPPSRCS:.cpp=.d) +-include $(DEBUG_CPPSRCS:.cpp=.d) + +release: \ + $(OBJDIR_RELEASE)/libmoz2d.a \ + $(OBJDIR_RELEASE)/unittest/unittest \ + $(OBJDIR_RELEASE)/perftest/perftest \ + $(OBJDIR_RELEASE)/recordbench/recordbench \ + $(OBJDIR_RELEASE)/.mkdir.done \ + $(NULL) + +debug: \ + $(OBJDIR_DEBUG)/libmoz2d.a \ + $(OBJDIR_DEBUG)/unittest/unittest \ + $(OBJDIR_DEBUG)/perftest/perftest \ + $(OBJDIR_DEBUG)/recordbench/recordbench \ + $(OBJDIR_DEBUG)/.mkdir.done \ + $(NULL) + +player2d: $(OBJDIR_RELEASE)/player2d/player2d $(OBJDIR_DEBUG)/player2d/player2d + +$(OBJDIR_RELEASE)/unittest/unittest: $(RELEASE_UNITTEST_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_UNITTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/unittest/unittest + +$(OBJDIR_DEBUG)/unittest/unittest: $(DEBUG_UNITTEST_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_UNITTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/unittest/unittest + +$(OBJDIR_RELEASE)/perftest/perftest: $(RELEASE_PERFTEST_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_PERFTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/perftest/perftest + +$(OBJDIR_DEBUG)/perftest/perftest: $(DEBUG_PERFTEST_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_PERFTEST_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/perftest/perftest + +$(OBJDIR_RELEASE)/recordbench/recordbench: $(RELEASE_RECORDBENCH_CPPSRCS:.cpp=.o) + $(CXX) $(RELEASE_RECORDBENCH_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_RELEASE)/recordbench/recordbench + +$(OBJDIR_DEBUG)/recordbench/recordbench: $(DEBUG_RECORDBENCH_CPPSRCS:.cpp=.o) + $(CXX) $(DEBUG_RECORDBENCH_CPPSRCS:.cpp=.o) $(LIBS) -o $(OBJDIR_DEBUG)/recordbench/recordbench + +$(OBJDIR_RELEASE)/libmoz2d.a: $(RELEASE_CPPSRCS:.cpp=.o) + ar rcs $(OBJDIR_RELEASE)/libmoz2d.a $(RELEASE_CPPSRCS:.cpp=.o) + +$(OBJDIR_DEBUG)/libmoz2d.a: $(DEBUG_CPPSRCS:.cpp=.o) + ar rcs $(OBJDIR_DEBUG)/libmoz2d.a $(DEBUG_CPPSRCS:.cpp=.o) + +$(OBJDIR_RELEASE)/player2d/player2d: $(OBJDIR_RELEASE)/.mkdir.done $(OBJDIR_RELEASE)/libmoz2d.a + @hash $(QMAKE_BIN) || "echo Please install Qt for your platform: http://qt-project.org/" + export MOZ2D_PLAYER2D_LIBS="$(MOZ2D_PLAYER2D_LIBS)" && cd $(OBJDIR_RELEASE)/player2d && $(QMAKE_BIN) ../../player2d $(QMAKE_PARAMS) && make + +$(OBJDIR_DEBUG)/player2d/player2d: $(OBJDIR_DEBUG)/.mkdir.done $(OBJDIR_DEBUG)/libmoz2d.a + @hash $(QMAKE_BIN) || "echo Please install Qt for your platform: http://qt-project.org/" + export MOZ2D_PLAYER2D_LIBS="$(MOZ2D_PLAYER2D_LIBS)" && cd $(OBJDIR_DEBUG)/player2d && $(QMAKE_BIN) ../../player2d $(QMAKE_PARAMS) MOZ2D_DEBUG=1 && make + +check: $(OBJDIR_RELEASE)/unittest/unittest $(OBJDIR_RELEASE)/perftest/perftest + $(OBJDIR_RELEASE)/unittest/unittest + $(OBJDIR_RELEASE)/perftest/perftest + +clean: + rm -rf $(OBJDIR_RELEASE) $(OBJDIR_DEBUG) + + + + +# ================== IMPLICIT RULES =========================== + +%/.mkdir.done: + mkdir -p $(dir $@)/perftest + mkdir -p $(dir $@)/unittest + mkdir -p $(dir $@)/recordbench + mkdir -p $(dir $@)/player2d + mkdir -p $(dir $@)/nvpr + mkdir -p $@ + +$(OBJDIR_RELEASE)/%.o: %.cpp $(OBJDIR_RELEASE)/.mkdir.done + $(CXX) -c $(COMPILER_DEFINES) $(RELEASEFLAGS) $(CXXFLAGS) -o $@ $< + $(CXX) -MM -MT $@ $(COMPILER_DEFINES) $(RELEASEFLAGS) $(CXXFLAGS) -o $(@:.o=.d) $< + +$(OBJDIR_DEBUG)/%.o: %.cpp $(OBJDIR_DEBUG)/.mkdir.done + $(CXX) $(COMPILER_DEFINES) $(DEBUGFLAGS) $(CXXFLAGS) -c -o $@ $< + $(CXX) -MM -MT $@ $(COMPILER_DEFINES) $(DEBUGFLAGS) $(CXXFLAGS) -o $(@:.o=.d) $< + diff --git a/libazure/Matrix.cpp b/libazure/Matrix.cpp new file mode 100644 index 0000000..0b9c26b --- /dev/null +++ b/libazure/Matrix.cpp @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Matrix.h" +#include "Tools.h" +#include +#include + +#include "mozilla/FloatingPoint.h" // for UnspecifiedNaN + +using namespace std; + +namespace mozilla { +namespace gfx { + +Matrix +Matrix::Rotation(Float aAngle) +{ + Matrix newMatrix; + + Float s = sin(aAngle); + Float c = cos(aAngle); + + newMatrix._11 = c; + newMatrix._12 = s; + newMatrix._21 = -s; + newMatrix._22 = c; + + return newMatrix; +} + +Rect +Matrix::TransformBounds(const Rect &aRect) const +{ + int i; + Point quad[4]; + Float min_x, max_x; + Float min_y, max_y; + + quad[0] = *this * aRect.TopLeft(); + quad[1] = *this * aRect.TopRight(); + quad[2] = *this * aRect.BottomLeft(); + quad[3] = *this * aRect.BottomRight(); + + min_x = max_x = quad[0].x; + min_y = max_y = quad[0].y; + + for (i = 1; i < 4; i++) { + if (quad[i].x < min_x) + min_x = quad[i].x; + if (quad[i].x > max_x) + max_x = quad[i].x; + + if (quad[i].y < min_y) + min_y = quad[i].y; + if (quad[i].y > max_y) + max_y = quad[i].y; + } + + return Rect(min_x, min_y, max_x - min_x, max_y - min_y); +} + +Matrix& +Matrix::NudgeToIntegers() +{ + NudgeToInteger(&_11); + NudgeToInteger(&_12); + NudgeToInteger(&_21); + NudgeToInteger(&_22); + NudgeToInteger(&_31); + NudgeToInteger(&_32); + return *this; +} + +Rect +Matrix4x4::TransformBounds(const Rect& aRect) const +{ + Point quad[4]; + Float min_x, max_x; + Float min_y, max_y; + + quad[0] = *this * aRect.TopLeft(); + quad[1] = *this * aRect.TopRight(); + quad[2] = *this * aRect.BottomLeft(); + quad[3] = *this * aRect.BottomRight(); + + min_x = max_x = quad[0].x; + min_y = max_y = quad[0].y; + + for (int i = 1; i < 4; i++) { + if (quad[i].x < min_x) { + min_x = quad[i].x; + } + if (quad[i].x > max_x) { + max_x = quad[i].x; + } + + if (quad[i].y < min_y) { + min_y = quad[i].y; + } + if (quad[i].y > max_y) { + max_y = quad[i].y; + } + } + + return Rect(min_x, min_y, max_x - min_x, max_y - min_y); +} + +Point4D ComputePerspectivePlaneIntercept(const Point4D& aFirst, + const Point4D& aSecond) +{ + // FIXME: See bug 1035611 + // Since we can't easily deal with points as w=0 (since we divide by w), we + // approximate this by finding a point with w just greater than 0. Unfortunately + // this is a tradeoff between accuracy and floating point precision. + + // We want to interpolate aFirst and aSecond to find a point as close to + // the positive side of the w=0 plane as possible. + + // Since we know what we want the w component to be, we can rearrange the + // interpolation equation and solve for t. + float w = 0.00001f; + float t = (w - aFirst.w) / (aSecond.w - aFirst.w); + + // Use t to find the remainder of the components + return aFirst + (aSecond - aFirst) * t; +} + +Rect Matrix4x4::ProjectRectBounds(const Rect& aRect) const +{ + Point4D points[4]; + + points[0] = ProjectPoint(aRect.TopLeft()); + points[1] = ProjectPoint(aRect.TopRight()); + points[2] = ProjectPoint(aRect.BottomLeft()); + points[3] = ProjectPoint(aRect.BottomRight()); + + Float min_x = std::numeric_limits::max(); + Float min_y = std::numeric_limits::max(); + Float max_x = -std::numeric_limits::max(); + Float max_y = -std::numeric_limits::max(); + + bool foundPoint = false; + for (int i=0; i<4; i++) { + // Only use points that exist above the w=0 plane + if (points[i].HasPositiveWCoord()) { + foundPoint = true; + Point point2d = points[i].As2DPoint(); + min_x = min(point2d.x, min_x); + max_x = max(point2d.x, max_x); + min_y = min(point2d.y, min_y); + max_y = max(point2d.y, max_y); + } + + int next = (i == 3) ? 0 : i + 1; + if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) { + // If the line between two points crosses the w=0 plane, then interpolate a point + // as close to the w=0 plane as possible and use that instead. + Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]); + + Point point2d = intercept.As2DPoint(); + min_x = min(point2d.x, min_x); + max_x = max(point2d.x, max_x); + min_y = min(point2d.y, min_y); + max_y = max(point2d.y, max_y); + } + } + + if (!foundPoint) { + return Rect(0, 0, 0, 0); + } + + return Rect(min_x, min_y, max_x - min_x, max_y - min_y); +} + +bool +Matrix4x4::Invert() +{ + Float det = Determinant(); + if (!det) { + return false; + } + + Matrix4x4 result; + result._11 = _23 * _34 * _42 - _24 * _33 * _42 + _24 * _32 * _43 - _22 * _34 * _43 - _23 * _32 * _44 + _22 * _33 * _44; + result._12 = _14 * _33 * _42 - _13 * _34 * _42 - _14 * _32 * _43 + _12 * _34 * _43 + _13 * _32 * _44 - _12 * _33 * _44; + result._13 = _13 * _24 * _42 - _14 * _23 * _42 + _14 * _22 * _43 - _12 * _24 * _43 - _13 * _22 * _44 + _12 * _23 * _44; + result._14 = _14 * _23 * _32 - _13 * _24 * _32 - _14 * _22 * _33 + _12 * _24 * _33 + _13 * _22 * _34 - _12 * _23 * _34; + result._21 = _24 * _33 * _41 - _23 * _34 * _41 - _24 * _31 * _43 + _21 * _34 * _43 + _23 * _31 * _44 - _21 * _33 * _44; + result._22 = _13 * _34 * _41 - _14 * _33 * _41 + _14 * _31 * _43 - _11 * _34 * _43 - _13 * _31 * _44 + _11 * _33 * _44; + result._23 = _14 * _23 * _41 - _13 * _24 * _41 - _14 * _21 * _43 + _11 * _24 * _43 + _13 * _21 * _44 - _11 * _23 * _44; + result._24 = _13 * _24 * _31 - _14 * _23 * _31 + _14 * _21 * _33 - _11 * _24 * _33 - _13 * _21 * _34 + _11 * _23 * _34; + result._31 = _22 * _34 * _41 - _24 * _32 * _41 + _24 * _31 * _42 - _21 * _34 * _42 - _22 * _31 * _44 + _21 * _32 * _44; + result._32 = _14 * _32 * _41 - _12 * _34 * _41 - _14 * _31 * _42 + _11 * _34 * _42 + _12 * _31 * _44 - _11 * _32 * _44; + result._33 = _12 * _24 * _41 - _14 * _22 * _41 + _14 * _21 * _42 - _11 * _24 * _42 - _12 * _21 * _44 + _11 * _22 * _44; + result._34 = _14 * _22 * _31 - _12 * _24 * _31 - _14 * _21 * _32 + _11 * _24 * _32 + _12 * _21 * _34 - _11 * _22 * _34; + result._41 = _23 * _32 * _41 - _22 * _33 * _41 - _23 * _31 * _42 + _21 * _33 * _42 + _22 * _31 * _43 - _21 * _32 * _43; + result._42 = _12 * _33 * _41 - _13 * _32 * _41 + _13 * _31 * _42 - _11 * _33 * _42 - _12 * _31 * _43 + _11 * _32 * _43; + result._43 = _13 * _22 * _41 - _12 * _23 * _41 - _13 * _21 * _42 + _11 * _23 * _42 + _12 * _21 * _43 - _11 * _22 * _43; + result._44 = _12 * _23 * _31 - _13 * _22 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 + _11 * _22 * _33; + + result._11 /= det; + result._12 /= det; + result._13 /= det; + result._14 /= det; + result._21 /= det; + result._22 /= det; + result._23 /= det; + result._24 /= det; + result._31 /= det; + result._32 /= det; + result._33 /= det; + result._34 /= det; + result._41 /= det; + result._42 /= det; + result._43 /= det; + result._44 /= det; + *this = result; + + return true; +} + +void +Matrix4x4::SetNAN() +{ + _11 = UnspecifiedNaN(); + _21 = UnspecifiedNaN(); + _31 = UnspecifiedNaN(); + _41 = UnspecifiedNaN(); + _12 = UnspecifiedNaN(); + _22 = UnspecifiedNaN(); + _32 = UnspecifiedNaN(); + _42 = UnspecifiedNaN(); + _13 = UnspecifiedNaN(); + _23 = UnspecifiedNaN(); + _33 = UnspecifiedNaN(); + _43 = UnspecifiedNaN(); + _14 = UnspecifiedNaN(); + _24 = UnspecifiedNaN(); + _34 = UnspecifiedNaN(); + _44 = UnspecifiedNaN(); +} + +} +} diff --git a/libazure/Matrix.h b/libazure/Matrix.h new file mode 100644 index 0000000..204be30 --- /dev/null +++ b/libazure/Matrix.h @@ -0,0 +1,874 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_MATRIX_H_ +#define MOZILLA_GFX_MATRIX_H_ + +#include "Types.h" +#include "Rect.h" +#include "Point.h" +#include +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace gfx { + +static bool FuzzyEqual(Float aV1, Float aV2) { + // XXX - Check if fabs does the smart thing and just negates the sign bit. + return fabs(aV2 - aV1) < 1e-6; +} + +class Matrix +{ +public: + Matrix() + : _11(1.0f), _12(0) + , _21(0), _22(1.0f) + , _31(0), _32(0) + {} + Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32) + : _11(a11), _12(a12) + , _21(a21), _22(a22) + , _31(a31), _32(a32) + {} + Float _11, _12; + Float _21, _22; + Float _31, _32; + + MOZ_ALWAYS_INLINE Matrix Copy() const + { + return Matrix(*this); + } + + Point operator *(const Point &aPoint) const + { + Point retPoint; + + retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31; + retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32; + + return retPoint; + } + + Size operator *(const Size &aSize) const + { + Size retSize; + + retSize.width = aSize.width * _11 + aSize.height * _21; + retSize.height = aSize.width * _12 + aSize.height * _22; + + return retSize; + } + + GFX2D_API Rect TransformBounds(const Rect& rect) const; + + static Matrix Translation(Float aX, Float aY) + { + return Matrix(1.0f, 0.0f, 0.0f, 1.0f, aX, aY); + } + + static Matrix Translation(Point aPoint) + { + return Translation(aPoint.x, aPoint.y); + } + + /** + * Apply a translation to this matrix. + * + * The "Pre" in this method's name means that the translation is applied + * -before- this matrix's existing transformation. That is, any vector that + * is multiplied by the resulting matrix will first be translated, then be + * transformed by the original transform. + * + * Thus calling this method will result in this matrix having the same value + * as the result of: + * + * Matrix::Translation(x, y) * this + * + * (Note that in performance critical code multiplying by the result of a + * Translation()/Scaling() call is not recommended since that results in a + * full matrix multiply involving 12 floating-point multiplications. Calling + * this method would be preferred since it only involves four floating-point + * multiplications.) + */ + Matrix &PreTranslate(Float aX, Float aY) + { + _31 += _11 * aX + _21 * aY; + _32 += _12 * aX + _22 * aY; + + return *this; + } + + Matrix &PreTranslate(const Point &aPoint) + { + return PreTranslate(aPoint.x, aPoint.y); + } + + /** + * Similar to PreTranslate, but the translation is applied -after- this + * matrix's existing transformation instead of before it. + * + * This method is generally less used than PreTranslate since typically code + * want to adjust an existing user space to device space matrix to create a + * transform to device space from a -new- user space (translated from the + * previous user space). In that case consumers will need to use the Pre* + * variants of the matrix methods rather than using the Post* methods, since + * the Post* methods add a transform to the device space end of the + * transformation. + */ + Matrix &PostTranslate(Float aX, Float aY) + { + _31 += aX; + _32 += aY; + return *this; + } + + Matrix &PostTranslate(const Point &aPoint) + { + return PostTranslate(aPoint.x, aPoint.y); + } + + static Matrix Scaling(Float aScaleX, Float aScaleY) + { + return Matrix(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f); + } + + /** + * Similar to PreTranslate, but applies a scale to this matrix. + */ + Matrix &PreScale(Float aX, Float aY) + { + _11 *= aX; + _12 *= aX; + _21 *= aY; + _22 *= aY; + + return *this; + } + + Matrix &PostScale(Float aX, Float aY) + { + _11 *= aX; + _21 *= aX; + _31 *= aX; + _12 *= aY; + _22 *= aY; + _32 *= aY; + + return *this; + } + + GFX2D_API static Matrix Rotation(Float aAngle); + + /** + * Similar to PreTranslate, but applies a rotation to this matrix. + */ + Matrix &PreRotate(Float aAngle) + { + return *this = Matrix::Rotation(aAngle) * *this; + } + + bool Invert() + { + // Compute co-factors. + Float A = _22; + Float B = -_21; + Float C = _21 * _32 - _22 * _31; + Float D = -_12; + Float E = _11; + Float F = _31 * _12 - _11 * _32; + + Float det = Determinant(); + + if (!det) { + return false; + } + + Float inv_det = 1 / det; + + _11 = inv_det * A; + _12 = inv_det * D; + _21 = inv_det * B; + _22 = inv_det * E; + _31 = inv_det * C; + _32 = inv_det * F; + + return true; + } + + Float Determinant() const + { + return _11 * _22 - _12 * _21; + } + + Matrix operator*(const Matrix &aMatrix) const + { + Matrix resultMatrix; + + resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21; + resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22; + resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21; + resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22; + resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31; + resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32; + + return resultMatrix; + } + + Matrix& operator*=(const Matrix &aMatrix) + { + *this = *this * aMatrix; + return *this; + } + + /** + * Multiplies in the opposite order to operator=*. + */ + Matrix &PreMultiply(const Matrix &aMatrix) + { + *this = aMatrix * *this; + return *this; + } + + /* Returns true if the other matrix is fuzzy-equal to this matrix. + * Note that this isn't a cheap comparison! + */ + bool operator==(const Matrix& other) const + { + return FuzzyEqual(_11, other._11) && FuzzyEqual(_12, other._12) && + FuzzyEqual(_21, other._21) && FuzzyEqual(_22, other._22) && + FuzzyEqual(_31, other._31) && FuzzyEqual(_32, other._32); + } + + bool operator!=(const Matrix& other) const + { + return !(*this == other); + } + + /* Returns true if the matrix is a rectilinear transformation (i.e. + * grid-aligned rectangles are transformed to grid-aligned rectangles) + */ + bool IsRectilinear() const { + if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) { + return true; + } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) { + return true; + } + + return false; + } + + /** + * Returns true if the matrix is anything other than a straight + * translation by integers. + */ + bool HasNonIntegerTranslation() const { + return HasNonTranslation() || + !FuzzyEqual(_31, floor(_31 + 0.5)) || + !FuzzyEqual(_32, floor(_32 + 0.5)); + } + + /** + * Returns true if the matrix only has an integer translation. + */ + bool HasOnlyIntegerTranslation() const { + return !HasNonIntegerTranslation(); + } + + /** + * Returns true if the matrix has any transform other + * than a straight translation. + */ + bool HasNonTranslation() const { + return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) || + !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0); + } + + /** + * Returns true if the matrix has any transform other + * than a translation or a -1 y scale (y axis flip) + */ + bool HasNonTranslationOrFlip() const { + return !FuzzyEqual(_11, 1.0) || + (!FuzzyEqual(_22, 1.0) && !FuzzyEqual(_22, -1.0)) || + !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0); + } + + /* Returns true if the matrix is an identity matrix. + */ + bool IsIdentity() const + { + return _11 == 1.0f && _12 == 0.0f && + _21 == 0.0f && _22 == 1.0f && + _31 == 0.0f && _32 == 0.0f; + } + + /* Returns true if the matrix is singular. + */ + bool IsSingular() const + { + return Determinant() == 0; + } + + GFX2D_API Matrix &NudgeToIntegers(); + + bool IsTranslation() const + { + return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) && + FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f); + } + + bool IsIntegerTranslation() const + { + return IsTranslation() && + FuzzyEqual(_31, floorf(_31 + 0.5f)) && + FuzzyEqual(_32, floorf(_32 + 0.5f)); + } + + Point GetTranslation() const { + return Point(_31, _32); + } + + /** + * Returns true if matrix is multiple of 90 degrees rotation with flipping, + * scaling and translation. + */ + bool PreservesAxisAlignedRectangles() const { + return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0)) + || (FuzzyEqual(_12, 0.0) && FuzzyEqual(_21, 0.0))); + } + + /** + * Returns true if the matrix has any transform other + * than a translation or scale; this is, if there is + * no rotation. + */ + bool HasNonAxisAlignedTransform() const { + return !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0); + } + + /** + * Returns true if the matrix has non-integer scale + */ + bool HasNonIntegerScale() const { + return !FuzzyEqual(_11, floor(_11 + 0.5)) || + !FuzzyEqual(_22, floor(_22 + 0.5)); + } +}; + +class Matrix4x4 +{ +public: + Matrix4x4() + : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f) + , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f) + , _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f) + , _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f) + {} + + Float _11, _12, _13, _14; + Float _21, _22, _23, _24; + Float _31, _32, _33, _34; + Float _41, _42, _43, _44; + + Point4D& operator[](int aIndex) + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return *reinterpret_cast((&_11)+4*aIndex); + } + const Point4D& operator[](int aIndex) const + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return *reinterpret_cast((&_11)+4*aIndex); + } + + /** + * Returns true if the matrix is isomorphic to a 2D affine transformation. + */ + bool Is2D() const + { + if (_13 != 0.0f || _14 != 0.0f || + _23 != 0.0f || _24 != 0.0f || + _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f || + _43 != 0.0f || _44 != 1.0f) { + return false; + } + return true; + } + + bool Is2D(Matrix* aMatrix) const { + if (!Is2D()) { + return false; + } + if (aMatrix) { + aMatrix->_11 = _11; + aMatrix->_12 = _12; + aMatrix->_21 = _21; + aMatrix->_22 = _22; + aMatrix->_31 = _41; + aMatrix->_32 = _42; + } + return true; + } + + Matrix As2D() const + { + MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform"); + + return Matrix(_11, _12, _21, _22, _41, _42); + } + + bool CanDraw2D(Matrix* aMatrix = nullptr) const { + if (_14 != 0.0f || + _24 != 0.0f || + _44 != 1.0f) { + return false; + } + if (aMatrix) { + aMatrix->_11 = _11; + aMatrix->_12 = _12; + aMatrix->_21 = _21; + aMatrix->_22 = _22; + aMatrix->_31 = _41; + aMatrix->_32 = _42; + } + return true; + } + + Matrix4x4& ProjectTo2D() { + _31 = 0.0f; + _32 = 0.0f; + _13 = 0.0f; + _23 = 0.0f; + _33 = 1.0f; + _43 = 0.0f; + _34 = 0.0f; + return *this; + } + + Point4D ProjectPoint(const Point& aPoint) const { + // Find a value for z that will transform to 0. + + // The transformed value of z is computed as: + // z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43; + + // Solving for z when z' = 0 gives us: + float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33; + + // Compute the transformed point + return *this * Point4D(aPoint.x, aPoint.y, z, 1); + } + + static Matrix4x4 From2D(const Matrix &aMatrix) { + Matrix4x4 matrix; + matrix._11 = aMatrix._11; + matrix._12 = aMatrix._12; + matrix._21 = aMatrix._21; + matrix._22 = aMatrix._22; + matrix._41 = aMatrix._31; + matrix._42 = aMatrix._32; + return matrix; + } + + bool Is2DIntegerTranslation() const + { + return Is2D() && As2D().IsIntegerTranslation(); + } + + Point4D TransposeTransform4D(const Point4D& aPoint) const + { + Float x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14; + Float y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24; + Float z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34; + Float w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44; + + return Point4D(x, y, z, w); + } + + Point4D operator *(const Point4D& aPoint) const + { + Point4D retPoint; + + retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41; + retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42; + retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43; + retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44; + + return retPoint; + } + + Point3D operator *(const Point3D& aPoint) const + { + Point4D temp(aPoint.x, aPoint.y, aPoint.z, 1); + + temp = *this * temp; + temp /= temp.w; + + return Point3D(temp.x, temp.y, temp.z); + } + + Point operator *(const Point &aPoint) const + { + Point4D temp(aPoint.x, aPoint.y, 0, 1); + + temp = *this * temp; + temp /= temp.w; + + return Point(temp.x, temp.y); + } + + GFX2D_API Rect TransformBounds(const Rect& rect) const; + + // Apply a scale to this matrix. This scale will be applied -before- the + // existing transformation of the matrix. + Matrix4x4 &Scale(Float aX, Float aY, Float aZ) + { + _11 *= aX; + _12 *= aX; + _13 *= aX; + _21 *= aY; + _22 *= aY; + _23 *= aY; + _31 *= aZ; + _32 *= aZ; + _33 *= aZ; + + return *this; + } + + Matrix4x4 &Translate(Float aX, Float aY, Float aZ) + { + _41 += aX * _11 + aY * _21 + aZ * _31; + _42 += aX * _12 + aY * _22 + aZ * _32; + _43 += aX * _13 + aY * _23 + aZ * _33; + _44 += aX * _14 + aY * _24 + aZ * _34; + + return *this; + } + + Rect ProjectRectBounds(const Rect& aRect) const; + + Matrix4x4 &PostTranslate(Float aX, Float aY, Float aZ) + { + _11 += _14 * aX; + _21 += _24 * aX; + _31 += _34 * aX; + _41 += _44 * aX; + _12 += _14 * aY; + _22 += _24 * aY; + _32 += _34 * aY; + _42 += _44 * aY; + _13 += _14 * aZ; + _23 += _24 * aZ; + _33 += _34 * aZ; + _43 += _44 * aZ; + + return *this; + } + + void SkewXY(Float aSkew) + { + (*this)[1] += (*this)[0] * aSkew; + } + + void SkewXZ(Float aSkew) + { + (*this)[2] += (*this)[0] * aSkew; + } + + void SkewYZ(Float aSkew) + { + (*this)[2] += (*this)[1] * aSkew; + } + + Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ) + { + // Translate to the origin before applying this matrix + Translate(-aX, -aY, -aZ); + + // Translate back into position after applying this matrix + PostTranslate(aX, aY, aZ); + + return *this; + } + + bool operator==(const Matrix4x4& o) const + { + // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics + return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 && + _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 && + _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 && + _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44; + } + + bool operator!=(const Matrix4x4& o) const + { + return !((*this) == o); + } + + Matrix4x4 operator*(const Matrix4x4 &aMatrix) const + { + Matrix4x4 matrix; + + matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41; + matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41; + matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41; + matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41; + matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42; + matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42; + matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42; + matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42; + matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43; + matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43; + matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43; + matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43; + matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44; + matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44; + matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44; + matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44; + + return matrix; + } + + Matrix4x4& operator*=(const Matrix4x4 &aMatrix) + { + Matrix4x4 resultMatrix = *this * aMatrix; + return *this = resultMatrix; + } + + /* Returns true if the matrix is an identity matrix. + */ + bool IsIdentity() const + { + return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f && + _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f && + _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f && + _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f; + } + + bool IsSingular() const + { + return Determinant() == 0.0; + } + + Float Determinant() const + { + return _14 * _23 * _32 * _41 + - _13 * _24 * _32 * _41 + - _14 * _22 * _33 * _41 + + _12 * _24 * _33 * _41 + + _13 * _22 * _34 * _41 + - _12 * _23 * _34 * _41 + - _14 * _23 * _31 * _42 + + _13 * _24 * _31 * _42 + + _14 * _21 * _33 * _42 + - _11 * _24 * _33 * _42 + - _13 * _21 * _34 * _42 + + _11 * _23 * _34 * _42 + + _14 * _22 * _31 * _43 + - _12 * _24 * _31 * _43 + - _14 * _21 * _32 * _43 + + _11 * _24 * _32 * _43 + + _12 * _21 * _34 * _43 + - _11 * _22 * _34 * _43 + - _13 * _22 * _31 * _44 + + _12 * _23 * _31 * _44 + + _13 * _21 * _32 * _44 + - _11 * _23 * _32 * _44 + - _12 * _21 * _33 * _44 + + _11 * _22 * _33 * _44; + } + + bool Invert(); + + void Normalize() + { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + (*this)[i][j] /= (*this)[3][3]; + } + } + } + + void ScalePost(Float aX, Float aY, Float aZ) + { + _11 *= aX; + _21 *= aX; + _31 *= aX; + _41 *= aX; + + _12 *= aY; + _22 *= aY; + _32 *= aY; + _42 *= aY; + + _13 *= aZ; + _23 *= aZ; + _33 *= aZ; + _43 *= aZ; + } + + void TranslatePost(Float aX, Float aY, Float aZ) + { + _11 += _14 * aX; + _21 += _24 * aX; + _31 += _34 * aX; + _41 += _44 * aX; + + _12 += _14 * aY; + _22 += _24 * aY; + _32 += _34 * aY; + _42 += _44 * aY; + + _13 += _14 * aZ; + _23 += _24 * aZ; + _33 += _34 * aZ; + _43 += _44 * aZ; + } + + bool FuzzyEqual(const Matrix4x4& o) const + { + return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) && + gfx::FuzzyEqual(_13, o._13) && gfx::FuzzyEqual(_14, o._14) && + gfx::FuzzyEqual(_21, o._21) && gfx::FuzzyEqual(_22, o._22) && + gfx::FuzzyEqual(_23, o._23) && gfx::FuzzyEqual(_24, o._24) && + gfx::FuzzyEqual(_31, o._31) && gfx::FuzzyEqual(_32, o._32) && + gfx::FuzzyEqual(_33, o._33) && gfx::FuzzyEqual(_34, o._34) && + gfx::FuzzyEqual(_41, o._41) && gfx::FuzzyEqual(_42, o._42) && + gfx::FuzzyEqual(_43, o._43) && gfx::FuzzyEqual(_44, o._44); + } + + bool IsBackfaceVisible() const + { + // Inverse()._33 < 0; + Float det = Determinant(); + Float __33 = _12*_24*_41 - _14*_22*_41 + + _14*_21*_42 - _11*_24*_42 - + _12*_21*_44 + _11*_22*_44; + return (__33 * det) < 0; + } + + Matrix4x4 &NudgeToIntegersFixedEpsilon() + { + static const float error = 1e-5f; + NudgeToInteger(&_11, error); + NudgeToInteger(&_12, error); + NudgeToInteger(&_13, error); + NudgeToInteger(&_14, error); + NudgeToInteger(&_21, error); + NudgeToInteger(&_22, error); + NudgeToInteger(&_23, error); + NudgeToInteger(&_24, error); + NudgeToInteger(&_31, error); + NudgeToInteger(&_32, error); + NudgeToInteger(&_33, error); + NudgeToInteger(&_34, error); + NudgeToInteger(&_41, error); + NudgeToInteger(&_42, error); + NudgeToInteger(&_43, error); + NudgeToInteger(&_44, error); + return *this; + } + + Point4D TransposedVector(int aIndex) const + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + return Point4D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex)); + } + + void SetTransposedVector(int aIndex, Point4D &aVector) + { + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); + *((&_11)+aIndex) = aVector.x; + *((&_21)+aIndex) = aVector.y; + *((&_31)+aIndex) = aVector.z; + *((&_41)+aIndex) = aVector.w; + } + + // Set all the members of the matrix to NaN + void SetNAN(); +}; + +class Matrix5x4 +{ +public: + Matrix5x4() + : _11(1.0f), _12(0), _13(0), _14(0) + , _21(0), _22(1.0f), _23(0), _24(0) + , _31(0), _32(0), _33(1.0f), _34(0) + , _41(0), _42(0), _43(0), _44(1.0f) + , _51(0), _52(0), _53(0), _54(0) + {} + Matrix5x4(Float a11, Float a12, Float a13, Float a14, + Float a21, Float a22, Float a23, Float a24, + Float a31, Float a32, Float a33, Float a34, + Float a41, Float a42, Float a43, Float a44, + Float a51, Float a52, Float a53, Float a54) + : _11(a11), _12(a12), _13(a13), _14(a14) + , _21(a21), _22(a22), _23(a23), _24(a24) + , _31(a31), _32(a32), _33(a33), _34(a34) + , _41(a41), _42(a42), _43(a43), _44(a44) + , _51(a51), _52(a52), _53(a53), _54(a54) + {} + + bool operator==(const Matrix5x4 &o) const + { + return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 && + _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 && + _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 && + _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44 && + _51 == o._51 && _52 == o._52 && _53 == o._53 && _54 == o._54; + } + + bool operator!=(const Matrix5x4 &aMatrix) const + { + return !(*this == aMatrix); + } + + Matrix5x4 operator*(const Matrix5x4 &aMatrix) const + { + Matrix5x4 resultMatrix; + + resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21 + this->_13 * aMatrix._31 + this->_14 * aMatrix._41; + resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22 + this->_13 * aMatrix._32 + this->_14 * aMatrix._42; + resultMatrix._13 = this->_11 * aMatrix._13 + this->_12 * aMatrix._23 + this->_13 * aMatrix._33 + this->_14 * aMatrix._43; + resultMatrix._14 = this->_11 * aMatrix._14 + this->_12 * aMatrix._24 + this->_13 * aMatrix._34 + this->_14 * aMatrix._44; + resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21 + this->_23 * aMatrix._31 + this->_24 * aMatrix._41; + resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22 + this->_23 * aMatrix._32 + this->_24 * aMatrix._42; + resultMatrix._23 = this->_21 * aMatrix._13 + this->_22 * aMatrix._23 + this->_23 * aMatrix._33 + this->_24 * aMatrix._43; + resultMatrix._24 = this->_21 * aMatrix._14 + this->_22 * aMatrix._24 + this->_23 * aMatrix._34 + this->_24 * aMatrix._44; + resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + this->_33 * aMatrix._31 + this->_34 * aMatrix._41; + resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + this->_33 * aMatrix._32 + this->_34 * aMatrix._42; + resultMatrix._33 = this->_31 * aMatrix._13 + this->_32 * aMatrix._23 + this->_33 * aMatrix._33 + this->_34 * aMatrix._43; + resultMatrix._34 = this->_31 * aMatrix._14 + this->_32 * aMatrix._24 + this->_33 * aMatrix._34 + this->_34 * aMatrix._44; + resultMatrix._41 = this->_41 * aMatrix._11 + this->_42 * aMatrix._21 + this->_43 * aMatrix._31 + this->_44 * aMatrix._41; + resultMatrix._42 = this->_41 * aMatrix._12 + this->_42 * aMatrix._22 + this->_43 * aMatrix._32 + this->_44 * aMatrix._42; + resultMatrix._43 = this->_41 * aMatrix._13 + this->_42 * aMatrix._23 + this->_43 * aMatrix._33 + this->_44 * aMatrix._43; + resultMatrix._44 = this->_41 * aMatrix._14 + this->_42 * aMatrix._24 + this->_43 * aMatrix._34 + this->_44 * aMatrix._44; + resultMatrix._51 = this->_51 * aMatrix._11 + this->_52 * aMatrix._21 + this->_53 * aMatrix._31 + this->_54 * aMatrix._41 + aMatrix._51; + resultMatrix._52 = this->_51 * aMatrix._12 + this->_52 * aMatrix._22 + this->_53 * aMatrix._32 + this->_54 * aMatrix._42 + aMatrix._52; + resultMatrix._53 = this->_51 * aMatrix._13 + this->_52 * aMatrix._23 + this->_53 * aMatrix._33 + this->_54 * aMatrix._43 + aMatrix._53; + resultMatrix._54 = this->_51 * aMatrix._14 + this->_52 * aMatrix._24 + this->_53 * aMatrix._34 + this->_54 * aMatrix._44 + aMatrix._54; + + return resultMatrix; + } + + Matrix5x4& operator*=(const Matrix5x4 &aMatrix) + { + *this = *this * aMatrix; + return *this; + } + + Float _11, _12, _13, _14; + Float _21, _22, _23, _24; + Float _31, _32, _33, _34; + Float _41, _42, _43, _44; + Float _51, _52, _53, _54; +}; + +} +} + +#endif /* MOZILLA_GFX_MATRIX_H_ */ diff --git a/libazure/NativeGLContext.h b/libazure/NativeGLContext.h new file mode 100644 index 0000000..b395713 --- /dev/null +++ b/libazure/NativeGLContext.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NATIVEGLCONTEXT_H_ +#define MOZILLA_GFX_NATIVEGLCONTEXT_H_ + +#include + +namespace mozilla { +namespace gfx { + +class NativeGLContext { +public: + NativeGLContext(const NativeGLContext* shareGroup = nullptr); + ~NativeGLContext(); + + bool IsCurrent() const; + void MakeCurrent() const; + +private: + Display* mDisplay; + Pixmap mPixmap; + GLXPixmap mGlxPixmap; + GLXContext mContext; +}; + +} +} + +#endif /* MOZILLA_GFX_NATIVEGLCONTEXT_H_ */ diff --git a/libazure/Path.cpp b/libazure/Path.cpp new file mode 100644 index 0000000..998ac07 --- /dev/null +++ b/libazure/Path.cpp @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "2D.h" +#include "PathAnalysis.h" +#include "PathHelpers.h" + +namespace mozilla { +namespace gfx { + +static float CubicRoot(float aValue) { + if (aValue < 0.0) { + return -CubicRoot(-aValue); + } + else { + return powf(aValue, 1.0f / 3.0f); + } +} + +struct BezierControlPoints +{ + BezierControlPoints() {} + BezierControlPoints(const Point &aCP1, const Point &aCP2, + const Point &aCP3, const Point &aCP4) + : mCP1(aCP1), mCP2(aCP2), mCP3(aCP3), mCP4(aCP4) + { + } + + Point mCP1, mCP2, mCP3, mCP4; +}; + +void +FlattenBezier(const BezierControlPoints &aPoints, + PathSink *aSink, Float aTolerance); + + +Path::Path() +{ +} + +Path::~Path() +{ +} + +Float +Path::ComputeLength() +{ + EnsureFlattenedPath(); + return mFlattenedPath->ComputeLength(); +} + +Point +Path::ComputePointAtLength(Float aLength, Point* aTangent) +{ + EnsureFlattenedPath(); + return mFlattenedPath->ComputePointAtLength(aLength, aTangent); +} + +void +Path::EnsureFlattenedPath() +{ + if (!mFlattenedPath) { + mFlattenedPath = new FlattenedPath(); + StreamToSink(mFlattenedPath); + } +} + +// This is the maximum deviation we allow (with an additional ~20% margin of +// error) of the approximation from the actual Bezier curve. +const Float kFlatteningTolerance = 0.0001f; + +void +FlattenedPath::MoveTo(const Point &aPoint) +{ + MOZ_ASSERT(!mCalculatedLength); + FlatPathOp op; + op.mType = FlatPathOp::OP_MOVETO; + op.mPoint = aPoint; + mPathOps.push_back(op); + + mLastMove = aPoint; +} + +void +FlattenedPath::LineTo(const Point &aPoint) +{ + MOZ_ASSERT(!mCalculatedLength); + FlatPathOp op; + op.mType = FlatPathOp::OP_LINETO; + op.mPoint = aPoint; + mPathOps.push_back(op); +} + +void +FlattenedPath::BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3) +{ + MOZ_ASSERT(!mCalculatedLength); + FlattenBezier(BezierControlPoints(CurrentPoint(), aCP1, aCP2, aCP3), this, kFlatteningTolerance); +} + +void +FlattenedPath::QuadraticBezierTo(const Point &aCP1, + const Point &aCP2) +{ + MOZ_ASSERT(!mCalculatedLength); + // We need to elevate the degree of this quadratic B�zier to cubic, so we're + // going to add an intermediate control point, and recompute control point 1. + // The first and last control points remain the same. + // This formula can be found on http://fontforge.sourceforge.net/bezier.html + Point CP0 = CurrentPoint(); + Point CP1 = (CP0 + aCP1 * 2.0) / 3.0; + Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0; + Point CP3 = aCP2; + + BezierTo(CP1, CP2, CP3); +} + +void +FlattenedPath::Close() +{ + MOZ_ASSERT(!mCalculatedLength); + LineTo(mLastMove); +} + +void +FlattenedPath::Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise) +{ + ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise); +} + +Float +FlattenedPath::ComputeLength() +{ + if (!mCalculatedLength) { + Point currentPoint; + + for (uint32_t i = 0; i < mPathOps.size(); i++) { + if (mPathOps[i].mType == FlatPathOp::OP_MOVETO) { + currentPoint = mPathOps[i].mPoint; + } else { + mCachedLength += Distance(currentPoint, mPathOps[i].mPoint); + currentPoint = mPathOps[i].mPoint; + } + } + + mCalculatedLength = true; + } + + return mCachedLength; +} + +Point +FlattenedPath::ComputePointAtLength(Float aLength, Point *aTangent) +{ + // We track the last point that -wasn't- in the same place as the current + // point so if we pass the edge of the path with a bunch of zero length + // paths we still get the correct tangent vector. + Point lastPointSinceMove; + Point currentPoint; + for (uint32_t i = 0; i < mPathOps.size(); i++) { + if (mPathOps[i].mType == FlatPathOp::OP_MOVETO) { + if (Distance(currentPoint, mPathOps[i].mPoint)) { + lastPointSinceMove = currentPoint; + } + currentPoint = mPathOps[i].mPoint; + } else { + Float segmentLength = Distance(currentPoint, mPathOps[i].mPoint); + + if (segmentLength) { + lastPointSinceMove = currentPoint; + if (segmentLength > aLength) { + Point currentVector = mPathOps[i].mPoint - currentPoint; + Point tangent = currentVector / segmentLength; + if (aTangent) { + *aTangent = tangent; + } + return currentPoint + tangent * aLength; + } + } + + aLength -= segmentLength; + currentPoint = mPathOps[i].mPoint; + } + } + + Point currentVector = currentPoint - lastPointSinceMove; + if (aTangent) { + if (hypotf(currentVector.x, currentVector.y)) { + *aTangent = currentVector / hypotf(currentVector.x, currentVector.y); + } else { + *aTangent = Point(); + } + } + return currentPoint; +} + +// This function explicitly permits aControlPoints to refer to the same object +// as either of the other arguments. +static void +SplitBezier(const BezierControlPoints &aControlPoints, + BezierControlPoints *aFirstSegmentControlPoints, + BezierControlPoints *aSecondSegmentControlPoints, + Float t) +{ + MOZ_ASSERT(aSecondSegmentControlPoints); + + *aSecondSegmentControlPoints = aControlPoints; + + Point cp1a = aControlPoints.mCP1 + (aControlPoints.mCP2 - aControlPoints.mCP1) * t; + Point cp2a = aControlPoints.mCP2 + (aControlPoints.mCP3 - aControlPoints.mCP2) * t; + Point cp1aa = cp1a + (cp2a - cp1a) * t; + Point cp3a = aControlPoints.mCP3 + (aControlPoints.mCP4 - aControlPoints.mCP3) * t; + Point cp2aa = cp2a + (cp3a - cp2a) * t; + Point cp1aaa = cp1aa + (cp2aa - cp1aa) * t; + aSecondSegmentControlPoints->mCP4 = aControlPoints.mCP4; + + if(aFirstSegmentControlPoints) { + aFirstSegmentControlPoints->mCP1 = aControlPoints.mCP1; + aFirstSegmentControlPoints->mCP2 = cp1a; + aFirstSegmentControlPoints->mCP3 = cp1aa; + aFirstSegmentControlPoints->mCP4 = cp1aaa; + } + aSecondSegmentControlPoints->mCP1 = cp1aaa; + aSecondSegmentControlPoints->mCP2 = cp2aa; + aSecondSegmentControlPoints->mCP3 = cp3a; +} + +static void +FlattenBezierCurveSegment(const BezierControlPoints &aControlPoints, + PathSink *aSink, + Float aTolerance) +{ + /* The algorithm implemented here is based on: + * http://cis.usouthal.edu/~hain/general/Publications/Bezier/Bezier%20Offset%20Curves.pdf + * + * The basic premise is that for a small t the third order term in the + * equation of a cubic bezier curve is insignificantly small. This can + * then be approximated by a quadratic equation for which the maximum + * difference from a linear approximation can be much more easily determined. + */ + BezierControlPoints currentCP = aControlPoints; + + Float t = 0; + while (t < 1.0f) { + Point cp21 = currentCP.mCP2 - currentCP.mCP3; + Point cp31 = currentCP.mCP3 - currentCP.mCP1; + + Float s3 = (cp31.x * cp21.y - cp31.y * cp21.x) / hypotf(cp21.x, cp21.y); + + t = 2 * Float(sqrt(aTolerance / (3. * abs(s3)))); + + if (t >= 1.0f) { + aSink->LineTo(aControlPoints.mCP4); + break; + } + + Point prevCP2, prevCP3, nextCP1, nextCP2, nextCP3; + SplitBezier(currentCP, nullptr, ¤tCP, t); + + aSink->LineTo(currentCP.mCP1); + } +} + +static inline void +FindInflectionApproximationRange(BezierControlPoints aControlPoints, + Float *aMin, Float *aMax, Float aT, + Float aTolerance) +{ + SplitBezier(aControlPoints, nullptr, &aControlPoints, aT); + + Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1; + Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1; + + if (cp21.x == 0.f && cp21.y == 0.f) { + // In this case s3 becomes lim[n->0] (cp41.x * n) / n - (cp41.y * n) / n = cp41.x - cp41.y. + + // Use the absolute value so that Min and Max will correspond with the + // minimum and maximum of the range. + *aMin = aT - CubicRoot(abs(aTolerance / (cp41.x - cp41.y))); + *aMax = aT + CubicRoot(abs(aTolerance / (cp41.x - cp41.y))); + return; + } + + Float s3 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y); + + if (s3 == 0) { + // This means within the precision we have it can be approximated + // infinitely by a linear segment. Deal with this by specifying the + // approximation range as extending beyond the entire curve. + *aMin = -1.0f; + *aMax = 2.0f; + return; + } + + Float tf = CubicRoot(abs(aTolerance / s3)); + + *aMin = aT - tf * (1 - aT); + *aMax = aT + tf * (1 - aT); +} + +/* Find the inflection points of a bezier curve. Will return false if the + * curve is degenerate in such a way that it is best approximated by a straight + * line. + * + * The below algorithm was written by Jeff Muizelaar , explanation follows: + * + * The lower inflection point is returned in aT1, the higher one in aT2. In the + * case of a single inflection point this will be in aT1. + * + * The method is inspired by the algorithm in "analysis of in?ection points for planar cubic bezier curve" + * + * Here are some differences between this algorithm and versions discussed elsewhere in the literature: + * + * zhang et. al compute a0, d0 and e0 incrementally using the follow formula: + * + * Point a0 = CP2 - CP1 + * Point a1 = CP3 - CP2 + * Point a2 = CP4 - CP1 + * + * Point d0 = a1 - a0 + * Point d1 = a2 - a1 + + * Point e0 = d1 - d0 + * + * this avoids any multiplications and may or may not be faster than the approach take below. + * + * "fast, precise flattening of cubic bezier path and ofset curves" by hain et. al + * Point a = CP1 + 3 * CP2 - 3 * CP3 + CP4 + * Point b = 3 * CP1 - 6 * CP2 + 3 * CP3 + * Point c = -3 * CP1 + 3 * CP2 + * Point d = CP1 + * the a, b, c, d can be expressed in terms of a0, d0 and e0 defined above as: + * c = 3 * a0 + * b = 3 * d0 + * a = e0 + * + * + * a = 3a = a.y * b.x - a.x * b.y + * b = 3b = a.y * c.x - a.x * c.y + * c = 9c = b.y * c.x - b.x * c.y + * + * The additional multiples of 3 cancel each other out as show below: + * + * x = (-b + sqrt(b * b - 4 * a * c)) / (2 * a) + * x = (-3 * b + sqrt(3 * b * 3 * b - 4 * a * 3 * 9 * c / 3)) / (2 * 3 * a) + * x = 3 * (-b + sqrt(b * b - 4 * a * c)) / (2 * 3 * a) + * x = (-b + sqrt(b * b - 4 * a * c)) / (2 * a) + * + * I haven't looked into whether the formulation of the quadratic formula in + * hain has any numerical advantages over the one used below. + */ +static inline void +FindInflectionPoints(const BezierControlPoints &aControlPoints, + Float *aT1, Float *aT2, uint32_t *aCount) +{ + // Find inflection points. + // See www.faculty.idc.ac.il/arik/quality/appendixa.html for an explanation + // of this approach. + Point A = aControlPoints.mCP2 - aControlPoints.mCP1; + Point B = aControlPoints.mCP3 - (aControlPoints.mCP2 * 2) + aControlPoints.mCP1; + Point C = aControlPoints.mCP4 - (aControlPoints.mCP3 * 3) + (aControlPoints.mCP2 * 3) - aControlPoints.mCP1; + + Float a = Float(B.x) * C.y - Float(B.y) * C.x; + Float b = Float(A.x) * C.y - Float(A.y) * C.x; + Float c = Float(A.x) * B.y - Float(A.y) * B.x; + + if (a == 0) { + // Not a quadratic equation. + if (b == 0) { + // Instead of a linear acceleration change we have a constant + // acceleration change. This means the equation has no solution + // and there are no inflection points, unless the constant is 0. + // In that case the curve is a straight line, essentially that means + // the easiest way to deal with is is by saying there's an inflection + // point at t == 0. The inflection point approximation range found will + // automatically extend into infinity. + if (c == 0) { + *aCount = 1; + *aT1 = 0; + return; + } + *aCount = 0; + return; + } + *aT1 = -c / b; + *aCount = 1; + return; + } else { + Float discriminant = b * b - 4 * a * c; + + if (discriminant < 0) { + // No inflection points. + *aCount = 0; + } else if (discriminant == 0) { + *aCount = 1; + *aT1 = -b / (2 * a); + } else { + /* Use the following formula for computing the roots: + * + * q = -1/2 * (b + sign(b) * sqrt(b^2 - 4ac)) + * t1 = q / a + * t2 = c / q + */ + Float q = sqrtf(discriminant); + if (b < 0) { + q = b - q; + } else { + q = b + q; + } + q *= Float(-1./2); + + *aT1 = q / a; + *aT2 = c / q; + if (*aT1 > *aT2) { + std::swap(*aT1, *aT2); + } + *aCount = 2; + } + } + + return; +} + +void +FlattenBezier(const BezierControlPoints &aControlPoints, + PathSink *aSink, Float aTolerance) +{ + Float t1; + Float t2; + uint32_t count; + + FindInflectionPoints(aControlPoints, &t1, &t2, &count); + + // Check that at least one of the inflection points is inside [0..1] + if (count == 0 || ((t1 < 0 || t1 > 1.0) && ((t2 < 0 || t2 > 1.0) || count == 1)) ) { + FlattenBezierCurveSegment(aControlPoints, aSink, aTolerance); + return; + } + + Float t1min = t1, t1max = t1, t2min = t2, t2max = t2; + + BezierControlPoints remainingCP = aControlPoints; + + // For both inflection points, calulate the range where they can be linearly + // approximated if they are positioned within [0,1] + if (count > 0 && t1 >= 0 && t1 < 1.0) { + FindInflectionApproximationRange(aControlPoints, &t1min, &t1max, t1, aTolerance); + } + if (count > 1 && t2 >= 0 && t2 < 1.0) { + FindInflectionApproximationRange(aControlPoints, &t2min, &t2max, t2, aTolerance); + } + BezierControlPoints nextCPs = aControlPoints; + BezierControlPoints prevCPs; + + // Process ranges. [t1min, t1max] and [t2min, t2max] are approximated by line + // segments. + if (t1min > 0) { + // Flatten the Bezier up until the first inflection point's approximation + // point. + SplitBezier(aControlPoints, &prevCPs, + &remainingCP, t1min); + FlattenBezierCurveSegment(prevCPs, aSink, aTolerance); + } + if (t1max >= 0 && t1max < 1.0 && (count == 1 || t2min > t1max)) { + // The second inflection point's approximation range begins after the end + // of the first, approximate the first inflection point by a line and + // subsequently flatten up until the end or the next inflection point. + SplitBezier(aControlPoints, nullptr, &nextCPs, t1max); + + aSink->LineTo(nextCPs.mCP1); + + if (count == 1 || (count > 1 && t2min >= 1.0)) { + // No more inflection points to deal with, flatten the rest of the curve. + FlattenBezierCurveSegment(nextCPs, aSink, aTolerance); + } + } else if (count > 1 && t2min > 1.0) { + // We've already concluded t2min <= t1max, so if this is true the + // approximation range for the first inflection point runs past the + // end of the curve, draw a line to the end and we're done. + aSink->LineTo(aControlPoints.mCP4); + return; + } + + if (count > 1 && t2min < 1.0 && t2max > 0) { + if (t2min > 0 && t2min < t1max) { + // In this case the t2 approximation range starts inside the t1 + // approximation range. + SplitBezier(aControlPoints, nullptr, &nextCPs, t1max); + aSink->LineTo(nextCPs.mCP1); + } else if (t2min > 0 && t1max > 0) { + SplitBezier(aControlPoints, nullptr, &nextCPs, t1max); + + // Find a control points describing the portion of the curve between t1max and t2min. + Float t2mina = (t2min - t1max) / (1 - t1max); + SplitBezier(nextCPs, &prevCPs, &nextCPs, t2mina); + FlattenBezierCurveSegment(prevCPs, aSink, aTolerance); + } else if (t2min > 0) { + // We have nothing interesting before t2min, find that bit and flatten it. + SplitBezier(aControlPoints, &prevCPs, &nextCPs, t2min); + FlattenBezierCurveSegment(prevCPs, aSink, aTolerance); + } + if (t2max < 1.0) { + // Flatten the portion of the curve after t2max + SplitBezier(aControlPoints, nullptr, &nextCPs, t2max); + + // Draw a line to the start, this is the approximation between t2min and + // t2max. + aSink->LineTo(nextCPs.mCP1); + FlattenBezierCurveSegment(nextCPs, aSink, aTolerance); + } else { + // Our approximation range extends beyond the end of the curve. + aSink->LineTo(aControlPoints.mCP4); + return; + } + } +} + +} +} diff --git a/libazure/PathAnalysis.h b/libazure/PathAnalysis.h new file mode 100644 index 0000000..6b9b33f --- /dev/null +++ b/libazure/PathAnalysis.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "2D.h" +#include + +namespace mozilla { +namespace gfx { + +struct FlatPathOp +{ + enum OpType { + OP_MOVETO, + OP_LINETO, + }; + + OpType mType; + Point mPoint; +}; + +class FlattenedPath : public PathSink +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FlattenedPath) + FlattenedPath() : mCachedLength(0) + , mCalculatedLength(false) + { + } + + virtual void MoveTo(const Point &aPoint); + virtual void LineTo(const Point &aPoint); + virtual void BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3); + virtual void QuadraticBezierTo(const Point &aCP1, + const Point &aCP2); + virtual void Close(); + virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise = false); + + virtual Point CurrentPoint() const { return mPathOps.empty() ? Point() : mPathOps[mPathOps.size() - 1].mPoint; } + + Float ComputeLength(); + Point ComputePointAtLength(Float aLength, Point *aTangent); + +private: + Float mCachedLength; + bool mCalculatedLength; + Point mLastMove; + + std::vector mPathOps; +}; + +} +} diff --git a/libazure/PathBuilderNVpr.cpp b/libazure/PathBuilderNVpr.cpp new file mode 100644 index 0000000..b972205 --- /dev/null +++ b/libazure/PathBuilderNVpr.cpp @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PathBuilderNVpr.h" +#include "PathNVpr.h" +#include "Line.h" +#include "nvpr/ConvexPolygon.h" +#include + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +class PathCache + : public map > + , public nvpr::UserData::Object +{}; + +PathBuilderNVpr::PathBuilderNVpr(FillRule aFillRule) + : mFillRule(aFillRule) + , mIsPolygon(true) +{ +} + +PathBuilderNVpr::PathBuilderNVpr(FillRule aFillRule, + TemporaryRef aPathObject) + : mFillRule(aFillRule) +{ + RefPtr pathObject = aPathObject; + mPathObject = pathObject.forget(); + mIsPolygon = mPathObject->Polygon().IsEmpty(); +} + +PathBuilderNVpr::PathBuilderNVpr(FillRule aFillRule, + TemporaryRef aPathObject, + const Matrix& aTransform) + : mFillRule(aFillRule) +{ + RefPtr pathObject = aPathObject; + mPathObject = new PathObjectNVpr(*pathObject, aTransform); + mIsPolygon = mPathObject->Polygon().IsEmpty(); +} + +PathBuilderNVpr::~PathBuilderNVpr() +{ +} + +void +PathBuilderNVpr::MoveTo(const Point& aPoint) +{ + MakeWritable(); + + if (!mDescription.IsEmpty()) { + mIsPolygon = false; + } + + mDescription.AppendCommand(GL_MOVE_TO_NV); + mDescription.AppendPoint(aPoint); + + mStartPoint = aPoint; + mCurrentPoint = aPoint; +} + +void +PathBuilderNVpr::LineTo(const Point& aPoint) +{ + MakeWritable(); + + if (mDescription.IsEmpty()) { + MoveTo(aPoint); + return; + } + + if (mDescription.mCommands.back() != GL_MOVE_TO_NV + && mDescription.mCommands.back() != GL_LINE_TO_NV) { + mIsPolygon = false; + } + + mDescription.AppendCommand(GL_LINE_TO_NV); + mDescription.AppendPoint(aPoint); + + mCurrentPoint = aPoint; +} + +void +PathBuilderNVpr::BezierTo(const Point& aCP1, + const Point& aCP2, + const Point& aCP3) +{ + MakeWritable(); + + if (mDescription.IsEmpty()) { + MoveTo(aCP1); + } + + mDescription.AppendCommand(GL_CUBIC_CURVE_TO_NV); + mDescription.AppendPoint(aCP1); + mDescription.AppendPoint(aCP2); + mDescription.AppendPoint(aCP3); + + mCurrentPoint = aCP3; + + mIsPolygon = false; +} + +void +PathBuilderNVpr::QuadraticBezierTo(const Point& aCP1, + const Point& aCP2) +{ + MakeWritable(); + + if (mDescription.IsEmpty()) { + MoveTo(aCP1); + } + + mDescription.AppendCommand(GL_QUADRATIC_CURVE_TO_NV); + mDescription.AppendPoint(aCP1); + mDescription.AppendPoint(aCP2); + + mCurrentPoint = aCP2; + + mIsPolygon = false; +} + +void +PathBuilderNVpr::Close() +{ + MakeWritable(); + + mDescription.AppendCommand(GL_CLOSE_PATH_NV); + + mCurrentPoint = mStartPoint; +} + +void +PathBuilderNVpr::Arc(const Point& aOrigin, Float aRadius, Float aStartAngle, + Float aEndAngle, bool aAntiClockwise) +{ + MakeWritable(); + + const Point startPoint(aOrigin.x + cos(aStartAngle) * aRadius, + aOrigin.y + sin(aStartAngle) * aRadius); + + // The spec says to begin with a line to the start point. + LineTo(startPoint); + + mIsPolygon = false; + + if (fabs(aEndAngle - aStartAngle) > 2 * M_PI - 1e-5) { + // The spec says to just draw the whole circle in this case. + mDescription.AppendCommand(GL_CIRCULAR_CCW_ARC_TO_NV); + mDescription.AppendPoint(aOrigin); + mDescription.AppendFloat(aRadius); + mDescription.AppendFloat(aStartAngle * 180 / M_PI); + mDescription.AppendFloat(360 + aStartAngle * 180 / M_PI); + return; + } + + const Point endPoint(aOrigin.x + cos(aEndAngle) * aRadius, + aOrigin.y + sin(aEndAngle) * aRadius); + + if (aAntiClockwise && aEndAngle < aStartAngle) { + aEndAngle += 2 * M_PI; + } else if (!aAntiClockwise && aEndAngle > aStartAngle) { + aEndAngle -= 2 * M_PI; + } + + // 'Anticlockwise' in HTML5 seems to be relative to a downward-pointing Y-axis, + // whereas CW/CCW are relative to an upward-facing Y-axis in NV_path_rendering. + if (fabs(aEndAngle - aStartAngle) < M_PI) { + mDescription.AppendCommand(aAntiClockwise ? GL_LARGE_CW_ARC_TO_NV + : GL_LARGE_CCW_ARC_TO_NV); + } else { + mDescription.AppendCommand(aAntiClockwise ? GL_SMALL_CW_ARC_TO_NV + : GL_SMALL_CCW_ARC_TO_NV); + } + mDescription.AppendFloat(aRadius); // x-radius + mDescription.AppendFloat(aRadius); // y-radius + mDescription.AppendFloat(0); + mDescription.AppendPoint(endPoint); + + mCurrentPoint = endPoint; +} + +Point +PathBuilderNVpr::CurrentPoint() const +{ + return mCurrentPoint; +} + +TemporaryRef +PathBuilderNVpr::Finish() +{ + if (mPathObject) { + MOZ_ASSERT(mDescription.IsEmpty()); + + // Client code called 'CopyToBuilder' and then didn't modify the path. + return new PathNVpr(mFillRule, mPathObject.forget()); + } + + PathCache& pathCache = gl->GetUserObject(&nvpr::UserData::mPathCache); + RefPtr& pathObject = pathCache[mDescription]; + + if (pathObject) { + return new PathNVpr(mFillRule, pathObject); + } + + if (mIsPolygon) { + vector points(mDescription.mCoords.size() / 2); + for (size_t i = 0; i < mDescription.mCoords.size(); i += 2) { + points.push_back(Point(mDescription.mCoords[i], + mDescription.mCoords[i + 1])); + } + + pathObject = new PathObjectNVpr(mDescription, mStartPoint, mCurrentPoint, + ConvexPolygon(points)); + } else { + pathObject = new PathObjectNVpr(mDescription, mStartPoint, mCurrentPoint); + } + + return new PathNVpr(mFillRule, pathObject); +} + +void +PathBuilderNVpr::MakeWritable() +{ + if (!mPathObject) { + return; + } + + MOZ_ASSERT(mDescription.IsEmpty()); + + gl->MakeCurrent(); + + GLint commandCount; + gl->GetPathParameterivNV(*mPathObject, GL_PATH_COMMAND_COUNT_NV, &commandCount); + mDescription.mCommands.resize(commandCount); + gl->GetPathCommandsNV(*mPathObject, mDescription.mCommands.data()); + + GLint coordCount; + gl->GetPathParameterivNV(*mPathObject, GL_PATH_COORD_COUNT_NV, &coordCount); + mDescription.mCoords.resize(coordCount); + gl->GetPathCoordsNV(*mPathObject, mDescription.mCoords.data()); + + mStartPoint = mPathObject->StartPoint(); + mCurrentPoint = mPathObject->CurrentPoint(); + + mPathObject = nullptr; +} + + +PathDescriptionNVpr::PathDescriptionNVpr(const PathDescriptionNVpr& aOther) + : mCommands(aOther.mCommands) + , mCoords(aOther.mCoords) +{ +} + +PathDescriptionNVpr::PathDescriptionNVpr(PathDescriptionNVpr&& aOther) +{ + swap(mCommands, aOther.mCommands); + swap(mCoords, aOther.mCoords); +} + +bool +PathDescriptionNVpr::operator <(const PathDescriptionNVpr& aOther) const +{ + if (mCoords.size() != aOther.mCoords.size()) { + return mCoords.size() < aOther.mCoords.size(); + } + + if (mCommands.size() != aOther.mCommands.size()) { + return mCommands.size() < aOther.mCommands.size(); + } + + for (size_t i = 0; i < mCoords.size(); i++) { + if (mCoords[i] != aOther.mCoords[i]) { + return mCoords[i] < aOther.mCoords[i]; + } + } + + for (size_t i = 0; i < mCommands.size(); i++) { + if (mCommands[i] != aOther.mCommands[i]) { + return mCommands[i] < aOther.mCommands[i]; + } + } + + // The path descriptions equal. + return false; +} + +} +} diff --git a/libazure/PathBuilderNVpr.h b/libazure/PathBuilderNVpr.h new file mode 100644 index 0000000..a5909d4 --- /dev/null +++ b/libazure/PathBuilderNVpr.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_PATHBUILDERNVPR_H_ +#define MOZILLA_GFX_PATHBUILDERNVPR_H_ + +#include "2D.h" +#include "nvpr/GL.h" +#include + +namespace mozilla { +namespace gfx { + +class PathObjectNVpr; + +/** + * This is basically just a wrapper for NV_path_rendering path commands. + * However, it also serves as the path cache's key data type. The path cache is + * a binary tree, so it uses this class's less-than operator to do its magic. + * Cache accesses are very quick because the less-than operator is an O(1) + * operation on average (we can almost always determine which of two path + * descriptions is "greater" by only looking at the lengths of the arrays, or + * the first couple of coordinates). + */ +struct PathDescriptionNVpr { + PathDescriptionNVpr() {} + + PathDescriptionNVpr(const PathDescriptionNVpr& aOther); + PathDescriptionNVpr(PathDescriptionNVpr&& aOther); + + bool operator <(const PathDescriptionNVpr& aOther) const; + + bool IsEmpty() const { return mCommands.empty() && mCoords.empty(); } + void Clear() { mCommands.clear(); mCoords.clear(); } + void AppendCommand(GLubyte aCommand) { mCommands.push_back(aCommand); } + void AppendPoint(const Point& aPt) { AppendFloat(aPt.x); AppendFloat(aPt.y); } + void AppendFloat(float aVal) { mCoords.push_back(aVal); } + + std::vector mCommands; + std::vector mCoords; +}; + +/** + * This is the NV_path_rendering-specific implementation for Azure's PathBuilder + * interface. A path builder generally has a PathDescriptionNVpr that it fills + * with commands. On Finish, it uses its path description to locate a saved GL + * path object in the draw target's path cache, or else create a new one. + * However, when Azure calls CopyToBuilder (or TransformedCopyToBuilder) on a + * path, this class just takes a reference to the existing GL path object. Once + * the client code actually tries to modify the path, it populates and begins + * using the path description, and releases the original GL path object. + */ +class PathBuilderNVpr : public PathBuilder +{ +public: + PathBuilderNVpr(FillRule aFillRule); + PathBuilderNVpr(FillRule aFillRule, TemporaryRef aPathObject); + PathBuilderNVpr(FillRule aFillRule, TemporaryRef aPathObject, + const Matrix& aTransform); + virtual ~PathBuilderNVpr(); + + virtual void MoveTo(const Point& aPoint); + virtual void LineTo(const Point& aPoint); + virtual void BezierTo(const Point& aCP1, + const Point& aCP2, + const Point& aCP3); + virtual void QuadraticBezierTo(const Point& aCP1, + const Point& aCP2); + virtual void Close(); + virtual void Arc(const Point& aOrigin, Float aRadius, Float aStartAngle, + Float aEndAngle, bool aAntiClockwise = false); + + virtual Point CurrentPoint() const; + + virtual TemporaryRef Finish(); + +private: + void MakeWritable(); + + const FillRule mFillRule; + RefPtr mPathObject; + PathDescriptionNVpr mDescription; + Point mStartPoint; + Point mCurrentPoint; + bool mIsPolygon; +}; + +} +} + +#endif /* MOZILLA_GFX_PATHBUILDERNVPR_H_ */ diff --git a/libazure/src/gfx/2d/PathCG.cpp b/libazure/PathCG.cpp similarity index 74% rename from libazure/src/gfx/2d/PathCG.cpp rename to libazure/PathCG.cpp index 191a403..d40f84f 100644 --- a/libazure/src/gfx/2d/PathCG.cpp +++ b/libazure/PathCG.cpp @@ -68,6 +68,20 @@ void PathBuilderCG::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, Float aEndAngle, bool aAntiClockwise) { + // Core Graphic's initial coordinate system is y-axis up, whereas Moz2D's is + // y-axis down. Core Graphics therefore considers "clockwise" to mean "sweep + // in the direction of decreasing angle" whereas Moz2D considers it to mean + // "sweep in the direction of increasing angle". In other words if this + // Moz2D method is instructed to sweep anti-clockwise we need to tell + // CGPathAddArc to sweep clockwise, and vice versa. Hence why we pass the + // value of aAntiClockwise directly to CGPathAddArc's "clockwise" bool + // parameter. + CGPathAddArc(mCGPath, nullptr, + aOrigin.x, aOrigin.y, + aRadius, + aStartAngle, + aEndAngle, + aAntiClockwise); } Point @@ -86,16 +100,14 @@ PathBuilderCG::EnsureActive(const Point &aPoint) TemporaryRef PathBuilderCG::Finish() { - RefPtr path = new PathCG(mCGPath, mFillRule); - return path; + return new PathCG(mCGPath, mFillRule); } TemporaryRef PathCG::CopyToBuilder(FillRule aFillRule) const { CGMutablePathRef path = CGPathCreateMutableCopy(mPath); - RefPtr builder = new PathBuilderCG(path, aFillRule); - return builder; + return new PathBuilderCG(path, aFillRule); } @@ -155,10 +167,57 @@ PathCG::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) c ta.transform = GfxMatrixToCGAffineTransform(aTransform); CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc); - RefPtr builder = new PathBuilderCG(ta.path, aFillRule); - return builder; + return new PathBuilderCG(ta.path, aFillRule); } +static void +StreamPathToSinkApplierFunc(void *vinfo, const CGPathElement *element) +{ + PathSink *sink = reinterpret_cast(vinfo); + switch (element->type) { + case kCGPathElementMoveToPoint: + { + CGPoint pt = element->points[0]; + sink->MoveTo(CGPointToPoint(pt)); + break; + } + case kCGPathElementAddLineToPoint: + { + CGPoint pt = element->points[0]; + sink->LineTo(CGPointToPoint(pt)); + break; + } + case kCGPathElementAddQuadCurveToPoint: + { + CGPoint cpt = element->points[0]; + CGPoint pt = element->points[1]; + sink->QuadraticBezierTo(CGPointToPoint(cpt), + CGPointToPoint(pt)); + break; + } + case kCGPathElementAddCurveToPoint: + { + CGPoint cpt1 = element->points[0]; + CGPoint cpt2 = element->points[1]; + CGPoint pt = element->points[2]; + sink->BezierTo(CGPointToPoint(cpt1), + CGPointToPoint(cpt2), + CGPointToPoint(pt)); + break; + } + case kCGPathElementCloseSubpath: + { + sink->Close(); + break; + } + } +} + +void +PathCG::StreamToSink(PathSink *aSink) const +{ + CGPathApply(mPath, aSink, StreamPathToSinkApplierFunc); +} bool PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const @@ -171,7 +230,7 @@ PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const // The transform parameter of CGPathContainsPoint doesn't seem to work properly on OS X 10.5 // so we transform aPoint ourselves. - return CGPathContainsPoint(mPath, nullptr, point, mFillRule == FILL_EVEN_ODD); + return CGPathContainsPoint(mPath, nullptr, point, mFillRule == FillRule::FILL_EVEN_ODD); } static size_t @@ -235,7 +294,8 @@ PathCG::GetBounds(const Matrix &aTransform) const { //XXX: are these bounds tight enough Rect bounds = CGRectToRect(CGPathGetBoundingBox(mPath)); - //XXX: curretnly this returns the bounds of the transformed bounds + + //XXX: currently this returns the bounds of the transformed bounds // this is strictly looser than the bounds of the transformed path return aTransform.TransformBounds(bounds); } @@ -260,6 +320,10 @@ PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions, CGContextRestoreGState(cg); + if (!bounds.IsFinite()) { + return Rect(); + } + return aTransform.TransformBounds(bounds); } diff --git a/libazure/src/gfx/2d/PathCG.h b/libazure/PathCG.h similarity index 83% rename from libazure/src/gfx/2d/PathCG.h rename to libazure/PathCG.h index 660e91d..615ad2c 100644 --- a/libazure/src/gfx/2d/PathCG.h +++ b/libazure/PathCG.h @@ -17,6 +17,7 @@ class PathCG; class PathBuilderCG : public PathBuilder { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderCG) // absorbs a reference of aPath PathBuilderCG(CGMutablePathRef aPath, FillRule aFillRule) : mFillRule(aFillRule) @@ -24,7 +25,7 @@ class PathBuilderCG : public PathBuilder mCGPath = aPath; } - PathBuilderCG(FillRule aFillRule) + explicit PathBuilderCG(FillRule aFillRule) : mFillRule(aFillRule) { mCGPath = CGPathCreateMutable(); @@ -60,6 +61,7 @@ class PathBuilderCG : public PathBuilder class PathCG : public Path { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCG) PathCG(CGMutablePathRef aPath, FillRule aFillRule) : mPath(aPath) , mFillRule(aFillRule) @@ -68,13 +70,13 @@ class PathCG : public Path } virtual ~PathCG() { CGPathRelease(mPath); } - // Paths will always return BACKEND_COREGRAPHICS, but note that they - // are compatible with BACKEND_COREGRAPHICS_ACCELERATED backend. - virtual BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; } + // Paths will always return BackendType::COREGRAPHICS, but note that they + // are compatible with BackendType::COREGRAPHICS_ACCELERATED backend. + virtual BackendType GetBackendType() const { return BackendType::COREGRAPHICS; } - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const; + FillRule aFillRule = FillRule::FILL_WINDING) const; virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, @@ -84,6 +86,8 @@ class PathCG : public Path virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform = Matrix()) const; + virtual void StreamToSink(PathSink *aSink) const; + virtual FillRule GetFillRule() const { return mFillRule; } CGMutablePathRef GetPath() const { return mPath; } @@ -92,7 +96,6 @@ class PathCG : public Path friend class DrawTargetCG; CGMutablePathRef mPath; - bool mEndedActive; Point mEndPoint; FillRule mFillRule; }; diff --git a/libazure/PathCairo.cpp b/libazure/PathCairo.cpp new file mode 100644 index 0000000..d0c9d05 --- /dev/null +++ b/libazure/PathCairo.cpp @@ -0,0 +1,323 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PathCairo.h" +#include +#include "DrawTargetCairo.h" +#include "Logging.h" +#include "PathHelpers.h" +#include "HelpersCairo.h" + +namespace mozilla { +namespace gfx { + +PathBuilderCairo::PathBuilderCairo(FillRule aFillRule) + : mFillRule(aFillRule) +{ +} + +void +PathBuilderCairo::MoveTo(const Point &aPoint) +{ + cairo_path_data_t data; + data.header.type = CAIRO_PATH_MOVE_TO; + data.header.length = 2; + mPathData.push_back(data); + data.point.x = aPoint.x; + data.point.y = aPoint.y; + mPathData.push_back(data); + + mBeginPoint = mCurrentPoint = aPoint; +} + +void +PathBuilderCairo::LineTo(const Point &aPoint) +{ + cairo_path_data_t data; + data.header.type = CAIRO_PATH_LINE_TO; + data.header.length = 2; + mPathData.push_back(data); + data.point.x = aPoint.x; + data.point.y = aPoint.y; + mPathData.push_back(data); + + mCurrentPoint = aPoint; +} + +void +PathBuilderCairo::BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3) +{ + cairo_path_data_t data; + data.header.type = CAIRO_PATH_CURVE_TO; + data.header.length = 4; + mPathData.push_back(data); + data.point.x = aCP1.x; + data.point.y = aCP1.y; + mPathData.push_back(data); + data.point.x = aCP2.x; + data.point.y = aCP2.y; + mPathData.push_back(data); + data.point.x = aCP3.x; + data.point.y = aCP3.y; + mPathData.push_back(data); + + mCurrentPoint = aCP3; +} + +void +PathBuilderCairo::QuadraticBezierTo(const Point &aCP1, + const Point &aCP2) +{ + // We need to elevate the degree of this quadratic Bézier to cubic, so we're + // going to add an intermediate control point, and recompute control point 1. + // The first and last control points remain the same. + // This formula can be found on http://fontforge.sourceforge.net/bezier.html + Point CP0 = CurrentPoint(); + Point CP1 = (CP0 + aCP1 * 2.0) / 3.0; + Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0; + Point CP3 = aCP2; + + cairo_path_data_t data; + data.header.type = CAIRO_PATH_CURVE_TO; + data.header.length = 4; + mPathData.push_back(data); + data.point.x = CP1.x; + data.point.y = CP1.y; + mPathData.push_back(data); + data.point.x = CP2.x; + data.point.y = CP2.y; + mPathData.push_back(data); + data.point.x = CP3.x; + data.point.y = CP3.y; + mPathData.push_back(data); + + mCurrentPoint = aCP2; +} + +void +PathBuilderCairo::Close() +{ + cairo_path_data_t data; + data.header.type = CAIRO_PATH_CLOSE_PATH; + data.header.length = 1; + mPathData.push_back(data); + + mCurrentPoint = mBeginPoint; +} + +void +PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise) +{ + ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise); +} + +Point +PathBuilderCairo::CurrentPoint() const +{ + return mCurrentPoint; +} + +TemporaryRef +PathBuilderCairo::Finish() +{ + return new PathCairo(mFillRule, mPathData, mCurrentPoint); +} + +PathCairo::PathCairo(FillRule aFillRule, std::vector &aPathData, const Point &aCurrentPoint) + : mFillRule(aFillRule) + , mContainingContext(nullptr) + , mCurrentPoint(aCurrentPoint) +{ + mPathData.swap(aPathData); +} + +PathCairo::PathCairo(cairo_t *aContext) + : mFillRule(FillRule::FILL_WINDING) + , mContainingContext(nullptr) +{ + cairo_path_t *path = cairo_copy_path(aContext); + + // XXX - mCurrentPoint is not properly set here, the same is true for the + // D2D Path code, we never require current point when hitting this codepath + // but this should be fixed. + for (int i = 0; i < path->num_data; i++) { + mPathData.push_back(path->data[i]); + } + + cairo_path_destroy(path); +} + +PathCairo::~PathCairo() +{ + if (mContainingContext) { + cairo_destroy(mContainingContext); + } +} + +TemporaryRef +PathCairo::CopyToBuilder(FillRule aFillRule) const +{ + RefPtr builder = new PathBuilderCairo(aFillRule); + + builder->mPathData = mPathData; + builder->mCurrentPoint = mCurrentPoint; + + return builder.forget(); +} + +TemporaryRef +PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const +{ + RefPtr builder = new PathBuilderCairo(aFillRule); + + AppendPathToBuilder(builder, &aTransform); + builder->mCurrentPoint = aTransform * mCurrentPoint; + + return builder.forget(); +} + +bool +PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformed = inverse * aPoint; + + EnsureContainingContext(); + + return cairo_in_fill(mContainingContext, transformed.x, transformed.y); +} + +bool +PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, + const Point &aPoint, + const Matrix &aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformed = inverse * aPoint; + + EnsureContainingContext(); + + SetCairoStrokeOptions(mContainingContext, aStrokeOptions); + + return cairo_in_stroke(mContainingContext, transformed.x, transformed.y); +} + +Rect +PathCairo::GetBounds(const Matrix &aTransform) const +{ + EnsureContainingContext(); + + double x1, y1, x2, y2; + + cairo_path_extents(mContainingContext, &x1, &y1, &x2, &y2); + Rect bounds(Float(x1), Float(y1), Float(x2 - x1), Float(y2 - y1)); + return aTransform.TransformBounds(bounds); +} + +Rect +PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions, + const Matrix &aTransform) const +{ + EnsureContainingContext(); + + double x1, y1, x2, y2; + + SetCairoStrokeOptions(mContainingContext, aStrokeOptions); + + cairo_stroke_extents(mContainingContext, &x1, &y1, &x2, &y2); + Rect bounds((Float)x1, (Float)y1, (Float)(x2 - x1), (Float)(y2 - y1)); + return aTransform.TransformBounds(bounds); +} + +void +PathCairo::StreamToSink(PathSink *aSink) const +{ + for (size_t i = 0; i < mPathData.size(); i++) { + switch (mPathData[i].header.type) { + case CAIRO_PATH_MOVE_TO: + i++; + aSink->MoveTo(Point(mPathData[i].point.x, mPathData[i].point.y)); + break; + case CAIRO_PATH_LINE_TO: + i++; + aSink->LineTo(Point(mPathData[i].point.x, mPathData[i].point.y)); + break; + case CAIRO_PATH_CURVE_TO: + aSink->BezierTo(Point(mPathData[i + 1].point.x, mPathData[i + 1].point.y), + Point(mPathData[i + 2].point.x, mPathData[i + 2].point.y), + Point(mPathData[i + 3].point.x, mPathData[i + 3].point.y)); + i += 3; + break; + case CAIRO_PATH_CLOSE_PATH: + aSink->Close(); + break; + default: + // Corrupt path data! + MOZ_ASSERT(false); + } + } +} + +void +PathCairo::EnsureContainingContext() const +{ + if (mContainingContext) { + return; + } + + mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface()); + + SetPathOnContext(mContainingContext); +} + +void +PathCairo::SetPathOnContext(cairo_t *aContext) const +{ + // Needs the correct fill rule set. + cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule)); + + cairo_new_path(aContext); + + if (mPathData.size()) { + cairo_path_t path; + path.data = const_cast(&mPathData.front()); + path.num_data = mPathData.size(); + path.status = CAIRO_STATUS_SUCCESS; + cairo_append_path(aContext, &path); + } +} + +void +PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const +{ + if (aTransform) { + size_t i = 0; + while (i < mPathData.size()) { + uint32_t pointCount = mPathData[i].header.length - 1; + aBuilder->mPathData.push_back(mPathData[i]); + i++; + for (uint32_t c = 0; c < pointCount; c++) { + cairo_path_data_t data; + Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y); + data.point.x = newPoint.x; + data.point.y = newPoint.y; + aBuilder->mPathData.push_back(data); + i++; + } + } + } else { + for (size_t i = 0; i < mPathData.size(); i++) { + aBuilder->mPathData.push_back(mPathData[i]); + } + } +} + +} +} diff --git a/libazure/PathCairo.h b/libazure/PathCairo.h new file mode 100644 index 0000000..6227a21 --- /dev/null +++ b/libazure/PathCairo.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_PATH_CAIRO_H_ +#define MOZILLA_GFX_PATH_CAIRO_H_ + +#include "2D.h" +#include "cairo.h" +#include + +namespace mozilla { +namespace gfx { + +class DrawTargetCairo; +class PathCairo; + +class PathBuilderCairo : public PathBuilder +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderCairo) + explicit PathBuilderCairo(FillRule aFillRule); + + virtual void MoveTo(const Point &aPoint); + virtual void LineTo(const Point &aPoint); + virtual void BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3); + virtual void QuadraticBezierTo(const Point &aCP1, + const Point &aCP2); + virtual void Close(); + virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise = false); + virtual Point CurrentPoint() const; + virtual TemporaryRef Finish(); + +private: // data + friend class PathCairo; + + FillRule mFillRule; + std::vector mPathData; + // It's easiest to track this here, parsing the path data to find the current + // point is a little tricky. + Point mCurrentPoint; + Point mBeginPoint; +}; + +class PathCairo : public Path +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCairo) + PathCairo(FillRule aFillRule, std::vector &aPathData, const Point &aCurrentPoint); + explicit PathCairo(cairo_t *aContext); + ~PathCairo(); + + virtual BackendType GetBackendType() const { return BackendType::CAIRO; } + + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; + virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, + FillRule aFillRule = FillRule::FILL_WINDING) const; + + virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; + + virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, + const Point &aPoint, + const Matrix &aTransform) const; + + virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const; + + virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, + const Matrix &aTransform = Matrix()) const; + + virtual void StreamToSink(PathSink *aSink) const; + + virtual FillRule GetFillRule() const { return mFillRule; } + + void SetPathOnContext(cairo_t *aContext) const; + + void AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform = nullptr) const; +private: + void EnsureContainingContext() const; + + FillRule mFillRule; + std::vector mPathData; + mutable cairo_t *mContainingContext; + Point mCurrentPoint; +}; + +} +} + +#endif /* MOZILLA_GFX_PATH_CAIRO_H_ */ diff --git a/libazure/src/gfx/2d/PathD2D.cpp b/libazure/PathD2D.cpp similarity index 77% rename from libazure/src/gfx/2d/PathD2D.cpp rename to libazure/PathD2D.cpp index 69431e0..3a58395 100644 --- a/libazure/src/gfx/2d/PathD2D.cpp +++ b/libazure/PathD2D.cpp @@ -91,6 +91,70 @@ class OpeningGeometrySink : public ID2D1SimplifiedGeometrySink bool mNeedsFigureEnded; }; +class StreamingGeometrySink : public ID2D1SimplifiedGeometrySink +{ +public: + StreamingGeometrySink(PathSink *aSink) + : mSink(aSink) + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(const IID &aIID, void **aPtr) + { + if (!aPtr) { + return E_POINTER; + } + + if (aIID == IID_IUnknown) { + *aPtr = static_cast(this); + return S_OK; + } else if (aIID == IID_ID2D1SimplifiedGeometrySink) { + *aPtr = static_cast(this); + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + + // We ignore SetFillMode, this depends on the destination sink. + STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE aMode) + { return; } + STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F aPoint, D2D1_FIGURE_BEGIN aBegin) + { mSink->MoveTo(ToPoint(aPoint)); } + STDMETHOD_(void, AddLines)(const D2D1_POINT_2F *aLines, UINT aCount) + { for (int i = 0; i < aCount; i++) { mSink->LineTo(ToPoint(aLines[i])); } } + STDMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *aSegments, UINT aCount) + { + for (int i = 0; i < aCount; i++) { + mSink->BezierTo(ToPoint(aSegments[i].point1), ToPoint(aSegments[i].point2), ToPoint(aSegments[i].point3)); + } + } + STDMETHOD(Close)() + { /* Should never be called! */ return S_OK; } + STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT aFlags) + { /* Should never be called! */ } + + STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END aEnd) + { + if (aEnd == D2D1_FIGURE_END_CLOSED) { + return mSink->Close(); + } + } +private: + + PathSink *mSink; +}; + PathBuilderD2D::~PathBuilderD2D() { } @@ -266,7 +330,7 @@ PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) return nullptr; } - if (aFillRule == FILL_WINDING) { + if (aFillRule == FillRule::FILL_WINDING) { sink->SetFillMode(D2D1_FILL_MODE_WINDING); } @@ -289,7 +353,7 @@ PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) pathBuilder->mFigureActive = true; } - return pathBuilder; + return pathBuilder.forget(); } bool @@ -314,8 +378,7 @@ PathD2D::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, { BOOL result; - RefPtr strokeStyle = - DrawTargetD2D::CreateStrokeStyleForOptions(aStrokeOptions); + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); HRESULT hr = mGeometry->StrokeContainsPoint(D2DPoint(aPoint), aStrokeOptions.mLineWidth, strokeStyle, @@ -333,36 +396,53 @@ PathD2D::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, Rect PathD2D::GetBounds(const Matrix &aTransform) const { - D2D1_RECT_F bounds; + D2D1_RECT_F d2dBounds; - HRESULT hr = mGeometry->GetBounds(D2DMatrix(aTransform), &bounds); + HRESULT hr = mGeometry->GetBounds(D2DMatrix(aTransform), &d2dBounds); - if (FAILED(hr)) { + Rect bounds = ToRect(d2dBounds); + if (FAILED(hr) || !bounds.IsFinite()) { gfxWarning() << "Failed to get stroked bounds for path. Code: " << hr; - bounds.bottom = bounds.left = bounds.right = bounds.top = 0; + return Rect(); } - return ToRect(bounds); + return bounds; } Rect PathD2D::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { - D2D1_RECT_F bounds; + D2D1_RECT_F d2dBounds; - RefPtr strokeStyle = - DrawTargetD2D::CreateStrokeStyleForOptions(aStrokeOptions); + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); HRESULT hr = mGeometry->GetWidenedBounds(aStrokeOptions.mLineWidth, strokeStyle, - D2DMatrix(aTransform), &bounds); + D2DMatrix(aTransform), &d2dBounds); - if (FAILED(hr)) { + Rect bounds = ToRect(d2dBounds); + if (FAILED(hr) || !bounds.IsFinite()) { gfxWarning() << "Failed to get stroked bounds for path. Code: " << hr; - bounds.bottom = bounds.left = bounds.right = bounds.top = 0; + return Rect(); } - return ToRect(bounds); + return bounds; +} + +void +PathD2D::StreamToSink(PathSink *aSink) const +{ + HRESULT hr; + + StreamingGeometrySink sink(aSink); + + hr = mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + D2D1::IdentityMatrix(), &sink); + + if (FAILED(hr)) { + gfxWarning() << "Failed to stream D2D path to sink. Code: " << hr; + return; + } } } diff --git a/libazure/src/gfx/2d/PathD2D.h b/libazure/PathD2D.h similarity index 88% rename from libazure/src/gfx/2d/PathD2D.h rename to libazure/PathD2D.h index 9b72b6c..d27f174 100644 --- a/libazure/src/gfx/2d/PathD2D.h +++ b/libazure/PathD2D.h @@ -6,8 +6,9 @@ #ifndef MOZILLA_GFX_PATHD2D_H_ #define MOZILLA_GFX_PATHD2D_H_ +#include + #include "2D.h" -#include "moz-d2d1-1.h" namespace mozilla { namespace gfx { @@ -17,6 +18,7 @@ class PathD2D; class PathBuilderD2D : public PathBuilder { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderD2D) PathBuilderD2D(ID2D1GeometrySink *aSink, ID2D1PathGeometry *aGeom, FillRule aFillRule) : mSink(aSink) , mGeometry(aGeom) @@ -59,6 +61,7 @@ class PathBuilderD2D : public PathBuilder class PathD2D : public Path { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathD2D) PathD2D(ID2D1PathGeometry *aGeometry, bool aEndedActive, const Point &aEndPoint, FillRule aFillRule) : mGeometry(aGeometry) @@ -67,11 +70,11 @@ class PathD2D : public Path , mFillRule(aFillRule) {} - virtual BackendType GetBackendType() const { return BACKEND_DIRECT2D; } + virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; } - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const; + FillRule aFillRule = FillRule::FILL_WINDING) const; virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; @@ -84,12 +87,15 @@ class PathD2D : public Path virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform = Matrix()) const; + virtual void StreamToSink(PathSink *aSink) const; + virtual FillRule GetFillRule() const { return mFillRule; } ID2D1Geometry *GetGeometry() { return mGeometry; } private: friend class DrawTargetD2D; + friend class DrawTargetD2D1; mutable RefPtr mGeometry; bool mEndedActive; diff --git a/libazure/PathHelpers.cpp b/libazure/PathHelpers.cpp new file mode 100644 index 0000000..8737937 --- /dev/null +++ b/libazure/PathHelpers.cpp @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PathHelpers.h" + +namespace mozilla { +namespace gfx { + +void +AppendRoundedRectToPath(PathBuilder* aPathBuilder, + const Rect& aRect, + // paren's needed due to operator precedence: + const Size(& aCornerRadii)[4], + bool aDrawClockwise) +{ + // For CW drawing, this looks like: + // + // ...******0** 1 C + // **** + // *** 2 + // ** + // * + // * + // 3 + // * + // * + // + // Where 0, 1, 2, 3 are the control points of the Bezier curve for + // the corner, and C is the actual corner point. + // + // At the start of the loop, the current point is assumed to be + // the point adjacent to the top left corner on the top + // horizontal. Note that corner indices start at the top left and + // continue clockwise, whereas in our loop i = 0 refers to the top + // right corner. + // + // When going CCW, the control points are swapped, and the first + // corner that's drawn is the top left (along with the top segment). + // + // There is considerable latitude in how one chooses the four + // control points for a Bezier curve approximation to an ellipse. + // For the overall path to be continuous and show no corner at the + // endpoints of the arc, points 0 and 3 must be at the ends of the + // straight segments of the rectangle; points 0, 1, and C must be + // collinear; and points 3, 2, and C must also be collinear. This + // leaves only two free parameters: the ratio of the line segments + // 01 and 0C, and the ratio of the line segments 32 and 3C. See + // the following papers for extensive discussion of how to choose + // these ratios: + // + // Dokken, Tor, et al. "Good approximation of circles by + // curvature-continuous Bezier curves." Computer-Aided + // Geometric Design 7(1990) 33--41. + // Goldapp, Michael. "Approximation of circular arcs by cubic + // polynomials." Computer-Aided Geometric Design 8(1991) 227--238. + // Maisonobe, Luc. "Drawing an elliptical arc using polylines, + // quadratic, or cubic Bezier curves." + // http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf + // + // We follow the approach in section 2 of Goldapp (least-error, + // Hermite-type approximation) and make both ratios equal to + // + // 2 2 + n - sqrt(2n + 28) + // alpha = - * --------------------- + // 3 n - 4 + // + // where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ). + // + // This is the result of Goldapp's equation (10b) when the angle + // swept out by the arc is pi/2, and the parameter "a-bar" is the + // expression given immediately below equation (21). + // + // Using this value, the maximum radial error for a circle, as a + // fraction of the radius, is on the order of 0.2 x 10^-3. + // Neither Dokken nor Goldapp discusses error for a general + // ellipse; Maisonobe does, but his choice of control points + // follows different constraints, and Goldapp's expression for + // 'alpha' gives much smaller radial error, even for very flat + // ellipses, than Maisonobe's equivalent. + // + // For the various corners and for each axis, the sign of this + // constant changes, or it might be 0 -- it's multiplied by the + // appropriate multiplier from the list before using. + + const Float alpha = Float(0.55191497064665766025); + + typedef struct { Float a, b; } twoFloats; + + twoFloats cwCornerMults[4] = { { -1, 0 }, // cc == clockwise + { 0, -1 }, + { +1, 0 }, + { 0, +1 } }; + twoFloats ccwCornerMults[4] = { { +1, 0 }, // ccw == counter-clockwise + { 0, -1 }, + { -1, 0 }, + { 0, +1 } }; + + twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults; + + Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(), + aRect.BottomRight(), aRect.BottomLeft() }; + + Point pc, p0, p1, p2, p3; + + // The indexes of the corners: + const int kTopLeft = 0, kTopRight = 1; + + if (aDrawClockwise) { + aPathBuilder->MoveTo(Point(aRect.X() + aCornerRadii[kTopLeft].width, + aRect.Y())); + } else { + aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aCornerRadii[kTopRight].width, + aRect.Y())); + } + + for (int i = 0; i < 4; ++i) { + // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw) + int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4); + + // i+2 and i+3 respectively. These are used to index into the corner + // multiplier table, and were deduced by calculating out the long form + // of each corner and finding a pattern in the signs and values. + int i2 = (i+2) % 4; + int i3 = (i+3) % 4; + + pc = cornerCoords[c]; + + if (aCornerRadii[c].width > 0.0 && aCornerRadii[c].height > 0.0) { + p0.x = pc.x + cornerMults[i].a * aCornerRadii[c].width; + p0.y = pc.y + cornerMults[i].b * aCornerRadii[c].height; + + p3.x = pc.x + cornerMults[i3].a * aCornerRadii[c].width; + p3.y = pc.y + cornerMults[i3].b * aCornerRadii[c].height; + + p1.x = p0.x + alpha * cornerMults[i2].a * aCornerRadii[c].width; + p1.y = p0.y + alpha * cornerMults[i2].b * aCornerRadii[c].height; + + p2.x = p3.x - alpha * cornerMults[i3].a * aCornerRadii[c].width; + p2.y = p3.y - alpha * cornerMults[i3].b * aCornerRadii[c].height; + + aPathBuilder->LineTo(p0); + aPathBuilder->BezierTo(p1, p2, p3); + } else { + aPathBuilder->LineTo(pc); + } + } + + aPathBuilder->Close(); +} + +void +AppendEllipseToPath(PathBuilder* aPathBuilder, + const Point& aCenter, + const Size& aDimensions) +{ + Size halfDim = aDimensions / 2.0; + Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions); + Size radii[] = { halfDim, halfDim, halfDim, halfDim }; + + AppendRoundedRectToPath(aPathBuilder, rect, radii); +} + +} // namespace gfx +} // namespace mozilla + diff --git a/libazure/PathHelpers.h b/libazure/PathHelpers.h new file mode 100644 index 0000000..80963cd --- /dev/null +++ b/libazure/PathHelpers.h @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_PATHHELPERS_H_ +#define MOZILLA_GFX_PATHHELPERS_H_ + +#include "2D.h" +#include "mozilla/Constants.h" + +namespace mozilla { +namespace gfx { + +template +void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius, + float aStartAngle, float aEndAngle, bool aAntiClockwise) +{ + Point startPoint(aOrigin.x + cosf(aStartAngle) * aRadius.width, + aOrigin.y + sinf(aStartAngle) * aRadius.height); + + aSink->LineTo(startPoint); + + // Clockwise we always sweep from the smaller to the larger angle, ccw + // it's vice versa. + if (!aAntiClockwise && (aEndAngle < aStartAngle)) { + Float correction = Float(ceil((aStartAngle - aEndAngle) / (2.0f * M_PI))); + aEndAngle += float(correction * 2.0f * M_PI); + } else if (aAntiClockwise && (aStartAngle < aEndAngle)) { + Float correction = (Float)ceil((aEndAngle - aStartAngle) / (2.0f * M_PI)); + aStartAngle += float(correction * 2.0f * M_PI); + } + + // Sweeping more than 2 * pi is a full circle. + if (!aAntiClockwise && (aEndAngle - aStartAngle > 2 * M_PI)) { + aEndAngle = float(aStartAngle + 2.0f * M_PI); + } else if (aAntiClockwise && (aStartAngle - aEndAngle > 2.0f * M_PI)) { + aEndAngle = float(aStartAngle - 2.0f * M_PI); + } + + // Calculate the total arc we're going to sweep. + Float arcSweepLeft = fabs(aEndAngle - aStartAngle); + + Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f; + + Float currentStartAngle = aStartAngle; + + while (arcSweepLeft > 0) { + // We guarantee here the current point is the start point of the next + // curve segment. + Float currentEndAngle; + + if (arcSweepLeft > M_PI / 2.0f) { + currentEndAngle = Float(currentStartAngle + M_PI / 2.0f * sweepDirection); + } else { + currentEndAngle = currentStartAngle + arcSweepLeft * sweepDirection; + } + + Point currentStartPoint(aOrigin.x + cosf(currentStartAngle) * aRadius.width, + aOrigin.y + sinf(currentStartAngle) * aRadius.height); + Point currentEndPoint(aOrigin.x + cosf(currentEndAngle) * aRadius.width, + aOrigin.y + sinf(currentEndAngle) * aRadius.height); + + // Calculate kappa constant for partial curve. The sign of angle in the + // tangent will actually ensure this is negative for a counter clockwise + // sweep, so changing signs later isn't needed. + Float kappaFactor = (4.0f / 3.0f) * tan((currentEndAngle - currentStartAngle) / 4.0f); + Float kappaX = kappaFactor * aRadius.width; + Float kappaY = kappaFactor * aRadius.height; + + Point tangentStart(-sin(currentStartAngle), cos(currentStartAngle)); + Point cp1 = currentStartPoint; + cp1 += Point(tangentStart.x * kappaX, tangentStart.y * kappaY); + + Point revTangentEnd(sin(currentEndAngle), -cos(currentEndAngle)); + Point cp2 = currentEndPoint; + cp2 += Point(revTangentEnd.x * kappaX, revTangentEnd.y * kappaY); + + aSink->BezierTo(cp1, cp2, currentEndPoint); + + arcSweepLeft -= Float(M_PI / 2.0f); + currentStartAngle = currentEndAngle; + } +} + +/* This is basically the ArcToBezier with the parameters for drawing a circle + * inlined which vastly simplifies it and avoids a bunch of transcedental function + * calls which should make it faster. */ +template +void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius) +{ + Point startPoint(aOrigin.x + aRadius.width, + aOrigin.y); + + aSink->LineTo(startPoint); + + // Calculate kappa constant for partial curve. The sign of angle in the + // tangent will actually ensure this is negative for a counter clockwise + // sweep, so changing signs later isn't needed. + Float kappaFactor = (4.0f / 3.0f) * tan((M_PI/2.0f) / 4.0f); + Float kappaX = kappaFactor * aRadius.width; + Float kappaY = kappaFactor * aRadius.height; + Float cosStartAngle = 1; + Float sinStartAngle = 0; + for (int i = 0; i < 4; i++) { + // We guarantee here the current point is the start point of the next + // curve segment. + Point currentStartPoint(aOrigin.x + cosStartAngle * aRadius.width, + aOrigin.y + sinStartAngle * aRadius.height); + Point currentEndPoint(aOrigin.x + -sinStartAngle * aRadius.width, + aOrigin.y + cosStartAngle * aRadius.height); + + Point tangentStart(-sinStartAngle, cosStartAngle); + Point cp1 = currentStartPoint; + cp1 += Point(tangentStart.x * kappaX, tangentStart.y * kappaY); + + Point revTangentEnd(cosStartAngle, sinStartAngle); + Point cp2 = currentEndPoint; + cp2 += Point(revTangentEnd.x * kappaX, revTangentEnd.y * kappaY); + + aSink->BezierTo(cp1, cp2, currentEndPoint); + + // cos(x+pi/2) == -sin(x) + // sin(x+pi/2) == cos(x) + Float tmp = cosStartAngle; + cosStartAngle = -sinStartAngle; + sinStartAngle = tmp; + } +} + +/** + * Appends a path represending a rounded rectangle to the path being built by + * aPathBuilder. + * + * aRect The rectangle to append. + * aCornerRadii Contains the radii of the top-left, top-right, bottom-right + * and bottom-left corners, in that order. + * aDrawClockwise If set to true, the path will start at the left of the top + * left edge and draw clockwise. If set to false the path will + * start at the right of the top left edge and draw counter- + * clockwise. + */ +GFX2D_API void AppendRoundedRectToPath(PathBuilder* aPathBuilder, + const Rect& aRect, + const Size(& aCornerRadii)[4], + bool aDrawClockwise = true); + +/** + * Appends a path represending an ellipse to the path being built by + * aPathBuilder. + * + * The ellipse extends aDimensions.width / 2.0 in the horizontal direction + * from aCenter, and aDimensions.height / 2.0 in the vertical direction. + */ +GFX2D_API void AppendEllipseToPath(PathBuilder* aPathBuilder, + const Point& aCenter, + const Size& aDimensions); + +static inline bool +UserToDevicePixelSnapped(Rect& aRect, const Matrix& aTransform) +{ + Point p1 = aTransform * aRect.TopLeft(); + Point p2 = aTransform * aRect.TopRight(); + Point p3 = aTransform * aRect.BottomRight(); + + // Check that the rectangle is axis-aligned. For an axis-aligned rectangle, + // two opposite corners define the entire rectangle. So check if + // the axis-aligned rectangle with opposite corners p1 and p3 + // define an axis-aligned rectangle whose other corners are p2 and p4. + // We actually only need to check one of p2 and p4, since an affine + // transform maps parallelograms to parallelograms. + if (p2 == Point(p1.x, p3.y) || p2 == Point(p3.x, p1.y)) { + p1.Round(); + p3.Round(); + + aRect.MoveTo(Point(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); + aRect.SizeTo(Size(std::max(p1.x, p3.x) - aRect.X(), + std::max(p1.y, p3.y) - aRect.Y())); + return true; + } + + return false; +} + +} // namespace gfx +} // namespace mozilla + +#endif /* MOZILLA_GFX_PATHHELPERS_H_ */ diff --git a/libazure/PathNVpr.cpp b/libazure/PathNVpr.cpp new file mode 100644 index 0000000..14d4045 --- /dev/null +++ b/libazure/PathNVpr.cpp @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PathNVpr.h" +#include "PathBuilderNVpr.h" +#include "Line.h" + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +PathObjectNVpr::PathObjectNVpr(const PathDescriptionNVpr& aDescription, + const Point& aStartPoint, + const Point& aCurrentPoint, + ConvexPolygon&& aPassPolygon) + : mStartPoint(aStartPoint) + , mCurrentPoint(aCurrentPoint) + , mStencilClipBits(0) + , mStrokeWidth(1) + , mMiterLimit(4) + , mDashOffset(0) + , mJoinStyle(JoinStyle::MITER_OR_BEVEL) + , mCapStyle(CapStyle::BUTT) +{ + mPolygon.Swap(aPassPolygon); + + gl->MakeCurrent(); + mObject = gl->GenPathsNV(1); + gl->PathCommandsNV(mObject, aDescription.mCommands.size(), + aDescription.mCommands.data(), aDescription.mCoords.size(), + GL_FLOAT, aDescription.mCoords.data()); +} + +PathObjectNVpr::PathObjectNVpr(const PathObjectNVpr& aPathObject, + const Matrix& aTransform) + : mStartPoint(aTransform * aPathObject.mStartPoint) + , mCurrentPoint(aTransform * aPathObject.mCurrentPoint) + , mStencilClipBits(0) + , mStrokeWidth(aPathObject.mStrokeWidth) + , mMiterLimit(aPathObject.mMiterLimit) + , mDashOffset(aPathObject.mDashOffset) + , mJoinStyle(aPathObject.mJoinStyle) + , mCapStyle(aPathObject.mCapStyle) +{ + mPolygon = aPathObject.mPolygon; + mPolygon.Transform(aTransform); + + gl->MakeCurrent(); + + GLfloat transform[] = { + aTransform._11, aTransform._21, aTransform._31, + aTransform._12, aTransform._22, aTransform._32 + }; + + mObject = gl->GenPathsNV(1); + gl->TransformPathNV(mObject, aPathObject.mObject, GL_AFFINE_2D_NV, transform); +} + +PathObjectNVpr::~PathObjectNVpr() +{ + gl->MakeCurrent(); + gl->DeletePathsNV(mObject, 1); +} + +void PathObjectNVpr::ApplyStrokeOptions(const StrokeOptions& aStrokeOptions) +{ + MOZ_ASSERT(gl->IsCurrent()); + + if (mStrokeWidth != aStrokeOptions.mLineWidth) { + gl->PathParameterfNV(mObject, GL_PATH_STROKE_WIDTH_NV, aStrokeOptions.mLineWidth); + mStrokeWidth = aStrokeOptions.mLineWidth; + } + + if (mMiterLimit != aStrokeOptions.mMiterLimit) { + gl->PathParameterfNV(mObject, GL_PATH_MITER_LIMIT_NV, aStrokeOptions.mMiterLimit); + mMiterLimit = aStrokeOptions.mMiterLimit; + } + + if (mDashOffset != aStrokeOptions.mDashOffset) { + gl->PathParameterfNV(mObject, GL_PATH_DASH_OFFSET_NV, aStrokeOptions.mDashOffset); + mDashOffset = aStrokeOptions.mDashOffset; + } + + if (mJoinStyle != aStrokeOptions.mLineJoin) { + GLenum newJoinStyle; + switch (aStrokeOptions.mLineJoin) { + default: + MOZ_ASSERT(!"Invalid line join style in StrokeOptions"); + case JoinStyle::MITER_OR_BEVEL: + newJoinStyle = GL_MITER_REVERT_NV; + break; + case JoinStyle::MITER: + newJoinStyle = GL_MITER_TRUNCATE_NV; + break; + case JoinStyle::ROUND: + newJoinStyle = GL_ROUND_NV; + break; + case JoinStyle::BEVEL: + newJoinStyle = GL_BEVEL_NV; + break; + } + + gl->PathParameteriNV(mObject, GL_PATH_JOIN_STYLE_NV, newJoinStyle); + + mJoinStyle = aStrokeOptions.mLineJoin; + } + + if (mCapStyle != aStrokeOptions.mLineCap) { + GLenum newCapStyle; + switch (aStrokeOptions.mLineCap) { + default: + MOZ_ASSERT(!"Invalid line cap style in StrokeOptions"); + case CapStyle::BUTT: + newCapStyle = GL_FLAT; + break; + case CapStyle::ROUND: + newCapStyle = GL_ROUND_NV; + break; + case CapStyle::SQUARE: + newCapStyle = GL_SQUARE_NV; + break; + } + + gl->PathParameteriNV(mObject, GL_PATH_INITIAL_END_CAP_NV, newCapStyle); + gl->PathParameteriNV(mObject, GL_PATH_TERMINAL_END_CAP_NV, newCapStyle); + gl->PathParameteriNV(mObject, GL_PATH_INITIAL_DASH_CAP_NV, newCapStyle); + gl->PathParameteriNV(mObject, GL_PATH_TERMINAL_DASH_CAP_NV, newCapStyle); + + mCapStyle = aStrokeOptions.mLineCap; + } + + MOZ_ASSERT(aStrokeOptions.mDashArray || !aStrokeOptions.mDashLength); + if (mDashArray.size() != aStrokeOptions.mDashLength + || memcmp(mDashArray.data(), aStrokeOptions.mDashPattern, + sizeof(mDashArray[0]) * aStrokeOptions.mDashLength)) { + + gl->PathDashArrayNV(mObject, aStrokeOptions.mDashLength, + aStrokeOptions.mDashPattern); + mDashArray.resize(aStrokeOptions.mDashLength); + memcpy(mDashArray.data(), aStrokeOptions.mDashPattern, + sizeof(mDashArray[0]) * aStrokeOptions.mDashLength); + } +} + + +PathNVpr::PathNVpr(FillRule aFillRule, TemporaryRef aPathObject) + : mFillRule(aFillRule) + , mPathObject(aPathObject) +{ +} + +TemporaryRef +PathNVpr::CopyToBuilder(FillRule aFillRule) const +{ + return new PathBuilderNVpr(aFillRule, mPathObject.get()); +} + +TemporaryRef +PathNVpr::TransformedCopyToBuilder(const Matrix& aTransform, FillRule aFillRule) const +{ + return new PathBuilderNVpr(aFillRule, mPathObject.get(), aTransform); +} + +bool +PathNVpr::ContainsPoint(const Point& aPoint, const Matrix& aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformed = inverse * aPoint; + + gl->MakeCurrent(); + return gl->IsPointInFillPathNV(*mPathObject, mFillRule == FillRule::FILL_WINDING ? ~0 : 0x1, + transformed.x, transformed.y); +} + +bool +PathNVpr::StrokeContainsPoint(const StrokeOptions& aStrokeOptions, + const Point& aPoint, + const Matrix& aTransform) const +{ + Matrix inverse = aTransform; + inverse.Invert(); + Point transformed = inverse * aPoint; + + gl->MakeCurrent(); + ApplyStrokeOptions(aStrokeOptions); + return gl->IsPointInStrokePathNV(*mPathObject, transformed.x, transformed.y); +} + +Rect +PathNVpr::GetBounds(const Matrix& aTransform) const +{ + gl->MakeCurrent(); + + GLfloat bounds[] = {0, 0, 0, 0}; + + if (aTransform.IsIdentity()) { + gl->GetPathParameterfvNV(*mPathObject, GL_PATH_OBJECT_BOUNDING_BOX_NV, bounds); + } else { + PathObjectNVpr transformed(*mPathObject, aTransform); + gl->GetPathParameterfvNV(transformed, GL_PATH_OBJECT_BOUNDING_BOX_NV, bounds); + } + + return Rect(bounds[0], bounds[2], bounds[2], bounds[3]); +} + +Rect +PathNVpr::GetStrokedBounds(const StrokeOptions& aStrokeOptions, + const Matrix& aTransform) const +{ + GLfloat bounds[] = {0, 0, 0, 0}; + + gl->MakeCurrent(); + + ApplyStrokeOptions(aStrokeOptions); + + if (aTransform.IsIdentity()) { + gl->GetPathParameterfvNV(*mPathObject, GL_PATH_STROKE_BOUNDING_BOX_NV, bounds); + } else { + PathObjectNVpr transformed(*mPathObject, aTransform); + gl->GetPathParameterfvNV(transformed, GL_PATH_STROKE_BOUNDING_BOX_NV, bounds); + } + + return Rect(bounds[0], bounds[2], bounds[2], bounds[3]); +} + +bool +PathNVpr::IsSamePath(const PathNVpr* aPath) const +{ + return mFillRule == aPath->mFillRule && mPathObject == aPath->mPathObject; +} + +TemporaryRef +PathNVpr::Clone() const +{ + return new PathNVpr(mFillRule, mPathObject.get()); +} + +void +PathNVpr::ApplyStrokeOptions(const StrokeOptions& aStrokeOptions) const +{ + mPathObject->ApplyStrokeOptions(aStrokeOptions); +} + +} +} diff --git a/libazure/PathNVpr.h b/libazure/PathNVpr.h new file mode 100644 index 0000000..389af7e --- /dev/null +++ b/libazure/PathNVpr.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_PATHNVPR_H_ +#define MOZILLA_GFX_PATHNVPR_H_ + +#include "2D.h" +#include "nvpr/ConvexPolygon.h" +#include "nvpr/GL.h" +#include + +namespace mozilla { +namespace gfx { + +struct Line; +struct PathDescriptionNVpr; + +/** + * This is a ref-counted wrapper for NV_path_rendering path objects. It manages + * the path's GL state and allows multiple clients to share the same GL object + * (e.g. PathNVpr, the path cache, etc.) + */ +class PathObjectNVpr : public RefCounted { +public: + PathObjectNVpr(const PathDescriptionNVpr& aDescription, + const Point& aStartPoint, const Point& aCurrentPoint, + nvpr::ConvexPolygon&& aPassPolygon = nvpr::ConvexPolygon()); + PathObjectNVpr(const PathObjectNVpr& aPath, const Matrix& aTransform); + ~PathObjectNVpr(); + + const Point& StartPoint() const { return mStartPoint; } + const Point& CurrentPoint() const { return mCurrentPoint; } + const nvpr::ConvexPolygon& Polygon() const { return mPolygon; } + operator GLuint() const { return mObject; } + + void ApplySencliClipBits(GLuint aClipBits); + void ApplyStrokeOptions(const StrokeOptions& aStrokeOptions); + +private: + const Point mStartPoint; + const Point mCurrentPoint; + nvpr::ConvexPolygon mPolygon; + GLuint mObject; + + GLuint mStencilClipBits; + GLfloat mStrokeWidth; + GLfloat mMiterLimit; + GLfloat mDashOffset; + JoinStyle mJoinStyle; + CapStyle mCapStyle; + std::vector mDashArray; +}; + +/** + * This is the NV_path_rendering-specific implementation for Azure's Path + * interface. It's basically just a reference to a GL path object plus a fill + * rule. + */ +class PathNVpr : public Path +{ +public: + PathNVpr(FillRule aFillRule, TemporaryRef aPathObject); + + virtual BackendType GetBackendType() const { return BackendType::NVPR; } + + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; + virtual TemporaryRef TransformedCopyToBuilder(const Matrix& aTransform, + FillRule aFillRule = FillRule::FILL_WINDING) const; + + virtual bool ContainsPoint(const Point& aPoint, const Matrix& aTransform) const; + + virtual bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions, + const Point& aPoint, + const Matrix& aTransform) const; + + virtual Rect GetBounds(const Matrix& aTransform = Matrix()) const; + + virtual Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions, + const Matrix& aTransform = Matrix()) const; + + virtual void StreamToSink(PathSink *aSink) const { MOZ_ASSERT(false); } + + virtual FillRule GetFillRule() const { return mFillRule; } + + bool IsSamePath(const PathNVpr* aPath) const; + + const nvpr::ConvexPolygon& Polygon() const { return mPathObject->Polygon(); } + + operator GLuint() const { return *mPathObject; } + + TemporaryRef Clone() const; + + void ApplyStrokeOptions(const StrokeOptions& aStrokeOptions) const; + +private: + const FillRule mFillRule; + RefPtr mPathObject; +}; + +} +} + +#endif /* MOZILLA_GFX_PATHNVPR_H_ */ diff --git a/libazure/src/gfx/2d/PathRecording.cpp b/libazure/PathRecording.cpp similarity index 98% rename from libazure/src/gfx/2d/PathRecording.cpp rename to libazure/PathRecording.cpp index 647649b..e438712 100644 --- a/libazure/src/gfx/2d/PathRecording.cpp +++ b/libazure/PathRecording.cpp @@ -90,7 +90,7 @@ PathRecording::CopyToBuilder(FillRule aFillRule) const RefPtr pathBuilder = mPath->CopyToBuilder(aFillRule); RefPtr recording = new PathBuilderRecording(pathBuilder, aFillRule); recording->mPathOps = mPathOps; - return recording; + return recording.forget(); } TemporaryRef @@ -113,7 +113,7 @@ PathRecording::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFill } recording->mPathOps.push_back(newPathOp); } - return recording; + return recording.forget(); } } diff --git a/libazure/src/gfx/2d/PathRecording.h b/libazure/PathRecording.h similarity index 91% rename from libazure/src/gfx/2d/PathRecording.h rename to libazure/PathRecording.h index 8c89cb7..97faa40 100644 --- a/libazure/src/gfx/2d/PathRecording.h +++ b/libazure/PathRecording.h @@ -37,6 +37,7 @@ class DrawEventRecorderPrivate; class PathBuilderRecording : public PathBuilder { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording) PathBuilderRecording(PathBuilder *aBuilder, FillRule aFillRule) : mPathBuilder(aBuilder), mFillRule(aFillRule) { @@ -82,6 +83,7 @@ class PathBuilderRecording : public PathBuilder class PathRecording : public Path { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording) PathRecording(Path *aPath, const std::vector aOps, FillRule aFillRule) : mPath(aPath), mPathOps(aOps), mFillRule(aFillRule) { @@ -89,10 +91,10 @@ class PathRecording : public Path ~PathRecording(); - virtual BackendType GetBackendType() const { return BACKEND_RECORDING; } - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual BackendType GetBackendType() const { return BackendType::RECORDING; } + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const; + FillRule aFillRule = FillRule::FILL_WINDING) const; virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const { return mPath->ContainsPoint(aPoint, aTransform); } virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, @@ -106,7 +108,9 @@ class PathRecording : public Path virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform = Matrix()) const { return mPath->GetStrokedBounds(aStrokeOptions, aTransform); } - + + virtual void StreamToSink(PathSink *aSink) const { mPath->StreamToSink(aSink); } + virtual FillRule GetFillRule() const { return mFillRule; } void StorePath(std::ostream &aStream) const; diff --git a/libazure/src/gfx/2d/PathSkia.cpp b/libazure/PathSkia.cpp similarity index 71% rename from libazure/src/gfx/2d/PathSkia.cpp rename to libazure/PathSkia.cpp index 132e5dc..efa0c6f 100644 --- a/libazure/src/gfx/2d/PathSkia.cpp +++ b/libazure/PathSkia.cpp @@ -31,7 +31,7 @@ void PathBuilderSkia::SetFillRule(FillRule aFillRule) { mFillRule = aFillRule; - if (mFillRule == FILL_WINDING) { + if (mFillRule == FillRule::FILL_WINDING) { mPath.setFillType(SkPath::kWinding_FillType); } else { mPath.setFillType(SkPath::kEvenOdd_FillType); @@ -88,7 +88,7 @@ void PathBuilderSkia::Arc(const Point &aOrigin, float aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) { - ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); + ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise); } Point @@ -105,8 +105,13 @@ PathBuilderSkia::CurrentPoint() const TemporaryRef PathBuilderSkia::Finish() { - RefPtr path = new PathSkia(mPath, mFillRule); - return path; + return new PathSkia(mPath, mFillRule); +} + +void +PathBuilderSkia::AppendPath(const SkPath &aPath) +{ + mPath.addPath(aPath); } TemporaryRef @@ -118,8 +123,7 @@ PathSkia::CopyToBuilder(FillRule aFillRule) const TemporaryRef PathSkia::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const { - RefPtr builder = new PathBuilderSkia(aTransform, mPath, aFillRule); - return builder; + return new PathBuilderSkia(aTransform, mPath, aFillRule); } bool @@ -137,24 +141,16 @@ PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const } SkRegion pointRect; - pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)), - int32_t(SkFloatToScalar(transformed.y - 1)), - int32_t(SkFloatToScalar(transformed.x + 1)), - int32_t(SkFloatToScalar(transformed.y + 1))); + pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)), + int32_t(SkFloatToScalar(transformed.y - 1.f)), + int32_t(SkFloatToScalar(transformed.x + 1.f)), + int32_t(SkFloatToScalar(transformed.y + 1.f))); SkRegion pathRegion; return pathRegion.setPath(mPath, pointRect); } -static Rect SkRectToRect(const SkRect& aBounds) -{ - return Rect(SkScalarToFloat(aBounds.fLeft), - SkScalarToFloat(aBounds.fTop), - SkScalarToFloat(aBounds.fRight - aBounds.fLeft), - SkScalarToFloat(aBounds.fBottom - aBounds.fTop)); -} - bool PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, const Point &aPoint, @@ -178,10 +174,10 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, } SkRegion pointRect; - pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)), - int32_t(SkFloatToScalar(transformed.y - 1)), - int32_t(SkFloatToScalar(transformed.x + 1)), - int32_t(SkFloatToScalar(transformed.y + 1))); + pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)), + int32_t(SkFloatToScalar(transformed.y - 1.f)), + int32_t(SkFloatToScalar(transformed.x + 1.f)), + int32_t(SkFloatToScalar(transformed.y + 1.f))); SkRegion pathRegion; @@ -209,5 +205,39 @@ PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions, return aTransform.TransformBounds(bounds); } +void +PathSkia::StreamToSink(PathSink *aSink) const +{ + SkPath::RawIter iter(mPath); + + SkPoint points[4]; + SkPath::Verb currentVerb; + while ((currentVerb = iter.next(points)) != SkPath::kDone_Verb) { + switch (currentVerb) { + case SkPath::kMove_Verb: + aSink->MoveTo(SkPointToPoint(points[0])); + break; + case SkPath::kLine_Verb: + aSink->LineTo(SkPointToPoint(points[1])); + break; + case SkPath::kCubic_Verb: + aSink->BezierTo(SkPointToPoint(points[1]), + SkPointToPoint(points[2]), + SkPointToPoint(points[3])); + break; + case SkPath::kQuad_Verb: + aSink->QuadraticBezierTo(SkPointToPoint(points[1]), + SkPointToPoint(points[2])); + break; + case SkPath::kClose_Verb: + aSink->Close(); + break; + default: + MOZ_ASSERT(false); + // Unexpected verb found in path! + } + } +} + } } diff --git a/libazure/src/gfx/2d/PathSkia.h b/libazure/PathSkia.h similarity index 84% rename from libazure/src/gfx/2d/PathSkia.h rename to libazure/PathSkia.h index 4475b6b..ccb61bc 100644 --- a/libazure/src/gfx/2d/PathSkia.h +++ b/libazure/PathSkia.h @@ -7,7 +7,7 @@ #define MOZILLA_GFX_PATH_SKIA_H_ #include "2D.h" -#include "SkPath.h" +#include "core/SkPath.h" namespace mozilla { namespace gfx { @@ -17,8 +17,9 @@ class PathSkia; class PathBuilderSkia : public PathBuilder { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderSkia) PathBuilderSkia(const Matrix& aTransform, const SkPath& aPath, FillRule aFillRule); - PathBuilderSkia(FillRule aFillRule); + explicit PathBuilderSkia(FillRule aFillRule); virtual void MoveTo(const Point &aPoint); virtual void LineTo(const Point &aPoint); @@ -33,7 +34,10 @@ class PathBuilderSkia : public PathBuilder virtual Point CurrentPoint() const; virtual TemporaryRef Finish(); + void AppendPath(const SkPath &aPath); + private: + void SetFillRule(FillRule aFillRule); SkPath mPath; @@ -43,17 +47,18 @@ class PathBuilderSkia : public PathBuilder class PathSkia : public Path { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSkia) PathSkia(SkPath& aPath, FillRule aFillRule) : mFillRule(aFillRule) { mPath.swap(aPath); } - virtual BackendType GetBackendType() const { return BACKEND_SKIA; } + virtual BackendType GetBackendType() const { return BackendType::SKIA; } - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const; virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const; + FillRule aFillRule = FillRule::FILL_WINDING) const; virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; @@ -66,6 +71,8 @@ class PathSkia : public Path virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform = Matrix()) const; + virtual void StreamToSink(PathSink *aSink) const; + virtual FillRule GetFillRule() const { return mFillRule; } const SkPath& GetPath() const { return mPath; } diff --git a/libazure/Point.h b/libazure/Point.h new file mode 100644 index 0000000..692f0c8 --- /dev/null +++ b/libazure/Point.h @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_POINT_H_ +#define MOZILLA_GFX_POINT_H_ + +#include "mozilla/Attributes.h" +#include "Types.h" +#include "Coord.h" +#include "BaseCoord.h" +#include "BasePoint.h" +#include "BasePoint3D.h" +#include "BasePoint4D.h" +#include "BaseSize.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +template struct IsPixel; +namespace gfx { + +// This should only be used by the typedefs below. +struct UnknownUnits {}; + +} // close namespace 'gfx' because IsPixel specialization must be in 'mozilla' + +template<> struct IsPixel : TrueType {}; + +namespace gfx { + +template +struct IntPointTyped : + public BasePoint< int32_t, IntPointTyped, IntCoordTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef IntCoordTyped Coord; + typedef BasePoint< int32_t, IntPointTyped, IntCoordTyped > Super; + + MOZ_CONSTEXPR IntPointTyped() : Super() {} + MOZ_CONSTEXPR IntPointTyped(int32_t aX, int32_t aY) : Super(Coord(aX), Coord(aY)) {} + // The mixed-type constructors (int, Coord) and (Coord, int) are needed to + // avoid ambiguities because Coord is implicitly convertible to int. + MOZ_CONSTEXPR IntPointTyped(int32_t aX, Coord aY) : Super(Coord(aX), aY) {} + MOZ_CONSTEXPR IntPointTyped(Coord aX, int32_t aY) : Super(aX, Coord(aY)) {} + MOZ_CONSTEXPR IntPointTyped(Coord aX, Coord aY) : Super(aX, aY) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static IntPointTyped FromUnknownPoint(const IntPointTyped& aPoint) { + return IntPointTyped(aPoint.x, aPoint.y); + } + + IntPointTyped ToUnknownPoint() const { + return IntPointTyped(this->x, this->y); + } +}; +typedef IntPointTyped IntPoint; + +template +struct PointTyped : + public BasePoint< Float, PointTyped, CoordTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef CoordTyped Coord; + typedef BasePoint< Float, PointTyped, CoordTyped > Super; + + MOZ_CONSTEXPR PointTyped() : Super() {} + MOZ_CONSTEXPR PointTyped(Float aX, Float aY) : Super(Coord(aX), Coord(aY)) {} + // The mixed-type constructors (Float, Coord) and (Coord, Float) are needed to + // avoid ambiguities because Coord is implicitly convertible to Float. + MOZ_CONSTEXPR PointTyped(Float aX, Coord aY) : Super(Coord(aX), aY) {} + MOZ_CONSTEXPR PointTyped(Coord aX, Float aY) : Super(aX, Coord(aY)) {} + MOZ_CONSTEXPR PointTyped(Coord aX, Coord aY) : Super(aX.value, aY.value) {} + MOZ_CONSTEXPR MOZ_IMPLICIT PointTyped(const IntPointTyped& point) : Super(float(point.x), float(point.y)) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static PointTyped FromUnknownPoint(const PointTyped& aPoint) { + return PointTyped(aPoint.x, aPoint.y); + } + + PointTyped ToUnknownPoint() const { + return PointTyped(this->x, this->y); + } +}; +typedef PointTyped Point; + +template +IntPointTyped RoundedToInt(const PointTyped& aPoint) { + return IntPointTyped(int32_t(floorf(aPoint.x + 0.5f)), + int32_t(floorf(aPoint.y + 0.5f))); +} + +template +IntPointTyped TruncatedToInt(const PointTyped& aPoint) { + return IntPointTyped(int32_t(aPoint.x), + int32_t(aPoint.y)); +} + +template +struct Point3DTyped : + public BasePoint3D< Float, Point3DTyped > { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BasePoint3D< Float, Point3DTyped > Super; + + Point3DTyped() : Super() {} + Point3DTyped(Float aX, Float aY, Float aZ) : Super(aX, aY, aZ) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static Point3DTyped FromUnknownPoint(const Point3DTyped& aPoint) { + return Point3DTyped(aPoint.x, aPoint.y); + } + + Point3DTyped ToUnknownPoint() const { + return Point3DTyped(this->x, this->y); + } +}; +typedef Point3DTyped Point3D; + +template +struct Point4DTyped : + public BasePoint4D< Float, Point4DTyped > { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BasePoint4D< Float, Point4DTyped > Super; + + Point4DTyped() : Super() {} + Point4DTyped(Float aX, Float aY, Float aZ, Float aW) : Super(aX, aY, aZ, aW) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static Point4DTyped FromUnknownPoint(const Point4DTyped& aPoint) { + return Point4DTyped(aPoint.x, aPoint.y, aPoint.z, aPoint.w); + } + + Point4DTyped ToUnknownPoint() const { + return Point4DTyped(this->x, this->y, this->z, this->w); + } + + PointTyped As2DPoint() { + return PointTyped(this->x / this->w, this->y / this->w); + } +}; +typedef Point4DTyped Point4D; + +template +struct IntSizeTyped : + public BaseSize< int32_t, IntSizeTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseSize< int32_t, IntSizeTyped > Super; + + MOZ_CONSTEXPR IntSizeTyped() : Super() {} + MOZ_CONSTEXPR IntSizeTyped(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static IntSizeTyped FromUnknownSize(const IntSizeTyped& aSize) { + return IntSizeTyped(aSize.width, aSize.height); + } + + IntSizeTyped ToUnknownSize() const { + return IntSizeTyped(this->width, this->height); + } +}; +typedef IntSizeTyped IntSize; + +template +struct SizeTyped : + public BaseSize< Float, SizeTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseSize< Float, SizeTyped > Super; + + MOZ_CONSTEXPR SizeTyped() : Super() {} + MOZ_CONSTEXPR SizeTyped(Float aWidth, Float aHeight) : Super(aWidth, aHeight) {} + explicit SizeTyped(const IntSizeTyped& size) : + Super(float(size.width), float(size.height)) {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static SizeTyped FromUnknownSize(const SizeTyped& aSize) { + return SizeTyped(aSize.width, aSize.height); + } + + SizeTyped ToUnknownSize() const { + return SizeTyped(this->width, this->height); + } +}; +typedef SizeTyped Size; + +} +} + +#endif /* MOZILLA_GFX_POINT_H_ */ diff --git a/libazure/src/gfx/2d/QuartzSupport.h b/libazure/QuartzSupport.h similarity index 94% rename from libazure/src/gfx/2d/QuartzSupport.h rename to libazure/QuartzSupport.h index 9467820..7bf45fe 100644 --- a/libazure/src/gfx/2d/QuartzSupport.h +++ b/libazure/QuartzSupport.h @@ -9,18 +9,13 @@ #ifdef XP_MACOSX #import -#import #import "ApplicationServices/ApplicationServices.h" +#include "gfxTypes.h" #include "mozilla/RefPtr.h" #include "mozilla/gfx/MacIOSurface.h" -#define nsresult bool -#define NS_OK true -#define NS_ERROR_FAILURE false -#define NS_ERROR(x) NSLog(@x) - // Get the system color space. -CGColorSpaceRef CreateSystemColorSpace(); +CGColorSpaceRef THEBES_API CreateSystemColorSpace(); // Manages a CARenderer struct _CGLPBufferObject; @@ -30,6 +25,7 @@ enum AllowOfflineRendererEnum { ALLOW_OFFLINE_RENDERER, DISALLOW_OFFLINE_RENDERE class nsCARenderer : public mozilla::RefCounted { public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(nsCARenderer) nsCARenderer() : mCARenderer(nullptr), mWrapperCALayer(nullptr), mFBOTexture(0), mOpenGLContext(nullptr), mCGImage(nullptr), mCGData(nullptr), mIOSurface(nullptr), mFBO(0), mIOTexture(0), @@ -55,7 +51,7 @@ class nsCARenderer : public mozilla::RefCounted { * is attached then an internal pixel buffer will be * used. */ - void AttachIOSurface(mozilla::RefPtr aSurface); + void AttachIOSurface(MacIOSurface *aSurface); IOSurfaceID GetIOSurfaceID(); // aX, aY, aWidth and aHeight are in "display pixels". Multiply by // surf->GetContentsScaleFactor() to get device pixels. diff --git a/libazure/src/gfx/2d/QuartzSupport.mm b/libazure/QuartzSupport.mm similarity index 99% rename from libazure/src/gfx/2d/QuartzSupport.mm rename to libazure/QuartzSupport.mm index 6503653..6b8b1b7 100644 --- a/libazure/src/gfx/2d/QuartzSupport.mm +++ b/libazure/QuartzSupport.mm @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "QuartzSupport.h" +#include "nsDebug.h" #import #import @@ -772,12 +773,9 @@ void cgdata_release_callback(void *aCGData, const void *data, size_t size) { ::glScalef(1.0, -1.0, 1.0); } -void nsCARenderer::AttachIOSurface(RefPtr aSurface) { +void nsCARenderer::AttachIOSurface(MacIOSurface *aSurface) { if (mIOSurface && aSurface->GetIOSurfaceID() == mIOSurface->GetIOSurfaceID()) { - // This object isn't needed since we already have a - // handle to the same io surface. - aSurface = nullptr; return; } @@ -939,8 +937,8 @@ void cgdata_release_callback(void *aCGData, const void *data, size_t size) { if (aHeight + aY > ioHeight) aHeight = ioHeight - aY; - if (aX < 0 || static_cast(aX) >= ioWidth || - aY < 0 || static_cast(aY) >= ioHeight) { + if (aX < 0 || aX >= ioWidth || + aY < 0 || aY >= ioHeight) { surf->Unlock(); return NS_ERROR_FAILURE; } diff --git a/libazure/RadialGradientEffectD2D1.cpp b/libazure/RadialGradientEffectD2D1.cpp new file mode 100644 index 0000000..d485ac3 --- /dev/null +++ b/libazure/RadialGradientEffectD2D1.cpp @@ -0,0 +1,391 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RadialGradientEffectD2D1.h" + +#include "Logging.h" + +#include "ShadersD2D1.h" +#include "HelpersD2D.h" + +#include + +#define TEXTW(x) L##x +#define XML(X) TEXTW(#X) // This macro creates a single string from multiple lines of text. + +static const PCWSTR kXmlDescription = + XML( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + +// {FB947CDA-718E-40CC-AE7B-D255830D7D14} +static const GUID GUID_SampleRadialGradientPS = + {0xfb947cda, 0x718e, 0x40cc, {0xae, 0x7b, 0xd2, 0x55, 0x83, 0xd, 0x7d, 0x14}}; +// {2C468128-6546-453C-8E25-F2DF0DE10A0F} +static const GUID GUID_SampleRadialGradientA0PS = + {0x2c468128, 0x6546, 0x453c, {0x8e, 0x25, 0xf2, 0xdf, 0xd, 0xe1, 0xa, 0xf}}; + +namespace mozilla { +namespace gfx { + +RadialGradientEffectD2D1::RadialGradientEffectD2D1() + : mRefCount(0) + , mCenter1(D2D1::Vector2F(0, 0)) + , mCenter2(D2D1::Vector2F(0, 0)) + , mRadius1(0) + , mRadius2(0) + , mTransform(D2D1::IdentityMatrix()) + +{ +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::Initialize(ID2D1EffectContext* pContextInternal, ID2D1TransformGraph* pTransformGraph) +{ + HRESULT hr; + + hr = pContextInternal->LoadPixelShader(GUID_SampleRadialGradientPS, SampleRadialGradientPS, sizeof(SampleRadialGradientPS)); + + if (FAILED(hr)) { + return hr; + } + + hr = pContextInternal->LoadPixelShader(GUID_SampleRadialGradientA0PS, SampleRadialGradientA0PS, sizeof(SampleRadialGradientA0PS)); + + if (FAILED(hr)) { + return hr; + } + + hr = pTransformGraph->SetSingleTransformNode(this); + + if (FAILED(hr)) { + return hr; + } + + mEffectContext = pContextInternal; + + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::PrepareForRender(D2D1_CHANGE_TYPE changeType) +{ + if (changeType == D2D1_CHANGE_TYPE_NONE) { + return S_OK; + } + + // We'll need to inverse transform our pixel, precompute inverse here. + Matrix mat = ToMatrix(mTransform); + if (!mat.Invert()) { + // Singular + return S_OK; + } + + if (!mStopCollection) { + return S_OK; + } + + D2D1_POINT_2F dc = D2D1::Point2F(mCenter2.x - mCenter1.x, mCenter2.y - mCenter2.y); + float dr = mRadius2 - mRadius1; + float A = dc.x * dc.x + dc.y * dc.y - dr * dr; + + HRESULT hr; + + if (A == 0) { + hr = mDrawInfo->SetPixelShader(GUID_SampleRadialGradientA0PS); + } else { + hr = mDrawInfo->SetPixelShader(GUID_SampleRadialGradientPS); + } + + if (FAILED(hr)) { + return hr; + } + + RefPtr tex = CreateGradientTexture(); + hr = mDrawInfo->SetResourceTexture(1, tex); + + if (FAILED(hr)) { + return hr; + } + + struct PSConstantBuffer + { + float diff[3]; + float padding; + float center1[2]; + float A; + float radius1; + float sq_radius1; + float repeat_correct; + float allow_odd; + float padding2[1]; + float transform[8]; + }; + + PSConstantBuffer buffer = { { dc.x, dc.y, dr }, 0, + { mCenter1.x, mCenter1.y }, + A, mRadius1, mRadius1 * mRadius1, + mStopCollection->GetExtendMode() != D2D1_EXTEND_MODE_CLAMP ? 1 : 0, + mStopCollection->GetExtendMode() == D2D1_EXTEND_MODE_MIRROR ? 1 : 0, + { 0 }, { mat._11, mat._21, mat._31, 0, + mat._12, mat._22, mat._32, 0 } }; + + hr = mDrawInfo->SetPixelShaderConstantBuffer((BYTE*)&buffer, sizeof(buffer)); + + if (FAILED(hr)) { + return hr; + } + + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::SetGraph(ID2D1TransformGraph* pGraph) +{ + return pGraph->SetSingleTransformNode(this); +} + +IFACEMETHODIMP_(ULONG) +RadialGradientEffectD2D1::AddRef() +{ + return ++mRefCount; +} + +IFACEMETHODIMP_(ULONG) +RadialGradientEffectD2D1::Release() +{ + if (!--mRefCount) { + delete this; + return 0; + } + return mRefCount; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::QueryInterface(const IID &aIID, void **aPtr) +{ + if (!aPtr) { + return E_POINTER; + } + + if (aIID == IID_IUnknown) { + *aPtr = static_cast(static_cast(this)); + } else if (aIID == IID_ID2D1EffectImpl) { + *aPtr = static_cast(this); + } else if (aIID == IID_ID2D1DrawTransform) { + *aPtr = static_cast(this); + } else if (aIID == IID_ID2D1Transform) { + *aPtr = static_cast(this); + } else if (aIID == IID_ID2D1TransformNode) { + *aPtr = static_cast(this); + } else { + return E_NOINTERFACE; + } + + static_cast(*aPtr)->AddRef(); + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::MapInputRectsToOutputRect(const D2D1_RECT_L* pInputRects, + const D2D1_RECT_L* pInputOpaqueSubRects, + UINT32 inputRectCount, + D2D1_RECT_L* pOutputRect, + D2D1_RECT_L* pOutputOpaqueSubRect) +{ + if (inputRectCount != 1) { + return E_INVALIDARG; + } + + *pOutputRect = *pInputRects; + *pOutputOpaqueSubRect = *pInputOpaqueSubRects; + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::MapOutputRectToInputRects(const D2D1_RECT_L* pOutputRect, + D2D1_RECT_L* pInputRects, + UINT32 inputRectCount) const +{ + if (inputRectCount != 1) { + return E_INVALIDARG; + } + + *pInputRects = *pOutputRect; + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::MapInvalidRect(UINT32 inputIndex, + D2D1_RECT_L invalidInputRect, + D2D1_RECT_L* pInvalidOutputRect) const +{ + MOZ_ASSERT(inputIndex = 0); + + *pInvalidOutputRect = invalidInputRect; + return S_OK; +} + +IFACEMETHODIMP +RadialGradientEffectD2D1::SetDrawInfo(ID2D1DrawInfo *pDrawInfo) +{ + mDrawInfo = pDrawInfo; + return S_OK; +} + +HRESULT +RadialGradientEffectD2D1::Register(ID2D1Factory1 *aFactory) +{ + D2D1_PROPERTY_BINDING bindings[] = { + D2D1_VALUE_TYPE_BINDING(L"StopCollection", &SetStopCollection, &GetStopCollection), + D2D1_VALUE_TYPE_BINDING(L"Center1", &SetCenter1, &GetCenter1), + D2D1_VALUE_TYPE_BINDING(L"Center2", &SetCenter2, &GetCenter2), + D2D1_VALUE_TYPE_BINDING(L"Radius1", &SetRadius1, &GetRadius1), + D2D1_VALUE_TYPE_BINDING(L"Radius2", &SetRadius2, &GetRadius2), + D2D1_VALUE_TYPE_BINDING(L"Transform", &SetTransform, &GetTransform) + }; + HRESULT hr = aFactory->RegisterEffectFromString(CLSID_RadialGradientEffect, kXmlDescription, bindings, ARRAYSIZE(bindings), CreateEffect); + + if (FAILED(hr)) { + gfxWarning() << "Failed to register radial gradient effect."; + } + return hr; +} + +HRESULT __stdcall +RadialGradientEffectD2D1::CreateEffect(IUnknown **aEffectImpl) +{ + *aEffectImpl = static_cast(new RadialGradientEffectD2D1()); + (*aEffectImpl)->AddRef(); + + return S_OK; +} + +HRESULT +RadialGradientEffectD2D1::SetStopCollection(IUnknown *aStopCollection) +{ + if (SUCCEEDED(aStopCollection->QueryInterface((ID2D1GradientStopCollection**)byRef(mStopCollection)))) { + return S_OK; + } + + return E_INVALIDARG; +} + +TemporaryRef +RadialGradientEffectD2D1::CreateGradientTexture() +{ + std::vector rawStops; + rawStops.resize(mStopCollection->GetGradientStopCount()); + mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size()); + + std::vector textureData; + textureData.resize(4096 * 4); + unsigned char *texData = &textureData.front(); + + float prevColorPos = 0; + float nextColorPos = 1.0f; + D2D1_COLOR_F prevColor = rawStops[0].color; + D2D1_COLOR_F nextColor = prevColor; + + if (rawStops.size() >= 2) { + nextColor = rawStops[1].color; + nextColorPos = rawStops[1].position; + } + + uint32_t stopPosition = 2; + + // Not the most optimized way but this will do for now. + for (int i = 0; i < 4096; i++) { + // The 4095 seems a little counter intuitive, but we want the gradient + // color at offset 0 at the first pixel, and at offset 1.0f at the last + // pixel. + float pos = float(i) / 4095; + + while (pos > nextColorPos) { + prevColor = nextColor; + prevColorPos = nextColorPos; + if (rawStops.size() > stopPosition) { + nextColor = rawStops[stopPosition].color; + nextColorPos = rawStops[stopPosition++].position; + } else { + nextColorPos = 1.0f; + } + } + + float interp; + + if (nextColorPos != prevColorPos) { + interp = (pos - prevColorPos) / (nextColorPos - prevColorPos); + } else { + interp = 0; + } + + Color newColor(prevColor.r + (nextColor.r - prevColor.r) * interp, + prevColor.g + (nextColor.g - prevColor.g) * interp, + prevColor.b + (nextColor.b - prevColor.b) * interp, + prevColor.a + (nextColor.a - prevColor.a) * interp); + + // Note D2D expects RGBA here!! + texData[i * 4] = (char)(255.0f * newColor.r); + texData[i * 4 + 1] = (char)(255.0f * newColor.g); + texData[i * 4 + 2] = (char)(255.0f * newColor.b); + texData[i * 4 + 3] = (char)(255.0f * newColor.a); + } + + RefPtr tex; + + UINT32 width = 4096; + UINT32 stride = 4096 * 4; + D2D1_RESOURCE_TEXTURE_PROPERTIES props; + // Older shader models do not support 1D textures. So just use a width x 1 texture. + props.dimensions = 2; + UINT32 dims[] = { width, 1 }; + props.extents = dims; + props.channelDepth = D2D1_CHANNEL_DEPTH_4; + props.bufferPrecision = D2D1_BUFFER_PRECISION_8BPC_UNORM; + props.filter = D2D1_FILTER_MIN_MAG_MIP_LINEAR; + D2D1_EXTEND_MODE extendMode[] = { mStopCollection->GetExtendMode(), mStopCollection->GetExtendMode() }; + props.extendModes = extendMode; + + HRESULT hr = mEffectContext->CreateResourceTexture(nullptr, &props, &textureData.front(), &stride, 4096 * 4, byRef(tex)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create resource texture: " << hr; + } + + return tex.forget(); +} + +} +} diff --git a/libazure/RadialGradientEffectD2D1.h b/libazure/RadialGradientEffectD2D1.h new file mode 100644 index 0000000..6218f73 --- /dev/null +++ b/libazure/RadialGradientEffectD2D1.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_RADIALGRADIENTEFFECTD2D1_H_ +#define MOZILLA_GFX_RADIALGRADIENTEFFECTD2D1_H_ + +#include +#include +#include + +#include "2D.h" + +// {97143DC6-CBC4-4DD4-A8BA-13342B0BA46D} +DEFINE_GUID(CLSID_RadialGradientEffect, +0x97143dc6, 0xcbc4, 0x4dd4, 0xa8, 0xba, 0x13, 0x34, 0x2b, 0xb, 0xa4, 0x6d); + +// Macro to keep our class nice and clean. +#define SIMPLE_PROP(type, name) \ +public: \ + HRESULT Set##name(type a##name) \ + { m##name = a##name; return S_OK; } \ + type Get##name() const { return m##name; } \ +private: \ + type m##name; + +namespace mozilla { +namespace gfx { + +enum { + RADIAL_PROP_STOP_COLLECTION = 0, + RADIAL_PROP_CENTER_1, + RADIAL_PROP_CENTER_2, + RADIAL_PROP_RADIUS_1, + RADIAL_PROP_RADIUS_2, + RADIAL_PROP_TRANSFORM +}; + +class RadialGradientEffectD2D1 : public ID2D1EffectImpl + , public ID2D1DrawTransform +{ +public: + // ID2D1EffectImpl + IFACEMETHODIMP Initialize(ID2D1EffectContext* pContextInternal, ID2D1TransformGraph* pTransformGraph); + IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType); + IFACEMETHODIMP SetGraph(ID2D1TransformGraph* pGraph); + + // IUnknown + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP_(ULONG) Release(); + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppOutput); + + // ID2D1Transform + IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L* pInputRects, + const D2D1_RECT_L* pInputOpaqueSubRects, + UINT32 inputRectCount, + D2D1_RECT_L* pOutputRect, + D2D1_RECT_L* pOutputOpaqueSubRect); + IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L* pOutputRect, + D2D1_RECT_L* pInputRects, + UINT32 inputRectCount) const; + IFACEMETHODIMP MapInvalidRect(UINT32 inputIndex, + D2D1_RECT_L invalidInputRect, + D2D1_RECT_L* pInvalidOutputRect) const; + + // ID2D1TransformNode + IFACEMETHODIMP_(UINT32) GetInputCount() const { return 1; } + + // ID2D1DrawTransform + IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDrawInfo); + + static HRESULT Register(ID2D1Factory1* aFactory); + static HRESULT __stdcall CreateEffect(IUnknown** aEffectImpl); + + HRESULT SetStopCollection(IUnknown *aStopCollection); + IUnknown *GetStopCollection() const { return mStopCollection; } + +private: + TemporaryRef CreateGradientTexture(); + + RadialGradientEffectD2D1(); + + uint32_t mRefCount; + RefPtr mStopCollection; + RefPtr mEffectContext; + RefPtr mDrawInfo; + SIMPLE_PROP(D2D1_VECTOR_2F, Center1); + SIMPLE_PROP(D2D1_VECTOR_2F, Center2); + SIMPLE_PROP(FLOAT, Radius1); + SIMPLE_PROP(FLOAT, Radius2); + SIMPLE_PROP(D2D_MATRIX_3X2_F, Transform); +}; + +} +} +#undef SIMPLE_PROP + +#endif diff --git a/libazure/src/gfx/2d/RecordedEvent.cpp b/libazure/RecordedEvent.cpp similarity index 76% rename from libazure/src/gfx/2d/RecordedEvent.cpp rename to libazure/RecordedEvent.cpp index c8b649b..8506029 100644 --- a/libazure/src/gfx/2d/RecordedEvent.cpp +++ b/libazure/RecordedEvent.cpp @@ -7,6 +7,8 @@ #include "PathRecording.h" #include "Tools.h" +#include "Filters.h" +#include "Logging.h" namespace mozilla { namespace gfx { @@ -16,9 +18,9 @@ using namespace std; static std::string NameFromBackend(BackendType aType) { switch (aType) { - case BACKEND_NONE: + case BackendType::NONE: return "None"; - case BACKEND_DIRECT2D: + case BackendType::DIRECT2D: return "Direct2D"; default: return "Unknown"; @@ -49,17 +51,96 @@ RecordedEvent::LoadEventFromStream(std::istream &aStream, EventType aType) LOAD_EVENT_TYPE(STROKE, RecordedStroke); LOAD_EVENT_TYPE(DRAWSURFACE, RecordedDrawSurface); LOAD_EVENT_TYPE(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow); + LOAD_EVENT_TYPE(DRAWFILTER, RecordedDrawFilter); LOAD_EVENT_TYPE(PATHCREATION, RecordedPathCreation); LOAD_EVENT_TYPE(PATHDESTRUCTION, RecordedPathDestruction); LOAD_EVENT_TYPE(SOURCESURFACECREATION, RecordedSourceSurfaceCreation); LOAD_EVENT_TYPE(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction); + LOAD_EVENT_TYPE(FILTERNODECREATION, RecordedFilterNodeCreation); + LOAD_EVENT_TYPE(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction); LOAD_EVENT_TYPE(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation); LOAD_EVENT_TYPE(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction); LOAD_EVENT_TYPE(SNAPSHOT, RecordedSnapshot); LOAD_EVENT_TYPE(SCALEDFONTCREATION, RecordedScaledFontCreation); LOAD_EVENT_TYPE(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction); + LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface); + LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute); + LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput); default: - return NULL; + return nullptr; + } +} + +string +RecordedEvent::GetEventName(EventType aType) +{ + switch (aType) { + case DRAWTARGETCREATION: + return "DrawTarget Creation"; + case DRAWTARGETDESTRUCTION: + return "DrawTarget Destruction"; + case FILLRECT: + return "FillRect"; + case STROKERECT: + return "StrokeRect"; + case STROKELINE: + return "StrokeLine"; + case CLEARRECT: + return "ClearRect"; + case COPYSURFACE: + return "CopySurface"; + case SETTRANSFORM: + return "SetTransform"; + case PUSHCLIP: + return "PushClip"; + case PUSHCLIPRECT: + return "PushClipRect"; + case POPCLIP: + return "PopClip"; + case FILL: + return "Fill"; + case FILLGLYPHS: + return "FillGlyphs"; + case MASK: + return "Mask"; + case STROKE: + return "Stroke"; + case DRAWSURFACE: + return "DrawSurface"; + case DRAWSURFACEWITHSHADOW: + return "DrawSurfaceWithShadow"; + case DRAWFILTER: + return "DrawFilter"; + case PATHCREATION: + return "PathCreation"; + case PATHDESTRUCTION: + return "PathDestruction"; + case SOURCESURFACECREATION: + return "SourceSurfaceCreation"; + case SOURCESURFACEDESTRUCTION: + return "SourceSurfaceDestruction"; + case FILTERNODECREATION: + return "FilterNodeCreation"; + case FILTERNODEDESTRUCTION: + return "FilterNodeDestruction"; + case GRADIENTSTOPSCREATION: + return "GradientStopsCreation"; + case GRADIENTSTOPSDESTRUCTION: + return "GradientStopsDestruction"; + case SNAPSHOT: + return "Snapshot"; + case SCALEDFONTCREATION: + return "ScaledFontCreation"; + case SCALEDFONTDESTRUCTION: + return "ScaledFontDestruction"; + case MASKSURFACE: + return "MaskSurface"; + case FILTERNODESETATTRIBUTE: + return "SetAttribute"; + case FILTERNODESETINPUT: + return "SetInput"; + default: + return "Unknown"; } } @@ -69,22 +150,22 @@ RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aP WriteElement(aStream, aPattern.mType); switch (aPattern.mType) { - case PATTERN_COLOR: + case PatternType::COLOR: { WriteElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { WriteElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { WriteElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_SURFACE: + case PatternType::SURFACE: { WriteElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; @@ -100,22 +181,22 @@ RecordedEvent::ReadPatternData(std::istream &aStream, PatternStorage &aPattern) ReadElement(aStream, aPattern.mType); switch (aPattern.mType) { - case PATTERN_COLOR: + case PatternType::COLOR: { ReadElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { ReadElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { ReadElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; } - case PATTERN_SURFACE: + case PatternType::SURFACE: { ReadElement(aStream, *reinterpret_cast(&aPattern.mStorage)); return; @@ -131,13 +212,13 @@ RecordedEvent::StorePattern(PatternStorage &aDestination, const Pattern &aSource aDestination.mType = aSource.GetType(); switch (aSource.GetType()) { - case PATTERN_COLOR: + case PatternType::COLOR: { reinterpret_cast(&aDestination.mStorage)->mColor = static_cast(&aSource)->mColor; return; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { LinearGradientPatternStorage *store = reinterpret_cast(&aDestination.mStorage); @@ -149,7 +230,7 @@ RecordedEvent::StorePattern(PatternStorage &aDestination, const Pattern &aSource store->mStops = pat->mStops.get(); return; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { RadialGradientPatternStorage *store = reinterpret_cast(&aDestination.mStorage); @@ -163,7 +244,7 @@ RecordedEvent::StorePattern(PatternStorage &aDestination, const Pattern &aSource store->mStops = pat->mStops.get(); return; } - case PATTERN_SURFACE: + case PatternType::SURFACE: { SurfacePatternStorage *store = reinterpret_cast(&aDestination.mStorage); @@ -230,13 +311,13 @@ void RecordedEvent::OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const { switch (aStorage.mType) { - case PATTERN_COLOR: + case PatternType::COLOR: { const Color color = reinterpret_cast(&aStorage.mStorage)->mColor; aOutput << "Color: (" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")"; return; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { const LinearGradientPatternStorage *store = reinterpret_cast(&aStorage.mStorage); @@ -245,7 +326,7 @@ RecordedEvent::OutputSimplePatternInfo(const PatternStorage &aStorage, std::stri ") - (" << store->mEnd.x << ", " << store->mEnd.y << ") Stops: " << store->mStops; return; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { const RadialGradientPatternStorage *store = reinterpret_cast(&aStorage.mStorage); @@ -253,7 +334,7 @@ RecordedEvent::OutputSimplePatternInfo(const PatternStorage &aStorage, std::stri store->mCenter2.y << ") Radius 2: " << store->mRadius2; return; } - case PATTERN_SURFACE: + case PatternType::SURFACE: { const SurfacePatternStorage *store = reinterpret_cast(&aStorage.mStorage); @@ -276,7 +357,7 @@ RecordedDrawingEvent::RecordToStream(ostream &aStream) const } ReferencePtr -RecordedDrawingEvent::GetObject() const +RecordedDrawingEvent::GetObjectRef() const { return mDT; } @@ -287,6 +368,11 @@ RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const RefPtr newDT = aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(mSize, mFormat); aTranslator->AddDrawTarget(mRefPtr, newDT); + + if (mHasExistingData) { + Rect dataRect(0, 0, mExistingData->GetSize().width, mExistingData->GetSize().height); + newDT->DrawSurface(mExistingData, dataRect, dataRect); + } } void @@ -296,15 +382,43 @@ RecordedDrawTargetCreation::RecordToStream(ostream &aStream) const WriteElement(aStream, mBackendType); WriteElement(aStream, mSize); WriteElement(aStream, mFormat); + WriteElement(aStream, mHasExistingData); + + if (mHasExistingData) { + MOZ_ASSERT(mExistingData); + MOZ_ASSERT(mExistingData->GetSize() == mSize); + RefPtr dataSurf = mExistingData->GetDataSurface(); + for (int y = 0; y < mSize.height; y++) { + aStream.write((const char*)dataSurf->GetData() + y * dataSurf->Stride(), + BytesPerPixel(mFormat) * mSize.width); + } + } } RecordedDrawTargetCreation::RecordedDrawTargetCreation(istream &aStream) : RecordedEvent(DRAWTARGETCREATION) + , mExistingData(nullptr) { ReadElement(aStream, mRefPtr); ReadElement(aStream, mBackendType); ReadElement(aStream, mSize); ReadElement(aStream, mFormat); + ReadElement(aStream, mHasExistingData); + + if (mHasExistingData) { + RefPtr dataSurf = Factory::CreateDataSourceSurface(mSize, mFormat); + if (!dataSurf) { + gfxWarning() << "RecordedDrawTargetCreation had to reset mHasExistingData"; + mHasExistingData = false; + return; + } + + for (int y = 0; y < mSize.height; y++) { + aStream.read((char*)dataSurf->GetData() + y * dataSurf->Stride(), + BytesPerPixel(mFormat) * mSize.width); + } + mExistingData = dataSurf; + } } void @@ -341,7 +455,7 @@ RecordedDrawTargetDestruction::OutputSimpleEventInfo(stringstream &aStringStream struct GenericPattern { GenericPattern(const PatternStorage &aStorage, Translator *aTranslator) - : mPattern(NULL), mTranslator(aTranslator) + : mPattern(nullptr), mTranslator(aTranslator) { mStorage = const_cast(&aStorage); } @@ -355,9 +469,9 @@ struct GenericPattern operator Pattern*() { switch(mStorage->mType) { - case PATTERN_COLOR: + case PatternType::COLOR: return new (mColPat) ColorPattern(reinterpret_cast(&mStorage->mStorage)->mColor); - case PATTERN_SURFACE: + case PatternType::SURFACE: { SurfacePatternStorage *storage = reinterpret_cast(&mStorage->mStorage); mPattern = @@ -365,7 +479,7 @@ struct GenericPattern storage->mExtend, storage->mMatrix, storage->mFilter); return mPattern; } - case PATTERN_LINEAR_GRADIENT: + case PatternType::LINEAR_GRADIENT: { LinearGradientPatternStorage *storage = reinterpret_cast(&mStorage->mStorage); mPattern = @@ -374,7 +488,7 @@ struct GenericPattern storage->mMatrix); return mPattern; } - case PATTERN_RADIAL_GRADIENT: + case PatternType::RADIAL_GRADIENT: { RadialGradientPatternStorage *storage = reinterpret_cast(&mStorage->mStorage); mPattern = @@ -827,6 +941,39 @@ RecordedDrawSurface::OutputSimpleEventInfo(stringstream &aStringStream) const aStringStream << "[" << mDT << "] DrawSurface (" << mRefSource << ")"; } +void +RecordedDrawFilter::PlayEvent(Translator *aTranslator) const +{ + aTranslator->LookupDrawTarget(mDT)-> + DrawFilter(aTranslator->LookupFilterNode(mNode), mSourceRect, + mDestPoint, mOptions); +} + +void +RecordedDrawFilter::RecordToStream(ostream &aStream) const +{ + RecordedDrawingEvent::RecordToStream(aStream); + WriteElement(aStream, mNode); + WriteElement(aStream, mSourceRect); + WriteElement(aStream, mDestPoint); + WriteElement(aStream, mOptions); +} + +RecordedDrawFilter::RecordedDrawFilter(istream &aStream) + : RecordedDrawingEvent(DRAWFILTER, aStream) +{ + ReadElement(aStream, mNode); + ReadElement(aStream, mSourceRect); + ReadElement(aStream, mDestPoint); + ReadElement(aStream, mOptions); +} + +void +RecordedDrawFilter::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mDT << "] DrawFilter (" << mNode << ")"; +} + void RecordedDrawSurfaceWithShadow::PlayEvent(Translator *aTranslator) const { @@ -1049,6 +1196,62 @@ RecordedSourceSurfaceDestruction::OutputSimpleEventInfo(stringstream &aStringStr aStringStream << "[" << mRefPtr << "] SourceSurface Destroyed"; } +RecordedFilterNodeCreation::~RecordedFilterNodeCreation() +{ +} + +void +RecordedFilterNodeCreation::PlayEvent(Translator *aTranslator) const +{ + RefPtr node = aTranslator->GetReferenceDrawTarget()-> + CreateFilter(mType); + aTranslator->AddFilterNode(mRefPtr, node); +} + +void +RecordedFilterNodeCreation::RecordToStream(ostream &aStream) const +{ + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mType); +} + +RecordedFilterNodeCreation::RecordedFilterNodeCreation(istream &aStream) + : RecordedEvent(FILTERNODECREATION) +{ + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mType); +} + +void +RecordedFilterNodeCreation::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mRefPtr << "] FilterNode created (Type: " << int(mType) << ")"; +} + +void +RecordedFilterNodeDestruction::PlayEvent(Translator *aTranslator) const +{ + aTranslator->RemoveFilterNode(mRefPtr); +} + +void +RecordedFilterNodeDestruction::RecordToStream(ostream &aStream) const +{ + WriteElement(aStream, mRefPtr); +} + +RecordedFilterNodeDestruction::RecordedFilterNodeDestruction(istream &aStream) + : RecordedEvent(FILTERNODEDESTRUCTION) +{ + ReadElement(aStream, mRefPtr); +} + +void +RecordedFilterNodeDestruction::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mRefPtr << "] FilterNode Destroyed"; +} + RecordedGradientStopsCreation::~RecordedGradientStopsCreation() { if (mDataOwned) { @@ -1216,5 +1419,151 @@ RecordedScaledFontDestruction::OutputSimpleEventInfo(stringstream &aStringStream aStringStream << "[" << mRefPtr << "] ScaledFont Destroyed"; } +void +RecordedMaskSurface::PlayEvent(Translator *aTranslator) const +{ + aTranslator->LookupDrawTarget(mDT)-> + MaskSurface(*GenericPattern(mPattern, aTranslator), + aTranslator->LookupSourceSurface(mRefMask), + mOffset, mOptions); +} + +void +RecordedMaskSurface::RecordToStream(ostream &aStream) const +{ + RecordedDrawingEvent::RecordToStream(aStream); + RecordPatternData(aStream, mPattern); + WriteElement(aStream, mRefMask); + WriteElement(aStream, mOffset); + WriteElement(aStream, mOptions); +} + +RecordedMaskSurface::RecordedMaskSurface(istream &aStream) + : RecordedDrawingEvent(MASKSURFACE, aStream) +{ + ReadPatternData(aStream, mPattern); + ReadElement(aStream, mRefMask); + ReadElement(aStream, mOffset); + ReadElement(aStream, mOptions); +} + +void +RecordedMaskSurface::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mDT << "] MaskSurface (" << mRefMask << ") Offset: (" << mOffset.x << "x" << mOffset.y << ") Pattern: "; + OutputSimplePatternInfo(mPattern, aStringStream); +} + +template +void +ReplaySetAttribute(FilterNode *aNode, uint32_t aIndex, T aValue) +{ + aNode->SetAttribute(aIndex, aValue); +} + +void +RecordedFilterNodeSetAttribute::PlayEvent(Translator *aTranslator) const +{ +#define REPLAY_SET_ATTRIBUTE(type, argtype) \ + case ARGTYPE_##argtype: \ + ReplaySetAttribute(aTranslator->LookupFilterNode(mNode), mIndex, *(type*)&mPayload.front()); \ + break + + switch (mArgType) { + REPLAY_SET_ATTRIBUTE(bool, BOOL); + REPLAY_SET_ATTRIBUTE(uint32_t, UINT32); + REPLAY_SET_ATTRIBUTE(Float, FLOAT); + REPLAY_SET_ATTRIBUTE(Size, SIZE); + REPLAY_SET_ATTRIBUTE(IntSize, INTSIZE); + REPLAY_SET_ATTRIBUTE(IntPoint, INTPOINT); + REPLAY_SET_ATTRIBUTE(Rect, RECT); + REPLAY_SET_ATTRIBUTE(IntRect, INTRECT); + REPLAY_SET_ATTRIBUTE(Point, POINT); + REPLAY_SET_ATTRIBUTE(Matrix5x4, MATRIX5X4); + REPLAY_SET_ATTRIBUTE(Point3D, POINT3D); + REPLAY_SET_ATTRIBUTE(Color, COLOR); + case ARGTYPE_FLOAT_ARRAY: + aTranslator->LookupFilterNode(mNode)->SetAttribute( + mIndex, + reinterpret_cast(&mPayload.front()), + mPayload.size() / sizeof(Float)); + break; + } +} + +void +RecordedFilterNodeSetAttribute::RecordToStream(ostream &aStream) const +{ + RecordedEvent::RecordToStream(aStream); + WriteElement(aStream, mNode); + WriteElement(aStream, mIndex); + WriteElement(aStream, mArgType); + WriteElement(aStream, uint64_t(mPayload.size())); + aStream.write((const char*)&mPayload.front(), mPayload.size()); +} + +RecordedFilterNodeSetAttribute::RecordedFilterNodeSetAttribute(istream &aStream) + : RecordedEvent(FILTERNODESETATTRIBUTE) +{ + ReadElement(aStream, mNode); + ReadElement(aStream, mIndex); + ReadElement(aStream, mArgType); + uint64_t size; + ReadElement(aStream, size); + mPayload.resize(size_t(size)); + aStream.read((char*)&mPayload.front(), size); +} + +void +RecordedFilterNodeSetAttribute::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ")"; +} + +void +RecordedFilterNodeSetInput::PlayEvent(Translator *aTranslator) const +{ + if (mInputFilter) { + aTranslator->LookupFilterNode(mNode)->SetInput( + mIndex, aTranslator->LookupFilterNode(mInputFilter)); + } else { + aTranslator->LookupFilterNode(mNode)->SetInput( + mIndex, aTranslator->LookupSourceSurface(mInputSurface)); + } +} + +void +RecordedFilterNodeSetInput::RecordToStream(ostream &aStream) const +{ + RecordedEvent::RecordToStream(aStream); + WriteElement(aStream, mNode); + WriteElement(aStream, mIndex); + WriteElement(aStream, mInputFilter); + WriteElement(aStream, mInputSurface); +} + +RecordedFilterNodeSetInput::RecordedFilterNodeSetInput(istream &aStream) + : RecordedEvent(FILTERNODESETINPUT) +{ + ReadElement(aStream, mNode); + ReadElement(aStream, mIndex); + ReadElement(aStream, mInputFilter); + ReadElement(aStream, mInputSurface); +} + +void +RecordedFilterNodeSetInput::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mNode << "] SetAttribute (" << mIndex << ", "; + + if (mInputFilter) { + aStringStream << "Filter: " << mInputFilter; + } else { + aStringStream << "Surface: " << mInputSurface; + } + + aStringStream << ")"; +} + } } diff --git a/libazure/src/gfx/2d/RecordedEvent.h b/libazure/RecordedEvent.h similarity index 70% rename from libazure/src/gfx/2d/RecordedEvent.h rename to libazure/RecordedEvent.h index bf7d391..fca0076 100644 --- a/libazure/src/gfx/2d/RecordedEvent.h +++ b/libazure/RecordedEvent.h @@ -20,10 +20,10 @@ namespace gfx { // loss of backwards compatibility. Old streams will not work in a player // using a newer major revision. And new streams will not work in a player // using an older major revision. -const uint16_t kMajorRevision = 2; +const uint16_t kMajorRevision = 3; // A change in minor revision means additions of new events. New streams will // not play in older players. -const uint16_t kMinorRevision = 0; +const uint16_t kMinorRevision = 2; struct ReferencePtr { @@ -31,7 +31,7 @@ struct ReferencePtr : mLongPtr(0) {} - ReferencePtr(const void* aLongPtr) + MOZ_IMPLICIT ReferencePtr(const void* aLongPtr) : mLongPtr(uint64_t(aLongPtr)) {} @@ -69,9 +69,12 @@ inline std::string StringFromPtr(ReferencePtr aPtr) class Translator { public: + virtual ~Translator() {} + virtual DrawTarget *LookupDrawTarget(ReferencePtr aRefPtr) = 0; virtual Path *LookupPath(ReferencePtr aRefPtr) = 0; virtual SourceSurface *LookupSourceSurface(ReferencePtr aRefPtr) = 0; + virtual FilterNode *LookupFilterNode(ReferencePtr aRefPtr) = 0; virtual GradientStops *LookupGradientStops(ReferencePtr aRefPtr) = 0; virtual ScaledFont *LookupScaledFont(ReferencePtr aRefPtr) = 0; virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) = 0; @@ -80,6 +83,8 @@ class Translator virtual void RemovePath(ReferencePtr aRefPtr) = 0; virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aPath) = 0; virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0; + virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, FilterNode *aSurface) = 0; + virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0; virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aPath) = 0; virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0; virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) = 0; @@ -160,8 +165,17 @@ class RecordedEvent { GRADIENTSTOPSDESTRUCTION, SNAPSHOT, SCALEDFONTCREATION, - SCALEDFONTDESTRUCTION + SCALEDFONTDESTRUCTION, + MASKSURFACE, + FILTERNODECREATION, + FILTERNODEDESTRUCTION, + DRAWFILTER, + FILTERNODESETATTRIBUTE, + FILTERNODESETINPUT }; + static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1; + + static std::string GetEventName(EventType aType); virtual void PlayEvent(Translator *aTranslator) const {} @@ -177,7 +191,7 @@ class RecordedEvent { virtual std::string GetName() const = 0; - virtual ReferencePtr GetObject() const = 0; + virtual ReferencePtr GetObjectRef() const = 0; virtual ReferencePtr GetDestinedDT() { return nullptr; } @@ -189,7 +203,7 @@ class RecordedEvent { protected: friend class DrawEventRecorderPrivate; - RecordedEvent(int32_t aType) : mType(aType) + MOZ_IMPLICIT RecordedEvent(int32_t aType) : mType(aType) {} int32_t mType; @@ -210,15 +224,17 @@ class RecordedDrawingEvent : public RecordedEvent RecordedDrawingEvent(EventType aType, std::istream &aStream); virtual void RecordToStream(std::ostream &aStream) const; - virtual ReferencePtr GetObject() const; + virtual ReferencePtr GetObjectRef() const; ReferencePtr mDT; }; class RecordedDrawTargetCreation : public RecordedEvent { public: - RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType, const IntSize &aSize, SurfaceFormat aFormat) + RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType, const IntSize &aSize, SurfaceFormat aFormat, + bool aHasExistingData = false, SourceSurface *aExistingData = nullptr) : RecordedEvent(DRAWTARGETCREATION), mRefPtr(aRefPtr), mBackendType(aType), mSize(aSize), mFormat(aFormat) + , mHasExistingData(aHasExistingData), mExistingData(aExistingData) {} virtual void PlayEvent(Translator *aTranslator) const; @@ -227,22 +243,24 @@ class RecordedDrawTargetCreation : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "DrawTarget Creation"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } ReferencePtr mRefPtr; BackendType mBackendType; IntSize mSize; SurfaceFormat mFormat; + bool mHasExistingData; + RefPtr mExistingData; private: friend class RecordedEvent; - RecordedDrawTargetCreation(std::istream &aStream); + MOZ_IMPLICIT RecordedDrawTargetCreation(std::istream &aStream); }; class RecordedDrawTargetDestruction : public RecordedEvent { public: - RecordedDrawTargetDestruction(ReferencePtr aRefPtr) + MOZ_IMPLICIT RecordedDrawTargetDestruction(ReferencePtr aRefPtr) : RecordedEvent(DRAWTARGETDESTRUCTION), mRefPtr(aRefPtr) {} @@ -252,7 +270,7 @@ class RecordedDrawTargetDestruction : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "DrawTarget Destruction"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } ReferencePtr mRefPtr; @@ -260,7 +278,7 @@ class RecordedDrawTargetDestruction : public RecordedEvent { private: friend class RecordedEvent; - RecordedDrawTargetDestruction(std::istream &aStream); + MOZ_IMPLICIT RecordedDrawTargetDestruction(std::istream &aStream); }; class RecordedFillRect : public RecordedDrawingEvent { @@ -280,7 +298,7 @@ class RecordedFillRect : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedFillRect(std::istream &aStream); + MOZ_IMPLICIT RecordedFillRect(std::istream &aStream); Rect mRect; PatternStorage mPattern; @@ -306,7 +324,7 @@ class RecordedStrokeRect : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedStrokeRect(std::istream &aStream); + MOZ_IMPLICIT RecordedStrokeRect(std::istream &aStream); Rect mRect; PatternStorage mPattern; @@ -334,7 +352,7 @@ class RecordedStrokeLine : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedStrokeLine(std::istream &aStream); + MOZ_IMPLICIT RecordedStrokeLine(std::istream &aStream); Point mBegin; Point mEnd; @@ -360,7 +378,7 @@ class RecordedFill : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedFill(std::istream &aStream); + MOZ_IMPLICIT RecordedFill(std::istream &aStream); ReferencePtr mPath; PatternStorage mPattern; @@ -389,7 +407,7 @@ class RecordedFillGlyphs : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedFillGlyphs(std::istream &aStream); + MOZ_IMPLICIT RecordedFillGlyphs(std::istream &aStream); ReferencePtr mScaledFont; PatternStorage mPattern; @@ -416,7 +434,7 @@ class RecordedMask : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedMask(std::istream &aStream); + MOZ_IMPLICIT RecordedMask(std::istream &aStream); PatternStorage mSource; PatternStorage mMask; @@ -442,7 +460,7 @@ class RecordedStroke : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedStroke(std::istream &aStream); + MOZ_IMPLICIT RecordedStroke(std::istream &aStream); ReferencePtr mPath; PatternStorage mPattern; @@ -466,7 +484,7 @@ class RecordedClearRect : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedClearRect(std::istream &aStream); + MOZ_IMPLICIT RecordedClearRect(std::istream &aStream); Rect mRect; }; @@ -489,7 +507,7 @@ class RecordedCopySurface : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedCopySurface(std::istream &aStream); + MOZ_IMPLICIT RecordedCopySurface(std::istream &aStream); ReferencePtr mSourceSurface; IntRect mSourceRect; @@ -512,7 +530,7 @@ class RecordedPushClip : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedPushClip(std::istream &aStream); + MOZ_IMPLICIT RecordedPushClip(std::istream &aStream); ReferencePtr mPath; }; @@ -533,14 +551,14 @@ class RecordedPushClipRect : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedPushClipRect(std::istream &aStream); + MOZ_IMPLICIT RecordedPushClipRect(std::istream &aStream); Rect mRect; }; class RecordedPopClip : public RecordedDrawingEvent { public: - RecordedPopClip(DrawTarget *aDT) + MOZ_IMPLICIT RecordedPopClip(DrawTarget *aDT) : RecordedDrawingEvent(POPCLIP, aDT) {} @@ -553,7 +571,7 @@ class RecordedPopClip : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedPopClip(std::istream &aStream); + MOZ_IMPLICIT RecordedPopClip(std::istream &aStream); }; class RecordedSetTransform : public RecordedDrawingEvent { @@ -572,7 +590,7 @@ class RecordedSetTransform : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedSetTransform(std::istream &aStream); + MOZ_IMPLICIT RecordedSetTransform(std::istream &aStream); Matrix mTransform; }; @@ -596,7 +614,7 @@ class RecordedDrawSurface : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedDrawSurface(std::istream &aStream); + MOZ_IMPLICIT RecordedDrawSurface(std::istream &aStream); ReferencePtr mRefSource; Rect mDest; @@ -624,7 +642,7 @@ class RecordedDrawSurfaceWithShadow : public RecordedDrawingEvent { private: friend class RecordedEvent; - RecordedDrawSurfaceWithShadow(std::istream &aStream); + MOZ_IMPLICIT RecordedDrawSurfaceWithShadow(std::istream &aStream); ReferencePtr mRefSource; Point mDest; @@ -634,9 +652,37 @@ class RecordedDrawSurfaceWithShadow : public RecordedDrawingEvent { CompositionOp mOp; }; +class RecordedDrawFilter : public RecordedDrawingEvent { +public: + RecordedDrawFilter(DrawTarget *aDT, ReferencePtr aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) + : RecordedDrawingEvent(DRAWFILTER, aDT), mNode(aNode), mSourceRect(aSourceRect) + , mDestPoint(aDestPoint), mOptions(aOptions) + { + } + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "DrawFilter"; } +private: + friend class RecordedEvent; + + MOZ_IMPLICIT RecordedDrawFilter(std::istream &aStream); + + ReferencePtr mNode; + Rect mSourceRect; + Point mDestPoint; + DrawOptions mOptions; +}; + class RecordedPathCreation : public RecordedEvent { public: - RecordedPathCreation(PathRecording *aPath); + MOZ_IMPLICIT RecordedPathCreation(PathRecording *aPath); ~RecordedPathCreation(); virtual void PlayEvent(Translator *aTranslator) const; @@ -645,7 +691,7 @@ class RecordedPathCreation : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "Path Creation"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; @@ -653,12 +699,12 @@ class RecordedPathCreation : public RecordedEvent { FillRule mFillRule; std::vector mPathOps; - RecordedPathCreation(std::istream &aStream); + MOZ_IMPLICIT RecordedPathCreation(std::istream &aStream); }; class RecordedPathDestruction : public RecordedEvent { public: - RecordedPathDestruction(PathRecording *aPath) + MOZ_IMPLICIT RecordedPathDestruction(PathRecording *aPath) : RecordedEvent(PATHDESTRUCTION), mRefPtr(aPath) { } @@ -669,13 +715,13 @@ class RecordedPathDestruction : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "Path Destruction"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; ReferencePtr mRefPtr; - RecordedPathDestruction(std::istream &aStream); + MOZ_IMPLICIT RecordedPathDestruction(std::istream &aStream); }; class RecordedSourceSurfaceCreation : public RecordedEvent { @@ -695,7 +741,7 @@ class RecordedSourceSurfaceCreation : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "SourceSurface Creation"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; @@ -706,12 +752,12 @@ class RecordedSourceSurfaceCreation : public RecordedEvent { SurfaceFormat mFormat; bool mDataOwned; - RecordedSourceSurfaceCreation(std::istream &aStream); + MOZ_IMPLICIT RecordedSourceSurfaceCreation(std::istream &aStream); }; class RecordedSourceSurfaceDestruction : public RecordedEvent { public: - RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr) + MOZ_IMPLICIT RecordedSourceSurfaceDestruction(ReferencePtr aRefPtr) : RecordedEvent(SOURCESURFACEDESTRUCTION), mRefPtr(aRefPtr) { } @@ -722,13 +768,60 @@ class RecordedSourceSurfaceDestruction : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "SourceSurface Destruction"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } +private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + MOZ_IMPLICIT RecordedSourceSurfaceDestruction(std::istream &aStream); +}; + +class RecordedFilterNodeCreation : public RecordedEvent { +public: + RecordedFilterNodeCreation(ReferencePtr aRefPtr, FilterType aType) + : RecordedEvent(FILTERNODECREATION), mRefPtr(aRefPtr), mType(aType) + { + } + + ~RecordedFilterNodeCreation(); + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "FilterNode Creation"; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; ReferencePtr mRefPtr; + FilterType mType; - RecordedSourceSurfaceDestruction(std::istream &aStream); + MOZ_IMPLICIT RecordedFilterNodeCreation(std::istream &aStream); +}; + +class RecordedFilterNodeDestruction : public RecordedEvent { +public: + MOZ_IMPLICIT RecordedFilterNodeDestruction(ReferencePtr aRefPtr) + : RecordedEvent(FILTERNODEDESTRUCTION), mRefPtr(aRefPtr) + { + } + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "FilterNode Destruction"; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } +private: + friend class RecordedEvent; + + ReferencePtr mRefPtr; + + MOZ_IMPLICIT RecordedFilterNodeDestruction(std::istream &aStream); }; class RecordedGradientStopsCreation : public RecordedEvent { @@ -748,7 +841,7 @@ class RecordedGradientStopsCreation : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "GradientStops Creation"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; @@ -758,12 +851,12 @@ class RecordedGradientStopsCreation : public RecordedEvent { ExtendMode mExtendMode; bool mDataOwned; - RecordedGradientStopsCreation(std::istream &aStream); + MOZ_IMPLICIT RecordedGradientStopsCreation(std::istream &aStream); }; class RecordedGradientStopsDestruction : public RecordedEvent { public: - RecordedGradientStopsDestruction(ReferencePtr aRefPtr) + MOZ_IMPLICIT RecordedGradientStopsDestruction(ReferencePtr aRefPtr) : RecordedEvent(GRADIENTSTOPSDESTRUCTION), mRefPtr(aRefPtr) { } @@ -774,13 +867,13 @@ class RecordedGradientStopsDestruction : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "GradientStops Destruction"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; ReferencePtr mRefPtr; - RecordedGradientStopsDestruction(std::istream &aStream); + MOZ_IMPLICIT RecordedGradientStopsDestruction(std::istream &aStream); }; class RecordedSnapshot : public RecordedEvent { @@ -796,14 +889,14 @@ class RecordedSnapshot : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "Snapshot"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; ReferencePtr mRefPtr; ReferencePtr mDT; - RecordedSnapshot(std::istream &aStream); + MOZ_IMPLICIT RecordedSnapshot(std::istream &aStream); }; class RecordedScaledFontCreation : public RecordedEvent { @@ -814,7 +907,7 @@ class RecordedScaledFontCreation : public RecordedEvent { } RecordedScaledFontCreation(ReferencePtr aRefPtr, ScaledFont *aScaledFont) - : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(NULL) + : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(nullptr) { aScaledFont->GetFontFileData(&FontDataProc, this); } @@ -827,7 +920,7 @@ class RecordedScaledFontCreation : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "ScaledFont Creation"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize); @@ -840,12 +933,12 @@ class RecordedScaledFontCreation : public RecordedEvent { Float mGlyphSize; uint32_t mIndex; - RecordedScaledFontCreation(std::istream &aStream); + MOZ_IMPLICIT RecordedScaledFontCreation(std::istream &aStream); }; class RecordedScaledFontDestruction : public RecordedEvent { public: - RecordedScaledFontDestruction(ReferencePtr aRefPtr) + MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr) : RecordedEvent(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr) { } @@ -856,13 +949,128 @@ class RecordedScaledFontDestruction : public RecordedEvent { virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; virtual std::string GetName() const { return "ScaledFont Destruction"; } - virtual ReferencePtr GetObject() const { return mRefPtr; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } private: friend class RecordedEvent; ReferencePtr mRefPtr; - RecordedScaledFontDestruction(std::istream &aStream); + MOZ_IMPLICIT RecordedScaledFontDestruction(std::istream &aStream); +}; + +class RecordedMaskSurface : public RecordedDrawingEvent { +public: + RecordedMaskSurface(DrawTarget *aDT, const Pattern &aPattern, ReferencePtr aRefMask, + const Point &aOffset, const DrawOptions &aOptions) + : RecordedDrawingEvent(MASKSURFACE, aDT), mRefMask(aRefMask), mOffset(aOffset) + , mOptions(aOptions) + { + StorePattern(mPattern, aPattern); + } + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "MaskSurface"; } +private: + friend class RecordedEvent; + + MOZ_IMPLICIT RecordedMaskSurface(std::istream &aStream); + + PatternStorage mPattern; + ReferencePtr mRefMask; + Point mOffset; + DrawOptions mOptions; +}; + +class RecordedFilterNodeSetAttribute : public RecordedEvent +{ +public: + enum ArgType { + ARGTYPE_UINT32, + ARGTYPE_BOOL, + ARGTYPE_FLOAT, + ARGTYPE_SIZE, + ARGTYPE_INTSIZE, + ARGTYPE_INTPOINT, + ARGTYPE_RECT, + ARGTYPE_INTRECT, + ARGTYPE_POINT, + ARGTYPE_MATRIX5X4, + ARGTYPE_POINT3D, + ARGTYPE_COLOR, + ARGTYPE_FLOAT_ARRAY + }; + + template + RecordedFilterNodeSetAttribute(FilterNode *aNode, uint32_t aIndex, T aArgument, ArgType aArgType) + : RecordedEvent(FILTERNODESETATTRIBUTE), mNode(aNode), mIndex(aIndex), mArgType(aArgType) + { + mPayload.resize(sizeof(T)); + memcpy(&mPayload.front(), &aArgument, sizeof(T)); + } + + RecordedFilterNodeSetAttribute(FilterNode *aNode, uint32_t aIndex, const Float *aFloat, uint32_t aSize) + : RecordedEvent(FILTERNODESETATTRIBUTE), mNode(aNode), mIndex(aIndex), mArgType(ARGTYPE_FLOAT_ARRAY) + { + mPayload.resize(sizeof(Float) * aSize); + memcpy(&mPayload.front(), aFloat, sizeof(Float) * aSize); + } + + virtual void PlayEvent(Translator *aTranslator) const; + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "SetAttribute"; } + + virtual ReferencePtr GetObjectRef() const { return mNode; } + +private: + friend class RecordedEvent; + + ReferencePtr mNode; + + uint32_t mIndex; + ArgType mArgType; + std::vector mPayload; + + MOZ_IMPLICIT RecordedFilterNodeSetAttribute(std::istream &aStream); +}; + +class RecordedFilterNodeSetInput : public RecordedEvent +{ +public: + RecordedFilterNodeSetInput(FilterNode* aNode, uint32_t aIndex, FilterNode* aInputNode) + : RecordedEvent(FILTERNODESETINPUT), mNode(aNode), mIndex(aIndex) + , mInputFilter(aInputNode), mInputSurface(nullptr) + { + } + + RecordedFilterNodeSetInput(FilterNode *aNode, uint32_t aIndex, SourceSurface *aInputSurface) + : RecordedEvent(FILTERNODESETINPUT), mNode(aNode), mIndex(aIndex) + , mInputFilter(nullptr), mInputSurface(aInputSurface) + { + } + + virtual void PlayEvent(Translator *aTranslator) const; + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "SetInput"; } + + virtual ReferencePtr GetObjectRef() const { return mNode; } + +private: + friend class RecordedEvent; + + ReferencePtr mNode; + uint32_t mIndex; + ReferencePtr mInputFilter; + ReferencePtr mInputSurface; + + MOZ_IMPLICIT RecordedFilterNodeSetInput(std::istream &aStream); }; } diff --git a/libazure/src/gfx/2d/RecordingTypes.h b/libazure/RecordingTypes.h similarity index 100% rename from libazure/src/gfx/2d/RecordingTypes.h rename to libazure/RecordingTypes.h diff --git a/libazure/Rect.h b/libazure/Rect.h new file mode 100644 index 0000000..baf5be0 --- /dev/null +++ b/libazure/Rect.h @@ -0,0 +1,159 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_RECT_H_ +#define MOZILLA_GFX_RECT_H_ + +#include "BaseRect.h" +#include "BaseMargin.h" +#include "Point.h" +#include "Tools.h" + +#include + +namespace mozilla { + +template struct IsPixel; + +namespace gfx { + +template +struct IntMarginTyped: + public BaseMargin >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseMargin > Super; + + IntMarginTyped() : Super() {} + IntMarginTyped(int32_t aTop, int32_t aRight, int32_t aBottom, int32_t aLeft) : + Super(aTop, aRight, aBottom, aLeft) {} +}; +typedef IntMarginTyped IntMargin; + +template +struct MarginTyped: + public BaseMargin >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseMargin > Super; + + MarginTyped() : Super() {} + MarginTyped(Float aTop, Float aRight, Float aBottom, Float aLeft) : + Super(aTop, aRight, aBottom, aLeft) {} + explicit MarginTyped(const IntMarginTyped& aMargin) : + Super(float(aMargin.top), float(aMargin.right), + float(aMargin.bottom), float(aMargin.left)) {} +}; +typedef MarginTyped Margin; + +template +struct IntRectTyped : + public BaseRect, IntPointTyped, IntSizeTyped, IntMarginTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseRect, IntPointTyped, IntSizeTyped, IntMarginTyped > Super; + + IntRectTyped() : Super() {} + IntRectTyped(IntPointTyped aPos, IntSizeTyped aSize) : + Super(aPos, aSize) {} + IntRectTyped(int32_t _x, int32_t _y, int32_t _width, int32_t _height) : + Super(_x, _y, _width, _height) {} + + // Rounding isn't meaningful on an integer rectangle. + void Round() {} + void RoundIn() {} + void RoundOut() {} + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static IntRectTyped FromUnknownRect(const IntRectTyped& rect) { + return IntRectTyped(rect.x, rect.y, rect.width, rect.height); + } + + IntRectTyped ToUnknownRect() const { + return IntRectTyped(this->x, this->y, this->width, this->height); + } +}; +typedef IntRectTyped IntRect; + +template +struct RectTyped : + public BaseRect, PointTyped, SizeTyped, MarginTyped >, + public units { + static_assert(IsPixel::value, + "'units' must be a coordinate system tag"); + + typedef BaseRect, PointTyped, SizeTyped, MarginTyped > Super; + + RectTyped() : Super() {} + RectTyped(PointTyped aPos, SizeTyped aSize) : + Super(aPos, aSize) {} + RectTyped(Float _x, Float _y, Float _width, Float _height) : + Super(_x, _y, _width, _height) {} + explicit RectTyped(const IntRectTyped& rect) : + Super(float(rect.x), float(rect.y), + float(rect.width), float(rect.height)) {} + + void NudgeToIntegers() + { + NudgeToInteger(&(this->x)); + NudgeToInteger(&(this->y)); + NudgeToInteger(&(this->width)); + NudgeToInteger(&(this->height)); + } + + bool ToIntRect(IntRectTyped *aOut) const + { + *aOut = IntRectTyped(int32_t(this->X()), int32_t(this->Y()), + int32_t(this->Width()), int32_t(this->Height())); + return RectTyped(Float(aOut->x), Float(aOut->y), + Float(aOut->width), Float(aOut->height)) + .IsEqualEdges(*this); + } + + // XXX When all of the code is ported, the following functions to convert to and from + // unknown types should be removed. + + static RectTyped FromUnknownRect(const RectTyped& rect) { + return RectTyped(rect.x, rect.y, rect.width, rect.height); + } + + RectTyped ToUnknownRect() const { + return RectTyped(this->x, this->y, this->width, this->height); + } +}; +typedef RectTyped Rect; + +template +IntRectTyped RoundedToInt(const RectTyped& aRect) +{ + return IntRectTyped(int32_t(floorf(aRect.x + 0.5f)), + int32_t(floorf(aRect.y + 0.5f)), + int32_t(floorf(aRect.width + 0.5f)), + int32_t(floorf(aRect.height + 0.5f))); +} + +template +IntRectTyped RoundedIn(const RectTyped& aRect) +{ + RectTyped copy(aRect); + copy.RoundIn(); + return IntRectTyped(int32_t(copy.x), + int32_t(copy.y), + int32_t(copy.width), + int32_t(copy.height)); +} + +} +} + +#endif /* MOZILLA_GFX_RECT_H_ */ diff --git a/libazure/SIMD.h b/libazure/SIMD.h new file mode 100644 index 0000000..6bf53a3 --- /dev/null +++ b/libazure/SIMD.h @@ -0,0 +1,1180 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MOZILLA_GFX_SIMD_H_ +#define _MOZILLA_GFX_SIMD_H_ + +/** + * Consumers of this file need to #define SIMD_COMPILE_SSE2 before including it + * if they want access to the SSE2 functions. + */ + +#ifdef SIMD_COMPILE_SSE2 +#include +#endif + +namespace mozilla { +namespace gfx { + +namespace simd { + +template +u8x16_t Load8(const uint8_t* aSource); + +template +u8x16_t From8(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, uint8_t m, uint8_t n, uint8_t o, uint8_t p); + +template +u8x16_t FromZero8(); + +template +i16x8_t FromI16(int16_t a, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g, int16_t h); + +template +u16x8_t FromU16(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h); + +template +i16x8_t FromI16(int16_t a); + +template +u16x8_t FromU16(uint16_t a); + +template +i32x4_t From32(int32_t a, int32_t b, int32_t c, int32_t d); + +template +i32x4_t From32(int32_t a); + +template +f32x4_t FromF32(float a, float b, float c, float d); + +template +f32x4_t FromF32(float a); + +// All SIMD backends overload these functions for their SIMD types: + +#if 0 + +// Store 16 bytes to a 16-byte aligned address +void Store8(uint8_t* aTarget, u8x16_t aM); + +// Fixed shifts +template i16x8_t ShiftRight16(i16x8_t aM); +template i32x4_t ShiftRight32(i32x4_t aM); + +i16x8_t Add16(i16x8_t aM1, i16x8_t aM2); +i32x4_t Add32(i32x4_t aM1, i32x4_t aM2); +i16x8_t Sub16(i16x8_t aM1, i16x8_t aM2); +i32x4_t Sub32(i32x4_t aM1, i32x4_t aM2); +u8x16_t Min8(u8x16_t aM1, iu8x16_t aM2); +u8x16_t Max8(u8x16_t aM1, iu8x16_t aM2); +i32x4_t Min32(i32x4_t aM1, i32x4_t aM2); +i32x4_t Max32(i32x4_t aM1, i32x4_t aM2); + +// Truncating i16 -> i16 multiplication +i16x8_t Mul16(i16x8_t aM1, i16x8_t aM2); + +// Long multiplication i16 -> i32 +// aFactorsA1B1 = (a1[4] b1[4]) +// aFactorsA2B2 = (a2[4] b2[4]) +// aProductA = a1 * a2, aProductB = b1 * b2 +void Mul16x4x2x2To32x4x2(i16x8_t aFactorsA1B1, i16x8_t aFactorsA2B2, + i32x4_t& aProductA, i32x4_t& aProductB); + +// Long multiplication + pairwise addition i16 -> i32 +// See the scalar implementation for specifics. +i32x4_t MulAdd16x8x2To32x4(i16x8_t aFactorsA, i16x8_t aFactorsB); +i32x4_t MulAdd16x8x2To32x4(u16x8_t aFactorsA, u16x8_t aFactorsB); + +// Set all four 32-bit components to the value of the component at aIndex. +template +i32x4_t Splat32(i32x4_t aM); + +// Interpret the input as four 32-bit values, apply Splat32 on them, +// re-interpret the result as sixteen 8-bit values. +template +u8x16_t Splat32On8(u8x16_t aM); + +template i32x4 Shuffle32(i32x4 aM); +template i16x8 ShuffleLo16(i16x8 aM); +template i16x8 ShuffleHi16(i16x8 aM); + +u8x16_t InterleaveLo8(u8x16_t m1, u8x16_t m2); +u8x16_t InterleaveHi8(u8x16_t m1, u8x16_t m2); +i16x8_t InterleaveLo16(i16x8_t m1, i16x8_t m2); +i16x8_t InterleaveHi16(i16x8_t m1, i16x8_t m2); +i32x4_t InterleaveLo32(i32x4_t m1, i32x4_t m2); + +i16x8_t UnpackLo8x8ToI16x8(u8x16_t m); +i16x8_t UnpackHi8x8ToI16x8(u8x16_t m); +u16x8_t UnpackLo8x8ToU16x8(u8x16_t m); +u16x8_t UnpackHi8x8ToU16x8(u8x16_t m); + +i16x8_t PackAndSaturate32To16(i32x4_t m1, i32x4_t m2); +u8x16_t PackAndSaturate16To8(i16x8_t m1, i16x8_t m2); +u8x16_t PackAndSaturate32To8(i32x4_t m1, i32x4_t m2, i32x4_t m3, const i32x4_t& m4); + +i32x4 FastDivideBy255(i32x4 m); +i16x8 FastDivideBy255_16(i16x8 m); + +#endif + +// Scalar + +struct Scalaru8x16_t { + uint8_t u8[16]; +}; + +union Scalari16x8_t { + int16_t i16[8]; + uint16_t u16[8]; +}; + +typedef Scalari16x8_t Scalaru16x8_t; + +struct Scalari32x4_t { + int32_t i32[4]; +}; + +struct Scalarf32x4_t { + float f32[4]; +}; + +template<> +inline Scalaru8x16_t +Load8(const uint8_t* aSource) +{ + return *(Scalaru8x16_t*)aSource; +} + +inline void Store8(uint8_t* aTarget, Scalaru8x16_t aM) +{ + *(Scalaru8x16_t*)aTarget = aM; +} + +template<> +inline Scalaru8x16_t From8(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, uint8_t m, uint8_t n, uint8_t o, uint8_t p) +{ + Scalaru8x16_t _m; + _m.u8[0] = a; + _m.u8[1] = b; + _m.u8[2] = c; + _m.u8[3] = d; + _m.u8[4] = e; + _m.u8[5] = f; + _m.u8[6] = g; + _m.u8[7] = h; + _m.u8[8+0] = i; + _m.u8[8+1] = j; + _m.u8[8+2] = k; + _m.u8[8+3] = l; + _m.u8[8+4] = m; + _m.u8[8+5] = n; + _m.u8[8+6] = o; + _m.u8[8+7] = p; + return _m; +} + +template<> +inline Scalaru8x16_t FromZero8() +{ + return From8(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); +} + +template<> +inline Scalari16x8_t FromI16(int16_t a, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g, int16_t h) +{ + Scalari16x8_t m; + m.i16[0] = a; + m.i16[1] = b; + m.i16[2] = c; + m.i16[3] = d; + m.i16[4] = e; + m.i16[5] = f; + m.i16[6] = g; + m.i16[7] = h; + return m; +} + +template<> +inline Scalaru16x8_t FromU16(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h) +{ + Scalaru16x8_t m; + m.u16[0] = a; + m.u16[1] = b; + m.u16[2] = c; + m.u16[3] = d; + m.u16[4] = e; + m.u16[5] = f; + m.u16[6] = g; + m.u16[7] = h; + return m; +} + +template<> +inline Scalari16x8_t FromI16(int16_t a) +{ + return FromI16(a, a, a, a, a, a, a, a); +} + +template<> +inline Scalaru16x8_t FromU16(uint16_t a) +{ + return FromU16(a, a, a, a, a, a, a, a); +} + +template<> +inline Scalari32x4_t From32(int32_t a, int32_t b, int32_t c, int32_t d) +{ + Scalari32x4_t m; + m.i32[0] = a; + m.i32[1] = b; + m.i32[2] = c; + m.i32[3] = d; + return m; +} + +template<> +inline Scalarf32x4_t FromF32(float a, float b, float c, float d) +{ + Scalarf32x4_t m; + m.f32[0] = a; + m.f32[1] = b; + m.f32[2] = c; + m.f32[3] = d; + return m; +} + +template<> +inline Scalarf32x4_t FromF32(float a) +{ + return FromF32(a, a, a, a); +} + +template<> +inline Scalari32x4_t From32(int32_t a) +{ + return From32(a, a, a, a); +} + +template +inline Scalari16x8_t ShiftRight16(Scalari16x8_t aM) +{ + return FromI16(uint16_t(aM.i16[0]) >> aNumberOfBits, uint16_t(aM.i16[1]) >> aNumberOfBits, + uint16_t(aM.i16[2]) >> aNumberOfBits, uint16_t(aM.i16[3]) >> aNumberOfBits, + uint16_t(aM.i16[4]) >> aNumberOfBits, uint16_t(aM.i16[5]) >> aNumberOfBits, + uint16_t(aM.i16[6]) >> aNumberOfBits, uint16_t(aM.i16[7]) >> aNumberOfBits); +} + +template +inline Scalari32x4_t ShiftRight32(Scalari32x4_t aM) +{ + return From32(aM.i32[0] >> aNumberOfBits, aM.i32[1] >> aNumberOfBits, + aM.i32[2] >> aNumberOfBits, aM.i32[3] >> aNumberOfBits); +} + +inline Scalaru16x8_t Add16(Scalaru16x8_t aM1, Scalaru16x8_t aM2) +{ + return FromU16(aM1.u16[0] + aM2.u16[0], aM1.u16[1] + aM2.u16[1], + aM1.u16[2] + aM2.u16[2], aM1.u16[3] + aM2.u16[3], + aM1.u16[4] + aM2.u16[4], aM1.u16[5] + aM2.u16[5], + aM1.u16[6] + aM2.u16[6], aM1.u16[7] + aM2.u16[7]); +} + +inline Scalari32x4_t Add32(Scalari32x4_t aM1, Scalari32x4_t aM2) +{ + return From32(aM1.i32[0] + aM2.i32[0], aM1.i32[1] + aM2.i32[1], + aM1.i32[2] + aM2.i32[2], aM1.i32[3] + aM2.i32[3]); +} + +inline Scalaru16x8_t Sub16(Scalaru16x8_t aM1, Scalaru16x8_t aM2) +{ + return FromU16(aM1.u16[0] - aM2.u16[0], aM1.u16[1] - aM2.u16[1], + aM1.u16[2] - aM2.u16[2], aM1.u16[3] - aM2.u16[3], + aM1.u16[4] - aM2.u16[4], aM1.u16[5] - aM2.u16[5], + aM1.u16[6] - aM2.u16[6], aM1.u16[7] - aM2.u16[7]); +} + +inline Scalari32x4_t Sub32(Scalari32x4_t aM1, Scalari32x4_t aM2) +{ + return From32(aM1.i32[0] - aM2.i32[0], aM1.i32[1] - aM2.i32[1], + aM1.i32[2] - aM2.i32[2], aM1.i32[3] - aM2.i32[3]); +} + +inline int32_t +umin(int32_t a, int32_t b) +{ + return a - ((a - b) & -(a > b)); +} + +inline int32_t +umax(int32_t a, int32_t b) +{ + return a - ((a - b) & -(a < b)); +} + +inline Scalaru8x16_t Min8(Scalaru8x16_t aM1, Scalaru8x16_t aM2) +{ + return From8(umin(aM1.u8[0], aM2.u8[0]), umin(aM1.u8[1], aM2.u8[1]), + umin(aM1.u8[2], aM2.u8[2]), umin(aM1.u8[3], aM2.u8[3]), + umin(aM1.u8[4], aM2.u8[4]), umin(aM1.u8[5], aM2.u8[5]), + umin(aM1.u8[6], aM2.u8[6]), umin(aM1.u8[7], aM2.u8[7]), + umin(aM1.u8[8+0], aM2.u8[8+0]), umin(aM1.u8[8+1], aM2.u8[8+1]), + umin(aM1.u8[8+2], aM2.u8[8+2]), umin(aM1.u8[8+3], aM2.u8[8+3]), + umin(aM1.u8[8+4], aM2.u8[8+4]), umin(aM1.u8[8+5], aM2.u8[8+5]), + umin(aM1.u8[8+6], aM2.u8[8+6]), umin(aM1.u8[8+7], aM2.u8[8+7])); +} + +inline Scalaru8x16_t Max8(Scalaru8x16_t aM1, Scalaru8x16_t aM2) +{ + return From8(umax(aM1.u8[0], aM2.u8[0]), umax(aM1.u8[1], aM2.u8[1]), + umax(aM1.u8[2], aM2.u8[2]), umax(aM1.u8[3], aM2.u8[3]), + umax(aM1.u8[4], aM2.u8[4]), umax(aM1.u8[5], aM2.u8[5]), + umax(aM1.u8[6], aM2.u8[6]), umax(aM1.u8[7], aM2.u8[7]), + umax(aM1.u8[8+0], aM2.u8[8+0]), umax(aM1.u8[8+1], aM2.u8[8+1]), + umax(aM1.u8[8+2], aM2.u8[8+2]), umax(aM1.u8[8+3], aM2.u8[8+3]), + umax(aM1.u8[8+4], aM2.u8[8+4]), umax(aM1.u8[8+5], aM2.u8[8+5]), + umax(aM1.u8[8+6], aM2.u8[8+6]), umax(aM1.u8[8+7], aM2.u8[8+7])); +} + +inline Scalari32x4_t Min32(Scalari32x4_t aM1, Scalari32x4_t aM2) +{ + return From32(umin(aM1.i32[0], aM2.i32[0]), umin(aM1.i32[1], aM2.i32[1]), + umin(aM1.i32[2], aM2.i32[2]), umin(aM1.i32[3], aM2.i32[3])); +} + +inline Scalari32x4_t Max32(Scalari32x4_t aM1, Scalari32x4_t aM2) +{ + return From32(umax(aM1.i32[0], aM2.i32[0]), umax(aM1.i32[1], aM2.i32[1]), + umax(aM1.i32[2], aM2.i32[2]), umax(aM1.i32[3], aM2.i32[3])); +} + +inline Scalaru16x8_t Mul16(Scalaru16x8_t aM1, Scalaru16x8_t aM2) +{ + return FromU16(uint16_t(int32_t(aM1.u16[0]) * int32_t(aM2.u16[0])), uint16_t(int32_t(aM1.u16[1]) * int32_t(aM2.u16[1])), + uint16_t(int32_t(aM1.u16[2]) * int32_t(aM2.u16[2])), uint16_t(int32_t(aM1.u16[3]) * int32_t(aM2.u16[3])), + uint16_t(int32_t(aM1.u16[4]) * int32_t(aM2.u16[4])), uint16_t(int32_t(aM1.u16[5]) * int32_t(aM2.u16[5])), + uint16_t(int32_t(aM1.u16[6]) * int32_t(aM2.u16[6])), uint16_t(int32_t(aM1.u16[7]) * int32_t(aM2.u16[7]))); +} + +inline void Mul16x4x2x2To32x4x2(Scalari16x8_t aFactorsA1B1, + Scalari16x8_t aFactorsA2B2, + Scalari32x4_t& aProductA, + Scalari32x4_t& aProductB) +{ + aProductA = From32(aFactorsA1B1.i16[0] * aFactorsA2B2.i16[0], + aFactorsA1B1.i16[1] * aFactorsA2B2.i16[1], + aFactorsA1B1.i16[2] * aFactorsA2B2.i16[2], + aFactorsA1B1.i16[3] * aFactorsA2B2.i16[3]); + aProductB = From32(aFactorsA1B1.i16[4] * aFactorsA2B2.i16[4], + aFactorsA1B1.i16[5] * aFactorsA2B2.i16[5], + aFactorsA1B1.i16[6] * aFactorsA2B2.i16[6], + aFactorsA1B1.i16[7] * aFactorsA2B2.i16[7]); +} + +inline Scalari32x4_t MulAdd16x8x2To32x4(Scalari16x8_t aFactorsA, + Scalari16x8_t aFactorsB) +{ + return From32(aFactorsA.i16[0] * aFactorsB.i16[0] + aFactorsA.i16[1] * aFactorsB.i16[1], + aFactorsA.i16[2] * aFactorsB.i16[2] + aFactorsA.i16[3] * aFactorsB.i16[3], + aFactorsA.i16[4] * aFactorsB.i16[4] + aFactorsA.i16[5] * aFactorsB.i16[5], + aFactorsA.i16[6] * aFactorsB.i16[6] + aFactorsA.i16[7] * aFactorsB.i16[7]); +} + +template +inline void AssertIndex() +{ + static_assert(aIndex == 0 || aIndex == 1 || aIndex == 2 || aIndex == 3, + "Invalid splat index"); +} + +template +inline Scalari32x4_t Splat32(Scalari32x4_t aM) +{ + AssertIndex(); + return From32(aM.i32[aIndex], aM.i32[aIndex], + aM.i32[aIndex], aM.i32[aIndex]); +} + +template +inline Scalaru8x16_t Splat32On8(Scalaru8x16_t aM) +{ + AssertIndex(); + return From8(aM.u8[i*4], aM.u8[i*4+1], aM.u8[i*4+2], aM.u8[i*4+3], + aM.u8[i*4], aM.u8[i*4+1], aM.u8[i*4+2], aM.u8[i*4+3], + aM.u8[i*4], aM.u8[i*4+1], aM.u8[i*4+2], aM.u8[i*4+3], + aM.u8[i*4], aM.u8[i*4+1], aM.u8[i*4+2], aM.u8[i*4+3]); +} + +template +inline Scalari32x4_t Shuffle32(Scalari32x4_t aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + Scalari32x4_t m = aM; + m.i32[0] = aM.i32[i3]; + m.i32[1] = aM.i32[i2]; + m.i32[2] = aM.i32[i1]; + m.i32[3] = aM.i32[i0]; + return m; +} + +template +inline Scalari16x8_t ShuffleLo16(Scalari16x8_t aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + Scalari16x8_t m = aM; + m.i16[0] = aM.i16[i3]; + m.i16[1] = aM.i16[i2]; + m.i16[2] = aM.i16[i1]; + m.i16[3] = aM.i16[i0]; + return m; +} + +template +inline Scalari16x8_t ShuffleHi16(Scalari16x8_t aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + Scalari16x8_t m = aM; + m.i16[4 + 0] = aM.i16[4 + i3]; + m.i16[4 + 1] = aM.i16[4 + i2]; + m.i16[4 + 2] = aM.i16[4 + i1]; + m.i16[4 + 3] = aM.i16[4 + i0]; + return m; +} + +template +inline Scalaru16x8_t Splat16(Scalaru16x8_t aM) +{ + AssertIndex(); + AssertIndex(); + Scalaru16x8_t m; + int16_t chosenValueLo = aM.u16[aIndexLo]; + m.u16[0] = chosenValueLo; + m.u16[1] = chosenValueLo; + m.u16[2] = chosenValueLo; + m.u16[3] = chosenValueLo; + int16_t chosenValueHi = aM.u16[4 + aIndexHi]; + m.u16[4] = chosenValueHi; + m.u16[5] = chosenValueHi; + m.u16[6] = chosenValueHi; + m.u16[7] = chosenValueHi; + return m; +} + +inline Scalaru8x16_t +InterleaveLo8(Scalaru8x16_t m1, Scalaru8x16_t m2) +{ + return From8(m1.u8[0], m2.u8[0], m1.u8[1], m2.u8[1], + m1.u8[2], m2.u8[2], m1.u8[3], m2.u8[3], + m1.u8[4], m2.u8[4], m1.u8[5], m2.u8[5], + m1.u8[6], m2.u8[6], m1.u8[7], m2.u8[7]); +} + +inline Scalaru8x16_t +InterleaveHi8(Scalaru8x16_t m1, Scalaru8x16_t m2) +{ + return From8(m1.u8[8+0], m2.u8[8+0], m1.u8[8+1], m2.u8[8+1], + m1.u8[8+2], m2.u8[8+2], m1.u8[8+3], m2.u8[8+3], + m1.u8[8+4], m2.u8[8+4], m1.u8[8+5], m2.u8[8+5], + m1.u8[8+6], m2.u8[8+6], m1.u8[8+7], m2.u8[8+7]); +} + +inline Scalaru16x8_t +InterleaveLo16(Scalaru16x8_t m1, Scalaru16x8_t m2) +{ + return FromU16(m1.u16[0], m2.u16[0], m1.u16[1], m2.u16[1], + m1.u16[2], m2.u16[2], m1.u16[3], m2.u16[3]); +} + +inline Scalaru16x8_t +InterleaveHi16(Scalaru16x8_t m1, Scalaru16x8_t m2) +{ + return FromU16(m1.u16[4], m2.u16[4], m1.u16[5], m2.u16[5], + m1.u16[6], m2.u16[6], m1.u16[7], m2.u16[7]); +} + +inline Scalari32x4_t +InterleaveLo32(Scalari32x4_t m1, Scalari32x4_t m2) +{ + return From32(m1.i32[0], m2.i32[0], m1.i32[1], m2.i32[1]); +} + +inline Scalari16x8_t +UnpackLo8x8ToI16x8(Scalaru8x16_t aM) +{ + Scalari16x8_t m; + m.i16[0] = aM.u8[0]; + m.i16[1] = aM.u8[1]; + m.i16[2] = aM.u8[2]; + m.i16[3] = aM.u8[3]; + m.i16[4] = aM.u8[4]; + m.i16[5] = aM.u8[5]; + m.i16[6] = aM.u8[6]; + m.i16[7] = aM.u8[7]; + return m; +} + +inline Scalari16x8_t +UnpackHi8x8ToI16x8(Scalaru8x16_t aM) +{ + Scalari16x8_t m; + m.i16[0] = aM.u8[8+0]; + m.i16[1] = aM.u8[8+1]; + m.i16[2] = aM.u8[8+2]; + m.i16[3] = aM.u8[8+3]; + m.i16[4] = aM.u8[8+4]; + m.i16[5] = aM.u8[8+5]; + m.i16[6] = aM.u8[8+6]; + m.i16[7] = aM.u8[8+7]; + return m; +} + +inline Scalaru16x8_t +UnpackLo8x8ToU16x8(Scalaru8x16_t aM) +{ + return FromU16(uint16_t(aM.u8[0]), uint16_t(aM.u8[1]), uint16_t(aM.u8[2]), uint16_t(aM.u8[3]), + uint16_t(aM.u8[4]), uint16_t(aM.u8[5]), uint16_t(aM.u8[6]), uint16_t(aM.u8[7])); +} + +inline Scalaru16x8_t +UnpackHi8x8ToU16x8(Scalaru8x16_t aM) +{ + return FromU16(aM.u8[8+0], aM.u8[8+1], aM.u8[8+2], aM.u8[8+3], + aM.u8[8+4], aM.u8[8+5], aM.u8[8+6], aM.u8[8+7]); +} + +template +inline Scalaru8x16_t +Rotate8(Scalaru8x16_t a1234, Scalaru8x16_t a5678) +{ + Scalaru8x16_t m; + for (uint8_t i = 0; i < 16; i++) { + uint8_t sourceByte = i + aNumBytes; + m.u8[i] = sourceByte < 16 ? a1234.u8[sourceByte] : a5678.u8[sourceByte - 16]; + } + return m; +} + +template +inline int16_t +SaturateTo16(T a) +{ + return int16_t(a >= INT16_MIN ? (a <= INT16_MAX ? a : INT16_MAX) : INT16_MIN); +} + +inline Scalari16x8_t +PackAndSaturate32To16(Scalari32x4_t m1, Scalari32x4_t m2) +{ + Scalari16x8_t m; + m.i16[0] = SaturateTo16(m1.i32[0]); + m.i16[1] = SaturateTo16(m1.i32[1]); + m.i16[2] = SaturateTo16(m1.i32[2]); + m.i16[3] = SaturateTo16(m1.i32[3]); + m.i16[4] = SaturateTo16(m2.i32[0]); + m.i16[5] = SaturateTo16(m2.i32[1]); + m.i16[6] = SaturateTo16(m2.i32[2]); + m.i16[7] = SaturateTo16(m2.i32[3]); + return m; +} + +template +inline uint16_t +SaturateToU16(T a) +{ + return uint16_t(umin(a & -(a >= 0), INT16_MAX)); +} + +inline Scalaru16x8_t +PackAndSaturate32ToU16(Scalari32x4_t m1, Scalari32x4_t m2) +{ + Scalaru16x8_t m; + m.u16[0] = SaturateToU16(m1.i32[0]); + m.u16[1] = SaturateToU16(m1.i32[1]); + m.u16[2] = SaturateToU16(m1.i32[2]); + m.u16[3] = SaturateToU16(m1.i32[3]); + m.u16[4] = SaturateToU16(m2.i32[0]); + m.u16[5] = SaturateToU16(m2.i32[1]); + m.u16[6] = SaturateToU16(m2.i32[2]); + m.u16[7] = SaturateToU16(m2.i32[3]); + return m; +} + +template +inline uint8_t +SaturateTo8(T a) +{ + return uint8_t(umin(a & -(a >= 0), 255)); +} + +inline Scalaru8x16_t +PackAndSaturate32To8(Scalari32x4_t m1, Scalari32x4_t m2, Scalari32x4_t m3, const Scalari32x4_t& m4) +{ + Scalaru8x16_t m; + m.u8[0] = SaturateTo8(m1.i32[0]); + m.u8[1] = SaturateTo8(m1.i32[1]); + m.u8[2] = SaturateTo8(m1.i32[2]); + m.u8[3] = SaturateTo8(m1.i32[3]); + m.u8[4] = SaturateTo8(m2.i32[0]); + m.u8[5] = SaturateTo8(m2.i32[1]); + m.u8[6] = SaturateTo8(m2.i32[2]); + m.u8[7] = SaturateTo8(m2.i32[3]); + m.u8[8] = SaturateTo8(m3.i32[0]); + m.u8[9] = SaturateTo8(m3.i32[1]); + m.u8[10] = SaturateTo8(m3.i32[2]); + m.u8[11] = SaturateTo8(m3.i32[3]); + m.u8[12] = SaturateTo8(m4.i32[0]); + m.u8[13] = SaturateTo8(m4.i32[1]); + m.u8[14] = SaturateTo8(m4.i32[2]); + m.u8[15] = SaturateTo8(m4.i32[3]); + return m; +} + +inline Scalaru8x16_t +PackAndSaturate16To8(Scalari16x8_t m1, Scalari16x8_t m2) +{ + Scalaru8x16_t m; + m.u8[0] = SaturateTo8(m1.i16[0]); + m.u8[1] = SaturateTo8(m1.i16[1]); + m.u8[2] = SaturateTo8(m1.i16[2]); + m.u8[3] = SaturateTo8(m1.i16[3]); + m.u8[4] = SaturateTo8(m1.i16[4]); + m.u8[5] = SaturateTo8(m1.i16[5]); + m.u8[6] = SaturateTo8(m1.i16[6]); + m.u8[7] = SaturateTo8(m1.i16[7]); + m.u8[8] = SaturateTo8(m2.i16[0]); + m.u8[9] = SaturateTo8(m2.i16[1]); + m.u8[10] = SaturateTo8(m2.i16[2]); + m.u8[11] = SaturateTo8(m2.i16[3]); + m.u8[12] = SaturateTo8(m2.i16[4]); + m.u8[13] = SaturateTo8(m2.i16[5]); + m.u8[14] = SaturateTo8(m2.i16[6]); + m.u8[15] = SaturateTo8(m2.i16[7]); + return m; +} + +// Fast approximate division by 255. It has the property that +// for all 0 <= n <= 255*255, FAST_DIVIDE_BY_255(n) == n/255. +// But it only uses two adds and two shifts instead of an +// integer division (which is expensive on many processors). +// +// equivalent to v/255 +template +inline B FastDivideBy255(A v) +{ + return ((v << 8) + v + 255) >> 16; +} + +inline Scalaru16x8_t +FastDivideBy255_16(Scalaru16x8_t m) +{ + return FromU16(FastDivideBy255(int32_t(m.u16[0])), + FastDivideBy255(int32_t(m.u16[1])), + FastDivideBy255(int32_t(m.u16[2])), + FastDivideBy255(int32_t(m.u16[3])), + FastDivideBy255(int32_t(m.u16[4])), + FastDivideBy255(int32_t(m.u16[5])), + FastDivideBy255(int32_t(m.u16[6])), + FastDivideBy255(int32_t(m.u16[7]))); +} + +inline Scalari32x4_t +FastDivideBy255(Scalari32x4_t m) +{ + return From32(FastDivideBy255(m.i32[0]), + FastDivideBy255(m.i32[1]), + FastDivideBy255(m.i32[2]), + FastDivideBy255(m.i32[3])); +} + +inline Scalaru8x16_t +Pick(Scalaru8x16_t mask, Scalaru8x16_t a, Scalaru8x16_t b) +{ + return From8((a.u8[0] & (~mask.u8[0])) | (b.u8[0] & mask.u8[0]), + (a.u8[1] & (~mask.u8[1])) | (b.u8[1] & mask.u8[1]), + (a.u8[2] & (~mask.u8[2])) | (b.u8[2] & mask.u8[2]), + (a.u8[3] & (~mask.u8[3])) | (b.u8[3] & mask.u8[3]), + (a.u8[4] & (~mask.u8[4])) | (b.u8[4] & mask.u8[4]), + (a.u8[5] & (~mask.u8[5])) | (b.u8[5] & mask.u8[5]), + (a.u8[6] & (~mask.u8[6])) | (b.u8[6] & mask.u8[6]), + (a.u8[7] & (~mask.u8[7])) | (b.u8[7] & mask.u8[7]), + (a.u8[8+0] & (~mask.u8[8+0])) | (b.u8[8+0] & mask.u8[8+0]), + (a.u8[8+1] & (~mask.u8[8+1])) | (b.u8[8+1] & mask.u8[8+1]), + (a.u8[8+2] & (~mask.u8[8+2])) | (b.u8[8+2] & mask.u8[8+2]), + (a.u8[8+3] & (~mask.u8[8+3])) | (b.u8[8+3] & mask.u8[8+3]), + (a.u8[8+4] & (~mask.u8[8+4])) | (b.u8[8+4] & mask.u8[8+4]), + (a.u8[8+5] & (~mask.u8[8+5])) | (b.u8[8+5] & mask.u8[8+5]), + (a.u8[8+6] & (~mask.u8[8+6])) | (b.u8[8+6] & mask.u8[8+6]), + (a.u8[8+7] & (~mask.u8[8+7])) | (b.u8[8+7] & mask.u8[8+7])); +} + +inline Scalari32x4_t +Pick(Scalari32x4_t mask, Scalari32x4_t a, Scalari32x4_t b) +{ + return From32((a.i32[0] & (~mask.i32[0])) | (b.i32[0] & mask.i32[0]), + (a.i32[1] & (~mask.i32[1])) | (b.i32[1] & mask.i32[1]), + (a.i32[2] & (~mask.i32[2])) | (b.i32[2] & mask.i32[2]), + (a.i32[3] & (~mask.i32[3])) | (b.i32[3] & mask.i32[3])); +} + +inline Scalarf32x4_t MixF32(Scalarf32x4_t a, Scalarf32x4_t b, float t) +{ + return FromF32(a.f32[0] + (b.f32[0] - a.f32[0]) * t, + a.f32[1] + (b.f32[1] - a.f32[1]) * t, + a.f32[2] + (b.f32[2] - a.f32[2]) * t, + a.f32[3] + (b.f32[3] - a.f32[3]) * t); +} + +inline Scalarf32x4_t WSumF32(Scalarf32x4_t a, Scalarf32x4_t b, float wa, float wb) +{ + return FromF32(a.f32[0] * wa + b.f32[0] * wb, + a.f32[1] * wa + b.f32[1] * wb, + a.f32[2] * wa + b.f32[2] * wb, + a.f32[3] * wa + b.f32[3] * wb); +} + +inline Scalarf32x4_t AbsF32(Scalarf32x4_t a) +{ + return FromF32(fabs(a.f32[0]), + fabs(a.f32[1]), + fabs(a.f32[2]), + fabs(a.f32[3])); +} + +inline Scalarf32x4_t AddF32(Scalarf32x4_t a, Scalarf32x4_t b) +{ + return FromF32(a.f32[0] + b.f32[0], + a.f32[1] + b.f32[1], + a.f32[2] + b.f32[2], + a.f32[3] + b.f32[3]); +} + +inline Scalarf32x4_t MulF32(Scalarf32x4_t a, Scalarf32x4_t b) +{ + return FromF32(a.f32[0] * b.f32[0], + a.f32[1] * b.f32[1], + a.f32[2] * b.f32[2], + a.f32[3] * b.f32[3]); +} + +inline Scalarf32x4_t DivF32(Scalarf32x4_t a, Scalarf32x4_t b) +{ + return FromF32(a.f32[0] / b.f32[0], + a.f32[1] / b.f32[1], + a.f32[2] / b.f32[2], + a.f32[3] / b.f32[3]); +} + +template +inline Scalarf32x4_t SplatF32(Scalarf32x4_t m) +{ + AssertIndex(); + return FromF32(m.f32[aIndex], + m.f32[aIndex], + m.f32[aIndex], + m.f32[aIndex]); +} + +inline Scalari32x4_t F32ToI32(Scalarf32x4_t m) +{ + return From32(int32_t(floor(m.f32[0] + 0.5f)), + int32_t(floor(m.f32[1] + 0.5f)), + int32_t(floor(m.f32[2] + 0.5f)), + int32_t(floor(m.f32[3] + 0.5f))); +} + +#ifdef SIMD_COMPILE_SSE2 + +// SSE2 + +template<> +inline __m128i +Load8<__m128i>(const uint8_t* aSource) +{ + return _mm_load_si128((const __m128i*)aSource); +} + +inline void Store8(uint8_t* aTarget, __m128i aM) +{ + _mm_store_si128((__m128i*)aTarget, aM); +} + +template<> +inline __m128i FromZero8<__m128i>() +{ + return _mm_setzero_si128(); +} + +template<> +inline __m128i From8<__m128i>(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, uint8_t m, uint8_t n, uint8_t o, uint8_t p) +{ + return _mm_setr_epi16((b << 8) + a, (d << 8) + c, (e << 8) + f, (h << 8) + g, + (j << 8) + i, (l << 8) + k, (m << 8) + n, (p << 8) + o); +} + +template<> +inline __m128i FromI16<__m128i>(int16_t a, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g, int16_t h) +{ + return _mm_setr_epi16(a, b, c, d, e, f, g, h); +} + +template<> +inline __m128i FromU16<__m128i>(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h) +{ + return _mm_setr_epi16(a, b, c, d, e, f, g, h); +} + +template<> +inline __m128i FromI16<__m128i>(int16_t a) +{ + return _mm_set1_epi16(a); +} + +template<> +inline __m128i FromU16<__m128i>(uint16_t a) +{ + return _mm_set1_epi16((int16_t)a); +} + +template<> +inline __m128i From32<__m128i>(int32_t a, int32_t b, int32_t c, int32_t d) +{ + return _mm_setr_epi32(a, b, c, d); +} + +template<> +inline __m128i From32<__m128i>(int32_t a) +{ + return _mm_set1_epi32(a); +} + +template<> +inline __m128 FromF32<__m128>(float a, float b, float c, float d) +{ + return _mm_setr_ps(a, b, c, d); +} + +template<> +inline __m128 FromF32<__m128>(float a) +{ + return _mm_set1_ps(a); +} + +template +inline __m128i ShiftRight16(__m128i aM) +{ + return _mm_srli_epi16(aM, aNumberOfBits); +} + +template +inline __m128i ShiftRight32(__m128i aM) +{ + return _mm_srai_epi32(aM, aNumberOfBits); +} + +inline __m128i Add16(__m128i aM1, __m128i aM2) +{ + return _mm_add_epi16(aM1, aM2); +} + +inline __m128i Add32(__m128i aM1, __m128i aM2) +{ + return _mm_add_epi32(aM1, aM2); +} + +inline __m128i Sub16(__m128i aM1, __m128i aM2) +{ + return _mm_sub_epi16(aM1, aM2); +} + +inline __m128i Sub32(__m128i aM1, __m128i aM2) +{ + return _mm_sub_epi32(aM1, aM2); +} + +inline __m128i Min8(__m128i aM1, __m128i aM2) +{ + return _mm_min_epu8(aM1, aM2); +} + +inline __m128i Max8(__m128i aM1, __m128i aM2) +{ + return _mm_max_epu8(aM1, aM2); +} + +inline __m128i Min32(__m128i aM1, __m128i aM2) +{ + __m128i m1_minus_m2 = _mm_sub_epi32(aM1, aM2); + __m128i m1_greater_than_m2 = _mm_cmpgt_epi32(aM1, aM2); + return _mm_sub_epi32(aM1, _mm_and_si128(m1_minus_m2, m1_greater_than_m2)); +} + +inline __m128i Max32(__m128i aM1, __m128i aM2) +{ + __m128i m1_minus_m2 = _mm_sub_epi32(aM1, aM2); + __m128i m2_greater_than_m1 = _mm_cmpgt_epi32(aM2, aM1); + return _mm_sub_epi32(aM1, _mm_and_si128(m1_minus_m2, m2_greater_than_m1)); +} + +inline __m128i Mul16(__m128i aM1, __m128i aM2) +{ + return _mm_mullo_epi16(aM1, aM2); +} + +inline __m128i MulU16(__m128i aM1, __m128i aM2) +{ + return _mm_mullo_epi16(aM1, aM2); +} + +inline void Mul16x4x2x2To32x4x2(__m128i aFactorsA1B1, + __m128i aFactorsA2B2, + __m128i& aProductA, + __m128i& aProductB) +{ + __m128i prodAB_lo = _mm_mullo_epi16(aFactorsA1B1, aFactorsA2B2); + __m128i prodAB_hi = _mm_mulhi_epi16(aFactorsA1B1, aFactorsA2B2); + aProductA = _mm_unpacklo_epi16(prodAB_lo, prodAB_hi); + aProductB = _mm_unpackhi_epi16(prodAB_lo, prodAB_hi); +} + +inline __m128i MulAdd16x8x2To32x4(__m128i aFactorsA, + __m128i aFactorsB) +{ + return _mm_madd_epi16(aFactorsA, aFactorsB); +} + +template +inline __m128i Shuffle32(__m128i aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + return _mm_shuffle_epi32(aM, _MM_SHUFFLE(i0, i1, i2, i3)); +} + +template +inline __m128i ShuffleLo16(__m128i aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + return _mm_shufflelo_epi16(aM, _MM_SHUFFLE(i0, i1, i2, i3)); +} + +template +inline __m128i ShuffleHi16(__m128i aM) +{ + AssertIndex(); + AssertIndex(); + AssertIndex(); + AssertIndex(); + return _mm_shufflehi_epi16(aM, _MM_SHUFFLE(i0, i1, i2, i3)); +} + +template +inline __m128i Splat32(__m128i aM) +{ + return Shuffle32(aM); +} + +template +inline __m128i Splat32On8(__m128i aM) +{ + return Shuffle32(aM); +} + +template +inline __m128i Splat16(__m128i aM) +{ + AssertIndex(); + AssertIndex(); + return ShuffleHi16( + ShuffleLo16(aM)); +} + +inline __m128i +UnpackLo8x8ToI16x8(__m128i m) +{ + __m128i zero = _mm_set1_epi8(0); + return _mm_unpacklo_epi8(m, zero); +} + +inline __m128i +UnpackHi8x8ToI16x8(__m128i m) +{ + __m128i zero = _mm_set1_epi8(0); + return _mm_unpackhi_epi8(m, zero); +} + +inline __m128i +UnpackLo8x8ToU16x8(__m128i m) +{ + __m128i zero = _mm_set1_epi8(0); + return _mm_unpacklo_epi8(m, zero); +} + +inline __m128i +UnpackHi8x8ToU16x8(__m128i m) +{ + __m128i zero = _mm_set1_epi8(0); + return _mm_unpackhi_epi8(m, zero); +} + +inline __m128i +InterleaveLo8(__m128i m1, __m128i m2) +{ + return _mm_unpacklo_epi8(m1, m2); +} + +inline __m128i +InterleaveHi8(__m128i m1, __m128i m2) +{ + return _mm_unpackhi_epi8(m1, m2); +} + +inline __m128i +InterleaveLo16(__m128i m1, __m128i m2) +{ + return _mm_unpacklo_epi16(m1, m2); +} + +inline __m128i +InterleaveHi16(__m128i m1, __m128i m2) +{ + return _mm_unpackhi_epi16(m1, m2); +} + +inline __m128i +InterleaveLo32(__m128i m1, __m128i m2) +{ + return _mm_unpacklo_epi32(m1, m2); +} + +template +inline __m128i +Rotate8(__m128i a1234, __m128i a5678) +{ + return _mm_or_si128(_mm_srli_si128(a1234, aNumBytes), _mm_slli_si128(a5678, 16 - aNumBytes)); +} + +inline __m128i +PackAndSaturate32To16(__m128i m1, __m128i m2) +{ + return _mm_packs_epi32(m1, m2); +} + +inline __m128i +PackAndSaturate32ToU16(__m128i m1, __m128i m2) +{ + return _mm_packs_epi32(m1, m2); +} + +inline __m128i +PackAndSaturate32To8(__m128i m1, __m128i m2, __m128i m3, const __m128i& m4) +{ + // Pack into 8 16bit signed integers (saturating). + __m128i m12 = _mm_packs_epi32(m1, m2); + __m128i m34 = _mm_packs_epi32(m3, m4); + + // Pack into 16 8bit unsigned integers (saturating). + return _mm_packus_epi16(m12, m34); +} + +inline __m128i +PackAndSaturate16To8(__m128i m1, __m128i m2) +{ + // Pack into 16 8bit unsigned integers (saturating). + return _mm_packus_epi16(m1, m2); +} + +inline __m128i +FastDivideBy255(__m128i m) +{ + // v = m << 8 + __m128i v = _mm_slli_epi32(m, 8); + // v = v + (m + (255,255,255,255)) + v = _mm_add_epi32(v, _mm_add_epi32(m, _mm_set1_epi32(255))); + // v = v >> 16 + return _mm_srai_epi32(v, 16); +} + +inline __m128i +FastDivideBy255_16(__m128i m) +{ + __m128i zero = _mm_set1_epi16(0); + __m128i lo = _mm_unpacklo_epi16(m, zero); + __m128i hi = _mm_unpackhi_epi16(m, zero); + return _mm_packs_epi32(FastDivideBy255(lo), FastDivideBy255(hi)); +} + +inline __m128i +Pick(__m128i mask, __m128i a, __m128i b) +{ + return _mm_or_si128(_mm_andnot_si128(mask, a), _mm_and_si128(mask, b)); +} + +inline __m128 MixF32(__m128 a, __m128 b, float t) +{ + return _mm_add_ps(a, _mm_mul_ps(_mm_sub_ps(b, a), _mm_set1_ps(t))); +} + +inline __m128 WSumF32(__m128 a, __m128 b, float wa, float wb) +{ + return _mm_add_ps(_mm_mul_ps(a, _mm_set1_ps(wa)), _mm_mul_ps(b, _mm_set1_ps(wb))); +} + +inline __m128 AbsF32(__m128 a) +{ + return _mm_max_ps(_mm_sub_ps(_mm_setzero_ps(), a), a); +} + +inline __m128 AddF32(__m128 a, __m128 b) +{ + return _mm_add_ps(a, b); +} + +inline __m128 MulF32(__m128 a, __m128 b) +{ + return _mm_mul_ps(a, b); +} + +inline __m128 DivF32(__m128 a, __m128 b) +{ + return _mm_div_ps(a, b); +} + +template +inline __m128 SplatF32(__m128 m) +{ + AssertIndex(); + return _mm_shuffle_ps(m, m, _MM_SHUFFLE(aIndex, aIndex, aIndex, aIndex)); +} + +inline __m128i F32ToI32(__m128 m) +{ + return _mm_cvtps_epi32(m); +} + +#endif // SIMD_COMPILE_SSE2 + +} // namespace simd + +} // namespace gfx +} // namespace mozilla + +#endif // _MOZILLA_GFX_SIMD_H_ diff --git a/libazure/src/gfx/2d/SSEHelpers.h b/libazure/SSEHelpers.h similarity index 100% rename from libazure/src/gfx/2d/SSEHelpers.h rename to libazure/SSEHelpers.h diff --git a/libazure/SVGTurbulenceRenderer-inl.h b/libazure/SVGTurbulenceRenderer-inl.h new file mode 100644 index 0000000..b784bd8 --- /dev/null +++ b/libazure/SVGTurbulenceRenderer-inl.h @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "2D.h" +#include "Filters.h" +#include "SIMD.h" + +namespace mozilla { +namespace gfx { + +template +class SVGTurbulenceRenderer +{ +public: + SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed, + int aNumOctaves, const Rect &aTileRect); + + TemporaryRef Render(const IntSize &aSize, const Point &aOffset) const; + +private: + /* The turbulence calculation code is an adapted version of what + appears in the SVG 1.1 specification: + http://www.w3.org/TR/SVG11/filters.html#feTurbulence + */ + + struct StitchInfo { + int32_t width; // How much to subtract to wrap for stitching. + int32_t height; + int32_t wrapX; // Minimum value to wrap. + int32_t wrapY; + }; + + const static int sBSize = 0x100; + const static int sBM = 0xff; + void InitFromSeed(int32_t aSeed); + void AdjustBaseFrequencyForStitch(const Rect &aTileRect); + IntPoint AdjustForStitch(IntPoint aLatticePoint, const StitchInfo& aStitchInfo) const; + StitchInfo CreateStitchInfo(const Rect &aTileRect) const; + f32x4_t Noise2(Point aVec, const StitchInfo& aStitchInfo) const; + i32x4_t Turbulence(const Point &aPoint) const; + Point EquivalentNonNegativeOffset(const Point &aOffset) const; + + Size mBaseFrequency; + int32_t mNumOctaves; + StitchInfo mStitchInfo; + bool mStitchable; + TurbulenceType mType; + uint8_t mLatticeSelector[sBSize]; + f32x4_t mGradient[sBSize][2]; +}; + +namespace { + +struct RandomNumberSource +{ + explicit RandomNumberSource(int32_t aSeed) : mLast(SetupSeed(aSeed)) {} + int32_t Next() { mLast = Random(mLast); return mLast; } + +private: + static const int32_t RAND_M = 2147483647; /* 2**31 - 1 */ + static const int32_t RAND_A = 16807; /* 7**5; primitive root of m */ + static const int32_t RAND_Q = 127773; /* m / a */ + static const int32_t RAND_R = 2836; /* m % a */ + + /* Produces results in the range [1, 2**31 - 2]. + Algorithm is: r = (a * r) mod m + where a = 16807 and m = 2**31 - 1 = 2147483647 + See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 + To test: the algorithm should produce the result 1043618065 + as the 10,000th generated number if the original seed is 1. + */ + + static int32_t + SetupSeed(int32_t aSeed) { + if (aSeed <= 0) + aSeed = -(aSeed % (RAND_M - 1)) + 1; + if (aSeed > RAND_M - 1) + aSeed = RAND_M - 1; + return aSeed; + } + + static int32_t + Random(int32_t aSeed) + { + int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q); + if (result <= 0) + result += RAND_M; + return result; + } + + int32_t mLast; +}; + +} // unnamed namespace + +template +SVGTurbulenceRenderer::SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed, + int aNumOctaves, const Rect &aTileRect) + : mBaseFrequency(aBaseFrequency) + , mNumOctaves(aNumOctaves) +{ + InitFromSeed(aSeed); + if (Stitch) { + AdjustBaseFrequencyForStitch(aTileRect); + mStitchInfo = CreateStitchInfo(aTileRect); + } +} + +template +static void +Swap(T& a, T& b) { + T c = a; + a = b; + b = c; +} + +template +void +SVGTurbulenceRenderer::InitFromSeed(int32_t aSeed) +{ + RandomNumberSource rand(aSeed); + + float gradient[4][sBSize][2]; + for (int32_t k = 0; k < 4; k++) { + for (int32_t i = 0; i < sBSize; i++) { + float a = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize; + float b = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize; + float s = sqrt(a * a + b * b); + gradient[k][i][0] = a / s; + gradient[k][i][1] = b / s; + } + } + + for (int32_t i = 0; i < sBSize; i++) { + mLatticeSelector[i] = i; + } + for (int32_t i1 = sBSize - 1; i1 > 0; i1--) { + int32_t i2 = rand.Next() % sBSize; + Swap(mLatticeSelector[i1], mLatticeSelector[i2]); + } + + for (int32_t i = 0; i < sBSize; i++) { + // Contrary to the code in the spec, we build the first lattice selector + // lookup into mGradient so that we don't need to do it again for every + // pixel. + // We also change the order of the gradient indexing so that we can process + // all four color channels at the same time. + uint8_t j = mLatticeSelector[i]; + mGradient[i][0] = simd::FromF32(gradient[2][j][0], gradient[1][j][0], + gradient[0][j][0], gradient[3][j][0]); + mGradient[i][1] = simd::FromF32(gradient[2][j][1], gradient[1][j][1], + gradient[0][j][1], gradient[3][j][1]); + } +} + +// Adjust aFreq such that aLength * AdjustForLength(aFreq, aLength) is integer +// and as close to aLength * aFreq as possible. +static inline float +AdjustForLength(float aFreq, float aLength) +{ + float lowFreq = floor(aLength * aFreq) / aLength; + float hiFreq = ceil(aLength * aFreq) / aLength; + if (aFreq / lowFreq < hiFreq / aFreq) { + return lowFreq; + } + return hiFreq; +} + +template +void +SVGTurbulenceRenderer::AdjustBaseFrequencyForStitch(const Rect &aTileRect) +{ + mBaseFrequency = Size(AdjustForLength(mBaseFrequency.width, aTileRect.width), + AdjustForLength(mBaseFrequency.height, aTileRect.height)); +} + +template +typename SVGTurbulenceRenderer::StitchInfo +SVGTurbulenceRenderer::CreateStitchInfo(const Rect &aTileRect) const +{ + StitchInfo stitch; + stitch.width = int32_t(floorf(aTileRect.width * mBaseFrequency.width + 0.5f)); + stitch.height = int32_t(floorf(aTileRect.height * mBaseFrequency.height + 0.5f)); + stitch.wrapX = int32_t(aTileRect.x * mBaseFrequency.width) + stitch.width; + stitch.wrapY = int32_t(aTileRect.y * mBaseFrequency.height) + stitch.height; + return stitch; +} + +static MOZ_ALWAYS_INLINE Float +SCurve(Float t) +{ + return t * t * (3 - 2 * t); +} + +static MOZ_ALWAYS_INLINE Point +SCurve(Point t) +{ + return Point(SCurve(t.x), SCurve(t.y)); +} + +template +static MOZ_ALWAYS_INLINE f32x4_t +BiMix(const f32x4_t& aa, const f32x4_t& ab, + const f32x4_t& ba, const f32x4_t& bb, Point s) +{ + return simd::MixF32(simd::MixF32(aa, ab, s.x), + simd::MixF32(ba, bb, s.x), s.y); +} + +template +IntPoint +SVGTurbulenceRenderer::AdjustForStitch(IntPoint aLatticePoint, + const StitchInfo& aStitchInfo) const +{ + if (Stitch) { + if (aLatticePoint.x >= aStitchInfo.wrapX) { + aLatticePoint.x -= aStitchInfo.width; + } + if (aLatticePoint.y >= aStitchInfo.wrapY) { + aLatticePoint.y -= aStitchInfo.height; + } + } + return aLatticePoint; +} + +template +f32x4_t +SVGTurbulenceRenderer::Noise2(Point aVec, const StitchInfo& aStitchInfo) const +{ + // aVec is guaranteed to be non-negative, so casting to int32_t always + // rounds towards negative infinity. + IntPoint topLeftLatticePoint(int32_t(aVec.x), int32_t(aVec.y)); + Point r = aVec - topLeftLatticePoint; // fractional offset + + IntPoint b0 = AdjustForStitch(topLeftLatticePoint, aStitchInfo); + IntPoint b1 = AdjustForStitch(b0 + IntPoint(1, 1), aStitchInfo); + + uint8_t i = mLatticeSelector[b0.x & sBM]; + uint8_t j = mLatticeSelector[b1.x & sBM]; + + const f32x4_t* qua = mGradient[(i + b0.y) & sBM]; + const f32x4_t* qub = mGradient[(i + b1.y) & sBM]; + const f32x4_t* qva = mGradient[(j + b0.y) & sBM]; + const f32x4_t* qvb = mGradient[(j + b1.y) & sBM]; + + return BiMix(simd::WSumF32(qua[0], qua[1], r.x, r.y), + simd::WSumF32(qva[0], qva[1], r.x - 1.f, r.y), + simd::WSumF32(qub[0], qub[1], r.x, r.y - 1.f), + simd::WSumF32(qvb[0], qvb[1], r.x - 1.f, r.y - 1.f), + SCurve(r)); +} + +template +static inline i32x4_t +ColorToBGRA(f32x4_t aUnscaledUnpreFloat) +{ + // Color is an unpremultiplied float vector where 1.0f means white. We will + // convert it into an integer vector where 255 means white. + f32x4_t alpha = simd::SplatF32<3>(aUnscaledUnpreFloat); + f32x4_t scaledUnpreFloat = simd::MulF32(aUnscaledUnpreFloat, simd::FromF32(255)); + i32x4_t scaledUnpreInt = simd::F32ToI32(scaledUnpreFloat); + + // Multiply all channels with alpha. + i32x4_t scaledPreInt = simd::F32ToI32(simd::MulF32(scaledUnpreFloat, alpha)); + + // Use the premultiplied color channels and the unpremultiplied alpha channel. + i32x4_t alphaMask = simd::From32(0, 0, 0, -1); + return simd::Pick(alphaMask, scaledPreInt, scaledUnpreInt); +} + +template +i32x4_t +SVGTurbulenceRenderer::Turbulence(const Point &aPoint) const +{ + StitchInfo stitchInfo = mStitchInfo; + f32x4_t sum = simd::FromF32(0); + Point vec(aPoint.x * mBaseFrequency.width, aPoint.y * mBaseFrequency.height); + f32x4_t ratio = simd::FromF32(1); + + for (int octave = 0; octave < mNumOctaves; octave++) { + f32x4_t thisOctave = Noise2(vec, stitchInfo); + if (Type == TURBULENCE_TYPE_TURBULENCE) { + thisOctave = simd::AbsF32(thisOctave); + } + sum = simd::AddF32(sum, simd::DivF32(thisOctave, ratio)); + vec = vec * 2; + ratio = simd::MulF32(ratio, simd::FromF32(2)); + + if (Stitch) { + stitchInfo.width *= 2; + stitchInfo.wrapX *= 2; + stitchInfo.height *= 2; + stitchInfo.wrapY *= 2; + } + } + + if (Type == TURBULENCE_TYPE_FRACTAL_NOISE) { + sum = simd::DivF32(simd::AddF32(sum, simd::FromF32(1)), simd::FromF32(2)); + } + return ColorToBGRA(sum); +} + +static inline Float +MakeNonNegative(Float aValue, Float aIncrementSize) +{ + if (aValue >= 0) { + return aValue; + } + return aValue + ceilf(-aValue / aIncrementSize) * aIncrementSize; +} + +template +Point +SVGTurbulenceRenderer::EquivalentNonNegativeOffset(const Point &aOffset) const +{ + Size basePeriod = Stitch ? Size(mStitchInfo.width, mStitchInfo.height) : + Size(sBSize, sBSize); + Size repeatingSize(basePeriod.width / mBaseFrequency.width, + basePeriod.height / mBaseFrequency.height); + return Point(MakeNonNegative(aOffset.x, repeatingSize.width), + MakeNonNegative(aOffset.y, repeatingSize.height)); +} + +template +TemporaryRef +SVGTurbulenceRenderer::Render(const IntSize &aSize, const Point &aOffset) const +{ + RefPtr target = + Factory::CreateDataSourceSurface(aSize, SurfaceFormat::B8G8R8A8); + if (!target) { + return nullptr; + } + + uint8_t* targetData = target->GetData(); + uint32_t stride = target->Stride(); + + Point startOffset = EquivalentNonNegativeOffset(aOffset); + + for (int32_t y = 0; y < aSize.height; y++) { + for (int32_t x = 0; x < aSize.width; x += 4) { + int32_t targIndex = y * stride + x * 4; + i32x4_t a = Turbulence(startOffset + Point(x, y)); + i32x4_t b = Turbulence(startOffset + Point(x + 1, y)); + i32x4_t c = Turbulence(startOffset + Point(x + 2, y)); + i32x4_t d = Turbulence(startOffset + Point(x + 3, y)); + u8x16_t result1234 = simd::PackAndSaturate32To8(a, b, c, d); + simd::Store8(&targetData[targIndex], result1234); + } + } + + return target; +} + +} // namespace gfx +} // namespace mozilla diff --git a/libazure/src/gfx/2d/Scale.cpp b/libazure/Scale.cpp similarity index 65% rename from libazure/src/gfx/2d/Scale.cpp rename to libazure/Scale.cpp index f396c9e..f22a92c 100644 --- a/libazure/src/gfx/2d/Scale.cpp +++ b/libazure/Scale.cpp @@ -7,8 +7,10 @@ #ifdef USE_SKIA #include "HelpersSkia.h" #include "SkBitmap.h" +#ifdef USE_IMAGE_OPERATIONS #include "image_operations.h" #endif +#endif namespace mozilla { namespace gfx { @@ -17,24 +19,25 @@ bool Scale(uint8_t* srcData, int32_t srcWidth, int32_t srcHeight, int32_t srcStr uint8_t* dstData, int32_t dstWidth, int32_t dstHeight, int32_t dstStride, SurfaceFormat format) { -#ifdef USE_SKIA - bool opaque; - if (format == FORMAT_B8G8R8A8) { - opaque = false; +#if defined(USE_SKIA) && defined(USE_IMAGE_OPERATIONS) + SkAlphaType alphaType; + if (format == SurfaceFormat::B8G8R8A8) { + alphaType = kPremul_SkAlphaType; } else { - opaque = true; + alphaType = kOpaque_SkAlphaType; } - SkBitmap::Config config = GfxFormatToSkiaConfig(format); + SkImageInfo info = SkImageInfo::Make(srcWidth, + srcHeight, + GfxFormatToSkiaColorType(format), + alphaType); SkBitmap imgSrc; - imgSrc.setConfig(config, srcWidth, srcHeight, srcStride); - imgSrc.setPixels(srcData); - imgSrc.setIsOpaque(opaque); + imgSrc.installPixels(info, srcData, srcStride); // Rescaler is compatible with 32 bpp only. Convert to RGB32 if needed. - if (config != SkBitmap::kARGB_8888_Config) { - imgSrc.copyTo(&imgSrc, SkBitmap::kARGB_8888_Config); + if (format != SurfaceFormat::B8G8R8A8) { + imgSrc.copyTo(&imgSrc, kBGRA_8888_SkColorType); } // This returns an SkBitmap backed by dstData; since it also wrote to dstData, diff --git a/libazure/src/gfx/2d/Scale.h b/libazure/Scale.h similarity index 100% rename from libazure/src/gfx/2d/Scale.h rename to libazure/Scale.h diff --git a/libazure/ScaledFontBase.cpp b/libazure/ScaledFontBase.cpp new file mode 100644 index 0000000..7d3b8bd --- /dev/null +++ b/libazure/ScaledFontBase.cpp @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ScaledFontBase.h" + +#ifdef USE_SKIA +#include "PathSkia.h" +#include "core/SkPaint.h" +#endif + +#ifdef USE_CAIRO +#include "PathCairo.h" +#include "DrawTargetCairo.h" +#include "HelpersCairo.h" +#endif + +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { + +ScaledFontBase::~ScaledFontBase() +{ +#ifdef USE_SKIA + SkSafeUnref(mTypeface); +#endif +#ifdef USE_CAIRO_SCALED_FONT + cairo_scaled_font_destroy(mScaledFont); +#endif +} + +ScaledFontBase::ScaledFontBase(Float aSize) + : mSize(aSize) +{ +#ifdef USE_SKIA + mTypeface = nullptr; +#endif +#ifdef USE_CAIRO_SCALED_FONT + mScaledFont = nullptr; +#endif +} + +#ifdef USE_SKIA +SkPath +ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer &aBuffer) +{ + SkTypeface *typeFace = GetSkTypeface(); + MOZ_ASSERT(typeFace); + + SkPaint paint; + paint.setTypeface(typeFace); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setTextSize(SkFloatToScalar(mSize)); + + std::vector indices; + std::vector offsets; + indices.resize(aBuffer.mNumGlyphs); + offsets.resize(aBuffer.mNumGlyphs); + + for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { + indices[i] = aBuffer.mGlyphs[i].mIndex; + offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x); + offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y); + } + + SkPath path; + paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path); + return path; +} +#endif + +TemporaryRef +ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) +{ +#ifdef USE_SKIA + if (aTarget->GetBackendType() == BackendType::SKIA) { + SkPath path = GetSkiaPathForGlyphs(aBuffer); + return new PathSkia(path, FillRule::FILL_WINDING); + } +#endif +#ifdef USE_CAIRO + if (aTarget->GetBackendType() == BackendType::CAIRO) { + MOZ_ASSERT(mScaledFont); + + DrawTarget *dt = const_cast(aTarget); + cairo_t *ctx = static_cast(dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT)); + + bool isNewContext = !ctx; + if (!ctx) { + ctx = cairo_create(DrawTargetCairo::GetDummySurface()); + cairo_matrix_t mat; + GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat); + cairo_set_matrix(ctx, &mat); + } + + cairo_set_scaled_font(ctx, mScaledFont); + + // Convert our GlyphBuffer into an array of Cairo glyphs. + std::vector glyphs(aBuffer.mNumGlyphs); + for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { + glyphs[i].index = aBuffer.mGlyphs[i].mIndex; + glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; + glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; + } + + cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs); + + RefPtr newPath = new PathCairo(ctx); + if (isNewContext) { + cairo_destroy(ctx); + } + + return newPath.forget(); + } +#endif + return nullptr; +} + +void +ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint) +{ +#ifdef USE_SKIA + if (aBackendType == BackendType::SKIA) { + PathBuilderSkia *builder = static_cast(aBuilder); + builder->AppendPath(GetSkiaPathForGlyphs(aBuffer)); + return; + } +#endif +#ifdef USE_CAIRO + if (aBackendType == BackendType::CAIRO) { + MOZ_ASSERT(mScaledFont); + + PathBuilderCairo* builder = static_cast(aBuilder); + cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface()); + + if (aTransformHint) { + cairo_matrix_t mat; + GfxMatrixToCairoMatrix(*aTransformHint, mat); + cairo_set_matrix(ctx, &mat); + } + + // Convert our GlyphBuffer into an array of Cairo glyphs. + std::vector glyphs(aBuffer.mNumGlyphs); + for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { + glyphs[i].index = aBuffer.mGlyphs[i].mIndex; + glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; + glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; + } + + cairo_set_scaled_font(ctx, mScaledFont); + cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs); + + RefPtr cairoPath = new PathCairo(ctx); + cairo_destroy(ctx); + + cairoPath->AppendPathToBuilder(builder); + return; + } +#endif + + MOZ_CRASH("The specified backend type is not supported by CopyGlyphsToBuilder"); +} + +#ifdef USE_CAIRO_SCALED_FONT +void +ScaledFontBase::SetCairoScaledFont(cairo_scaled_font_t* font) +{ + MOZ_ASSERT(!mScaledFont); + + if (font == mScaledFont) + return; + + if (mScaledFont) + cairo_scaled_font_destroy(mScaledFont); + + mScaledFont = font; + cairo_scaled_font_reference(mScaledFont); +} + +void +ScaledFontBase::InitScaledFontFromFace(cairo_font_face_t* aFace) +{ + cairo_matrix_t sizeMatrix; + cairo_matrix_t identityMatrix; + + cairo_matrix_init_scale(&sizeMatrix, mSize, mSize); + cairo_matrix_init_identity(&identityMatrix); + + cairo_font_options_t *fontOptions = cairo_font_options_create(); + + mScaledFont = cairo_scaled_font_create(aFace, &sizeMatrix, &identityMatrix, fontOptions); + + cairo_font_options_destroy(fontOptions); +} +#endif + +} +} diff --git a/libazure/src/gfx/2d/ScaledFontBase.h b/libazure/ScaledFontBase.h similarity index 75% rename from libazure/src/gfx/2d/ScaledFontBase.h rename to libazure/ScaledFontBase.h index 5b45e7c..f2450c8 100644 --- a/libazure/src/gfx/2d/ScaledFontBase.h +++ b/libazure/ScaledFontBase.h @@ -9,7 +9,8 @@ #include "2D.h" #ifdef USE_SKIA -#include "SkTypeface.h" +#include "core/SkPath.h" +#include "core/SkTypeface.h" #endif #ifdef USE_CAIRO #include "cairo.h" @@ -23,12 +24,13 @@ namespace gfx { class ScaledFontBase : public ScaledFont { public: - ScaledFontBase(Float aSize); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontBase) + explicit ScaledFontBase(Float aSize); virtual ~ScaledFontBase(); virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget); - virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder); + virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint); float GetSize() { return mSize; } @@ -37,17 +39,19 @@ class ScaledFontBase : public ScaledFont #endif // Not true, but required to instantiate a ScaledFontBase. - virtual FontType GetType() const { return FONT_SKIA; } + virtual FontType GetType() const { return FontType::SKIA; } #ifdef USE_CAIRO cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; } void SetCairoScaledFont(cairo_scaled_font_t* font); + void InitScaledFontFromFace(cairo_font_face_t *aFace); #endif protected: friend class DrawTargetSkia; #ifdef USE_SKIA SkTypeface* mTypeface; + SkPath GetSkiaPathForGlyphs(const GlyphBuffer &aBuffer); #endif #ifdef USE_CAIRO cairo_scaled_font_t* mScaledFont; diff --git a/libazure/ScaledFontCairo.cpp b/libazure/ScaledFontCairo.cpp new file mode 100644 index 0000000..5bcacb3 --- /dev/null +++ b/libazure/ScaledFontCairo.cpp @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ScaledFontCairo.h" +#include "Logging.h" + +#include +#include + +#ifdef MOZ_ENABLE_FREETYPE +#include +#include FT_FREETYPE_H + +#include "cairo-ft.h" +#endif + +#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE) +#include "skia/SkTypeface.h" +#include "skia/SkTypeface_cairo.h" +#endif + +#ifdef USE_CAIRO +#include "PathCairo.h" +#endif + +typedef struct FT_FaceRec_* FT_Face; + +using namespace std; + +namespace mozilla { +namespace gfx { + +// On Linux and Android our "platform" font is a cairo_scaled_font_t and we use +// an SkFontHost implementation that allows Skia to render using this. +// This is mainly because FT_Face is not good for sharing between libraries, which +// is a requirement when we consider runtime switchable backends and so on +ScaledFontCairo::ScaledFontCairo(cairo_scaled_font_t* aScaledFont, Float aSize) + : ScaledFontBase(aSize) +#ifdef MOZ_ENABLE_FREETYPE + , mFTFace(nullptr) +#endif +{ + SetCairoScaledFont(aScaledFont); +} + +ScaledFontCairo::ScaledFontCairo(const uint8_t* aData, uint32_t aFileSize, uint32_t aIndex, Float aSize) + : ScaledFontBase(aSize) +{ +#ifdef MOZ_ENABLE_FREETYPE + FT_New_Memory_Face(Factory::GetFreetypeLibrary(), aData, aFileSize, aIndex, &mFTFace); + + cairo_font_face_t *face = cairo_ft_font_face_create_for_ft_face(mFTFace, FT_LOAD_DEFAULT); + + InitScaledFontFromFace(face); + + cairo_font_face_destroy(face); +#else + // Implement me! + MOZ_ASSERT(false); +#endif +} + +ScaledFontCairo::~ScaledFontCairo() +{ +#ifdef MOZ_ENABLE_FREETYPE + if (mFTFace) { + FT_Done_Face(mFTFace); + } +#endif +} + +#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE) +SkTypeface* ScaledFontCairo::GetSkTypeface() +{ + if (!mTypeface) { + cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(mScaledFont); + FT_Face face = cairo_ft_scaled_font_lock_face(mScaledFont); + + int style = SkTypeface::kNormal; + + if (face->style_flags & FT_STYLE_FLAG_ITALIC) + style |= SkTypeface::kItalic; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + style |= SkTypeface::kBold; + + bool isFixedWidth = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH; + cairo_ft_scaled_font_unlock_face(mScaledFont); + + mTypeface = SkCreateTypefaceFromCairoFont(fontFace, (SkTypeface::Style)style, isFixedWidth); + } + + return mTypeface; +} +#endif + +} +} diff --git a/libazure/ScaledFontCairo.h b/libazure/ScaledFontCairo.h new file mode 100644 index 0000000..7a2651e --- /dev/null +++ b/libazure/ScaledFontCairo.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SCALEDFONTCAIRO_H_ +#define MOZILLA_GFX_SCALEDFONTCAIRO_H_ + +#include "ScaledFontBase.h" + +namespace mozilla { +namespace gfx { + +class ScaledFontCairo : public ScaledFontBase +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontCairo) + + ScaledFontCairo(cairo_scaled_font_t* aScaledFont, Float aSize); + ScaledFontCairo(const uint8_t* aData, uint32_t aFileSize, uint32_t aIndex, Float aSize); + ~ScaledFontCairo(); + +#if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE) + virtual SkTypeface* GetSkTypeface(); +#endif + +private: +#ifdef MOZ_ENABLE_FREETYPE + FT_Face mFTFace; +#endif +}; + +// We need to be able to tell Skia whether or not to use +// hinting when rendering text, so that the glyphs it renders +// are the same as what layout is expecting. At the moment, only +// Skia uses this class when rendering with FreeType, as gfxFT2Font +// is the only gfxFont that honours gfxPlatform::FontHintingEnabled(). +class GlyphRenderingOptionsCairo : public GlyphRenderingOptions +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsCairo) + GlyphRenderingOptionsCairo() + : mHinting(FontHinting::NORMAL) + , mAutoHinting(false) + { + } + + void SetHinting(FontHinting aHinting) { mHinting = aHinting; } + void SetAutoHinting(bool aAutoHinting) { mAutoHinting = aAutoHinting; } + FontHinting GetHinting() const { return mHinting; } + bool GetAutoHinting() const { return mAutoHinting; } + virtual FontType GetType() const { return FontType::CAIRO; } +private: + FontHinting mHinting; + bool mAutoHinting; +}; + +} +} + +#endif /* MOZILLA_GFX_SCALEDFONTCAIRO_H_ */ diff --git a/libazure/src/gfx/2d/ScaledFontDWrite.cpp b/libazure/ScaledFontDWrite.cpp similarity index 93% rename from libazure/src/gfx/2d/ScaledFontDWrite.cpp rename to libazure/ScaledFontDWrite.cpp index 47a0d50..41ea874 100644 --- a/libazure/src/gfx/2d/ScaledFontDWrite.cpp +++ b/libazure/ScaledFontDWrite.cpp @@ -213,7 +213,7 @@ DoGrayscale(IDWriteFontFace *aDWFace, Float ppem) return true; } -IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = NULL; +IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr; HRESULT STDMETHODCALLTYPE DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, @@ -275,7 +275,7 @@ DWriteFontFileStream::ReadFileFragment(const void **fragmentStart, // We should be alive for the duration of this. *fragmentStart = &mData[index]; - *fragmentContext = NULL; + *fragmentContext = nullptr; return S_OK; } @@ -309,7 +309,7 @@ ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData, uint32_t aSize, TemporaryRef ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) { - if (aTarget->GetType() != BACKEND_DIRECT2D) { + if (aTarget->GetBackendType() != BackendType::DIRECT2D && aTarget->GetBackendType() != BackendType::DIRECT2D1_1) { return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget); } @@ -324,9 +324,13 @@ ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget } void -ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder) +ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint) { - // XXX - Check path builder type! + if (aBackendType != BackendType::DIRECT2D) { + ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint); + return; + } + PathBuilderD2D *pathBuilderD2D = static_cast(aBuilder); @@ -405,23 +409,23 @@ ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton AntialiasMode ScaledFontDWrite::GetDefaultAAMode() { - AntialiasMode defaultMode = AA_SUBPIXEL; + AntialiasMode defaultMode = AntialiasMode::SUBPIXEL; switch (GetSystemTextQuality()) { case CLEARTYPE_QUALITY: - defaultMode = AA_SUBPIXEL; + defaultMode = AntialiasMode::SUBPIXEL; break; case ANTIALIASED_QUALITY: - defaultMode = AA_GRAY; + defaultMode = AntialiasMode::GRAY; break; case DEFAULT_QUALITY: - defaultMode = AA_NONE; + defaultMode = AntialiasMode::NONE; break; } - if (defaultMode == AA_GRAY) { + if (defaultMode == AntialiasMode::GRAY) { if (!DoGrayscale(mFontFace, mSize)) { - defaultMode = AA_NONE; + defaultMode = AntialiasMode::NONE; } } return defaultMode; diff --git a/libazure/src/gfx/2d/ScaledFontDWrite.h b/libazure/ScaledFontDWrite.h similarity index 81% rename from libazure/src/gfx/2d/ScaledFontDWrite.h rename to libazure/ScaledFontDWrite.h index 2f5cc94..69f9e0d 100644 --- a/libazure/src/gfx/2d/ScaledFontDWrite.h +++ b/libazure/ScaledFontDWrite.h @@ -17,16 +17,17 @@ namespace gfx { class ScaledFontDWrite MOZ_FINAL : public ScaledFontBase { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite) ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize) : mFontFace(aFont) , ScaledFontBase(aSize) {} ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize); - virtual FontType GetType() const { return FONT_DWRITE; } + virtual FontType GetType() const { return FontType::DWRITE; } virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget); - virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder); + virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint); void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink); @@ -48,15 +49,17 @@ class ScaledFontDWrite MOZ_FINAL : public ScaledFontBase class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptionsDWrite) GlyphRenderingOptionsDWrite(IDWriteRenderingParams *aParams) : mParams(aParams) { } - virtual FontType GetType() const { return FONT_DWRITE; } + virtual FontType GetType() const { return FontType::DWRITE; } private: friend class DrawTargetD2D; + friend class DrawTargetD2D1; RefPtr mParams; }; diff --git a/libazure/src/gfx/2d/ScaledFontMac.cpp b/libazure/ScaledFontMac.cpp similarity index 89% rename from libazure/src/gfx/2d/ScaledFontMac.cpp rename to libazure/ScaledFontMac.cpp index 248734d..b2b276d 100644 --- a/libazure/src/gfx/2d/ScaledFontMac.cpp +++ b/libazure/ScaledFontMac.cpp @@ -6,9 +6,9 @@ #include "ScaledFontMac.h" #ifdef USE_SKIA #include "PathSkia.h" -#include "SkPaint.h" -#include "SkPath.h" -#include "SkTypeface_mac.h" +#include "core/SkPaint.h" +#include "core/SkPath.h" +#include "ports/SkTypeface_mac.h" #endif #include "DrawTargetCG.h" #include @@ -79,7 +79,8 @@ SkTypeface* ScaledFontMac::GetSkTypeface() TemporaryRef ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) { - if (aTarget->GetType() == BACKEND_COREGRAPHICS || aTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) { + if (aTarget->GetBackendType() == BackendType::COREGRAPHICS || + aTarget->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) { CGMutablePathRef path = CGPathCreateMutable(); for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { @@ -93,12 +94,11 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT CGPathAddPath(path, &matrix, glyphPath); CGPathRelease(glyphPath); } - TemporaryRef ret = new PathCG(path, FILL_WINDING); + TemporaryRef ret = new PathCG(path, FillRule::FILL_WINDING); CGPathRelease(path); return ret; - } else { - return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget); } + return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget); } } diff --git a/libazure/src/gfx/2d/ScaledFontMac.h b/libazure/ScaledFontMac.h similarity index 92% rename from libazure/src/gfx/2d/ScaledFontMac.h rename to libazure/ScaledFontMac.h index 456919b..f3aae9c 100644 --- a/libazure/src/gfx/2d/ScaledFontMac.h +++ b/libazure/ScaledFontMac.h @@ -17,10 +17,11 @@ namespace gfx { class ScaledFontMac : public ScaledFontBase { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontMac) ScaledFontMac(CGFontRef aFont, Float aSize); virtual ~ScaledFontMac(); - virtual FontType GetType() const { return FONT_MAC; } + virtual FontType GetType() const { return FontType::MAC; } #ifdef USE_SKIA virtual SkTypeface* GetSkTypeface(); #endif diff --git a/libazure/ScaledFontNVpr.cpp b/libazure/ScaledFontNVpr.cpp new file mode 100644 index 0000000..deb6c13 --- /dev/null +++ b/libazure/ScaledFontNVpr.cpp @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef WIN32 +#include "Windows.h" +#endif + +#include "ScaledFontNVpr.h" +#include +#include +#include + +#define MAX_UNICODE_INDEX 0x10ffff + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +bool operator <(const FontOptions& aLeft, const FontOptions& aRight) +{ + if (aLeft.mStyle != aRight.mStyle) { + return aLeft.mStyle < aRight.mStyle; + } + return aLeft.mName < aRight.mName; +} + +TemporaryRef +ScaledFontNVpr::Create(const FontOptions* aFont, GLfloat aSize) +{ + struct FontCache + : public map > + , public nvpr::UserData::Object + {}; + + FontCache& fontCache = gl->GetUserObject(&nvpr::UserData::mFonts); + + RefPtr& font = fontCache[*aFont]; + if (!font) { + font = FontNVpr::Create(aFont); + } + + return new ScaledFontNVpr(font, aSize); +} + +TemporaryRef +ScaledFontNVpr::Create(const uint8_t* aData, uint32_t aFileSize, + uint32_t aIndex, GLfloat aSize) +{ + ostringstream tempFontFile; +#ifdef WIN32 + // XXX - Terrible hacking time! We need a way to get this into a file for + // the API to be able to accept this. + CHAR buf [MAX_PATH]; + ::GetTempPathA(MAX_PATH, buf); + tempFontFile << buf << "nvpr-font-" << rand() << rand() << rand() << rand(); +#else + tempFontFile << "/tmp/nvpr-font-" << rand() << rand() << rand() << rand(); +#endif + + ofstream outputFile(tempFontFile.str(), ofstream::binary); + outputFile.write((const char*)aData, aFileSize); + + FontOptions fontOptions; + fontOptions.mName = tempFontFile.str(); + fontOptions.mStyle = FontStyle::NORMAL; + + return Create(&fontOptions, aSize); +} + +FontNVpr::FontNVpr(const FontOptions* aFont) +{ + GLenum fontStyle; + switch (aFont->mStyle) { + default: + MOZ_ASSERT(!"Invalid font style"); + case FontStyle::NORMAL: + fontStyle = 0; + break; + case FontStyle::ITALIC: + fontStyle = GL_ITALIC_BIT_NV; + break; + case FontStyle::BOLD: + fontStyle = GL_BOLD_BIT_NV; + break; + case FontStyle::BOLD_ITALIC: + fontStyle = GL_BOLD_BIT_NV | GL_ITALIC_BIT_NV; + break; + } + + gl->MakeCurrent(); + + GLuint templatePath = gl->GenPathsNV(1); + gl->PathCommandsNV(templatePath, 0, nullptr, 0, GL_FLOAT, nullptr); + + mGlyphPaths = gl->GenPathsNV(MAX_UNICODE_INDEX + 1); + gl->PathGlyphRangeNV(mGlyphPaths, GL_FILE_NAME_NV, aFont->mName.c_str(), + fontStyle, 0, MAX_UNICODE_INDEX + 1, + GL_SKIP_MISSING_GLYPH_NV, templatePath, 1); + + struct {GLfloat x1, y1, x2, y2;} bounds; + gl->GetPathMetricRangeNV(GL_FONT_X_MIN_BOUNDS_BIT_NV | GL_FONT_Y_MIN_BOUNDS_BIT_NV + | GL_FONT_X_MAX_BOUNDS_BIT_NV | GL_FONT_Y_MAX_BOUNDS_BIT_NV, + mGlyphPaths, 1, 0, &bounds.x1); + + // HACK! The driver currently seems to return all -1's. + bounds.x1 = -.25; + bounds.y1 = -1.25; + bounds.x2 = 1; + bounds.y2 = .5; + + mGlyphsBoundingBox = Rect(bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); +} + +FontNVpr::~FontNVpr() +{ +} + +ScaledFontNVpr::ScaledFontNVpr(TemporaryRef aFont, GLfloat aSize) + : mFont(aFont) + , mSize(aSize) + , mInverseSize(1 / aSize) +{ + mGlyphsBoundingBox = mFont->GlyphsBoundingBox(); + mGlyphsBoundingBox.Scale(aSize, aSize); +} + +} +} diff --git a/libazure/ScaledFontNVpr.h b/libazure/ScaledFontNVpr.h new file mode 100644 index 0000000..aa5c4ce --- /dev/null +++ b/libazure/ScaledFontNVpr.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SCALEDFONTNVPR_H_ +#define MOZILLA_GFX_SCALEDFONTNVPR_H_ + +#include "2D.h" +#include "nvpr/GL.h" +#include + +namespace mozilla { +namespace gfx { + +class FontCacheNVpr; +class FontNVpr; + +class FontNVpr : public RefCounted { +public: + static TemporaryRef Create(const FontOptions* aFont) + { + return new FontNVpr(aFont); + } + + ~FontNVpr(); + + const Rect& GlyphsBoundingBox() const { return mGlyphsBoundingBox; } + operator GLuint() const { return mGlyphPaths; } + +private: + FontNVpr(const FontOptions* aFont); + + GLuint mGlyphPaths; + Rect mGlyphsBoundingBox; +}; + + +class ScaledFontNVpr : public ScaledFont { +public: + static TemporaryRef Create(const FontOptions* aFont, GLfloat aSize); + + static TemporaryRef Create(const uint8_t* aData, uint32_t aFileSize, + uint32_t aIndex, GLfloat aSize); + + GLfloat Size() const { return mSize; } + GLfloat InverseSize() const { return mInverseSize; } + const Rect& GlyphsBoundingBox() const { return mGlyphsBoundingBox; } + operator GLuint() const { return *mFont; } + + virtual FontType GetType() const { return FontType::NVPR; } + + virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, + const DrawTarget *aTarget) + { + return nullptr; + } + + virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, + PathBuilder *aBuilder, + BackendType aBackendType, + const Matrix *aTransformHint) + {} + +private: + ScaledFontNVpr(TemporaryRef aFont, GLfloat aSize); + + const RefPtr mFont; + const GLfloat mSize; + const GLfloat mInverseSize; + Rect mGlyphsBoundingBox; +}; + +} +} + +#endif /* MOZILLA_GFX_SCALEDFONTNVPR_H_ */ diff --git a/libazure/src/gfx/2d/ScaledFontFreetype.cpp b/libazure/ScaledFontSkia.cpp similarity index 52% rename from libazure/src/gfx/2d/ScaledFontFreetype.cpp rename to libazure/ScaledFontSkia.cpp index 3d29474..121c09c 100644 --- a/libazure/src/gfx/2d/ScaledFontFreetype.cpp +++ b/libazure/ScaledFontSkia.cpp @@ -3,13 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "ScaledFontFreetype.h" +#include "ScaledFontSkia.h" #include "Logging.h" -#ifdef USE_SKIA #include "SkTypeface.h" #include "SkStream.h" -#endif #include @@ -23,13 +21,13 @@ static SkTypeface::Style fontStyleToSkia(FontStyle aStyle) { switch (aStyle) { - case FONT_STYLE_NORMAL: + case FontStyle::NORMAL: return SkTypeface::kNormal; - case FONT_STYLE_ITALIC: + case FontStyle::ITALIC: return SkTypeface::kItalic; - case FONT_STYLE_BOLD: + case FontStyle::BOLD: return SkTypeface::kBold; - case FONT_STYLE_BOLD_ITALIC: + case FontStyle::BOLD_ITALIC: return SkTypeface::kBoldItalic; } @@ -38,20 +36,23 @@ fontStyleToSkia(FontStyle aStyle) } #endif -ScaledFontFreetype::ScaledFontFreetype(FontOptions* aFont, Float aSize) +// Ideally we want to use FT_Face here but as there is currently no way to get +// an SkTypeface from an FT_Face we do this. +ScaledFontSkia::ScaledFontSkia(FontOptions* aFont, Float aSize) : ScaledFontBase(aSize) { -#ifdef USE_SKIA - if (aFont->mData) - { - SkStream *stream = new SkMemoryStream(aFont->mData, aFont->mDataSize, true); - mTypeface = SkTypeface::CreateFromStream(stream); - } - else - { - mTypeface = SkTypeface::CreateFromName(aFont->mName.c_str(), fontStyleToSkia(aFont->mStyle)); - } -#endif + mTypeface = SkTypeface::CreateFromName(aFont->mName.c_str(), fontStyleToSkia(aFont->mStyle)); +} + +ScaledFontSkia::ScaledFontSkia(const uint8_t* aData, uint32_t aFileSize, uint32_t aIndex, Float aSize) + : ScaledFontBase(aSize) +{ + SkStream *stream = new SkMemoryStream(aData, aFileSize, true); + mTypeface = SkTypeface::CreateFromStream(stream); +} + +ScaledFontSkia::~ScaledFontSkia() +{ } } diff --git a/libazure/ScaledFontSkia.h b/libazure/ScaledFontSkia.h new file mode 100644 index 0000000..497986f --- /dev/null +++ b/libazure/ScaledFontSkia.h @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SCALEDFONTSKIA_H_ +#define MOZILLA_GFX_SCALEDFONTSKIA_H_ + +#include "ScaledFontBase.h" + +namespace mozilla { +namespace gfx { + +class ScaledFontSkia : public ScaledFontBase +{ +public: + + ScaledFontSkia(FontOptions* aFont, Float aSize); + ScaledFontSkia(const uint8_t* aData, uint32_t aFileSize, uint32_t aIndex, Float aSize); + ~ScaledFontSkia(); +}; + +} +} + +#endif /* MOZILLA_GFX_SCALEDFONTSKIA_H_ */ diff --git a/libazure/src/gfx/2d/ScaledFontWin.cpp b/libazure/ScaledFontWin.cpp similarity index 95% rename from libazure/src/gfx/2d/ScaledFontWin.cpp rename to libazure/ScaledFontWin.cpp index 3469132..ea93967 100644 --- a/libazure/src/gfx/2d/ScaledFontWin.cpp +++ b/libazure/ScaledFontWin.cpp @@ -7,7 +7,7 @@ #include "ScaledFontBase.h" #ifdef USE_SKIA -#include "SkTypeface_win.h" +#include "ports/SkTypeface_win.h" #endif namespace mozilla { diff --git a/libazure/src/gfx/2d/ScaledFontWin.h b/libazure/ScaledFontWin.h similarity index 86% rename from libazure/src/gfx/2d/ScaledFontWin.h rename to libazure/ScaledFontWin.h index 7a99bf5..20c95ed 100644 --- a/libazure/src/gfx/2d/ScaledFontWin.h +++ b/libazure/ScaledFontWin.h @@ -15,9 +15,10 @@ namespace gfx { class ScaledFontWin : public ScaledFontBase { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin) ScaledFontWin(LOGFONT* aFont, Float aSize); - virtual FontType GetType() const { return FONT_GDI; } + virtual FontType GetType() const { return FontType::GDI; } #ifdef USE_SKIA virtual SkTypeface* GetSkTypeface(); #endif diff --git a/libazure/src/gfx/2d/ShadersD2D.fx b/libazure/ShadersD2D.fx similarity index 100% rename from libazure/src/gfx/2d/ShadersD2D.fx rename to libazure/ShadersD2D.fx diff --git a/libazure/ShadersD2D1.hlsl b/libazure/ShadersD2D1.hlsl new file mode 100644 index 0000000..42337af --- /dev/null +++ b/libazure/ShadersD2D1.hlsl @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Texture2D InputTexture : register(t0); +SamplerState InputSampler : register(s0); +Texture2D GradientTexture : register(t1); +SamplerState GradientSampler : register(s1); + +cbuffer constants : register(b0) +{ + // Precalculate as much as we can! + float3 diff : packoffset(c0.x); + float2 center1 : packoffset(c1.x); + float A : packoffset(c1.z); + float radius1 : packoffset(c1.w); + float sq_radius1 : packoffset(c2.x); + + // The next two values are used for a hack to compensate for an apparent + // bug in D2D where the GradientSampler SamplerState doesn't get the + // correct addressing modes. + float repeat_correct : packoffset(c2.y); + float allow_odd : packoffset(c2.z); + + float3x2 transform : packoffset(c3.x); +} + +float4 SampleRadialGradientPS( + float4 clipSpaceOutput : SV_POSITION, + float4 sceneSpaceOutput : SCENE_POSITION, + float4 texelSpaceInput0 : TEXCOORD0 + ) : SV_Target +{ + // Radial gradient painting is defined as the set of circles whose centers + // are described by C(t) = (C2 - C1) * t + C1; with radii + // R(t) = (R2 - R1) * t + R1; for R(t) > 0. This shader solves the + // quadratic equation that arises when calculating t for pixel (x, y). + // + // A more extensive derrivation can be found in the pixman radial gradient + // code. + + float2 p = float2(sceneSpaceOutput.x * transform._11 + sceneSpaceOutput.y * transform._21 + transform._31, + sceneSpaceOutput.x * transform._12 + sceneSpaceOutput.y * transform._22 + transform._32); + float3 dp = float3(p - center1, radius1); + + // dpx * dcx + dpy * dcy + r * dr + float B = dot(dp, diff); + + float C = pow(dp.x, 2) + pow(dp.y, 2) - sq_radius1; + + float det = pow(B, 2) - A * C; + + float sqrt_det = sqrt(abs(det)); + + float2 t = (B + float2(sqrt_det, -sqrt_det)) / A; + + float2 isValid = step(float2(-radius1, -radius1), t * diff.z); + + float upper_t = lerp(t.y, t.x, isValid.x); + + // Addressing mode bug work-around.. first let's see if we should consider odd repetitions separately. + float oddeven = abs(fmod(floor(upper_t), 2)) * allow_odd; + + // Now let's calculate even or odd addressing in a branchless manner. + float upper_t_repeated = ((upper_t - floor(upper_t)) * (1.0f - oddeven)) + ((ceil(upper_t) - upper_t) * oddeven); + + float4 output = GradientTexture.Sample(GradientSampler, float2(upper_t * (1.0f - repeat_correct) + upper_t_repeated * repeat_correct, 0.5)); + // Premultiply + output.rgb *= output.a; + // Multiply the output color by the input mask for the operation. + output *= InputTexture.Sample(InputSampler, texelSpaceInput0.xy); + + // In order to compile for PS_4_0_level_9_3 we need to be branchless. + // This is essentially returning nothing, i.e. bailing early if: + // det < 0 || max(isValid.x, isValid.y) <= 0 + return output * abs(step(max(isValid.x, isValid.y), 0) - 1.0f) * step(0, det); +}; + +float4 SampleRadialGradientA0PS( + float4 clipSpaceOutput : SV_POSITION, + float4 sceneSpaceOutput : SCENE_POSITION, + float4 texelSpaceInput0 : TEXCOORD0 + ) : SV_Target +{ + // This simpler shader is used for the degenerate case where A is 0, + // i.e. we're actually solving a linear equation. + + float2 p = float2(sceneSpaceOutput.x * transform._11 + sceneSpaceOutput.y * transform._21 + transform._31, + sceneSpaceOutput.x * transform._12 + sceneSpaceOutput.y * transform._22 + transform._32); + float3 dp = float3(p - center1, radius1); + + // dpx * dcx + dpy * dcy + r * dr + float B = dot(dp, diff); + + float C = pow(dp.x, 2) + pow(dp.y, 2) - pow(radius1, 2); + + float t = 0.5 * C / B; + + // Addressing mode bug work-around.. first let's see if we should consider odd repetitions separately. + float oddeven = abs(fmod(floor(t), 2)) * allow_odd; + + // Now let's calculate even or odd addressing in a branchless manner. + float t_repeated = ((t - floor(t)) * (1.0f - oddeven)) + ((ceil(t) - t) * oddeven); + + float4 output = GradientTexture.Sample(GradientSampler, float2(t * (1.0f - repeat_correct) + t_repeated * repeat_correct, 0.5)); + // Premultiply + output.rgb *= output.a; + // Multiply the output color by the input mask for the operation. + output *= InputTexture.Sample(InputSampler, texelSpaceInput0.xy); + + // In order to compile for PS_4_0_level_9_3 we need to be branchless. + // This is essentially returning nothing, i.e. bailing early if: + // -radius1 >= t * diff.z + return output * abs(step(t * diff.z, -radius1) - 1.0f); +}; + diff --git a/libazure/src/gfx/2d/SourceSurfaceCG.cpp b/libazure/SourceSurfaceCG.cpp similarity index 77% rename from libazure/src/gfx/2d/SourceSurfaceCG.cpp rename to libazure/SourceSurfaceCG.cpp index 7be284c..49def43 100644 --- a/libazure/src/gfx/2d/SourceSurfaceCG.cpp +++ b/libazure/SourceSurfaceCG.cpp @@ -5,8 +5,12 @@ #include "SourceSurfaceCG.h" #include "DrawTargetCG.h" +#include "DataSourceSurfaceWrapper.h" +#include "DataSurfaceHelpers.h" +#include "mozilla/Types.h" // for decltype -#include "QuartzSupport.h" +#include "MacIOSurface.h" +#include "Tools.h" namespace mozilla { namespace gfx { @@ -37,21 +41,39 @@ SourceSurfaceCG::GetDataSurface() { //XXX: we should be more disciplined about who takes a reference and where CGImageRetain(mImage); - RefPtr dataSurf = - new DataSourceSurfaceCG(mImage); - return dataSurf; + RefPtr dataSurf = new DataSourceSurfaceCG(mImage); + + // We also need to make sure that the returned surface has + // surface->GetType() == SurfaceType::DATA. + return new DataSourceSurfaceWrapper(dataSurf); } static void releaseCallback(void *info, const void *data, size_t size) { free(info); } -static CGImageRef +CGImageRef CreateCGImage(void *aInfo, const void *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) +{ + return CreateCGImage(releaseCallback, + aInfo, + aData, + aSize, + aStride, + aFormat); +} + +CGImageRef +CreateCGImage(CGDataProviderReleaseDataCallback aCallback, + void *aInfo, + const void *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) { //XXX: we should avoid creating this colorspace everytime CGColorSpaceRef colorSpace = nullptr; @@ -60,21 +82,21 @@ CreateCGImage(void *aInfo, int bitsPerPixel = 0; switch (aFormat) { - case FORMAT_B8G8R8A8: + case SurfaceFormat::B8G8R8A8: colorSpace = CGColorSpaceCreateDeviceRGB(); bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; bitsPerComponent = 8; bitsPerPixel = 32; break; - case FORMAT_B8G8R8X8: + case SurfaceFormat::B8G8R8X8: colorSpace = CGColorSpaceCreateDeviceRGB(); bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; bitsPerComponent = 8; bitsPerPixel = 32; break; - case FORMAT_A8: + case SurfaceFormat::A8: // XXX: why don't we set a colorspace here? bitsPerComponent = 8; bitsPerPixel = 8; @@ -84,13 +106,17 @@ CreateCGImage(void *aInfo, MOZ_CRASH(); } + size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height); + if (bufLen == 0) { + return nullptr; + } CGDataProviderRef dataProvider = CGDataProviderCreateWithData(aInfo, aData, - aSize.height * aStride, - releaseCallback); + bufLen, + aCallback); CGImageRef image; - if (aFormat == FORMAT_A8) { + if (aFormat == SurfaceFormat::A8) { CGFloat decode[] = {1.0, 0.0}; image = CGImageMaskCreate (aSize.width, aSize.height, bitsPerComponent, @@ -126,8 +152,16 @@ SourceSurfaceCG::InitFromData(unsigned char *aData, { assert(aSize.width >= 0 && aSize.height >= 0); - void *data = malloc(aStride * aSize.height); - memcpy(data, aData, aStride * aSize.height); + size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height); + if (bufLen == 0) { + mImage = nullptr; + return false; + } + + void *data = malloc(bufLen); + // Copy all the data except the stride padding on the very last + // row since we can't guarantee that is readable. + memcpy(data, aData, bufLen - aStride + (aSize.width * BytesPerPixel(aFormat))); mFormat = aFormat; mImage = CreateCGImage(data, data, aSize, aStride, aFormat); @@ -157,12 +191,28 @@ DataSourceSurfaceCG::InitFromData(unsigned char *aData, int32_t aStride, SurfaceFormat aFormat) { - void *data = malloc(aStride * aSize.height); - memcpy(data, aData, aStride * aSize.height); + if (aSize.width <= 0 || aSize.height <= 0) { + return false; + } + + size_t bufLen = BufferSizeFromStrideAndHeight(aStride, aSize.height); + if (bufLen == 0) { + mImage = nullptr; + return false; + } + + void *data = malloc(bufLen); + memcpy(data, aData, bufLen - aStride + (aSize.width * BytesPerPixel(aFormat))); + mFormat = aFormat; mImage = CreateCGImage(data, data, aSize, aStride, aFormat); - return mImage; + if (!mImage) { + free(data); + return false; + } + + return true; } CGContextRef CreateBitmapContextForImage(CGImageRef image) @@ -201,6 +251,7 @@ CGContextRef CreateBitmapContextForImage(CGImageRef image) DataSourceSurfaceCG::DataSourceSurfaceCG(CGImageRef aImage) { + mFormat = SurfaceFormat::B8G8R8A8; mImage = aImage; mCg = CreateBitmapContextForImage(aImage); if (mCg == nullptr) { @@ -241,7 +292,8 @@ DataSourceSurfaceCG::GetData() SourceSurfaceCGBitmapContext::SourceSurfaceCGBitmapContext(DrawTargetCG *aDrawTarget) { mDrawTarget = aDrawTarget; - mCg = (CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT); + mFormat = aDrawTarget->GetFormat(); + mCg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT); if (!mCg) abort(); @@ -263,21 +315,8 @@ void SourceSurfaceCGBitmapContext::EnsureImage() const // memcpy when the bitmap context is modified gives us more predictable // performance characteristics. if (!mImage) { - void *info; - if (mCg) { - // if we have an mCg than it owns the data - // and we don't want to tranfer ownership - // to the CGDataProviderCreateWithData - info = nullptr; - } else { - // otherwise we transfer ownership to - // the dataProvider - info = mData; - } - if (!mData) abort(); - - mImage = CreateCGImage(info, mData, mSize, mStride, FORMAT_B8G8R8A8); + mImage = CreateCGImage(nullptr, mData, mSize, mStride, mFormat); } } @@ -295,13 +334,21 @@ SourceSurfaceCGBitmapContext::DrawTargetWillChange() size_t stride = CGBitmapContextGetBytesPerRow(mCg); size_t height = CGBitmapContextGetHeight(mCg); - //XXX: infalliable malloc? - mData = malloc(stride * height); - - // copy out the data from the CGBitmapContext - // we'll maintain ownership of mData until - // we transfer it to mImage - memcpy(mData, CGBitmapContextGetData(mCg), stride*height); + size_t bufLen = BufferSizeFromStrideAndHeight(stride, height); + if (bufLen == 0) { + mDataHolder.Dealloc(); + mData = nullptr; + } else { + static_assert(sizeof(decltype(mDataHolder[0])) == 1, + "mDataHolder.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen"); + mDataHolder.Realloc(/* actually an object count */ bufLen); + mData = mDataHolder; + + // copy out the data from the CGBitmapContext + // we'll maintain ownership of mData until + // we transfer it to mImage + memcpy(mData, CGBitmapContextGetData(mCg), bufLen); + } // drop the current image for the data associated with the CGBitmapContext if (mImage) @@ -315,20 +362,17 @@ SourceSurfaceCGBitmapContext::DrawTargetWillChange() SourceSurfaceCGBitmapContext::~SourceSurfaceCGBitmapContext() { - if (!mImage && !mCg) { - // neither mImage or mCg owns the data - free(mData); - } if (mImage) CGImageRelease(mImage); } SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget) { - CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT_ACCELERATED); + CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT_ACCELERATED); RefPtr surf = MacIOSurface::IOSurfaceContextGetSurface(cg); + mFormat = aDrawTarget->GetFormat(); mSize.width = surf->GetWidth(); mSize.height = surf->GetHeight(); @@ -361,7 +405,7 @@ void SourceSurfaceCGIOSurfaceContext::EnsureImage() const // memcpy when the bitmap context is modified gives us more predictable // performance characteristics. if (!mImage) { - mImage = CreateCGImage(mData, mData, mSize, mStride, FORMAT_B8G8R8A8); + mImage = CreateCGImage(mData, mData, mSize, mStride, SurfaceFormat::B8G8R8A8); } } diff --git a/libazure/src/gfx/2d/SourceSurfaceCG.h b/libazure/SourceSurfaceCG.h similarity index 59% rename from libazure/src/gfx/2d/SourceSurfaceCG.h rename to libazure/SourceSurfaceCG.h index 63bd675..24529e3 100644 --- a/libazure/src/gfx/2d/SourceSurfaceCG.h +++ b/libazure/SourceSurfaceCG.h @@ -3,7 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#pragma once +#ifndef _MOZILLA_GFX_SOURCESURFACECG_H +#define _MOZILLA_GFX_SOURCESURFACECG_H #include @@ -14,16 +15,32 @@ class MacIOSurface; namespace mozilla { namespace gfx { +CGImageRef +CreateCGImage(CGDataProviderReleaseDataCallback aCallback, + void *aInfo, + const void *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat); + +CGImageRef +CreateCGImage(void *aInfo, + const void *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat); + class DrawTargetCG; class SourceSurfaceCG : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCG) SourceSurfaceCG() {} - SourceSurfaceCG(CGImageRef aImage) : mImage(aImage) {} + explicit SourceSurfaceCG(CGImageRef aImage) : mImage(aImage) {} ~SourceSurfaceCG(); - virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_IMAGE; } + virtual SurfaceType GetType() const { return SurfaceType::COREGRAPHICS_IMAGE; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; virtual TemporaryRef GetDataSurface(); @@ -47,13 +64,14 @@ class SourceSurfaceCG : public SourceSurface class DataSourceSurfaceCG : public DataSourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceCG) DataSourceSurfaceCG() {} - DataSourceSurfaceCG(CGImageRef aImage); + explicit DataSourceSurfaceCG(CGImageRef aImage); ~DataSourceSurfaceCG(); - virtual SurfaceType GetType() const { return SURFACE_DATA; } + virtual SurfaceType GetType() const { return SurfaceType::DATA; } virtual IntSize GetSize() const; - virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; } + virtual SurfaceFormat GetFormat() const { return mFormat; } CGImageRef GetImage() { return mImage; } @@ -70,6 +88,7 @@ class DataSourceSurfaceCG : public DataSourceSurface private: CGContextRef mCg; CGImageRef mImage; + SurfaceFormat mFormat; //XXX: we don't need to store mData we can just get it from the CGContext void *mData; /* It might be better to just use the bitmap info from the CGImageRef to @@ -80,6 +99,7 @@ class DataSourceSurfaceCG : public DataSourceSurface class SourceSurfaceCGContext : public DataSourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceCGContext) virtual void DrawTargetWillChange() = 0; virtual CGImageRef GetImage() = 0; }; @@ -87,12 +107,27 @@ class SourceSurfaceCGContext : public DataSourceSurface class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext { public: - SourceSurfaceCGBitmapContext(DrawTargetCG *); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceCGBitmapContext) + explicit SourceSurfaceCGBitmapContext(DrawTargetCG *); ~SourceSurfaceCGBitmapContext(); - virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_CGCONTEXT; } + virtual SurfaceType GetType() const { return SurfaceType::COREGRAPHICS_CGCONTEXT; } virtual IntSize GetSize() const; - virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; } + virtual SurfaceFormat GetFormat() const { return mFormat; } + virtual TemporaryRef GetDataSurface() + { + // This call to DrawTargetWillChange() is needed to make a local copy of + // the data from mDrawTarget. If we don't do that, the data can end up + // getting deleted before the CGImageRef it belongs to. + // + // Another reason we need a local copy of the data is that the data in + // mDrawTarget could change when someone touches the original DrawTargetCG + // object. But a SourceSurface object should be immutable. + // + // For more information see bug 925448. + DrawTargetWillChange(); + return this; + } CGImageRef GetImage() { EnsureImage(); return mImage; } @@ -110,6 +145,7 @@ class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext // The cycle is broken by DrawTargetWillChange DrawTargetCG *mDrawTarget; CGContextRef mCg; + SurfaceFormat mFormat; mutable CGImageRef mImage; @@ -117,6 +153,9 @@ class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext // mImage, mCg or SourceSurfaceCGBitmapContext void *mData; + // The image buffer, if the buffer is owned by this class. + AlignedArray mDataHolder; + int32_t mStride; IntSize mSize; }; @@ -124,12 +163,13 @@ class SourceSurfaceCGBitmapContext : public SourceSurfaceCGContext class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext { public: - SourceSurfaceCGIOSurfaceContext(DrawTargetCG *); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceCGIOSurfaceContext) + explicit SourceSurfaceCGIOSurfaceContext(DrawTargetCG *); ~SourceSurfaceCGIOSurfaceContext(); - virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_CGCONTEXT; } + virtual SurfaceType GetType() const { return SurfaceType::COREGRAPHICS_CGCONTEXT; } virtual IntSize GetSize() const; - virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; } + virtual SurfaceFormat GetFormat() const { return mFormat; } CGImageRef GetImage() { EnsureImage(); return mImage; } @@ -143,6 +183,7 @@ class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext virtual void DrawTargetWillChange(); void EnsureImage() const; + SurfaceFormat mFormat; mutable CGImageRef mImage; MacIOSurface* mIOSurface; @@ -155,3 +196,5 @@ class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext } } + +#endif // _MOZILLA_GFX_SOURCESURFACECG_H diff --git a/libazure/src/gfx/2d/SourceSurfaceCairo.cpp b/libazure/SourceSurfaceCairo.cpp similarity index 90% rename from libazure/src/gfx/2d/SourceSurfaceCairo.cpp rename to libazure/SourceSurfaceCairo.cpp index 81438b6..a1ecfe5 100644 --- a/libazure/src/gfx/2d/SourceSurfaceCairo.cpp +++ b/libazure/SourceSurfaceCairo.cpp @@ -6,6 +6,7 @@ #include "SourceSurfaceCairo.h" #include "DrawTargetCairo.h" #include "HelpersCairo.h" +#include "DataSourceSurfaceWrapper.h" #include "cairo.h" @@ -18,13 +19,13 @@ CairoFormatToSurfaceFormat(cairo_format_t format) switch (format) { case CAIRO_FORMAT_ARGB32: - return FORMAT_B8G8R8A8; + return SurfaceFormat::B8G8R8A8; case CAIRO_FORMAT_RGB24: - return FORMAT_B8G8R8X8; + return SurfaceFormat::B8G8R8X8; case CAIRO_FORMAT_A8: - return FORMAT_A8; + return SurfaceFormat::A8; default: - return FORMAT_B8G8R8A8; + return SurfaceFormat::B8G8R8A8; } } @@ -60,7 +61,7 @@ SourceSurfaceCairo::GetFormat() const TemporaryRef SourceSurfaceCairo::GetDataSurface() { - RefPtr dataSurf; + RefPtr dataSurf; if (cairo_surface_get_type(mSurface) == CAIRO_SURFACE_TYPE_IMAGE) { dataSurf = new DataSourceSurfaceCairo(mSurface); @@ -78,7 +79,9 @@ SourceSurfaceCairo::GetDataSurface() cairo_surface_destroy(imageSurf); } - return dataSurf; + // We also need to make sure that the returned surface has + // surface->GetType() == SurfaceType::DATA. + return new DataSourceSurfaceWrapper(dataSurf); } cairo_surface_t* diff --git a/libazure/src/gfx/2d/SourceSurfaceCairo.h b/libazure/SourceSurfaceCairo.h similarity index 84% rename from libazure/src/gfx/2d/SourceSurfaceCairo.h rename to libazure/SourceSurfaceCairo.h index 4f26de1..7ea0e02 100644 --- a/libazure/src/gfx/2d/SourceSurfaceCairo.h +++ b/libazure/SourceSurfaceCairo.h @@ -16,6 +16,7 @@ class DrawTargetCairo; class SourceSurfaceCairo : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCairo) // Create a SourceSurfaceCairo. The surface will not be copied, but simply // referenced. // If aDrawTarget is non-nullptr, it is assumed that this is a snapshot source @@ -26,7 +27,7 @@ class SourceSurfaceCairo : public SourceSurface DrawTargetCairo* aDrawTarget = nullptr); virtual ~SourceSurfaceCairo(); - virtual SurfaceType GetType() const { return SURFACE_CAIRO; } + virtual SurfaceType GetType() const { return SurfaceType::CAIRO; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; virtual TemporaryRef GetDataSurface(); @@ -47,12 +48,13 @@ class SourceSurfaceCairo : public SourceSurface class DataSourceSurfaceCairo : public DataSourceSurface { public: - DataSourceSurfaceCairo(cairo_surface_t* imageSurf); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceCairo) + explicit DataSourceSurfaceCairo(cairo_surface_t* imageSurf); virtual ~DataSourceSurfaceCairo(); virtual unsigned char *GetData(); virtual int32_t Stride(); - virtual SurfaceType GetType() const { return SURFACE_CAIRO_IMAGE; } + virtual SurfaceType GetType() const { return SurfaceType::CAIRO_IMAGE; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; diff --git a/libazure/src/gfx/2d/SourceSurfaceD2D.cpp b/libazure/SourceSurfaceD2D.cpp similarity index 71% rename from libazure/src/gfx/2d/SourceSurfaceD2D.cpp rename to libazure/SourceSurfaceD2D.cpp index c6ff601..1b8a3b2 100644 --- a/libazure/src/gfx/2d/SourceSurfaceD2D.cpp +++ b/libazure/SourceSurfaceD2D.cpp @@ -45,7 +45,7 @@ SourceSurfaceD2D::GetDataSurface() { RefPtr result = new DataSourceSurfaceD2D(this); if (result->IsValid()) { - return result; + return result.forget(); } return nullptr; } @@ -68,15 +68,21 @@ SourceSurfaceD2D::InitFromData(unsigned char *aData, return false; } - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); - hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap)); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); + hr = aRT->CreateBitmap(D2DIntSize(aSize), props, byRef(mBitmap)); if (FAILED(hr)) { gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hr; return false; } + hr = mBitmap->CopyFromMemory(nullptr, aData, aStride); + + if (FAILED(hr)) { + gfxWarning() << "Failed to copy data to D2D bitmap. Code: " << hr; + return false; + } + DrawTargetD2D::mVRAMUsageSS += GetByteSize(); mDevice = Factory::GetDirect3D10Device(); @@ -105,8 +111,7 @@ SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture, mSize = IntSize(desc.Width, desc.Height); mFormat = aFormat; - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); if (FAILED(hr)) { @@ -156,13 +161,13 @@ DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface) return; } - D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties( - D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)); RefPtr renderTarget; - hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface, - &rtProps, + hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface, + &rtProps, byRef(renderTarget)); if (FAILED(hr)) { gfxWarning() << "Failed to create render target. Code: " << hr; @@ -170,13 +175,25 @@ DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface) } renderTarget->BeginDraw(); - renderTarget->DrawBitmap(aSourceSurface->mBitmap, - D2D1::RectF(0, 0, - Float(mSize.width), - Float(mSize.height))); - renderTarget->EndDraw(); + renderTarget->Clear(D2D1::ColorF(0, 0.0f)); + if (aSourceSurface->GetFormat() != SurfaceFormat::A8) { + renderTarget->DrawBitmap(aSourceSurface->mBitmap, + D2D1::RectF(0, 0, + Float(mSize.width), + Float(mSize.height))); + } else { + RefPtr brush; + renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush)); + renderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + renderTarget->FillOpacityMask(aSourceSurface->mBitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS); + } + hr = renderTarget->EndDraw(); + if (FAILED(hr)) { + gfxWarning() << "Failed to draw bitmap. Code: " << hr; + return; + } - desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE; desc.Usage = D3D10_USAGE_STAGING; desc.BindFlags = 0; hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture)); @@ -230,9 +247,58 @@ DataSourceSurfaceD2D::GetFormat() const return mFormat; } +bool +DataSourceSurfaceD2D::Map(MapType aMapType, MappedSurface *aMappedSurface) +{ + // DataSourceSurfaces used with the new Map API should not be used with GetData!! + MOZ_ASSERT(!mMapped); + MOZ_ASSERT(!mIsMapped); + + if (!mTexture) { + return false; + } + + D3D10_MAP mapType; + + if (aMapType == MapType::READ) { + mapType = D3D10_MAP_READ; + } else if (aMapType == MapType::WRITE) { + mapType = D3D10_MAP_WRITE; + } else { + mapType = D3D10_MAP_READ_WRITE; + } + + D3D10_MAPPED_TEXTURE2D map; + + HRESULT hr = mTexture->Map(0, mapType, 0, &map); + + if (FAILED(hr)) { + gfxWarning() << "Texture map failed with code: " << hr; + return false; + } + + aMappedSurface->mData = (uint8_t*)map.pData; + aMappedSurface->mStride = map.RowPitch; + mIsMapped = true; + + return true; +} + +void +DataSourceSurfaceD2D::Unmap() +{ + MOZ_ASSERT(mIsMapped); + + mIsMapped = false; + mTexture->Unmap(0); +} + void DataSourceSurfaceD2D::EnsureMappedTexture() { + // Do not use GetData() after having used Map! + MOZ_ASSERT(!mIsMapped); + if (mMapped || !mTexture) { return; diff --git a/libazure/src/gfx/2d/SourceSurfaceD2D.h b/libazure/SourceSurfaceD2D.h similarity index 87% rename from libazure/src/gfx/2d/SourceSurfaceD2D.h rename to libazure/SourceSurfaceD2D.h index bafbd20..c2622d7 100644 --- a/libazure/src/gfx/2d/SourceSurfaceD2D.h +++ b/libazure/SourceSurfaceD2D.h @@ -18,10 +18,11 @@ class DataSourceSurfaceD2D; class SourceSurfaceD2D : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceD2D) SourceSurfaceD2D(); ~SourceSurfaceD2D(); - virtual SurfaceType GetType() const { return SURFACE_D2D1_BITMAP; } + virtual SurfaceType GetType() const { return SurfaceType::D2D1_BITMAP; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; virtual bool IsValid() const; @@ -55,6 +56,7 @@ class SourceSurfaceD2D : public SourceSurface class DataSourceSurfaceD2D : public DataSourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2D) DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface); virtual ~DataSourceSurfaceD2D(); @@ -62,6 +64,8 @@ class DataSourceSurfaceD2D : public DataSourceSurface virtual int32_t Stride(); virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; + virtual bool Map(MapType, MappedSurface *aMappedSurface); + virtual void Unmap(); bool IsValid() { diff --git a/libazure/SourceSurfaceD2D1.cpp b/libazure/SourceSurfaceD2D1.cpp new file mode 100644 index 0000000..ca5bb75 --- /dev/null +++ b/libazure/SourceSurfaceD2D1.cpp @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SourceSurfaceD2D1.h" +#include "DrawTargetD2D1.h" +#include "Tools.h" + +namespace mozilla { +namespace gfx { + +SourceSurfaceD2D1::SourceSurfaceD2D1(ID2D1Image *aImage, ID2D1DeviceContext *aDC, + SurfaceFormat aFormat, const IntSize &aSize, + DrawTargetD2D1 *aDT) + : mImage(aImage) + , mDC(aDC) + , mDrawTarget(aDT) +{ + aImage->QueryInterface((ID2D1Bitmap1**)byRef(mRealizedBitmap)); + + mFormat = aFormat; + mSize = aSize; +} + +SourceSurfaceD2D1::~SourceSurfaceD2D1() +{ +} + +TemporaryRef +SourceSurfaceD2D1::GetDataSurface() +{ + EnsureRealizedBitmap(); + + RefPtr softwareBitmap; + D2D1_BITMAP_PROPERTIES1 props; + props.dpiX = 96; + props.dpiY = 96; + props.pixelFormat = D2DPixelFormat(mFormat); + props.colorContext = nullptr; + props.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | + D2D1_BITMAP_OPTIONS_CPU_READ; + mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(softwareBitmap)); + + D2D1_POINT_2U point = D2D1::Point2U(0, 0); + D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height); + softwareBitmap->CopyFromBitmap(&point, mRealizedBitmap, &rect); + return new DataSourceSurfaceD2D1(softwareBitmap, mFormat); +} + +void +SourceSurfaceD2D1::EnsureRealizedBitmap() +{ + if (mRealizedBitmap) { + return; + } + + RefPtr dc; + Factory::GetD2D1Device()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, byRef(dc)); + + D2D1_BITMAP_PROPERTIES1 props; + props.dpiX = 96; + props.dpiY = 96; + props.pixelFormat = D2DPixelFormat(mFormat); + props.colorContext = nullptr; + props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET; + dc->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mRealizedBitmap)); + + dc->SetTarget(mRealizedBitmap); + + dc->BeginDraw(); + dc->DrawImage(mImage); + dc->EndDraw(); +} + +void +SourceSurfaceD2D1::DrawTargetWillChange() +{ + // At this point in time this should always be true here. + MOZ_ASSERT(mRealizedBitmap); + + RefPtr oldBitmap = mRealizedBitmap; + + D2D1_BITMAP_PROPERTIES1 props; + props.dpiX = 96; + props.dpiY = 96; + props.pixelFormat = D2DPixelFormat(mFormat); + props.colorContext = nullptr; + props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET; + mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mRealizedBitmap)); + + D2D1_POINT_2U point = D2D1::Point2U(0, 0); + D2D1_RECT_U rect = D2D1::RectU(0, 0, mSize.width, mSize.height); + mRealizedBitmap->CopyFromBitmap(&point, oldBitmap, &rect); + mImage = mRealizedBitmap; + + DrawTargetD2D1::mVRAMUsageSS += mSize.width * mSize.height * BytesPerPixel(mFormat); + + // We now no longer depend on the source surface content remaining the same. + MarkIndependent(); +} + +void +SourceSurfaceD2D1::MarkIndependent() +{ + if (mDrawTarget) { + MOZ_ASSERT(mDrawTarget->mSnapshot == this); + mDrawTarget->mSnapshot = nullptr; + mDrawTarget = nullptr; + } +} + +DataSourceSurfaceD2D1::DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat) + : mBitmap(aMappableBitmap) + , mFormat(aFormat) + , mMapped(false) +{ +} + +DataSourceSurfaceD2D1::~DataSourceSurfaceD2D1() +{ + if (mMapped) { + mBitmap->Unmap(); + } +} + +IntSize +DataSourceSurfaceD2D1::GetSize() const +{ + D2D1_SIZE_F size = mBitmap->GetSize(); + + return IntSize(int32_t(size.width), int32_t(size.height)); +} + +uint8_t* +DataSourceSurfaceD2D1::GetData() +{ + EnsureMapped(); + + return mMap.bits; +} + +bool +DataSourceSurfaceD2D1::Map(MapType aMapType, MappedSurface *aMappedSurface) +{ + // DataSourceSurfaces used with the new Map API should not be used with GetData!! + MOZ_ASSERT(!mMapped); + MOZ_ASSERT(!mIsMapped); + + D2D1_MAP_OPTIONS options; + if (aMapType == MapType::READ) { + options = D2D1_MAP_OPTIONS_READ; + } else { + MOZ_CRASH("No support for Write maps on D2D1 DataSourceSurfaces yet!"); + } + + D2D1_MAPPED_RECT map; + mBitmap->Map(D2D1_MAP_OPTIONS_READ, &map); + aMappedSurface->mData = map.bits; + aMappedSurface->mStride = map.pitch; + + mIsMapped = true; + return true; +} + +void +DataSourceSurfaceD2D1::Unmap() +{ + MOZ_ASSERT(mIsMapped); + + mIsMapped = false; + mBitmap->Unmap(); +} + +int32_t +DataSourceSurfaceD2D1::Stride() +{ + EnsureMapped(); + + return mMap.pitch; +} + +void +DataSourceSurfaceD2D1::EnsureMapped() +{ + // Do not use GetData() after having used Map! + MOZ_ASSERT(!mIsMapped); + if (mMapped) { + return; + } + mBitmap->Map(D2D1_MAP_OPTIONS_READ, &mMap); + mMapped = true; +} + +} +} diff --git a/libazure/SourceSurfaceD2D1.h b/libazure/SourceSurfaceD2D1.h new file mode 100644 index 0000000..ae3357f --- /dev/null +++ b/libazure/SourceSurfaceD2D1.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SOURCESURFACED2D1_H_ +#define MOZILLA_GFX_SOURCESURFACED2D1_H_ + +#include "2D.h" +#include "HelpersD2D.h" +#include +#include +#include + +namespace mozilla { +namespace gfx { + +class DrawTargetD2D1; + +class SourceSurfaceD2D1 : public SourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceD2D1) + SourceSurfaceD2D1(ID2D1Image* aImage, ID2D1DeviceContext *aDC, + SurfaceFormat aFormat, const IntSize &aSize, + DrawTargetD2D1 *aDT = nullptr); + ~SourceSurfaceD2D1(); + + virtual SurfaceType GetType() const { return SurfaceType::D2D1_1_IMAGE; } + virtual IntSize GetSize() const { return mSize; } + virtual SurfaceFormat GetFormat() const { return mFormat; } + virtual TemporaryRef GetDataSurface(); + + ID2D1Image *GetImage() { return mImage; } + + void EnsureIndependent() { if (!mDrawTarget) return; DrawTargetWillChange(); } + +private: + friend class DrawTargetD2D1; + + void EnsureRealizedBitmap(); + + // This function is called by the draw target this texture belongs to when + // it is about to be changed. The texture will be required to make a copy + // of itself when this happens. + void DrawTargetWillChange(); + + // This will mark the surface as no longer depending on its drawtarget, + // this may happen on destruction or copying. + void MarkIndependent(); + + RefPtr mImage; + // This may be null if we were created for a non-bitmap image and have not + // had a reason yet to realize ourselves. + RefPtr mRealizedBitmap; + RefPtr mDC; + + SurfaceFormat mFormat; + IntSize mSize; + DrawTargetD2D1* mDrawTarget; +}; + +class DataSourceSurfaceD2D1 : public DataSourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2D1) + DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat); + ~DataSourceSurfaceD2D1(); + + virtual SurfaceType GetType() const { return SurfaceType::DATA; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const { return mFormat; } + virtual uint8_t *GetData(); + virtual int32_t Stride(); + virtual bool Map(MapType, MappedSurface *aMappedSurface); + virtual void Unmap(); + +private: + friend class SourceSurfaceD2DTarget; + void EnsureMapped(); + + mutable RefPtr mBitmap; + SurfaceFormat mFormat; + D2D1_MAPPED_RECT mMap; + bool mMapped; +}; + +} +} + +#endif /* MOZILLA_GFX_SOURCESURFACED2D2TARGET_H_ */ diff --git a/libazure/src/gfx/2d/SourceSurfaceD2DTarget.cpp b/libazure/SourceSurfaceD2DTarget.cpp similarity index 75% rename from libazure/src/gfx/2d/SourceSurfaceD2DTarget.cpp rename to libazure/SourceSurfaceD2DTarget.cpp index 6f66cdb..21a97f9 100644 --- a/libazure/src/gfx/2d/SourceSurfaceD2DTarget.cpp +++ b/libazure/SourceSurfaceD2DTarget.cpp @@ -54,7 +54,7 @@ TemporaryRef SourceSurfaceD2DTarget::GetDataSurface() { RefPtr dataSurf = - new DataSourceSurfaceD2DTarget(); + new DataSourceSurfaceD2DTarget(mFormat); D3D10_TEXTURE2D_DESC desc; mTexture->GetDesc(&desc); @@ -72,7 +72,16 @@ SourceSurfaceD2DTarget::GetDataSurface() } Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); - return dataSurf; + return dataSurf.forget(); +} + +void* +SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType) +{ + if (aType == NativeSurfaceType::D3D10_TEXTURE) { + return static_cast(mTexture.get()); + } + return nullptr; } ID3D10ShaderResourceView* @@ -133,16 +142,19 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) return nullptr; } - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); if (FAILED(hr)) { - // This seems to happen for FORMAT_A8 sometimes... - aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), - AlphaMode(mFormat))), - byRef(mBitmap)); + // This seems to happen for SurfaceFormat::A8 sometimes... + hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), + D2D1::BitmapProperties(D2DPixelFormat(mFormat)), + byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed in CreateBitmap. Code: " << hr; + return nullptr; + } RefPtr rt; @@ -164,7 +176,7 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) } D2D1_RENDER_TARGET_PROPERTIES props = - D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat)); hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); if (FAILED(hr)) { @@ -190,8 +202,8 @@ SourceSurfaceD2DTarget::MarkIndependent() } } -DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget() - : mFormat(FORMAT_B8G8R8A8) +DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat) + : mFormat(aFormat) , mMapped(false) { } @@ -233,9 +245,57 @@ DataSourceSurfaceD2DTarget::Stride() return mMap.RowPitch; } +bool +DataSourceSurfaceD2DTarget::Map(MapType aMapType, MappedSurface *aMappedSurface) +{ + // DataSourceSurfaces used with the new Map API should not be used with GetData!! + MOZ_ASSERT(!mMapped); + MOZ_ASSERT(!mIsMapped); + + if (!mTexture) { + return false; + } + + D3D10_MAP mapType; + + if (aMapType == MapType::READ) { + mapType = D3D10_MAP_READ; + } else if (aMapType == MapType::WRITE) { + mapType = D3D10_MAP_WRITE; + } else { + mapType = D3D10_MAP_READ_WRITE; + } + + D3D10_MAPPED_TEXTURE2D map; + + HRESULT hr = mTexture->Map(0, mapType, 0, &map); + + if (FAILED(hr)) { + gfxWarning() << "Texture map failed with code: " << hr; + return false; + } + + aMappedSurface->mData = (uint8_t*)map.pData; + aMappedSurface->mStride = map.RowPitch; + mIsMapped = true; + + return true; +} + +void +DataSourceSurfaceD2DTarget::Unmap() +{ + MOZ_ASSERT(mIsMapped); + + mIsMapped = false; + mTexture->Unmap(0); +} + void DataSourceSurfaceD2DTarget::EnsureMapped() { + // Do not use GetData() after having used Map! + MOZ_ASSERT(!mIsMapped); if (!mMapped) { HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap); if (FAILED(hr)) { diff --git a/libazure/src/gfx/2d/SourceSurfaceD2DTarget.h b/libazure/SourceSurfaceD2DTarget.h similarity index 81% rename from libazure/src/gfx/2d/SourceSurfaceD2DTarget.h rename to libazure/SourceSurfaceD2DTarget.h index 2be02df..a665050 100644 --- a/libazure/src/gfx/2d/SourceSurfaceD2DTarget.h +++ b/libazure/SourceSurfaceD2DTarget.h @@ -19,17 +19,23 @@ class DrawTargetD2D; class SourceSurfaceD2DTarget : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceD2DTarget) SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget, ID3D10Texture2D* aTexture, SurfaceFormat aFormat); ~SourceSurfaceD2DTarget(); - virtual SurfaceType GetType() const { return SURFACE_D2D1_DRAWTARGET; } + virtual SurfaceType GetType() const { return SurfaceType::D2D1_DRAWTARGET; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; virtual TemporaryRef GetDataSurface(); + virtual void *GetNativeSurface(NativeSurfaceType aType); + + DrawTargetD2D* GetDT() { return mDrawTarget; } + ID2D1Bitmap *GetBitmap(ID2D1RenderTarget *aRT); private: friend class DrawTargetD2D; + ID3D10ShaderResourceView *GetSRView(); // This function is called by the draw target this texture belongs to when @@ -41,8 +47,6 @@ class SourceSurfaceD2DTarget : public SourceSurface // this may happen on destruction or copying. void MarkIndependent(); - ID2D1Bitmap *GetBitmap(ID2D1RenderTarget *aRT); - RefPtr mSRView; RefPtr mBitmap; // Non-null if this is a "lazy copy" of the given draw target. @@ -58,14 +62,17 @@ class SourceSurfaceD2DTarget : public SourceSurface class DataSourceSurfaceD2DTarget : public DataSourceSurface { public: - DataSourceSurfaceD2DTarget(); + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2DTarget) + DataSourceSurfaceD2DTarget(SurfaceFormat aFormat); ~DataSourceSurfaceD2DTarget(); - virtual SurfaceType GetType() const { return SURFACE_DATA; } + virtual SurfaceType GetType() const { return SurfaceType::DATA; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; virtual uint8_t *GetData(); virtual int32_t Stride(); + virtual bool Map(MapType, MappedSurface *aMappedSurface); + virtual void Unmap(); private: friend class SourceSurfaceD2DTarget; diff --git a/libazure/src/gfx/2d/SourceSurfaceDual.h b/libazure/SourceSurfaceDual.h similarity index 89% rename from libazure/src/gfx/2d/SourceSurfaceDual.h rename to libazure/SourceSurfaceDual.h index 0b783cb..aaa85dc 100644 --- a/libazure/src/gfx/2d/SourceSurfaceDual.h +++ b/libazure/SourceSurfaceDual.h @@ -17,12 +17,13 @@ class DualPattern; class SourceSurfaceDual : public SourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceDual) SourceSurfaceDual(DrawTarget *aDTA, DrawTarget *aDTB) : mA(aDTA->Snapshot()) , mB(aDTB->Snapshot()) { } - virtual SurfaceType GetType() const { return SURFACE_DUAL_DT; } + virtual SurfaceType GetType() const { return SurfaceType::DUAL_DT; } virtual IntSize GetSize() const { return mA->GetSize(); } virtual SurfaceFormat GetFormat() const { return mA->GetFormat(); } diff --git a/libazure/SourceSurfaceNVpr.cpp b/libazure/SourceSurfaceNVpr.cpp new file mode 100644 index 0000000..5ba52bc --- /dev/null +++ b/libazure/SourceSurfaceNVpr.cpp @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SourceSurfaceNVpr.h" + +using namespace mozilla::gfx::nvpr; +using namespace std; + +namespace mozilla { +namespace gfx { + +TextureObjectNVpr::TextureObjectNVpr(SurfaceFormat aFormat, const IntSize& aSize, + bool& aSuccess) + : mFormat(aFormat) + , mSize(aSize) + , mTextureId(0) + , mWrapMode(GL_REPEAT) + , mFilter(Filter::LINEAR) + , mHasMipmaps(false) +{ + MOZ_ASSERT(mSize.width >= 0 && mSize.height >= 0); + + aSuccess = false; + + gl->MakeCurrent(); + + if (max(mSize.width, mSize.height) > gl->MaxTextureSize()) { + return; + } + + gl->GenTextures(1, &mTextureId); + + GLenum internalFormat; + switch (mFormat) { + case SurfaceFormat::YUV: + case SurfaceFormat::UNKNOWN: + default: + return; + case SurfaceFormat::B8G8R8A8: + internalFormat = GL_RGBA8; + mGLFormat = GL_BGRA; + mGLType = GL_UNSIGNED_BYTE; + mBytesPerPixel = 4; + break; + case SurfaceFormat::B8G8R8X8: + internalFormat = GL_RGB8; + mGLFormat = GL_BGRA; + mGLType = GL_UNSIGNED_BYTE; + mBytesPerPixel = 4; + break; + case SurfaceFormat::R8G8B8A8: + internalFormat = GL_RGBA8; + mGLFormat = GL_RGBA; + mGLType = GL_UNSIGNED_BYTE; + mBytesPerPixel = 4; + break; + case SurfaceFormat::R8G8B8X8: + internalFormat = GL_RGB8; + mGLFormat = GL_RGBA; + mGLType = GL_UNSIGNED_BYTE; + mBytesPerPixel = 4; + break; + case SurfaceFormat::R5G6B5: + internalFormat = GL_RGB565; + mGLFormat = GL_RGB; + mGLType = GL_UNSIGNED_SHORT_5_6_5; + mBytesPerPixel = 2; + break; + case SurfaceFormat::A8: + internalFormat = GL_ALPHA; + mGLFormat = GL_ALPHA; + mGLType = GL_UNSIGNED_BYTE; + mBytesPerPixel = 1; + break; + } + + gl->TextureImage2DEXT(mTextureId, GL_TEXTURE_2D, 0, internalFormat, mSize.width, + mSize.height, 0, mGLFormat, mGLType, nullptr); + + // The initial value for MIN_FILTER is NEAREST_MIPMAP_LINEAR. We initialize it + // to what 'Filter::LINEAR' expects. + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (gl->HasExtension(GL::EXT_texture_filter_anisotropic)) { + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, + GL_TEXTURE_MAX_ANISOTROPY_EXT, gl->MaxAnisotropy()); + } + + aSuccess = true; +} + +TemporaryRef +TextureObjectNVpr::Create(DataSourceSurface* aData) +{ + return Create(aData->GetFormat(), aData->GetSize(), aData->GetData(), + aData->Stride()); +} + +TemporaryRef +TextureObjectNVpr::Create(SurfaceFormat aFormat, const IntSize& aSize, + const GLvoid* aData, GLsizei aStride) +{ + bool success; + RefPtr surface = + new TextureObjectNVpr(aFormat, aSize, success); + if (!success) { + return nullptr; + } + + if (aData) { + surface->WritePixels(aData, aStride); + } + + return surface.forget(); +} + +TextureObjectNVpr::~TextureObjectNVpr() +{ + gl->MakeCurrent(); + gl->DeleteTexture(mTextureId); +} + +void +TextureObjectNVpr::SetWrapMode(ExtendMode aExtendMode) +{ + switch (aExtendMode) { + default: + MOZ_ASSERT(!"Invalid extend mode"); + case ExtendMode::CLAMP: + SetWrapMode(GL_CLAMP_TO_EDGE); + return; + case ExtendMode::REPEAT: + SetWrapMode(GL_REPEAT); + return; + case ExtendMode::REFLECT: + SetWrapMode(GL_MIRRORED_REPEAT); + return; + } +} + +void +TextureObjectNVpr::SetWrapMode(GLenum aWrapMode) +{ + if (mWrapMode == aWrapMode) { + return; + } + + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + aWrapMode); + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + aWrapMode); + + mWrapMode = aWrapMode; +} + +void +TextureObjectNVpr::SetFilter(Filter aFilter) +{ + if (mFilter != aFilter) { + GLenum minFilter; + GLenum magFilter; + GLint anisotropy; + switch (aFilter) { + default: + MOZ_ASSERT(!"Invalid filter"); + case Filter::GOOD: + minFilter = GL_LINEAR_MIPMAP_LINEAR; + magFilter = GL_LINEAR; + anisotropy = gl->MaxAnisotropy(); + break; + case Filter::LINEAR: + minFilter = GL_LINEAR; + magFilter = GL_LINEAR; + anisotropy = 1; + break; + case Filter::POINT: + minFilter = magFilter = GL_NEAREST; + anisotropy = 1; + break; + } + + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, minFilter); + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, magFilter); + + if (gl->HasExtension(GL::EXT_texture_filter_anisotropic)) { + gl->TextureParameteriEXT(mTextureId, GL_TEXTURE_2D, + GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + } + + mFilter = aFilter; + } + + if (mFilter == Filter::GOOD && !mHasMipmaps) { + gl->GenerateTextureMipmapEXT(mTextureId, GL_TEXTURE_2D); + mHasMipmaps = true; + } +} + +void +TextureObjectNVpr::WritePixels(const GLvoid* aData, GLsizei aStride, + NotifyDataSurface aNotifyDataSurface) +{ + const GLsizei bytesPerRow = mSize.width * mBytesPerPixel; + const GLubyte* pixelData = static_cast(aData); + vector packBuffer; + + gl->MakeCurrent(); + + if (aStride == 0 || aStride == bytesPerRow) { + gl->PixelStorei(GL_PACK_ALIGNMENT, 1); + } else if (aStride == bytesPerRow + 2 - (bytesPerRow % 2)) { + gl->PixelStorei(GL_PACK_ALIGNMENT, 2); + } else if (aStride == bytesPerRow + 4 - (bytesPerRow % 4)) { + gl->PixelStorei(GL_PACK_ALIGNMENT, 4); + } else if (aStride == bytesPerRow + 8 - (bytesPerRow % 8)) { + gl->PixelStorei(GL_PACK_ALIGNMENT, 8); + } else { + packBuffer.resize(mSize.height * bytesPerRow); + for (int i = 0; i < mSize.height; i++) { + memcpy(&packBuffer[i * bytesPerRow], &pixelData[i * aStride], bytesPerRow); + } + pixelData = packBuffer.data(); + gl->PixelStorei(GL_PACK_ALIGNMENT, 1); + } + + gl->TextureSubImage2DEXT(mTextureId, GL_TEXTURE_2D, 0, 0, 0, mSize.width, + mSize.height, mGLFormat, mGLType, pixelData); + + MarkChanged(aNotifyDataSurface); +} + +void +TextureObjectNVpr::ReadPixels(GLvoid* aBuffer) +{ + gl->MakeCurrent(); + gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); + gl->GetTextureImageEXT(mTextureId, GL_TEXTURE_2D, 0, mGLFormat, mGLType, aBuffer); +} + +void +TextureObjectNVpr::MarkChanged(NotifyDataSurface aNotifyDataSurface) +{ + if (aNotifyDataSurface == NOTIFY_DATA_SURFACE && mDataSurface) { + mDataSurface->OnTextureChanged(); + } + + mHasMipmaps = false; +} + +TemporaryRef +TextureObjectNVpr::GetDataSurface() +{ + if (mDataSurface) { + return mDataSurface.get(); + } + + RefPtr dataSurface = new DataSourceSurfaceNVpr(this); + mDataSurface = dataSurface; + + return dataSurface.forget(); +} + +unsigned char* +DataSourceSurfaceNVpr::GetData() +{ + if (mShadowBuffer.empty()) { + mShadowBuffer.resize(mTexture->Size().height * Stride()); + mTexture->ReadPixels(mShadowBuffer.data()); + } + + return mShadowBuffer.data(); +} + +int32_t +DataSourceSurfaceNVpr::Stride() +{ + return mTexture->BytesPerPixel() * mTexture->Size().width; +} + +void +DataSourceSurfaceNVpr::MarkDirty() +{ + if (mShadowBuffer.empty()) { + return; + } + + mTexture->WritePixels(mShadowBuffer.data(), 0, + TextureObjectNVpr::DO_NOT_NOTIFY_DATA_SURFACE); +} + +void +DataSourceSurfaceNVpr::OnTextureChanged() +{ + mShadowBuffer.clear(); +} + +} +} diff --git a/libazure/SourceSurfaceNVpr.h b/libazure/SourceSurfaceNVpr.h new file mode 100644 index 0000000..4c56533 --- /dev/null +++ b/libazure/SourceSurfaceNVpr.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_SOURCESURFACENVPR_H_ +#define MOZILLA_GFX_SOURCESURFACENVPR_H_ + +#include "2D.h" +#include "nvpr/GL.h" +#include +#include +#include + +namespace mozilla { +namespace gfx { + +class DataSourceSurfaceNVpr; + +class TextureObjectNVpr : public RefCounted +{ + friend class DataSourceSurfaceNVpr; + enum NotifyDataSurface { NOTIFY_DATA_SURFACE, DO_NOT_NOTIFY_DATA_SURFACE }; + +public: + static TemporaryRef + Create(DataSourceSurface* aData); + + static TemporaryRef + Create(SurfaceFormat aFormat, const IntSize& aSize, + const GLvoid* aData = nullptr, GLsizei aStride = 0); + + ~TextureObjectNVpr(); + + SurfaceFormat Format() const { return mFormat; } + IntSize Size() const { return mSize; } + GLsizei BytesPerPixel() const { return mBytesPerPixel; } + operator GLuint() const { return mTextureId; } + + void SetWrapMode(ExtendMode aExtendMode); + void SetWrapMode(GLenum aWrapMode); + void SetFilter(Filter aFilter); + + TemporaryRef GetDataSurface(); + + // Use this method when the texture contents are changed without the + // DataSurface (i.e. by using direct OpenGL calls). + void MarkChanged() { MarkChanged(NOTIFY_DATA_SURFACE); } + +private: + TextureObjectNVpr(SurfaceFormat aFormat, const IntSize& aSize, + bool& aSuccess); + + void WritePixels(const GLvoid* aData, GLsizei aStride, + NotifyDataSurface aNotifyDataSurface = NOTIFY_DATA_SURFACE); + void ReadPixels(GLvoid* aBuffer); + + void MarkChanged(NotifyDataSurface aNotifyDataSurface); + + const SurfaceFormat mFormat; + const IntSize mSize; + GLenum mGLFormat; + GLenum mGLType; + GLsizei mBytesPerPixel; + GLuint mTextureId; + GLenum mWrapMode; + Filter mFilter; + bool mHasMipmaps; + WeakPtr mDataSurface; +}; + +class SourceSurfaceNVpr : public SourceSurface { +public: + SourceSurfaceNVpr(TemporaryRef aTexture) + : mTexture(aTexture) + {} + + TextureObjectNVpr* Texture() const { return mTexture; } + operator GLuint() const { return *mTexture; } + + void SetWrapMode(ExtendMode aExtendMode) { mTexture->SetWrapMode(aExtendMode); } + void SetWrapMode(GLenum aWrapMode) { mTexture->SetWrapMode(aWrapMode); } + void SetFilter(Filter aFilter) { mTexture->SetFilter(aFilter); } + + virtual SurfaceType GetType() const { return SurfaceType::NVPR_TEXTURE; } + virtual SurfaceFormat GetFormat() const { return mTexture->Format(); } + virtual IntSize GetSize() const { return mTexture->Size(); } + + void MarkChanged() { mTexture->MarkChanged(); } + + virtual TemporaryRef GetDataSurface() { + return mTexture->GetDataSurface(); + } + +private: + RefPtr mTexture; +}; + +class DataSourceSurfaceNVpr + : public DataSourceSurface + , public SupportsWeakPtr +{ +public: + DataSourceSurfaceNVpr(TemporaryRef aTexture) + : mTexture(aTexture) + {} + + virtual IntSize GetSize() const { return mTexture->Size(); } + virtual SurfaceFormat GetFormat() const { return mTexture->Format(); } + + virtual unsigned char* GetData(); + virtual int32_t Stride(); + + virtual void MarkDirty(); + + void OnTextureChanged(); + +private: + RefPtr mTexture; + std::vector mShadowBuffer; +}; + +} +} + +#endif /* MOZILLA_GFX_SOURCESURFACENVPR_H_ */ diff --git a/libazure/SourceSurfaceRawData.cpp b/libazure/SourceSurfaceRawData.cpp new file mode 100644 index 0000000..97b19d3 --- /dev/null +++ b/libazure/SourceSurfaceRawData.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SourceSurfaceRawData.h" + +#include "DataSurfaceHelpers.h" +#include "Logging.h" +#include "mozilla/Types.h" // for decltype +#include + +namespace mozilla { +namespace gfx { + +bool +SourceSurfaceRawData::InitWrappingData(uint8_t *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat, + bool aOwnData) +{ + mRawData = aData; + mSize = aSize; + mStride = aStride; + mFormat = aFormat; + mOwnData = aOwnData; + + return true; +} + +void +SourceSurfaceRawData::GuaranteePersistance() +{ + if (mOwnData) { + return; + } + + uint8_t* oldData = mRawData; + mRawData = new uint8_t[mStride * mSize.height]; + + memcpy(mRawData, oldData, mStride * mSize.height); + mOwnData = true; +} + +bool +SourceSurfaceAlignedRawData::Init(const IntSize &aSize, + SurfaceFormat aFormat, + bool aZero) +{ + mFormat = aFormat; + mStride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat)); + + size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height); + if (bufLen > 0) { + static_assert(sizeof(decltype(mArray[0])) == 1, + "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen"); + mArray.Realloc(/* actually an object count */ bufLen, aZero); + mSize = aSize; + } else { + mArray.Dealloc(); + mSize.SizeTo(0, 0); + } + + return mArray != nullptr; +} + +bool +SourceSurfaceAlignedRawData::InitWithStride(const IntSize &aSize, + SurfaceFormat aFormat, + int32_t aStride, + bool aZero) +{ + mFormat = aFormat; + mStride = aStride; + + size_t bufLen = BufferSizeFromStrideAndHeight(mStride, aSize.height); + if (bufLen > 0) { + static_assert(sizeof(decltype(mArray[0])) == 1, + "mArray.Realloc() takes an object count, so its objects must be 1-byte sized if we use bufLen"); + mArray.Realloc(/* actually an object count */ bufLen, aZero); + mSize = aSize; + } else { + mArray.Dealloc(); + mSize.SizeTo(0, 0); + } + + return mArray != nullptr; +} + +} +} diff --git a/libazure/src/gfx/2d/SourceSurfaceRawData.h b/libazure/SourceSurfaceRawData.h similarity index 53% rename from libazure/src/gfx/2d/SourceSurfaceRawData.h rename to libazure/SourceSurfaceRawData.h index 4b7a33f..13a84e5 100644 --- a/libazure/src/gfx/2d/SourceSurfaceRawData.h +++ b/libazure/SourceSurfaceRawData.h @@ -7,6 +7,7 @@ #define MOZILLA_GFX_SOURCESURFACERAWDATA_H_ #include "2D.h" +#include "Tools.h" namespace mozilla { namespace gfx { @@ -14,13 +15,14 @@ namespace gfx { class SourceSurfaceRawData : public DataSourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData) SourceSurfaceRawData() {} ~SourceSurfaceRawData() { if(mOwnData) delete [] mRawData; } virtual uint8_t *GetData() { return mRawData; } virtual int32_t Stride() { return mStride; } - virtual SurfaceType GetType() const { return SURFACE_DATA; } + virtual SurfaceType GetType() const { return SurfaceType::DATA; } virtual IntSize GetSize() const { return mSize; } virtual SurfaceFormat GetFormat() const { return mFormat; } @@ -30,6 +32,8 @@ class SourceSurfaceRawData : public DataSourceSurface SurfaceFormat aFormat, bool aOwnData); + virtual void GuaranteePersistance(); + private: uint8_t *mRawData; int32_t mStride; @@ -38,6 +42,34 @@ class SourceSurfaceRawData : public DataSourceSurface bool mOwnData; }; +class SourceSurfaceAlignedRawData : public DataSourceSurface +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData) + SourceSurfaceAlignedRawData() {} + + virtual uint8_t *GetData() { return mArray; } + virtual int32_t Stride() { return mStride; } + + virtual SurfaceType GetType() const { return SurfaceType::DATA; } + virtual IntSize GetSize() const { return mSize; } + virtual SurfaceFormat GetFormat() const { return mFormat; } + + bool Init(const IntSize &aSize, + SurfaceFormat aFormat, + bool aZero); + bool InitWithStride(const IntSize &aSize, + SurfaceFormat aFormat, + int32_t aStride, + bool aZero); + +private: + AlignedArray mArray; + int32_t mStride; + SurfaceFormat mFormat; + IntSize mSize; +}; + } } diff --git a/libazure/src/gfx/2d/SourceSurfaceSkia.cpp b/libazure/SourceSurfaceSkia.cpp similarity index 56% rename from libazure/src/gfx/2d/SourceSurfaceSkia.cpp rename to libazure/SourceSurfaceSkia.cpp index 044ed38..45f752c 100644 --- a/libazure/src/gfx/2d/SourceSurfaceSkia.cpp +++ b/libazure/SourceSurfaceSkia.cpp @@ -6,22 +6,27 @@ #include "Logging.h" #include "SourceSurfaceSkia.h" -#include "SkBitmap.h" -#include "SkDevice.h" +#include "core/SkBitmap.h" +#include "core/SkDevice.h" #include "HelpersSkia.h" #include "DrawTargetSkia.h" +#include "DataSurfaceHelpers.h" namespace mozilla { namespace gfx { SourceSurfaceSkia::SourceSurfaceSkia() - : mDrawTarget(nullptr) + : mDrawTarget(nullptr), mLocked(false) { } SourceSurfaceSkia::~SourceSurfaceSkia() { - MarkIndependent(); + MaybeUnlock(); + if (mDrawTarget) { + mDrawTarget->SnapshotDestroyed(); + mDrawTarget = nullptr; + } } IntSize @@ -36,6 +41,23 @@ SourceSurfaceSkia::GetFormat() const return mFormat; } +bool +SourceSurfaceSkia::InitFromCanvas(SkCanvas* aCanvas, + SurfaceFormat aFormat, + DrawTargetSkia* aOwner) +{ + SkISize size = aCanvas->getDeviceSize(); + + mBitmap = (SkBitmap)aCanvas->getDevice()->accessBitmap(false); + mFormat = aFormat; + + mSize = IntSize(size.fWidth, size.fHeight); + mStride = mBitmap.rowBytes(); + mDrawTarget = aOwner; + + return true; +} + bool SourceSurfaceSkia::InitFromData(unsigned char* aData, const IntSize &aSize, @@ -43,81 +65,61 @@ SourceSurfaceSkia::InitFromData(unsigned char* aData, SurfaceFormat aFormat) { SkBitmap temp; - temp.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride); + SkAlphaType alphaType = (aFormat == SurfaceFormat::B8G8R8X8) ? + kOpaque_SkAlphaType : kPremul_SkAlphaType; + + SkImageInfo info = SkImageInfo::Make(aSize.width, + aSize.height, + GfxFormatToSkiaColorType(aFormat), + alphaType); + temp.setInfo(info, aStride); temp.setPixels(aData); - if (!temp.copyTo(&mBitmap, GfxFormatToSkiaConfig(aFormat))) { + if (!temp.copyTo(&mBitmap, GfxFormatToSkiaColorType(aFormat))) { return false; } - if (aFormat == FORMAT_B8G8R8X8) { - mBitmap.lockPixels(); - // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX - ConvertBGRXToBGRA(reinterpret_cast(mBitmap.getPixels()), aSize, aStride); - mBitmap.unlockPixels(); - mBitmap.notifyPixelsChanged(); - mBitmap.setIsOpaque(true); + if (aFormat == SurfaceFormat::B8G8R8X8) { + mBitmap.setAlphaType(kIgnore_SkAlphaType); } mSize = aSize; mFormat = aFormat; - mStride = aStride; + mStride = mBitmap.rowBytes(); return true; } -bool -SourceSurfaceSkia::InitWithBitmap(const SkBitmap& aBitmap, - SurfaceFormat aFormat, - DrawTargetSkia* aOwner) -{ - mFormat = aFormat; - mSize = IntSize(aBitmap.width(), aBitmap.height()); - - if (aOwner) { - mBitmap = aBitmap; - mStride = aBitmap.rowBytes(); - mDrawTarget = aOwner; - return true; - } else if (aBitmap.copyTo(&mBitmap, aBitmap.getConfig())) { - mStride = mBitmap.rowBytes(); - return true; - } - return false; -} - unsigned char* SourceSurfaceSkia::GetData() { - mBitmap.lockPixels(); + if (!mLocked) { + mBitmap.lockPixels(); + mLocked = true; + } + unsigned char *pixels = (unsigned char *)mBitmap.getPixels(); - mBitmap.unlockPixels(); return pixels; - } void SourceSurfaceSkia::DrawTargetWillChange() { if (mDrawTarget) { + MaybeUnlock(); + mDrawTarget = nullptr; SkBitmap temp = mBitmap; mBitmap.reset(); - temp.copyTo(&mBitmap, temp.getConfig()); + temp.copyTo(&mBitmap, temp.colorType()); } } void -SourceSurfaceSkia::DrawTargetDestroyed() +SourceSurfaceSkia::MaybeUnlock() { - mDrawTarget = nullptr; -} - -void -SourceSurfaceSkia::MarkIndependent() -{ - if (mDrawTarget) { - mDrawTarget->RemoveSnapshot(this); - mDrawTarget = nullptr; + if (mLocked) { + mBitmap.unlockPixels(); + mLocked = false; } } diff --git a/libazure/src/gfx/2d/SourceSurfaceSkia.h b/libazure/SourceSurfaceSkia.h similarity index 75% rename from libazure/src/gfx/2d/SourceSurfaceSkia.h rename to libazure/SourceSurfaceSkia.h index a1d2cc9..0db22f3 100644 --- a/libazure/src/gfx/2d/SourceSurfaceSkia.h +++ b/libazure/SourceSurfaceSkia.h @@ -8,8 +8,8 @@ #include "2D.h" #include -#include "SkCanvas.h" -#include "SkBitmap.h" +#include "core/SkCanvas.h" +#include "core/SkBitmap.h" namespace mozilla { namespace gfx { @@ -19,10 +19,11 @@ class DrawTargetSkia; class SourceSurfaceSkia : public DataSourceSurface { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceSkia) SourceSurfaceSkia(); ~SourceSurfaceSkia(); - virtual SurfaceType GetType() const { return SURFACE_SKIA; } + virtual SurfaceType GetType() const { return SurfaceType::SKIA; } virtual IntSize GetSize() const; virtual SurfaceFormat GetFormat() const; @@ -33,15 +34,10 @@ class SourceSurfaceSkia : public DataSourceSurface int32_t aStride, SurfaceFormat aFormat); - /** - * If aOwner is nullptr, we make a copy of the pixel data in the bitmap, - * otherwise we just reference this data until DrawTargetWillChange is called. - */ - bool InitWithBitmap(const SkBitmap& aBitmap, + bool InitFromCanvas(SkCanvas* aCanvas, SurfaceFormat aFormat, DrawTargetSkia* aOwner); - virtual unsigned char *GetData(); virtual int32_t Stride() { return mStride; } @@ -50,14 +46,14 @@ class SourceSurfaceSkia : public DataSourceSurface friend class DrawTargetSkia; void DrawTargetWillChange(); - void DrawTargetDestroyed(); - void MarkIndependent(); + void MaybeUnlock(); SkBitmap mBitmap; SurfaceFormat mFormat; IntSize mSize; int32_t mStride; - DrawTargetSkia* mDrawTarget; + RefPtr mDrawTarget; + bool mLocked; }; } diff --git a/libazure/StackArray.h b/libazure/StackArray.h new file mode 100644 index 0000000..e3c2684 --- /dev/null +++ b/libazure/StackArray.h @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A handy class that will allocate data for size*T objects on the stack and + * otherwise allocate them on the heap. It is similar in purpose to nsAutoTArray */ + +template +class StackArray +{ +public: + StackArray(size_t count) { + if (count > size) { + mData = new T[count]; + } else { + mData = mStackData; + } + } + ~StackArray() { + if (mData != mStackData) { + delete[] mData; + } + } + T& operator[](size_t n) { return mData[n]; } + const T& operator[](size_t n) const { return mData[n]; } + T* data() { return mData; }; +private: + T mStackData[size]; + T* mData; +}; diff --git a/libazure/Tools.h b/libazure/Tools.h new file mode 100644 index 0000000..2df3f31 --- /dev/null +++ b/libazure/Tools.h @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_TOOLS_H_ +#define MOZILLA_GFX_TOOLS_H_ + +#include "mozilla/CheckedInt.h" +#include "mozilla/TypeTraits.h" +#include "Types.h" +#include "Point.h" +#include +#if defined(_MSC_VER) && (_MSC_VER < 1600) +#define hypotf _hypotf +#endif + +namespace mozilla { +namespace gfx { + +static inline bool +IsOperatorBoundByMask(CompositionOp aOp) { + switch (aOp) { + case CompositionOp::OP_IN: + case CompositionOp::OP_OUT: + case CompositionOp::OP_DEST_IN: + case CompositionOp::OP_DEST_ATOP: + case CompositionOp::OP_SOURCE: + return false; + default: + return true; + } +} + +template +struct ClassStorage +{ + char bytes[sizeof(T)]; + + const T *addr() const { return (const T *)bytes; } + T *addr() { return (T *)(void *)bytes; } +}; + +static inline bool +FuzzyEqual(Float aA, Float aB, Float aErr) +{ + if ((aA + aErr >= aB) && (aA - aErr <= aB)) { + return true; + } + return false; +} + +static inline void +NudgeToInteger(float *aVal) +{ + float r = floorf(*aVal + 0.5f); + // The error threshold should be proportional to the rounded value. This + // bounds the relative error introduced by the nudge operation. However, + // when the rounded value is 0, the error threshold can't be proportional + // to the rounded value (we'd never round), so we just choose the same + // threshold as for a rounded value of 1. + if (FuzzyEqual(r, *aVal, r == 0.0f ? 1e-6f : fabs(r*1e-6f))) { + *aVal = r; + } +} + +static inline void +NudgeToInteger(float *aVal, float aErr) +{ + float r = floorf(*aVal + 0.5f); + if (FuzzyEqual(r, *aVal, aErr)) { + *aVal = r; + } +} + +static inline Float +Distance(Point aA, Point aB) +{ + return hypotf(aB.x - aA.x, aB.y - aA.y); +} + +static inline int +BytesPerPixel(SurfaceFormat aFormat) +{ + switch (aFormat) { + case SurfaceFormat::A8: + return 1; + case SurfaceFormat::R5G6B5: + return 2; + default: + return 4; + } +} + +template +struct AlignedArray +{ + typedef T value_type; + + AlignedArray() + : mPtr(nullptr) + , mStorage(nullptr) + { + } + + explicit MOZ_ALWAYS_INLINE AlignedArray(size_t aCount, bool aZero = false) + : mStorage(nullptr) + , mCount(0) + { + Realloc(aCount, aZero); + } + + MOZ_ALWAYS_INLINE ~AlignedArray() + { + Dealloc(); + } + + void Dealloc() + { + // If we fail this assert we'll need to uncomment the loop below to make + // sure dtors are properly invoked. If we do that, we should check that the + // comment about compiler dead code elimination is in fact true for all the + // compilers that we care about. + static_assert(mozilla::IsPod::value, + "Destructors must be invoked for this type"); +#if 0 + for (size_t i = 0; i < mCount; ++i) { + // Since we used the placement |operator new| function to construct the + // elements of this array we need to invoke their destructors manually. + // For types where the destructor does nothing the compiler's dead code + // elimination step should optimize this loop away. + mPtr[i].~T(); + } +#endif + + delete [] mStorage; + mStorage = nullptr; + mPtr = nullptr; + } + + MOZ_ALWAYS_INLINE void Realloc(size_t aCount, bool aZero = false) + { + delete [] mStorage; + CheckedInt32 storageByteCount = + CheckedInt32(sizeof(T)) * aCount + (alignment - 1); + if (!storageByteCount.isValid()) { + mStorage = nullptr; + mPtr = nullptr; + mCount = 0; + return; + } + // We don't create an array of T here, since we don't want ctors to be + // invoked at the wrong places if we realign below. + if (aZero) { + mStorage = static_cast(calloc(1, storageByteCount.value())); + } else { + mStorage = new (std::nothrow) uint8_t[storageByteCount.value()]; + } + if (!mStorage) { + mStorage = nullptr; + mPtr = nullptr; + mCount = 0; + return; + } + if (uintptr_t(mStorage) % alignment) { + // Our storage does not start at a -byte boundary. Make sure mPtr does! + mPtr = (T*)(uintptr_t(mStorage) + alignment - (uintptr_t(mStorage) % alignment)); + } else { + mPtr = (T*)(mStorage); + } + // Now that mPtr is pointing to the aligned position we can use placement + // |operator new| to invoke any ctors at the correct positions. For types + // that have a no-op default constructor the compiler's dead code + // elimination step should optimize this away. + mPtr = new (mPtr) T[aCount]; + mCount = aCount; + } + + MOZ_ALWAYS_INLINE operator T*() + { + return mPtr; + } + + T *mPtr; + +private: + uint8_t *mStorage; + size_t mCount; +}; + +/** + * Returns aStride increased, if necessary, so that it divides exactly into + * |alignment|. + * + * Note that currently |alignment| must be a power-of-2. If for some reason we + * want to support NPOT alignment we can revert back to this functions old + * implementation. + */ +template +int32_t GetAlignedStride(int32_t aStride) +{ + static_assert(alignment > 0 && (alignment & (alignment-1)) == 0, + "This implementation currently require power-of-two alignment"); + const int32_t mask = alignment - 1; + return (aStride + mask) & ~mask; +} + +} +} + +#endif /* MOZILLA_GFX_TOOLS_H_ */ diff --git a/libazure/Types.h b/libazure/Types.h new file mode 100644 index 0000000..bc86a09 --- /dev/null +++ b/libazure/Types.h @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_TYPES_H_ +#define MOZILLA_GFX_TYPES_H_ + +#include "mozilla/NullPtr.h" +#include "mozilla/TypedEnum.h" + +#include + +// Required so that INT32_MAX can be defined on certain gcc versions +#define __STDC_LIMIT_MACROS +#include + +namespace mozilla { +namespace gfx { + +typedef float Float; + +MOZ_BEGIN_ENUM_CLASS(SurfaceType, int8_t) + DATA, /* Data surface - bitmap in memory */ + D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */ + D2D1_DRAWTARGET, /* Surface made from a D2D draw target */ + CAIRO, /* Surface wrapping a cairo surface */ + CAIRO_IMAGE, /* Data surface wrapping a cairo image surface */ + COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */ + COREGRAPHICS_CGCONTEXT, /* Surface wrapping a CG context */ + SKIA, /* Surface wrapping a Skia bitmap */ + DUAL_DT, /* Snapshot of a dual drawtarget */ + D2D1_1_IMAGE, /* A D2D 1.1 ID2D1Image SourceSurface */ + RECORDING, /* Surface used for recording */ + NVPR_TEXTURE, /* Surface wrapping an OpenGL texture, used by NV_path_rendering */ + TILED /* Surface from a tiled DrawTarget */ +MOZ_END_ENUM_CLASS(SurfaceType) + +MOZ_BEGIN_ENUM_CLASS(SurfaceFormat, int8_t) + B8G8R8A8, + B8G8R8X8, + R8G8B8A8, + R8G8B8X8, + R5G6B5, + A8, + YUV, + UNKNOWN +MOZ_END_ENUM_CLASS(SurfaceFormat) + +MOZ_BEGIN_ENUM_CLASS(FilterType, int8_t) + BLEND = 0, + TRANSFORM, + MORPHOLOGY, + COLOR_MATRIX, + FLOOD, + TILE, + TABLE_TRANSFER, + DISCRETE_TRANSFER, + LINEAR_TRANSFER, + GAMMA_TRANSFER, + CONVOLVE_MATRIX, + DISPLACEMENT_MAP, + TURBULENCE, + ARITHMETIC_COMBINE, + COMPOSITE, + DIRECTIONAL_BLUR, + GAUSSIAN_BLUR, + POINT_DIFFUSE, + POINT_SPECULAR, + SPOT_DIFFUSE, + SPOT_SPECULAR, + DISTANT_DIFFUSE, + DISTANT_SPECULAR, + CROP, + PREMULTIPLY, + UNPREMULTIPLY +MOZ_END_ENUM_CLASS(FilterType) + +MOZ_BEGIN_ENUM_CLASS(DrawTargetType, int8_t) + SOFTWARE_RASTER = 0, + HARDWARE_RASTER, + VECTOR +MOZ_END_ENUM_CLASS(DrawTargetType) + +MOZ_BEGIN_ENUM_CLASS(BackendType, int8_t) + NONE = 0, + DIRECT2D, + COREGRAPHICS, + COREGRAPHICS_ACCELERATED, + CAIRO, + SKIA, + RECORDING, + DIRECT2D1_1, + NVPR +MOZ_END_ENUM_CLASS(BackendType) + +MOZ_BEGIN_ENUM_CLASS(FontType, int8_t) + DWRITE, + GDI, + MAC, + SKIA, + CAIRO, + COREGRAPHICS, + NVPR +MOZ_END_ENUM_CLASS(FontType) + +MOZ_BEGIN_ENUM_CLASS(NativeSurfaceType, int8_t) + D3D10_TEXTURE, + CAIRO_SURFACE, + CAIRO_CONTEXT, + CGCONTEXT, + CGCONTEXT_ACCELERATED, + OPENGL_TEXTURE +MOZ_END_ENUM_CLASS(NativeSurfaceType) + +MOZ_BEGIN_ENUM_CLASS(NativeFontType, int8_t) + DWRITE_FONT_FACE, + GDI_FONT_FACE, + MAC_FONT_FACE, + SKIA_FONT_FACE, + CAIRO_FONT_FACE, + NVPR_FONT_FACE +MOZ_END_ENUM_CLASS(NativeFontType) + +MOZ_BEGIN_ENUM_CLASS(FontStyle, int8_t) + NORMAL, + ITALIC, + BOLD, + BOLD_ITALIC +MOZ_END_ENUM_CLASS(FontStyle) + +MOZ_BEGIN_ENUM_CLASS(FontHinting, int8_t) + NONE, + LIGHT, + NORMAL, + FULL +MOZ_END_ENUM_CLASS(FontHinting) + +MOZ_BEGIN_ENUM_CLASS(CompositionOp, int8_t) + OP_OVER, + OP_ADD, + OP_ATOP, + OP_OUT, + OP_IN, + OP_SOURCE, + OP_DEST_IN, + OP_DEST_OUT, + OP_DEST_OVER, + OP_DEST_ATOP, + OP_XOR, + OP_MULTIPLY, + OP_SCREEN, + OP_OVERLAY, + OP_DARKEN, + OP_LIGHTEN, + OP_COLOR_DODGE, + OP_COLOR_BURN, + OP_HARD_LIGHT, + OP_SOFT_LIGHT, + OP_DIFFERENCE, + OP_EXCLUSION, + OP_HUE, + OP_SATURATION, + OP_COLOR, + OP_LUMINOSITY, + OP_COUNT +MOZ_END_ENUM_CLASS(CompositionOp) + +MOZ_BEGIN_ENUM_CLASS(ExtendMode, int8_t) + CLAMP, + REPEAT, + REFLECT +MOZ_END_ENUM_CLASS(ExtendMode) + +MOZ_BEGIN_ENUM_CLASS(FillRule, int8_t) + FILL_WINDING, + FILL_EVEN_ODD +MOZ_END_ENUM_CLASS(FillRule) + +MOZ_BEGIN_ENUM_CLASS(AntialiasMode, int8_t) + NONE, + GRAY, + SUBPIXEL, + DEFAULT +MOZ_END_ENUM_CLASS(AntialiasMode) + +MOZ_BEGIN_ENUM_CLASS(Filter, int8_t) + GOOD, + LINEAR, + POINT +MOZ_END_ENUM_CLASS(Filter) + +MOZ_BEGIN_ENUM_CLASS(PatternType, int8_t) + COLOR, + SURFACE, + LINEAR_GRADIENT, + RADIAL_GRADIENT +MOZ_END_ENUM_CLASS(PatternType) + +MOZ_BEGIN_ENUM_CLASS(JoinStyle, int8_t) + BEVEL, + ROUND, + MITER, + MITER_OR_BEVEL +MOZ_END_ENUM_CLASS(JoinStyle) + +MOZ_BEGIN_ENUM_CLASS(CapStyle, int8_t) + BUTT, + ROUND, + SQUARE +MOZ_END_ENUM_CLASS(CapStyle) + +MOZ_BEGIN_ENUM_CLASS(SamplingBounds, int8_t) + UNBOUNDED, + BOUNDED +MOZ_END_ENUM_CLASS(SamplingBounds) + +/* Color is stored in non-premultiplied form */ +struct Color +{ +public: + Color() + : r(0.0f), g(0.0f), b(0.0f), a(0.0f) + {} + Color(Float aR, Float aG, Float aB, Float aA) + : r(aR), g(aG), b(aB), a(aA) + {} + Color(Float aR, Float aG, Float aB) + : r(aR), g(aG), b(aB), a(1.0f) + {} + + static Color FromABGR(uint32_t aColor) + { + Color newColor(((aColor >> 0) & 0xff) * (1.0f / 255.0f), + ((aColor >> 8) & 0xff) * (1.0f / 255.0f), + ((aColor >> 16) & 0xff) * (1.0f / 255.0f), + ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); + + return newColor; + } + + uint32_t ToABGR() const + { + return uint32_t(r * 255.0f) | uint32_t(g * 255.0f) << 8 | + uint32_t(b * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; + } + + Float r, g, b, a; +}; + +struct GradientStop +{ + bool operator<(const GradientStop& aOther) const { + return offset < aOther.offset; + } + + Float offset; + Color color; +}; + +} +} + +#if defined(XP_WIN) && defined(MOZ_GFX) +#ifdef GFX2D_INTERNAL +#define GFX2D_API __declspec(dllexport) +#else +#define GFX2D_API __declspec(dllimport) +#endif +#else +#define GFX2D_API +#endif + +namespace mozilla { +// Side constants for use in various places. +enum Side { eSideTop, eSideRight, eSideBottom, eSideLeft }; + +enum SideBits { + eSideBitsNone = 0, + eSideBitsTop = 1 << eSideTop, + eSideBitsRight = 1 << eSideRight, + eSideBitsBottom = 1 << eSideBottom, + eSideBitsLeft = 1 << eSideLeft, + eSideBitsTopBottom = eSideBitsTop | eSideBitsBottom, + eSideBitsLeftRight = eSideBitsLeft | eSideBitsRight, + eSideBitsAll = eSideBitsTopBottom | eSideBitsLeftRight +}; +} // namespace mozilla + +#define NS_SIDE_TOP mozilla::eSideTop +#define NS_SIDE_RIGHT mozilla::eSideRight +#define NS_SIDE_BOTTOM mozilla::eSideBottom +#define NS_SIDE_LEFT mozilla::eSideLeft + +#endif /* MOZILLA_GFX_TYPES_H_ */ diff --git a/libazure/include/mozilla/gfx/UserData.h b/libazure/UserData.h similarity index 100% rename from libazure/include/mozilla/gfx/UserData.h rename to libazure/UserData.h diff --git a/libazure/config/autoconf.mk b/libazure/config/autoconf.mk deleted file mode 100644 index e69de29..0000000 diff --git a/libazure/config/rules.mk b/libazure/config/rules.mk deleted file mode 100644 index e69de29..0000000 diff --git a/libazure/convolver.cpp b/libazure/convolver.cpp new file mode 100644 index 0000000..0e9adbd --- /dev/null +++ b/libazure/convolver.cpp @@ -0,0 +1,492 @@ +// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google, Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +#include "2D.h" +#include "convolver.h" + +#include + +#include "SkTypes.h" + + +#if defined(USE_SSE2) +#include "convolverSSE2.h" +#endif + +using mozilla::gfx::Factory; + +#if defined(SK_CPU_LENDIAN) +#define R_OFFSET_IDX 0 +#define G_OFFSET_IDX 1 +#define B_OFFSET_IDX 2 +#define A_OFFSET_IDX 3 +#else +#define R_OFFSET_IDX 3 +#define G_OFFSET_IDX 2 +#define B_OFFSET_IDX 1 +#define A_OFFSET_IDX 0 +#endif + +namespace skia { + +namespace { + +// Converts the argument to an 8-bit unsigned value by clamping to the range +// 0-255. +inline unsigned char ClampTo8(int a) { + if (static_cast(a) < 256) + return a; // Avoid the extra check in the common case. + if (a < 0) + return 0; + return 255; +} + +// Stores a list of rows in a circular buffer. The usage is you write into it +// by calling AdvanceRow. It will keep track of which row in the buffer it +// should use next, and the total number of rows added. +class CircularRowBuffer { + public: + // The number of pixels in each row is given in |source_row_pixel_width|. + // The maximum number of rows needed in the buffer is |max_y_filter_size| + // (we only need to store enough rows for the biggest filter). + // + // We use the |first_input_row| to compute the coordinates of all of the + // following rows returned by Advance(). + CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size, + int first_input_row) + : row_byte_width_(dest_row_pixel_width * 4), + num_rows_(max_y_filter_size), + next_row_(0), + next_row_coordinate_(first_input_row) { + buffer_.resize(row_byte_width_ * max_y_filter_size); + row_addresses_.resize(num_rows_); + } + + // Moves to the next row in the buffer, returning a pointer to the beginning + // of it. + unsigned char* AdvanceRow() { + unsigned char* row = &buffer_[next_row_ * row_byte_width_]; + next_row_coordinate_++; + + // Set the pointer to the next row to use, wrapping around if necessary. + next_row_++; + if (next_row_ == num_rows_) + next_row_ = 0; + return row; + } + + // Returns a pointer to an "unrolled" array of rows. These rows will start + // at the y coordinate placed into |*first_row_index| and will continue in + // order for the maximum number of rows in this circular buffer. + // + // The |first_row_index_| may be negative. This means the circular buffer + // starts before the top of the image (it hasn't been filled yet). + unsigned char* const* GetRowAddresses(int* first_row_index) { + // Example for a 4-element circular buffer holding coords 6-9. + // Row 0 Coord 8 + // Row 1 Coord 9 + // Row 2 Coord 6 <- next_row_ = 2, next_row_coordinate_ = 10. + // Row 3 Coord 7 + // + // The "next" row is also the first (lowest) coordinate. This computation + // may yield a negative value, but that's OK, the math will work out + // since the user of this buffer will compute the offset relative + // to the first_row_index and the negative rows will never be used. + *first_row_index = next_row_coordinate_ - num_rows_; + + int cur_row = next_row_; + for (int i = 0; i < num_rows_; i++) { + row_addresses_[i] = &buffer_[cur_row * row_byte_width_]; + + // Advance to the next row, wrapping if necessary. + cur_row++; + if (cur_row == num_rows_) + cur_row = 0; + } + return &row_addresses_[0]; + } + + private: + // The buffer storing the rows. They are packed, each one row_byte_width_. + std::vector buffer_; + + // Number of bytes per row in the |buffer_|. + int row_byte_width_; + + // The number of rows available in the buffer. + int num_rows_; + + // The next row index we should write into. This wraps around as the + // circular buffer is used. + int next_row_; + + // The y coordinate of the |next_row_|. This is incremented each time a + // new row is appended and does not wrap. + int next_row_coordinate_; + + // Buffer used by GetRowAddresses(). + std::vector row_addresses_; +}; + +// Convolves horizontally along a single row. The row data is given in +// |src_data| and continues for the [begin, end) of the filter. +template +// This function is miscompiled with gcc 4.5 with pgo. See bug 827946. +#if defined(__GNUC__) && defined(MOZ_GCC_VERSION_AT_LEAST) +#if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) && !MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) +__attribute__((optimize("-O1"))) +#endif +#endif +void ConvolveHorizontally(const unsigned char* src_data, + int begin, int end, + const ConvolutionFilter1D& filter, + unsigned char* out_row) { + // Loop over each pixel on this row in the output image. + for (int out_x = begin; out_x < end; out_x++) { + // Get the filter that determines the current output pixel. + int filter_offset, filter_length; + const ConvolutionFilter1D::Fixed* filter_values = + filter.FilterForValue(out_x, &filter_offset, &filter_length); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filter_length| pixels (4 bytes each) after this. + const unsigned char* row_to_filter = &src_data[filter_offset * 4]; + + // Apply the filter to the row to get the destination pixel in |accum|. + int accum[4] = {0}; + for (int filter_x = 0; filter_x < filter_length; filter_x++) { + ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_x]; + accum[0] += cur_filter * row_to_filter[filter_x * 4 + R_OFFSET_IDX]; + accum[1] += cur_filter * row_to_filter[filter_x * 4 + G_OFFSET_IDX]; + accum[2] += cur_filter * row_to_filter[filter_x * 4 + B_OFFSET_IDX]; + if (has_alpha) + accum[3] += cur_filter * row_to_filter[filter_x * 4 + A_OFFSET_IDX]; + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of fractional part. + accum[0] >>= ConvolutionFilter1D::kShiftBits; + accum[1] >>= ConvolutionFilter1D::kShiftBits; + accum[2] >>= ConvolutionFilter1D::kShiftBits; + if (has_alpha) + accum[3] >>= ConvolutionFilter1D::kShiftBits; + + // Store the new pixel. + out_row[out_x * 4 + R_OFFSET_IDX] = ClampTo8(accum[0]); + out_row[out_x * 4 + G_OFFSET_IDX] = ClampTo8(accum[1]); + out_row[out_x * 4 + B_OFFSET_IDX] = ClampTo8(accum[2]); + if (has_alpha) + out_row[out_x * 4 + A_OFFSET_IDX] = ClampTo8(accum[3]); + } +} + +// Does vertical convolution to produce one output row. The filter values and +// length are given in the first two parameters. These are applied to each +// of the rows pointed to in the |source_data_rows| array, with each row +// being |end - begin| wide. +// +// The output must have room for |(end - begin) * 4| bytes. +template +void ConvolveVertically(const ConvolutionFilter1D::Fixed* filter_values, + int filter_length, + unsigned char* const* source_data_rows, + int begin, int end, unsigned char* out_row) { + // We go through each column in the output and do a vertical convolution, + // generating one output pixel each time. + for (int out_x = begin; out_x < end; out_x++) { + // Compute the number of bytes over in each row that the current column + // we're convolving starts at. The pixel will cover the next 4 bytes. + int byte_offset = out_x * 4; + + // Apply the filter to one column of pixels. + int accum[4] = {0}; + for (int filter_y = 0; filter_y < filter_length; filter_y++) { + ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_y]; + accum[0] += cur_filter + * source_data_rows[filter_y][byte_offset + R_OFFSET_IDX]; + accum[1] += cur_filter + * source_data_rows[filter_y][byte_offset + G_OFFSET_IDX]; + accum[2] += cur_filter + * source_data_rows[filter_y][byte_offset + B_OFFSET_IDX]; + if (has_alpha) + accum[3] += cur_filter + * source_data_rows[filter_y][byte_offset + A_OFFSET_IDX]; + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of precision. + accum[0] >>= ConvolutionFilter1D::kShiftBits; + accum[1] >>= ConvolutionFilter1D::kShiftBits; + accum[2] >>= ConvolutionFilter1D::kShiftBits; + if (has_alpha) + accum[3] >>= ConvolutionFilter1D::kShiftBits; + + // Store the new pixel. + out_row[byte_offset + R_OFFSET_IDX] = ClampTo8(accum[0]); + out_row[byte_offset + G_OFFSET_IDX] = ClampTo8(accum[1]); + out_row[byte_offset + B_OFFSET_IDX] = ClampTo8(accum[2]); + if (has_alpha) { + unsigned char alpha = ClampTo8(accum[3]); + + // Make sure the alpha channel doesn't come out smaller than any of the + // color channels. We use premultipled alpha channels, so this should + // never happen, but rounding errors will cause this from time to time. + // These "impossible" colors will cause overflows (and hence random pixel + // values) when the resulting bitmap is drawn to the screen. + // + // We only need to do this when generating the final output row (here). + int max_color_channel = std::max(out_row[byte_offset + R_OFFSET_IDX], + std::max(out_row[byte_offset + G_OFFSET_IDX], out_row[byte_offset + B_OFFSET_IDX])); + if (alpha < max_color_channel) + out_row[byte_offset + A_OFFSET_IDX] = max_color_channel; + else + out_row[byte_offset + A_OFFSET_IDX] = alpha; + } else { + // No alpha channel, the image is opaque. + out_row[byte_offset + A_OFFSET_IDX] = 0xff; + } + } +} + +} // namespace + +// ConvolutionFilter1D --------------------------------------------------------- + +ConvolutionFilter1D::ConvolutionFilter1D() + : max_filter_(0) { +} + +ConvolutionFilter1D::~ConvolutionFilter1D() { +} + +void ConvolutionFilter1D::AddFilter(int filter_offset, + const float* filter_values, + int filter_length) { + SkASSERT(filter_length > 0); + + std::vector fixed_values; + fixed_values.reserve(filter_length); + + for (int i = 0; i < filter_length; ++i) + fixed_values.push_back(FloatToFixed(filter_values[i])); + + AddFilter(filter_offset, &fixed_values[0], filter_length); +} + +void ConvolutionFilter1D::AddFilter(int filter_offset, + const Fixed* filter_values, + int filter_length) { + // It is common for leading/trailing filter values to be zeros. In such + // cases it is beneficial to only store the central factors. + // For a scaling to 1/4th in each dimension using a Lanczos-2 filter on + // a 1080p image this optimization gives a ~10% speed improvement. + int first_non_zero = 0; + while (first_non_zero < filter_length && filter_values[first_non_zero] == 0) + first_non_zero++; + + if (first_non_zero < filter_length) { + // Here we have at least one non-zero factor. + int last_non_zero = filter_length - 1; + while (last_non_zero >= 0 && filter_values[last_non_zero] == 0) + last_non_zero--; + + filter_offset += first_non_zero; + filter_length = last_non_zero + 1 - first_non_zero; + SkASSERT(filter_length > 0); + + for (int i = first_non_zero; i <= last_non_zero; i++) + filter_values_.push_back(filter_values[i]); + } else { + // Here all the factors were zeroes. + filter_length = 0; + } + + FilterInstance instance; + + // We pushed filter_length elements onto filter_values_ + instance.data_location = (static_cast(filter_values_.size()) - + filter_length); + instance.offset = filter_offset; + instance.length = filter_length; + filters_.push_back(instance); + + max_filter_ = std::max(max_filter_, filter_length); +} + +void BGRAConvolve2D(const unsigned char* source_data, + int source_byte_row_stride, + bool source_has_alpha, + const ConvolutionFilter1D& filter_x, + const ConvolutionFilter1D& filter_y, + int output_byte_row_stride, + unsigned char* output) { + bool use_sse2 = Factory::HasSSE2(); + +#if !defined(USE_SSE2) + // Even we have runtime support for SSE2 instructions, since the binary + // was not built with SSE2 support, we had to fallback to C version. + use_sse2 = false; +#endif + + + int max_y_filter_size = filter_y.max_filter(); + + // The next row in the input that we will generate a horizontally + // convolved row for. If the filter doesn't start at the beginning of the + // image (this is the case when we are only resizing a subset), then we + // don't want to generate any output rows before that. Compute the starting + // row for convolution as the first pixel for the first vertical filter. + int filter_offset, filter_length; + const ConvolutionFilter1D::Fixed* filter_values = + filter_y.FilterForValue(0, &filter_offset, &filter_length); + int next_x_row = filter_offset; + + // We loop over each row in the input doing a horizontal convolution. This + // will result in a horizontally convolved image. We write the results into + // a circular buffer of convolved rows and do vertical convolution as rows + // are available. This prevents us from having to store the entire + // intermediate image and helps cache coherency. + // We will need four extra rows to allow horizontal convolution could be done + // simultaneously. We also padding each row in row buffer to be aligned-up to + // 16 bytes. + // TODO(jiesun): We do not use aligned load from row buffer in vertical + // convolution pass yet. Somehow Windows does not like it. + int row_buffer_width = (filter_x.num_values() + 15) & ~0xF; + int row_buffer_height = max_y_filter_size + (use_sse2 ? 4 : 0); + CircularRowBuffer row_buffer(row_buffer_width, + row_buffer_height, + filter_offset); + + // Loop over every possible output row, processing just enough horizontal + // convolutions to run each subsequent vertical convolution. + SkASSERT(output_byte_row_stride >= filter_x.num_values() * 4); + int num_output_rows = filter_y.num_values(); + int pixel_width = filter_x.num_values(); + + // We need to check which is the last line to convolve before we advance 4 + // lines in one iteration. + int last_filter_offset, last_filter_length; + filter_y.FilterForValue(num_output_rows - 1, &last_filter_offset, + &last_filter_length); + + for (int out_y = 0; out_y < num_output_rows; out_y++) { + filter_values = filter_y.FilterForValue(out_y, + &filter_offset, &filter_length); + + // Generate output rows until we have enough to run the current filter. + if (use_sse2) { +#if defined(USE_SSE2) + // We don't want to process too much rows in batches of 4 because + // we can go out-of-bounds at the end + while (next_x_row < filter_offset + filter_length) { + if (next_x_row + 3 < last_filter_offset + last_filter_length - 3) { + const unsigned char* src[4]; + unsigned char* out_row[4]; + for (int i = 0; i < 4; ++i) { + src[i] = &source_data[(next_x_row + i) * source_byte_row_stride]; + out_row[i] = row_buffer.AdvanceRow(); + } + ConvolveHorizontally4_SSE2(src, 0, pixel_width, filter_x, out_row); + next_x_row += 4; + } else { + unsigned char* buffer = row_buffer.AdvanceRow(); + + // For last rows, SSE2 load possibly to access data beyond the + // image area. therefore we use cobined C+SSE version here + int simd_width = pixel_width & ~3; + if (simd_width) { + ConvolveHorizontally_SSE2( + &source_data[next_x_row * source_byte_row_stride], + 0, simd_width, filter_x, buffer); + } + + if (pixel_width > simd_width) { + if (source_has_alpha) { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + simd_width, pixel_width, filter_x, buffer); + } else { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + simd_width, pixel_width, filter_x, buffer); + } + } + next_x_row++; + } + } +#endif + } else { + while (next_x_row < filter_offset + filter_length) { + if (source_has_alpha) { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + 0, pixel_width, filter_x, row_buffer.AdvanceRow()); + } else { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + 0, pixel_width, filter_x, row_buffer.AdvanceRow()); + } + next_x_row++; + } + } + + // Compute where in the output image this row of final data will go. + unsigned char* cur_output_row = &output[out_y * output_byte_row_stride]; + + // Get the list of rows that the circular buffer has, in order. + int first_row_in_circular_buffer; + unsigned char* const* rows_to_convolve = + row_buffer.GetRowAddresses(&first_row_in_circular_buffer); + + // Now compute the start of the subset of those rows that the filter + // needs. + unsigned char* const* first_row_for_filter = + &rows_to_convolve[filter_offset - first_row_in_circular_buffer]; + + int processed = 0; +#if defined(USE_SSE2) + int simd_width = pixel_width & ~3; + if (use_sse2 && simd_width) { + ConvolveVertically_SSE2(filter_values, filter_length, first_row_for_filter, + 0, simd_width, cur_output_row, source_has_alpha); + processed = simd_width; + } +#endif + if (source_has_alpha) { + ConvolveVertically(filter_values, filter_length, + first_row_for_filter, + processed, pixel_width, cur_output_row); + } else { + ConvolveVertically(filter_values, filter_length, + first_row_for_filter, + processed, pixel_width, cur_output_row); + } + } +} + +} // namespace skia diff --git a/libazure/src/gfx/2d/convolver.h b/libazure/convolver.h similarity index 96% rename from libazure/src/gfx/2d/convolver.h rename to libazure/convolver.h index 91f9863..0d2dd9c 100644 --- a/libazure/src/gfx/2d/convolver.h +++ b/libazure/convolver.h @@ -32,9 +32,6 @@ #include #include -/* #include "base/basictypes.h" */ -/* #include "base/cpu.h" */ -#include "mozilla/Assertions.h" #include "SkTypes.h" // avoid confusion with Mac OS X's math library (Carbon) @@ -74,8 +71,7 @@ class ConvolutionFilter1D { // The cast relies on Fixed being a short, implying that on // the platforms we care about all (16) bits will fit into // the mantissa of a (32-bit) float. - MOZ_STATIC_ASSERT(sizeof(Fixed) == 2, - "fixed type should fit in float mantissa"); + //COMPILE_ASSERT(sizeof(Fixed) == 2, fixed_type_should_fit_in_float_mantissa); float raw = static_cast(x); return ldexpf(raw, -kShiftBits); } @@ -184,8 +180,8 @@ void BGRAConvolve2D(const unsigned char* source_data, const ConvolutionFilter1D& xfilter, const ConvolutionFilter1D& yfilter, int output_byte_row_stride, - unsigned char* output, - bool use_sse2); + unsigned char* output); + } // namespace skia #endif // SKIA_EXT_CONVOLVER_H_ diff --git a/libazure/convolverSSE2.cpp b/libazure/convolverSSE2.cpp new file mode 100644 index 0000000..4073130 --- /dev/null +++ b/libazure/convolverSSE2.cpp @@ -0,0 +1,476 @@ +// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google, Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +#include "convolver.h" +#include +#include "SkTypes.h" + +#include // ARCH_CPU_X86_FAMILY was defined in build/config.h + +namespace skia { + +// Convolves horizontally along a single row. The row data is given in +// |src_data| and continues for the [begin, end) of the filter. +void ConvolveHorizontally_SSE2(const unsigned char* src_data, + int begin, int end, + const ConvolutionFilter1D& filter, + unsigned char* out_row) { + + int filter_offset, filter_length; + __m128i zero = _mm_setzero_si128(); + __m128i mask[3]; + // |mask| will be used to decimate all extra filter coefficients that are + // loaded by SIMD when |filter_length| is not divisible by 4. + mask[0] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); + mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); + mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); + + // This buffer is used for tails + __m128i buffer; + + // Output one pixel each iteration, calculating all channels (RGBA) together. + for (int out_x = begin; out_x < end; out_x++) { + const ConvolutionFilter1D::Fixed* filter_values = + filter.FilterForValue(out_x, &filter_offset, &filter_length); + + __m128i accum = _mm_setzero_si128(); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filter_length| pixels (4 bytes each) after this. + const __m128i* row_to_filter = + reinterpret_cast(&src_data[filter_offset << 2]); + + // We will load and accumulate with four coefficients per iteration. + for (int filter_x = 0; filter_x < filter_length >> 2; filter_x++) { + + // Load 4 coefficients => duplicate 1st and 2nd of them for all channels. + __m128i coeff, coeff16; + // [16] xx xx xx xx c3 c2 c1 c0 + coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); + // [16] xx xx xx xx c1 c1 c0 c0 + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + // [16] c1 c1 c1 c1 c0 c0 c0 c0 + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + + // Load four pixels => unpack the first two pixels to 16 bits => + // multiply with coefficients => accumulate the convolution result. + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src8 = _mm_loadu_si128(row_to_filter); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0*c0 b0*c0 g0*c0 r0*c0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + // [32] a1*c1 b1*c1 g1*c1 r1*c1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + + // Duplicate 3rd and 4th coefficients for all channels => + // unpack the 3rd and 4th pixels to 16 bits => multiply with coefficients + // => accumulate the convolution results. + // [16] xx xx xx xx c3 c3 c2 c2 + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + // [16] c3 c3 c3 c3 c2 c2 c2 c2 + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + // [16] a3 g3 b3 r3 a2 g2 b2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2*c2 b2*c2 g2*c2 r2*c2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + // [32] a3*c3 b3*c3 g3*c3 r3*c3 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + + // Advance the pixel and coefficients pointers. + row_to_filter += 1; + filter_values += 4; + } + + // When |filter_length| is not divisible by 4, we need to decimate some of + // the filter coefficient that was loaded incorrectly to zero; Other than + // that the algorithm is same with above, except that the 4th pixel will be + // always absent. + int r = filter_length & 3; + if (r) { + memcpy(&buffer, row_to_filter, r * 4); + // Note: filter_values must be padded to align_up(filter_offset, 8). + __m128i coeff, coeff16; + coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); + // Mask out extra filter taps. + coeff = _mm_and_si128(coeff, mask[r-1]); + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + + // Note: line buffer must be padded to align_up(filter_offset, 16). + // We resolve this by temporary buffer + __m128i src8 = _mm_loadu_si128(&buffer); + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + + src16 = _mm_unpackhi_epi8(src8, zero); + coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum = _mm_add_epi32(accum, t); + } + + // Shift right for fixed point implementation. + accum = _mm_srai_epi32(accum, ConvolutionFilter1D::kShiftBits); + + // Packing 32 bits |accum| to 16 bits per channel (signed saturation). + accum = _mm_packs_epi32(accum, zero); + // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). + accum = _mm_packus_epi16(accum, zero); + + // Store the pixel value of 32 bits. + *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum); + out_row += 4; + } +} + +// Convolves horizontally along four rows. The row data is given in +// |src_data| and continues for the [begin, end) of the filter. +// The algorithm is almost same as |ConvolveHorizontally_SSE2|. Please +// refer to that function for detailed comments. +void ConvolveHorizontally4_SSE2(const unsigned char* src_data[4], + int begin, int end, + const ConvolutionFilter1D& filter, + unsigned char* out_row[4]) { + int filter_offset, filter_length; + __m128i zero = _mm_setzero_si128(); + __m128i mask[3]; + // |mask| will be used to decimate all extra filter coefficients that are + // loaded by SIMD when |filter_length| is not divisible by 4. + mask[0] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); + mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); + mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); + + // Output one pixel each iteration, calculating all channels (RGBA) together. + for (int out_x = begin; out_x < end; out_x++) { + const ConvolutionFilter1D::Fixed* filter_values = + filter.FilterForValue(out_x, &filter_offset, &filter_length); + + // four pixels in a column per iteration. + __m128i accum0 = _mm_setzero_si128(); + __m128i accum1 = _mm_setzero_si128(); + __m128i accum2 = _mm_setzero_si128(); + __m128i accum3 = _mm_setzero_si128(); + int start = (filter_offset<<2); + // We will load and accumulate with four coefficients per iteration. + for (int filter_x = 0; filter_x < (filter_length >> 2); filter_x++) { + __m128i coeff, coeff16lo, coeff16hi; + // [16] xx xx xx xx c3 c2 c1 c0 + coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); + // [16] xx xx xx xx c1 c1 c0 c0 + coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + // [16] c1 c1 c1 c1 c0 c0 c0 c0 + coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); + // [16] xx xx xx xx c3 c3 c2 c2 + coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + // [16] c3 c3 c3 c3 c2 c2 c2 c2 + coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); + + __m128i src8, src16, mul_hi, mul_lo, t; + +#define ITERATION(src, accum) \ + src8 = _mm_loadu_si128(reinterpret_cast(src)); \ + src16 = _mm_unpacklo_epi8(src8, zero); \ + mul_hi = _mm_mulhi_epi16(src16, coeff16lo); \ + mul_lo = _mm_mullo_epi16(src16, coeff16lo); \ + t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + src16 = _mm_unpackhi_epi8(src8, zero); \ + mul_hi = _mm_mulhi_epi16(src16, coeff16hi); \ + mul_lo = _mm_mullo_epi16(src16, coeff16hi); \ + t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t); \ + t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ + accum = _mm_add_epi32(accum, t) + + ITERATION(src_data[0] + start, accum0); + ITERATION(src_data[1] + start, accum1); + ITERATION(src_data[2] + start, accum2); + ITERATION(src_data[3] + start, accum3); + + start += 16; + filter_values += 4; + } + + int r = filter_length & 3; + if (r) { + // Note: filter_values must be padded to align_up(filter_offset, 8); + __m128i coeff; + coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); + // Mask out extra filter taps. + coeff = _mm_and_si128(coeff, mask[r-1]); + + __m128i coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); + /* c1 c1 c1 c1 c0 c0 c0 c0 */ + coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); + __m128i coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); + coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); + + __m128i src8, src16, mul_hi, mul_lo, t; + + ITERATION(src_data[0] + start, accum0); + ITERATION(src_data[1] + start, accum1); + ITERATION(src_data[2] + start, accum2); + ITERATION(src_data[3] + start, accum3); + } + + accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); + accum0 = _mm_packs_epi32(accum0, zero); + accum0 = _mm_packus_epi16(accum0, zero); + accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); + accum1 = _mm_packs_epi32(accum1, zero); + accum1 = _mm_packus_epi16(accum1, zero); + accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); + accum2 = _mm_packs_epi32(accum2, zero); + accum2 = _mm_packus_epi16(accum2, zero); + accum3 = _mm_srai_epi32(accum3, ConvolutionFilter1D::kShiftBits); + accum3 = _mm_packs_epi32(accum3, zero); + accum3 = _mm_packus_epi16(accum3, zero); + + *(reinterpret_cast(out_row[0])) = _mm_cvtsi128_si32(accum0); + *(reinterpret_cast(out_row[1])) = _mm_cvtsi128_si32(accum1); + *(reinterpret_cast(out_row[2])) = _mm_cvtsi128_si32(accum2); + *(reinterpret_cast(out_row[3])) = _mm_cvtsi128_si32(accum3); + + out_row[0] += 4; + out_row[1] += 4; + out_row[2] += 4; + out_row[3] += 4; + } +} + +// Does vertical convolution to produce one output row. The filter values and +// length are given in the first two parameters. These are applied to each +// of the rows pointed to in the |source_data_rows| array, with each row +// being |end - begin| wide. +// +// The output must have room for |(end - begin) * 4| bytes. +template +void ConvolveVertically_SSE2_impl(const ConvolutionFilter1D::Fixed* filter_values, + int filter_length, + unsigned char* const* source_data_rows, + int begin, int end, + unsigned char* out_row) { + __m128i zero = _mm_setzero_si128(); + __m128i accum0, accum1, accum2, accum3, coeff16; + const __m128i* src; + int out_x; + // Output four pixels per iteration (16 bytes). + for (out_x = begin; out_x + 3 < end; out_x += 4) { + + // Accumulated result for each pixel. 32 bits per RGBA channel. + accum0 = _mm_setzero_si128(); + accum1 = _mm_setzero_si128(); + accum2 = _mm_setzero_si128(); + accum3 = _mm_setzero_si128(); + + // Convolve with one filter coefficient per iteration. + for (int filter_y = 0; filter_y < filter_length; filter_y++) { + + // Duplicate the filter coefficient 8 times. + // [16] cj cj cj cj cj cj cj cj + coeff16 = _mm_set1_epi16(filter_values[filter_y]); + + // Load four pixels (16 bytes) together. + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + src = reinterpret_cast( + &source_data_rows[filter_y][out_x << 2]); + __m128i src8 = _mm_loadu_si128(src); + + // Unpack 1st and 2nd pixels from 8 bits to 16 bits for each channels => + // multiply with current coefficient => accumulate the result. + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0 b0 g0 r0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum0 = _mm_add_epi32(accum0, t); + // [32] a1 b1 g1 r1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum1 = _mm_add_epi32(accum1, t); + + // Unpack 3rd and 4th pixels from 8 bits to 16 bits for each channels => + // multiply with current coefficient => accumulate the result. + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2 b2 g2 r2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum2 = _mm_add_epi32(accum2, t); + // [32] a3 b3 g3 r3 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum3 = _mm_add_epi32(accum3, t); + } + + // Shift right for fixed point implementation. + accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); + accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); + accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); + accum3 = _mm_srai_epi32(accum3, ConvolutionFilter1D::kShiftBits); + + // Packing 32 bits |accum| to 16 bits per channel (signed saturation). + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packs_epi32(accum0, accum1); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + accum2 = _mm_packs_epi32(accum2, accum3); + + // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packus_epi16(accum0, accum2); + + if (has_alpha) { + // Compute the max(ri, gi, bi) for each pixel. + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + __m128i a = _mm_srli_epi32(accum0, 8); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = _mm_srli_epi32(accum0, 16); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = _mm_max_epu8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = _mm_slli_epi32(b, 24); + + // Make sure the value of alpha channel is always larger than maximum + // value of color channels. + accum0 = _mm_max_epu8(b, accum0); + } else { + // Set value of alpha channels to 0xFF. + __m128i mask = _mm_set1_epi32(0xff000000); + accum0 = _mm_or_si128(accum0, mask); + } + + // Store the convolution result (16 bytes) and advance the pixel pointers. + _mm_storeu_si128(reinterpret_cast<__m128i*>(out_row), accum0); + out_row += 16; + } + + // When the width of the output is not divisible by 4, We need to save one + // pixel (4 bytes) each time. And also the fourth pixel is always absent. + int r = end - out_x; + if (r > 0) { + // Since accum3 is never used here, we'll use it as a buffer + __m128i *buffer = &accum3; + + accum0 = _mm_setzero_si128(); + accum1 = _mm_setzero_si128(); + accum2 = _mm_setzero_si128(); + for (int filter_y = 0; filter_y < filter_length; ++filter_y) { + coeff16 = _mm_set1_epi16(filter_values[filter_y]); + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + src = reinterpret_cast( + &source_data_rows[filter_y][out_x * 4]); + memcpy(buffer, src, r * 4); + __m128i src8 = _mm_loadu_si128(buffer); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + __m128i src16 = _mm_unpacklo_epi8(src8, zero); + __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); + __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a0 b0 g0 r0 + __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum0 = _mm_add_epi32(accum0, t); + // [32] a1 b1 g1 r1 + t = _mm_unpackhi_epi16(mul_lo, mul_hi); + accum1 = _mm_add_epi32(accum1, t); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + src16 = _mm_unpackhi_epi8(src8, zero); + mul_hi = _mm_mulhi_epi16(src16, coeff16); + mul_lo = _mm_mullo_epi16(src16, coeff16); + // [32] a2 b2 g2 r2 + t = _mm_unpacklo_epi16(mul_lo, mul_hi); + accum2 = _mm_add_epi32(accum2, t); + } + + accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); + accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); + accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); + // [16] a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packs_epi32(accum0, accum1); + // [16] a3 b3 g3 r3 a2 b2 g2 r2 + accum2 = _mm_packs_epi32(accum2, zero); + // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 + accum0 = _mm_packus_epi16(accum0, accum2); + if (has_alpha) { + // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 + __m128i a = _mm_srli_epi32(accum0, 8); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. + // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 + a = _mm_srli_epi32(accum0, 16); + // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 + b = _mm_max_epu8(a, b); // Max of r and g and b. + // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 + b = _mm_slli_epi32(b, 24); + accum0 = _mm_max_epu8(b, accum0); + } else { + __m128i mask = _mm_set1_epi32(0xff000000); + accum0 = _mm_or_si128(accum0, mask); + } + + for (; out_x < end; out_x++) { + *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum0); + accum0 = _mm_srli_si128(accum0, 4); + out_row += 4; + } + } +} + +void ConvolveVertically_SSE2(const ConvolutionFilter1D::Fixed* filter_values, + int filter_length, + unsigned char* const* source_data_rows, + int begin, int end, + unsigned char* out_row, bool has_alpha) { + if (has_alpha) { + ConvolveVertically_SSE2_impl(filter_values, filter_length, + source_data_rows, begin, end, out_row); + } else { + ConvolveVertically_SSE2_impl(filter_values, filter_length, + source_data_rows, begin, end, out_row); + } +} + +} // namespace skia diff --git a/libazure/convolverSSE2.h b/libazure/convolverSSE2.h new file mode 100644 index 0000000..2d88733 --- /dev/null +++ b/libazure/convolverSSE2.h @@ -0,0 +1,70 @@ +// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google, Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +#ifndef SKIA_EXT_CONVOLVER_SSE_H_ +#define SKIA_EXT_CONVOLVER_SSE_H_ + +#include "convolver.h" + +#include + +#include "SkTypes.h" + +namespace skia { + +// Convolves horizontally along a single row. The row data is given in +// |src_data| and continues for the [begin, end) of the filter. +void ConvolveHorizontally_SSE2(const unsigned char* src_data, + int begin, int end, + const ConvolutionFilter1D& filter, + unsigned char* out_row); + +// Convolves horizontally along four rows. The row data is given in +// |src_data| and continues for the [begin, end) of the filter. +// The algorithm is almost same as |ConvolveHorizontally_SSE2|. Please +// refer to that function for detailed comments. +void ConvolveHorizontally4_SSE2(const unsigned char* src_data[4], + int begin, int end, + const ConvolutionFilter1D& filter, + unsigned char* out_row[4]); + +// Does vertical convolution to produce one output row. The filter values and +// length are given in the first two parameters. These are applied to each +// of the rows pointed to in the |source_data_rows| array, with each row +// being |pixel_width| wide. +// +// The output must have room for |pixel_width * 4| bytes. +void ConvolveVertically_SSE2(const ConvolutionFilter1D::Fixed* filter_values, + int filter_length, + unsigned char* const* source_data_rows, + int begin, int end, + unsigned char* out_row, bool has_alpha); + +} // namespace skia + +#endif // SKIA_EXT_CONVOLVER_SSE_H_ diff --git a/libazure/src/gfx/2d/genshaders.sh b/libazure/genshaders.sh similarity index 100% rename from libazure/src/gfx/2d/genshaders.sh rename to libazure/genshaders.sh diff --git a/libazure/gfx2d.sln b/libazure/gfx2d.sln new file mode 100644 index 0000000..8f0cc98 --- /dev/null +++ b/libazure/gfx2d.sln @@ -0,0 +1,65 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx2d", "gfx2d.vcxproj", "{FDF1302F-77E8-975E-39C0-B4AD3F190A84}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest", "unittest\unittest.vcxproj", "{CCF4BC8B-0CED-47CA-B621-ABF1832527D9}" + ProjectSection(ProjectDependencies) = postProject + {FDF1302F-77E8-975E-39C0-B4AD3F190A84} = {FDF1302F-77E8-975E-39C0-B4AD3F190A84} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "perftest", "perftest\perftest.vcxproj", "{AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}" + ProjectSection(ProjectDependencies) = postProject + {FDF1302F-77E8-975E-39C0-B4AD3F190A84} = {FDF1302F-77E8-975E-39C0-B4AD3F190A84} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recordbench", "recordbench\recordbench.vcxproj", "{10760766-5991-426D-A2D3-C0A0789A3BB6}" + ProjectSection(ProjectDependencies) = postProject + {FDF1302F-77E8-975E-39C0-B4AD3F190A84} = {FDF1302F-77E8-975E-39C0-B4AD3F190A84} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug (With Skia)|Win32 = Debug (With Skia)|Win32 + Debug|Win32 = Debug|Win32 + Release (With Skia)|Win32 = Release (With Skia)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Debug (With Skia)|Win32.ActiveCfg = Debug (With Skia)|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Debug (With Skia)|Win32.Build.0 = Debug (With Skia)|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Debug|Win32.ActiveCfg = Debug|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Debug|Win32.Build.0 = Debug|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Release (With Skia)|Win32.ActiveCfg = Release (With Skia)|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Release (With Skia)|Win32.Build.0 = Release (With Skia)|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Release|Win32.ActiveCfg = Release|Win32 + {FDF1302F-77E8-975E-39C0-B4AD3F190A84}.Release|Win32.Build.0 = Release|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug (With Skia)|Win32.ActiveCfg = Debug (With Skia)|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug (With Skia)|Win32.Build.0 = Debug (With Skia)|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug|Win32.Build.0 = Debug|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release (With Skia)|Win32.ActiveCfg = Release (With Skia)|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release (With Skia)|Win32.Build.0 = Release (With Skia)|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release|Win32.ActiveCfg = Release|Win32 + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release|Win32.Build.0 = Release|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Debug (With Skia)|Win32.ActiveCfg = Debug (With Skia)|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Debug (With Skia)|Win32.Build.0 = Debug (With Skia)|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Debug|Win32.Build.0 = Debug|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Release (With Skia)|Win32.ActiveCfg = Release (With Skia)|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Release (With Skia)|Win32.Build.0 = Release (With Skia)|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Release|Win32.ActiveCfg = Release|Win32 + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172}.Release|Win32.Build.0 = Release|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Debug (With Skia)|Win32.ActiveCfg = Debug (With Skia)|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Debug (With Skia)|Win32.Build.0 = Debug (With Skia)|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Debug|Win32.ActiveCfg = Debug|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Debug|Win32.Build.0 = Debug|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Release (With Skia)|Win32.ActiveCfg = Release (With Skia)|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Release (With Skia)|Win32.Build.0 = Release (With Skia)|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Release|Win32.ActiveCfg = Release|Win32 + {10760766-5991-426D-A2D3-C0A0789A3BB6}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libazure/gfx2d.suo b/libazure/gfx2d.suo new file mode 100644 index 0000000..350a9bf Binary files /dev/null and b/libazure/gfx2d.suo differ diff --git a/libazure/gfx2d.vcxproj b/libazure/gfx2d.vcxproj new file mode 100644 index 0000000..c300683 --- /dev/null +++ b/libazure/gfx2d.vcxproj @@ -0,0 +1,393 @@ + + + + + Debug (With Skia) + Win32 + + + Debug + Win32 + + + Release (With Skia) + Win32 + + + Release + Win32 + + + + Win32Proj + {FDF1302F-77E8-975E-39C0-B4AD3F190A84} + + + + StaticLibrary + true + v120 + + + StaticLibrary + true + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + + + + + + + + + + + + + + + + + true + $(DXSDK_DIR)\Utilities\bin\x86;$(ExecutablePath) + $(ProjectDir);$(IncludePath) + + + true + $(DXSDK_DIR)\Utilities\bin\x86;$(ExecutablePath) + $(ProjectDir);$(IncludePath) + + + true + + + true + $(ProjectDir);C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Include;$(IncludePath) + + + + USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + true + false + + + MachineX86 + true + Windows + + + + + + + + + + + + + USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN;USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD;USE_CAIRO_SCALED_FONT + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + $(ProjectDir)/../cairo/src;$(ProjectDir)/..;$(ProjectDir)/../skia/include;$(ProjectDir)/../skia/include/core;$(ProjectDir)/../skia/include/utils;$(ProjectDir)/../skia/include/gpu;$(ProjectDir)/../skia/include/config + true + false + + + MachineX86 + true + Windows + + + + + + + + + + + + + USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + ./ + true + + + MachineX86 + true + Windows + true + true + + + + + USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD;USE_CAIRO_SCALED_FONT + MultiThreadedDLL + Level3 + ProgramDatabase + $(ProjectDir)/../cairo/src;$(ProjectDir)/..;$(ProjectDir)/../skia/include;$(ProjectDir)/../skia/include/core;$(ProjectDir)/../skia/include/utils;$(ProjectDir)/../skia/include/gpu;$(ProjectDir)/../skia/include/config + true + + + MachineX86 + true + Windows + true + true + + + + + + + + + + + + + + + + true + true + + + + + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + true + true + + + + + + + + + true + true + + + + + true + true + + + + true + true + + + + + + + + true + true + + + + + + + + + + + + + + + true + true + + + + + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + true + true + + + + + + true + true + + + + + true + true + + + + true + true + + + + + + + + true + true + + + + + + Document + fxc /Tfx_4_0 /FhShadersD2D.h ShadersD2D.fx /Vn d2deffect + fxc /Tfx_4_0 /FhShadersD2D.h ShadersD2D.fx /Vn d2deffect + ShadersD2D.h + ShadersD2D.h + + + + + + HLSL + fxc ShadersD2D1.hlsl -ESampleRadialGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientPS +type tmpfile > ShadersD2D1.h +fxc ShadersD2D1.hlsl -ESampleRadialGradientA0PS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientA0PS +type tmpfile >> ShadersD2D1.h +del tmpfile + + Compiling D2D 1.1 Shaders + ShadersD2D1.h + false + fxc ShadersD2D1.hlsl -ESampleRadialGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientPS +type tmpfile > ShadersD2D1.h +fxc ShadersD2D1.hlsl -ESampleRadialGradientA0PS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientA0PS +type tmpfile >> ShadersD2D1.h +del tmpfile + + Compiling D2D 1.1 Shaders + ShadersD2D1.h + false + fxc ShadersD2D1.hlsl -ESampleRadialGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientPS +type tmpfile > ShadersD2D1.h +fxc ShadersD2D1.hlsl -ESampleRadialGradientA0PS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientA0PS +type tmpfile >> ShadersD2D1.h +del tmpfile + + Compiling D2D 1.1 Shaders + ShadersD2D1.h + false + fxc ShadersD2D1.hlsl -ESampleRadialGradientPS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientPS +type tmpfile > ShadersD2D1.h +fxc ShadersD2D1.hlsl -ESampleRadialGradientA0PS -nologo -Tps_4_0_level_9_3 -Fhtmpfile -VnSampleRadialGradientA0PS +type tmpfile >> ShadersD2D1.h +del tmpfile + + Compiling D2D 1.1 Shaders + ShadersD2D1.h + false + + + + + + \ No newline at end of file diff --git a/libazure/src/gfx/2d/image_operations.cpp b/libazure/image_operations.cpp similarity index 94% rename from libazure/src/gfx/2d/image_operations.cpp rename to libazure/image_operations.cpp index 821c29a..04be0db 100644 --- a/libazure/src/gfx/2d/image_operations.cpp +++ b/libazure/image_operations.cpp @@ -26,8 +26,6 @@ // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. -#include "base/basictypes.h" - #define _USE_MATH_DEFINES #include #include @@ -35,8 +33,6 @@ #include "image_operations.h" -// #include "nsAlgorithm.h" -#include "base/stack_container.h" #include "convolver.h" #include "SkColorPriv.h" #include "SkBitmap.h" @@ -161,8 +157,7 @@ class ResizeFilter { // for the transform is also specified. void ComputeFilters(int src_size, int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolutionFilter1D* output); + float scale, ConvolutionFilter1D* output); // Computes the filter value given the coordinate in filter space. inline float ComputeFilter(float pos) { @@ -182,11 +177,6 @@ class ResizeFilter { ImageOperations::ResizeMethod method_; - // Size of the filter support on one side only in the destination space. - // See GetFilterSupport. - float x_filter_support_; - float y_filter_support_; - // Subset of scaled destination bitmap to compute. SkIRect out_bounds_; @@ -211,17 +201,10 @@ ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, float scale_y = static_cast(dest_height) / static_cast(src_full_height); - x_filter_support_ = GetFilterSupport(scale_x); - y_filter_support_ = GetFilterSupport(scale_y); - - // Support of the filter in source space. - float src_x_support = x_filter_support_ / scale_x; - float src_y_support = y_filter_support_ / scale_y; - ComputeFilters(src_full_width, dest_subset.fLeft, dest_subset.width(), - scale_x, src_x_support, &x_filter_); + scale_x, &x_filter_); ComputeFilters(src_full_height, dest_subset.fTop, dest_subset.height(), - scale_y, src_y_support, &y_filter_); + scale_y, &y_filter_); } // TODO(egouriou): Take advantage of periods in the convolution. @@ -237,8 +220,7 @@ ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, // loading the factors only once outside the borders. void ResizeFilter::ComputeFilters(int src_size, int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolutionFilter1D* output) { + float scale, ConvolutionFilter1D* output) { int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) // When we're doing a magnification, the scale will be larger than one. This @@ -248,6 +230,8 @@ void ResizeFilter::ComputeFilters(int src_size, // some computations. float clamped_scale = std::min(1.0f, scale); + float src_support = GetFilterSupport(clamped_scale) / clamped_scale; + // Speed up the divisions below by turning them into multiplies. float inv_scale = 1.0f / scale; @@ -409,9 +393,13 @@ SkBitmap ImageOperations::ResizeSubpixel(const SkBitmap& source, // Render into subpixels. SkBitmap result; - result.setConfig(SkBitmap::kARGB_8888_Config, dest_subset.width(), - dest_subset.height()); - result.allocPixels(); + SkImageInfo info = SkImageInfo::Make(dest_subset.width(), + dest_subset.height(), + kBGRA_8888_SkColorType, + kPremul_SkAlphaType); + + + result.allocPixels(info); if (!result.readyToDraw()) return img; @@ -471,7 +459,7 @@ SkBitmap ImageOperations::ResizeSubpixel(const SkBitmap& source, src_row += h * row_words; dst_row += result.rowBytes() / 4; } - result.setIsOpaque(img.isOpaque()); + result.setAlphaType(img.alphaType()); return result; #else return SkBitmap(); @@ -516,13 +504,15 @@ SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source, // Convolve into the result. SkBitmap result; - result.setConfig(SkBitmap::kARGB_8888_Config, - dest_subset.width(), dest_subset.height()); + SkImageInfo info = SkImageInfo::Make(dest_subset.width(), + dest_subset.height(), + kBGRA_8888_SkColorType, + kPremul_SkAlphaType); if (dest_pixels) { - result.setPixels(dest_pixels); + result.installPixels(info, dest_pixels, info.minRowBytes()); } else { - result.allocPixels(); + result.allocPixels(info); } if (!result.readyToDraw()) @@ -531,11 +521,10 @@ SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source, BGRAConvolve2D(source_subset, static_cast(source.rowBytes()), !source.isOpaque(), filter.x_filter(), filter.y_filter(), static_cast(result.rowBytes()), - static_cast(result.getPixels()), - /* sse = */ false); + static_cast(result.getPixels())); // Preserve the "opaque" flag for use as an optimization later. - result.setIsOpaque(source.isOpaque()); + result.setAlphaType(source.alphaType()); return result; } diff --git a/libazure/src/gfx/2d/image_operations.h b/libazure/image_operations.h similarity index 100% rename from libazure/src/gfx/2d/image_operations.h rename to libazure/image_operations.h diff --git a/libazure/include/mozilla/Assertions.h b/libazure/include/mozilla/Assertions.h deleted file mode 100644 index 8942ddd..0000000 --- a/libazure/include/mozilla/Assertions.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Implementations of runtime and static assertion macros for C and C++. */ - -#ifndef mozilla_Assertions_h_ -#define mozilla_Assertions_h_ - -#include "mozilla/Attributes.h" -#include "mozilla/Compiler.h" - -#include -#include -#include -#ifdef WIN32 - /* - * TerminateProcess and GetCurrentProcess are defined in , which - * further depends on . We hardcode these few definitions manually - * because those headers clutter the global namespace with a significant - * number of undesired macros and symbols. - */ -# ifdef __cplusplus - extern "C" { -# endif - __declspec(dllimport) int __stdcall - TerminateProcess(void* hProcess, unsigned int uExitCode); - __declspec(dllimport) void* __stdcall GetCurrentProcess(void); -# ifdef __cplusplus - } -# endif -#else -# include -#endif -#ifdef ANDROID -# include -#endif - -/* - * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time*. This - * can be useful when you make certain assumptions about what must hold for - * optimal, or even correct, behavior. For example, you might assert that the - * size of a struct is a multiple of the target architecture's word size: - * - * struct S { ... }; - * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0, - * "S should be a multiple of word size for efficiency"); - * - * This macro can be used in any location where both an extern declaration and a - * typedef could be used. - * - * Be aware of the gcc 4.2 concerns noted further down when writing patches that - * use this macro, particularly if a patch only bounces on OS X. - */ -#ifdef __cplusplus -# if defined(__clang__) -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_extension(cxx_static_assert) -# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), reason) -# endif -# elif defined(__GNUC__) -# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) -# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), reason) -# endif -# elif defined(_MSC_VER) -# if _MSC_VER >= 1600 /* MSVC 10 */ -# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), reason) -# endif -# elif defined(__HP_aCC) -# if __HP_aCC >= 62500 && defined(_HP_CXX0x_SOURCE) -# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), reason) -# endif -# endif -#endif -#ifndef MOZ_STATIC_ASSERT - /* - * Some of the definitions below create an otherwise-unused typedef. This - * triggers compiler warnings with some versions of gcc, so mark the typedefs - * as permissibly-unused to disable the warnings. - */ -# if defined(__GNUC__) -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -# else -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ -# endif -# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y -# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) -# if defined(__SUNPRO_CC) - /* - * The Sun Studio C++ compiler is buggy when declaring, inside a function, - * another extern'd function with an array argument whose length contains a - * sizeof, triggering the error message "sizeof expression not accepted as - * size of array parameter". This bug (6688515, not public yet) would hit - * defining moz_static_assert as a function, so we always define an extern - * array for Sun Studio. - * - * We include the line number in the symbol name in a best-effort attempt - * to avoid conflicts (see below). - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] -# elif defined(__COUNTER__) - /* - * If there was no preferred alternative, use a compiler-agnostic version. - * - * Note that the non-__COUNTER__ version has a bug in C++: it can't be used - * in both |extern "C"| and normal C++ in the same translation unit. (Alas - * |extern "C"| isn't allowed in a function.) The only affected compiler - * we really care about is gcc 4.2. For that compiler and others like it, - * we include the line number in the function name to do the best we can to - * avoid conflicts. These should be rare: a conflict would require use of - * MOZ_STATIC_ASSERT on the same line in separate files in the same - * translation unit, *and* the uses would have to be in code with - * different linkage, *and* the first observed use must be in C++-linkage - * code. - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# else -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# endif -#endif - -#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * MOZ_CRASH crashes the program, plain and simple, in a Breakpad-compatible - * way, in both debug and release builds. - * - * MOZ_CRASH is a good solution for "handling" failure cases when you're - * unwilling or unable to handle them more cleanly -- for OOM, for likely memory - * corruption, and so on. It's also a good solution if you need safe behavior - * in release builds as well as debug builds. But if the failure is one that - * should be debugged and fixed, MOZ_ASSERT is generally preferable. - */ -#if defined(_MSC_VER) - /* - * On MSVC use the __debugbreak compiler intrinsic, which produces an inline - * (not nested in a system function) breakpoint. This distinctively invokes - * Breakpad without requiring system library symbols on all stack-processing - * machines, as a nested breakpoint would require. We use TerminateProcess - * with the exit code aborting would generate because we don't want to invoke - * atexit handlers, destructors, library unload handlers, and so on when our - * process might be in a compromised state. We don't use abort() because - * it'd cause Windows to annoyingly pop up the process error dialog multiple - * times. See bug 345118 and bug 426163. - * - * (Technically these are Windows requirements, not MSVC requirements. But - * practically you need MSVC for debugging, and we only ship builds created - * by MSVC, so doing it this way reduces complexity.) - */ -# ifdef __cplusplus -# define MOZ_CRASH() \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = 123; \ - ::TerminateProcess(::GetCurrentProcess(), 3); \ - } while (0) -# else -# define MOZ_CRASH() \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = 123; \ - TerminateProcess(GetCurrentProcess(), 3); \ - } while (0) -# endif -#else -# ifdef __cplusplus -# define MOZ_CRASH() \ - do { \ - *((volatile int*) NULL) = 123; \ - ::abort(); \ - } while (0) -# else -# define MOZ_CRASH() \ - do { \ - *((volatile int*) NULL) = 123; \ - abort(); \ - } while (0) -# endif -#endif - -/* - * Prints |s| as an assertion failure (using file and ln as the location of the - * assertion) to the standard debug-output channel. - * - * Usually you should use MOZ_ASSERT instead of this method. This method is - * primarily for internal use in this header, and only secondarily for use in - * implementing release-build assertions. - */ -static MOZ_ALWAYS_INLINE void -MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) -{ -#ifdef ANDROID - __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", - "Assertion failure: %s, at %s:%d\n", s, file, ln); -#else - fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); - fflush(stderr); -#endif -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/* - * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in - * debug builds. If it is, execution continues. Otherwise, an error message - * including the expression and the explanation-string (if provided) is printed, - * an attempt is made to invoke any existing debugger, and execution halts. - * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition - * which can correctly be falsy. - * - * The optional explanation-string, if provided, must be a string literal - * explaining the assertion. It is intended for use with assertions whose - * correctness or rationale is non-obvious, and for assertions where the "real" - * condition being tested is best described prosaically. Don't provide an - * explanation if it's not actually helpful. - * - * // No explanation needed: pointer arguments often must not be NULL. - * MOZ_ASSERT(arg); - * - * // An explanation can be helpful to explain exactly how we know an - * // assertion is valid. - * MOZ_ASSERT(state == WAITING_FOR_RESPONSE, - * "given that and , we must have..."); - * - * // Or it might disambiguate multiple identical (save for their location) - * // assertions of the same expression. - * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), - * "we already set [[PrimitiveThis]] for this Boolean object"); - * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), - * "we already set [[PrimitiveThis]] for this String object"); - * - * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs - * *only* during debugging, not "in the field". - */ -#ifdef DEBUG - /* First the single-argument form. */ -# define MOZ_ASSERT_HELPER1(expr) \ - do { \ - if (!(expr)) { \ - MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ - MOZ_CRASH(); \ - } \ - } while (0) - /* Now the two-argument form. */ -# define MOZ_ASSERT_HELPER2(expr, explain) \ - do { \ - if (!(expr)) { \ - MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ - MOZ_CRASH(); \ - } \ - } while (0) - /* And now, helper macrology up the wazoo. */ - /* - * Count the number of arguments passed to MOZ_ASSERT, very carefully - * tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a - * single token in argument lists. See these URLs for details: - * - * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement - * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 - */ -# define MOZ_COUNT_ASSERT_ARGS_IMPL2(_1, _2, count, ...) \ - count -# define MOZ_COUNT_ASSERT_ARGS_IMPL(args) \ - MOZ_COUNT_ASSERT_ARGS_IMPL2 args -# define MOZ_COUNT_ASSERT_ARGS(...) \ - MOZ_COUNT_ASSERT_ARGS_IMPL((__VA_ARGS__, 2, 1, 0)) - /* Pick the right helper macro to invoke. */ -# define MOZ_ASSERT_CHOOSE_HELPER2(count) MOZ_ASSERT_HELPER##count -# define MOZ_ASSERT_CHOOSE_HELPER1(count) MOZ_ASSERT_CHOOSE_HELPER2(count) -# define MOZ_ASSERT_CHOOSE_HELPER(count) MOZ_ASSERT_CHOOSE_HELPER1(count) - /* The actual macro. */ -# define MOZ_ASSERT_GLUE(x, y) x y -# define MOZ_ASSERT(...) \ - MOZ_ASSERT_GLUE(MOZ_ASSERT_CHOOSE_HELPER(MOZ_COUNT_ASSERT_ARGS(__VA_ARGS__)), \ - (__VA_ARGS__)) -#else -# define MOZ_ASSERT(...) do { } while(0) -#endif /* DEBUG */ - -/* - * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is - * true. - * - * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num)); - * - * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is - * designed to catch bugs during debugging, not "in the field". - */ -#ifdef DEBUG -# define MOZ_ASSERT_IF(cond, expr) \ - do { \ - if (cond) \ - MOZ_ASSERT(expr); \ - } while (0) -#else -# define MOZ_ASSERT_IF(cond, expr) do { } while (0) -#endif - -/* - * MOZ_NOT_REACHED_MARKER() expands to an expression which states that it is - * undefined behavior for execution to reach this point. No guarantees are made - * about what will happen if this is reached at runtime. Most code should - * probably use the higher level MOZ_NOT_REACHED, which uses this when - * appropriate. - */ -#if defined(__clang__) -# define MOZ_NOT_REACHED_MARKER() __builtin_unreachable() -#elif defined(__GNUC__) - /* - * __builtin_unreachable() was implemented in gcc 4.5. If we don't have - * that, call a noreturn function; abort() will do nicely. Qualify the call - * in C++ in case there's another abort() visible in local scope. - */ -# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) -# define MOZ_NOT_REACHED_MARKER() __builtin_unreachable() -# else -# ifdef __cplusplus -# define MOZ_NOT_REACHED_MARKER() ::abort() -# else -# define MOZ_NOT_REACHED_MARKER() abort() -# endif -# endif -#elif defined(_MSC_VER) -# define MOZ_NOT_REACHED_MARKER() __assume(0) -#else -# ifdef __cplusplus -# define MOZ_NOT_REACHED_MARKER() ::abort() -# else -# define MOZ_NOT_REACHED_MARKER() abort() -# endif -#endif - -/* - * MOZ_NOT_REACHED(reason) indicates that the given point can't be reached - * during execution: simply reaching that point in execution is a bug. It takes - * as an argument an error message indicating the reason why that point should - * not have been reachable. - * - * // ...in a language parser... - * void handle(BooleanLiteralNode node) - * { - * if (node.isTrue()) - * handleTrueLiteral(); - * else if (node.isFalse()) - * handleFalseLiteral(); - * else - * MOZ_NOT_REACHED("boolean literal that's not true or false?"); - * } - */ -#if defined(DEBUG) -# define MOZ_NOT_REACHED(reason) \ - do { \ - MOZ_ASSERT(false, reason); \ - MOZ_NOT_REACHED_MARKER(); \ - } while (0) -#else -# define MOZ_NOT_REACHED(reason) MOZ_NOT_REACHED_MARKER() -#endif - -/* - * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided - * expression, in debug builds and in release builds both. Then, in debug - * builds only, the value of the expression is asserted either true or false - * using MOZ_ASSERT. - */ -#ifdef DEBUG -# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) -# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) -#else -# define MOZ_ALWAYS_TRUE(expr) ((void)(expr)) -# define MOZ_ALWAYS_FALSE(expr) ((void)(expr)) -#endif - -#endif /* mozilla_Assertions_h_ */ diff --git a/libazure/include/mozilla/CheckedInt.h b/libazure/include/mozilla/CheckedInt.h deleted file mode 100644 index 1f35b9e..0000000 --- a/libazure/include/mozilla/CheckedInt.h +++ /dev/null @@ -1,806 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Provides checked integers, detecting integer overflow and divide-by-0. */ - -#ifndef mozilla_CheckedInt_h_ -#define mozilla_CheckedInt_h_ - -// Enable relying of Mozilla's MFBT for possibly-available C++11 features -#define MOZ_CHECKEDINT_USE_MFBT - -#ifdef MOZ_CHECKEDINT_USE_MFBT -# include "mozilla/Assertions.h" -# include "mozilla/StandardInteger.h" -#else -# include -# include -# define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason) -# define MOZ_ASSERT(cond, reason) assert((cond) && reason) -# define MOZ_DELETE -#endif - -#include -#include - -namespace mozilla { - -template class CheckedInt; - -namespace detail { - -/* - * Step 1: manually record supported types - * - * What's nontrivial here is that there are different families of integer - * types: basic integer types and stdint types. It is merrily undefined which - * types from one family may be just typedefs for a type from another family. - * - * For example, on GCC 4.6, aside from the basic integer types, the only other - * type that isn't just a typedef for some of them, is int8_t. - */ - -struct UnsupportedType {}; - -template -struct IsSupportedPass2 -{ - static const bool value = false; -}; - -template -struct IsSupported -{ - static const bool value = IsSupportedPass2::value; -}; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - - -/* - * Step 2: some integer-traits kind of stuff. - */ - -template -struct StdintTypeForSizeAndSignedness -{}; - -template<> -struct StdintTypeForSizeAndSignedness<1, true> -{ typedef int8_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<1, false> -{ typedef uint8_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<2, true> -{ typedef int16_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<2, false> -{ typedef uint16_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<4, true> -{ typedef int32_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<4, false> -{ typedef uint32_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<8, true> -{ typedef int64_t Type; }; - -template<> -struct StdintTypeForSizeAndSignedness<8, false> -{ typedef uint64_t Type; }; - -template -struct UnsignedType -{ - typedef typename StdintTypeForSizeAndSignedness::Type Type; -}; - -template -struct IsSigned -{ - static const bool value = IntegerType(-1) <= IntegerType(0); -}; - -template -struct TwiceBiggerType -{ - typedef typename StdintTypeForSizeAndSignedness< - sizeof(IntegerType) * 2, - IsSigned::value - >::Type Type; -}; - -template -struct TwiceBiggerType -{ - typedef UnsupportedType Type; -}; - -template -struct PositionOfSignBit -{ - static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1; -}; - -template -struct MinValue -{ - private: - typedef typename UnsignedType::Type UnsignedIntegerType; - static const size_t PosOfSignBit = PositionOfSignBit::value; - - public: - // Bitwise ops may return a larger type, that's why we cast explicitly. - // In C++, left bit shifts on signed values is undefined by the standard - // unless the shifted value is representable. - // Notice that signed-to-unsigned conversions are always well-defined in - // the standard as the value congruent to 2**n, as expected. By contrast, - // unsigned-to-signed is only well-defined if the value is representable. - static const IntegerType value = - IsSigned::value - ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) - : IntegerType(0); -}; - -template -struct MaxValue -{ - // Tricksy, but covered by the unit test. - // Relies heavily on the type of MinValue::value - // being IntegerType. - static const IntegerType value = ~MinValue::value; -}; - -/* - * Step 3: Implement the actual validity checks. - * - * Ideas taken from IntegerLib, code different. - */ - -template -inline bool -HasSignBit(T x) -{ - // In C++, right bit shifts on negative values is undefined by the standard. - // Notice that signed-to-unsigned conversions are always well-defined in the - // standard, as the value congruent modulo 2**n as expected. By contrast, - // unsigned-to-signed is only well-defined if the value is representable. - return bool(typename UnsignedType::Type(x) - >> PositionOfSignBit::value); -} - -// Bitwise ops may return a larger type, so it's good to use this inline -// helper guaranteeing that the result is really of type T. -template -inline T -BinaryComplement(T x) -{ - return ~x; -} - -template::value, - bool IsUSigned = IsSigned::value> -struct DoesRangeContainRange -{ -}; - -template -struct DoesRangeContainRange -{ - static const bool value = sizeof(T) >= sizeof(U); -}; - -template -struct DoesRangeContainRange -{ - static const bool value = sizeof(T) > sizeof(U); -}; - -template -struct DoesRangeContainRange -{ - static const bool value = false; -}; - -template::value, - bool IsUSigned = IsSigned::value, - bool DoesTRangeContainURange = DoesRangeContainRange::value> -struct IsInRangeImpl {}; - -template -struct IsInRangeImpl -{ - static bool run(U) - { - return true; - } -}; - -template -struct IsInRangeImpl -{ - static bool run(U x) - { - return x <= MaxValue::value && x >= MinValue::value; - } -}; - -template -struct IsInRangeImpl -{ - static bool run(U x) - { - return x <= MaxValue::value; - } -}; - -template -struct IsInRangeImpl -{ - static bool run(U x) - { - return sizeof(T) > sizeof(U) || x <= U(MaxValue::value); - } -}; - -template -struct IsInRangeImpl -{ - static bool run(U x) - { - return sizeof(T) >= sizeof(U) - ? x >= 0 - : x >= 0 && x <= U(MaxValue::value); - } -}; - -template -inline bool -IsInRange(U x) -{ - return IsInRangeImpl::run(x); -} - -template -inline bool -IsAddValid(T x, T y) -{ - // Addition is valid if the sign of x+y is equal to either that of x or that - // of y. Since the value of x+y is undefined if we have a signed type, we - // compute it using the unsigned type of the same size. - // Beware! These bitwise operations can return a larger integer type, - // if T was a small type like int8_t, so we explicitly cast to T. - - typename UnsignedType::Type ux = x; - typename UnsignedType::Type uy = y; - typename UnsignedType::Type result = ux + uy; - return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y)))) - : BinaryComplement(x) >= y; -} - -template -inline bool -IsSubValid(T x, T y) -{ - // Subtraction is valid if either x and y have same sign, or x-y and x have - // same sign. Since the value of x-y is undefined if we have a signed type, - // we compute it using the unsigned type of the same size. - typename UnsignedType::Type ux = x; - typename UnsignedType::Type uy = y; - typename UnsignedType::Type result = ux - uy; - - return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y)))) - : x >= y; -} - -template::value, - bool TwiceBiggerTypeIsSupported = - IsSupported::Type>::value> -struct IsMulValidImpl {}; - -template -struct IsMulValidImpl -{ - static bool run(T x, T y) - { - typedef typename TwiceBiggerType::Type TwiceBiggerType; - TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y); - return IsInRange(product); - } -}; - -template -struct IsMulValidImpl -{ - static bool run(T x, T y) - { - const T max = MaxValue::value; - const T min = MinValue::value; - - if (x == 0 || y == 0) - return true; - - if (x > 0) { - return y > 0 - ? x <= max / y - : y >= min / x; - } - - // If we reach this point, we know that x < 0. - return y > 0 - ? x >= min / y - : y >= max / x; - } -}; - -template -struct IsMulValidImpl -{ - static bool run(T x, T y) - { - return y == 0 || x <= MaxValue::value / y; - } -}; - -template -inline bool -IsMulValid(T x, T y) -{ - return IsMulValidImpl::run(x, y); -} - -template -inline bool -IsDivValid(T x, T y) -{ - // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max. - return y != 0 && - !(IsSigned::value && x == MinValue::value && y == T(-1)); -} - -template::value> -struct NegateImpl; - -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& val) - { - // Handle negation separately for signed/unsigned, for simpler code and to - // avoid an MSVC warning negating an unsigned value. - return CheckedInt(0, val.isValid() && val.mValue == 0); - } -}; - -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& val) - { - // Watch out for the min-value, which (with twos-complement) can't be - // negated as -min-value is then (max-value + 1). - if (!val.isValid() || val.mValue == MinValue::value) - return CheckedInt(val.mValue, false); - return CheckedInt(-val.mValue, true); - } -}; - -} // namespace detail - - -/* - * Step 4: Now define the CheckedInt class. - */ - -/** - * @class CheckedInt - * @brief Integer wrapper class checking for integer overflow and other errors - * @param T the integer type to wrap. Can be any type among the following: - * - any basic integer type such as |int| - * - any stdint type such as |int8_t| - * - * This class implements guarded integer arithmetic. Do a computation, check - * that isValid() returns true, you then have a guarantee that no problem, such - * as integer overflow, happened during this computation, and you can call - * value() to get the plain integer value. - * - * The arithmetic operators in this class are guaranteed not to raise a signal - * (e.g. in case of a division by zero). - * - * For example, suppose that you want to implement a function that computes - * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by - * zero or integer overflow). You could code it as follows: - @code - bool computeXPlusYOverZ(int x, int y, int z, int *result) - { - CheckedInt checkedResult = (CheckedInt(x) + y) / z; - if (checkedResult.isValid()) { - *result = checkedResult.value(); - return true; - } else { - return false; - } - } - @endcode - * - * Implicit conversion from plain integers to checked integers is allowed. The - * plain integer is checked to be in range before being casted to the - * destination type. This means that the following lines all compile, and the - * resulting CheckedInts are correctly detected as valid or invalid: - * @code - // 1 is of type int, is found to be in range for uint8_t, x is valid - CheckedInt x(1); - // -1 is of type int, is found not to be in range for uint8_t, x is invalid - CheckedInt x(-1); - // -1 is of type int, is found to be in range for int8_t, x is valid - CheckedInt x(-1); - // 1000 is of type int16_t, is found not to be in range for int8_t, - // x is invalid - CheckedInt x(int16_t(1000)); - // 3123456789 is of type uint32_t, is found not to be in range for int32_t, - // x is invalid - CheckedInt x(uint32_t(3123456789)); - * @endcode - * Implicit conversion from - * checked integers to plain integers is not allowed. As shown in the - * above example, to get the value of a checked integer as a normal integer, - * call value(). - * - * Arithmetic operations between checked and plain integers is allowed; the - * result type is the type of the checked integer. - * - * Checked integers of different types cannot be used in the same arithmetic - * expression. - * - * There are convenience typedefs for all stdint types, of the following form - * (these are just 2 examples): - @code - typedef CheckedInt CheckedInt32; - typedef CheckedInt CheckedUint16; - @endcode - */ -template -class CheckedInt -{ - protected: - T mValue; - bool mIsValid; - - template - CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid) - { - MOZ_STATIC_ASSERT(detail::IsSupported::value, - "This type is not supported by CheckedInt"); - } - - friend class detail::NegateImpl; - - public: - /** - * Constructs a checked integer with given @a value. The checked integer is - * initialized as valid or invalid depending on whether the @a value - * is in range. - * - * This constructor is not explicit. Instead, the type of its argument is a - * separate template parameter, ensuring that no conversion is performed - * before this constructor is actually called. As explained in the above - * documentation for class CheckedInt, this constructor checks that its - * argument is valid. - */ - template - CheckedInt(U value) - : mValue(T(value)), - mIsValid(detail::IsInRange(value)) - { - MOZ_STATIC_ASSERT(detail::IsSupported::value, - "This type is not supported by CheckedInt"); - } - - /** Constructs a valid checked integer with initial value 0 */ - CheckedInt() : mValue(0), mIsValid(true) - { - MOZ_STATIC_ASSERT(detail::IsSupported::value, - "This type is not supported by CheckedInt"); - } - - /** @returns the actual value */ - T value() const - { - MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)"); - return mValue; - } - - /** - * @returns true if the checked integer is valid, i.e. is not the result - * of an invalid operation or of an operation involving an invalid checked - * integer - */ - bool isValid() const - { - return mIsValid; - } - - template - friend CheckedInt operator +(const CheckedInt& lhs, - const CheckedInt& rhs); - template - CheckedInt& operator +=(U rhs); - template - friend CheckedInt operator -(const CheckedInt& lhs, - const CheckedInt &rhs); - template - CheckedInt& operator -=(U rhs); - template - friend CheckedInt operator *(const CheckedInt& lhs, - const CheckedInt &rhs); - template - CheckedInt& operator *=(U rhs); - template - friend CheckedInt operator /(const CheckedInt& lhs, - const CheckedInt &rhs); - template - CheckedInt& operator /=(U rhs); - - CheckedInt operator -() const - { - return detail::NegateImpl::negate(*this); - } - - /** - * @returns true if the left and right hand sides are valid - * and have the same value. - * - * Note that these semantics are the reason why we don't offer - * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b) - * but that would mean that whenever a or b is invalid, a!=b - * is always true, which would be very confusing. - * - * For similar reasons, operators <, >, <=, >= would be very tricky to - * specify, so we just avoid offering them. - * - * Notice that these == semantics are made more reasonable by these facts: - * 1. a==b implies equality at the raw data level - * (the converse is false, as a==b is never true among invalids) - * 2. This is similar to the behavior of IEEE floats, where a==b - * means that a and b have the same value *and* neither is NaN. - */ - bool operator ==(const CheckedInt& other) const - { - return mIsValid && other.mIsValid && mValue == other.mValue; - } - - /** prefix ++ */ - CheckedInt& operator++() - { - *this += 1; - return *this; - } - - /** postfix ++ */ - CheckedInt operator++(int) - { - CheckedInt tmp = *this; - *this += 1; - return tmp; - } - - /** prefix -- */ - CheckedInt& operator--() - { - *this -= 1; - return *this; - } - - /** postfix -- */ - CheckedInt operator--(int) - { - CheckedInt tmp = *this; - *this -= 1; - return tmp; - } - - private: - /** - * The !=, <, <=, >, >= operators are disabled: - * see the comment on operator==. - */ - template - bool operator !=(U other) const MOZ_DELETE; - template - bool operator <(U other) const MOZ_DELETE; - template - bool operator <=(U other) const MOZ_DELETE; - template - bool operator >(U other) const MOZ_DELETE; - template - bool operator >=(U other) const MOZ_DELETE; -}; - -#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ -template \ -inline CheckedInt operator OP(const CheckedInt &lhs, \ - const CheckedInt &rhs) \ -{ \ - if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \ - return CheckedInt(0, false); \ - \ - return CheckedInt(lhs.mValue OP rhs.mValue, \ - lhs.mIsValid && rhs.mIsValid); \ -} - -MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) -MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) -MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) -MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) - -#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR - -// Implement castToCheckedInt(x), making sure that -// - it allows x to be either a CheckedInt or any integer type -// that can be casted to T -// - if x is already a CheckedInt, we just return a reference to it, -// instead of copying it (optimization) - -namespace detail { - -template -struct CastToCheckedIntImpl -{ - typedef CheckedInt ReturnType; - static CheckedInt run(U u) { return u; } -}; - -template -struct CastToCheckedIntImpl > -{ - typedef const CheckedInt& ReturnType; - static const CheckedInt& run(const CheckedInt& u) { return u; } -}; - -} // namespace detail - -template -inline typename detail::CastToCheckedIntImpl::ReturnType -castToCheckedInt(U u) -{ - return detail::CastToCheckedIntImpl::run(u); -} - -#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ -template \ -template \ -CheckedInt& CheckedInt::operator COMPOUND_OP(U rhs) \ -{ \ - *this = *this OP castToCheckedInt(rhs); \ - return *this; \ -} \ -template \ -inline CheckedInt operator OP(const CheckedInt &lhs, U rhs) \ -{ \ - return lhs OP castToCheckedInt(rhs); \ -} \ -template \ -inline CheckedInt operator OP(U lhs, const CheckedInt &rhs) \ -{ \ - return castToCheckedInt(lhs) OP rhs; \ -} - -MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) -MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) -MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) -MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) - -#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS - -template -inline bool -operator ==(const CheckedInt &lhs, U rhs) -{ - return lhs == castToCheckedInt(rhs); -} - -template -inline bool -operator ==(U lhs, const CheckedInt &rhs) -{ - return castToCheckedInt(lhs) == rhs; -} - -// Convenience typedefs. -typedef CheckedInt CheckedInt8; -typedef CheckedInt CheckedUint8; -typedef CheckedInt CheckedInt16; -typedef CheckedInt CheckedUint16; -typedef CheckedInt CheckedInt32; -typedef CheckedInt CheckedUint32; -typedef CheckedInt CheckedInt64; -typedef CheckedInt CheckedUint64; - -} // namespace mozilla - -#endif /* mozilla_CheckedInt_h_ */ diff --git a/libazure/include/mozilla/Compiler.h b/libazure/include/mozilla/Compiler.h deleted file mode 100644 index 7afa390..0000000 --- a/libazure/include/mozilla/Compiler.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Various compiler checks. */ - -#ifndef mozilla_Compiler_h_ -#define mozilla_Compiler_h_ - -#if !defined(__clang__) && defined(__GNUC__) - /* - * This macro should simplify gcc version checking. For example, to check - * for gcc 4.5.1 or later, check `#ifdef MOZ_GCC_VERSION_AT_LEAST(4, 5, 1)`. - */ -# define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ - ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ - >= ((major) * 10000 + (minor) * 100 + (patchlevel))) -#if !MOZ_GCC_VERSION_AT_LEAST(4, 4, 0) -// RBA: Not true for servo! -//# error "mfbt (and Gecko) require at least gcc 4.4 to build." -#endif -#endif - -#endif /* mozilla_Compiler_h_ */ diff --git a/libazure/include/mozilla/NullPtr.h b/libazure/include/mozilla/NullPtr.h deleted file mode 100644 index d564dc8..0000000 --- a/libazure/include/mozilla/NullPtr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Implements a workaround for compilers which do not support the C++11 nullptr - * constant. - */ - -#ifndef mozilla_NullPtr_h_ -#define mozilla_NullPtr_h_ - -#include "mozilla/Compiler.h" -#include - -#if defined(__clang__) -# ifndef __has_extension -# define __has_extension __has_feature -# endif -# if __has_extension(cxx_nullptr) -# define MOZ_HAVE_CXX11_NULLPTR -# endif -#elif defined(__GNUC__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) -# define MOZ_HAVE_CXX11_NULLPTR -# endif -# endif -#elif _MSC_VER >= 1600 -# define MOZ_HAVE_CXX11_NULLPTR -#endif - -/** - * Use C++11 nullptr if available; otherwise use __null for gcc, or a 0 literal - * with the correct size to match the size of a pointer on a given platform. - */ - -#ifndef MOZ_HAVE_CXX11_NULLPTR -# if defined(__GNUC__) -# define nullptr __null -# elif defined(_WIN64) -# define nullptr 0LL -# else -# define nullptr 0L -# endif -#endif - -#endif /* mozilla_NullPtr_h_ */ diff --git a/libazure/include/mozilla/RefPtr.h b/libazure/include/mozilla/RefPtr.h deleted file mode 100644 index a298706..0000000 --- a/libazure/include/mozilla/RefPtr.h +++ /dev/null @@ -1,413 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Helpers for defining and using refcounted objects. */ - -#ifndef mozilla_RefPtr_h_ -#define mozilla_RefPtr_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" - -namespace mozilla { - -template class RefCounted; -template class RefPtr; -template class TemporaryRef; -template class OutParamRef; -template OutParamRef byRef(RefPtr&); - -/** - * RefCounted is a sort of a "mixin" for a class T. RefCounted - * manages, well, refcounting for T, and because RefCounted is - * parameterized on T, RefCounted can call T's destructor directly. - * This means T doesn't need to have a virtual dtor and so doesn't - * need a vtable. - * - * RefCounted is created with refcount == 0. Newly-allocated - * RefCounted must immediately be assigned to a RefPtr to make the - * refcount > 0. It's an error to allocate and free a bare - * RefCounted, i.e. outside of the RefPtr machinery. Attempts to - * do so will abort DEBUG builds. - * - * Live RefCounted have refcount > 0. The lifetime (refcounts) of - * live RefCounted are controlled by RefPtr and - * RefPtr. Upon a transition from refcounted==1 - * to 0, the RefCounted "dies" and is destroyed. The "destroyed" - * state is represented in DEBUG builds by refcount==0xffffdead. This - * state distinguishes use-before-ref (refcount==0) from - * use-after-destroy (refcount==0xffffdead). - */ -#ifdef DEBUG -namespace detail { -static const int DEAD = 0xffffdead; -} -#endif - -template -class RefCounted -{ - friend class RefPtr; - - protected: - RefCounted() : refCnt(0) { } - ~RefCounted() { MOZ_ASSERT(refCnt == detail::DEAD); } - - public: - // Compatibility with nsRefPtr. - void AddRef() { - MOZ_ASSERT(refCnt >= 0); - ++refCnt; - } - - void Release() { - MOZ_ASSERT(refCnt > 0); - if (0 == --refCnt) { -#ifdef DEBUG - refCnt = detail::DEAD; -#endif - delete static_cast(this); - } - } - - // Compatibility with wtf::RefPtr. - void ref() { AddRef(); } - void deref() { Release(); } - int refCount() const { return refCnt; } - bool hasOneRef() const { - MOZ_ASSERT(refCnt > 0); - return refCnt == 1; - } - - private: - int refCnt; -}; - -/** - * RefPtr points to a refcounted thing that has AddRef and Release - * methods to increase/decrease the refcount, respectively. After a - * RefPtr is assigned a T*, the T* can be used through the RefPtr - * as if it were a T*. - * - * A RefPtr can forget its underlying T*, which results in the T* - * being wrapped in a temporary object until the T* is either - * re-adopted from or released by the temporary. - */ -template -class RefPtr -{ - // To allow them to use unref() - friend class TemporaryRef; - friend class OutParamRef; - - struct DontRef {}; - - public: - RefPtr() : ptr(0) { } - RefPtr(const RefPtr& o) : ptr(ref(o.ptr)) {} - RefPtr(const TemporaryRef& o) : ptr(o.drop()) {} - RefPtr(T* t) : ptr(ref(t)) {} - - template - RefPtr(const RefPtr& o) : ptr(ref(o.get())) {} - - ~RefPtr() { unref(ptr); } - - RefPtr& operator=(const RefPtr& o) { - assign(ref(o.ptr)); - return *this; - } - RefPtr& operator=(const TemporaryRef& o) { - assign(o.drop()); - return *this; - } - RefPtr& operator=(T* t) { - assign(ref(t)); - return *this; - } - - template - RefPtr& operator=(const RefPtr& o) { - assign(ref(o.get())); - return *this; - } - - TemporaryRef forget() { - T* tmp = ptr; - ptr = 0; - return TemporaryRef(tmp, DontRef()); - } - - T* get() const { return ptr; } - operator T*() const { return ptr; } - T* operator->() const { return ptr; } - T& operator*() const { return *ptr; } - template - operator TemporaryRef() { return TemporaryRef(ptr); } - - private: - void assign(T* t) { - unref(ptr); - ptr = t; - } - - T* ptr; - - static MOZ_ALWAYS_INLINE T* ref(T* t) { - if (t) - t->AddRef(); - return t; - } - - static MOZ_ALWAYS_INLINE void unref(T* t) { - if (t) - t->Release(); - } -}; - -/** - * TemporaryRef represents an object that holds a temporary - * reference to a T. TemporaryRef objects can't be manually ref'd or - * unref'd (being temporaries, not lvalues), so can only relinquish - * references to other objects, or unref on destruction. - */ -template -class TemporaryRef -{ - // To allow it to construct TemporaryRef from a bare T* - friend class RefPtr; - - typedef typename RefPtr::DontRef DontRef; - - public: - TemporaryRef(T* t) : ptr(RefPtr::ref(t)) {} - TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} - - template - TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} - - ~TemporaryRef() { RefPtr::unref(ptr); } - - T* drop() const { - T* tmp = ptr; - ptr = 0; - return tmp; - } - - private: - TemporaryRef(T* t, const DontRef&) : ptr(t) {} - - mutable T* ptr; - - TemporaryRef() MOZ_DELETE; - void operator=(const TemporaryRef&) MOZ_DELETE; -}; - -/** - * OutParamRef is a wrapper that tracks a refcounted pointer passed as - * an outparam argument to a function. OutParamRef implements COM T** - * outparam semantics: this requires the callee to AddRef() the T* - * returned through the T** outparam on behalf of the caller. This - * means the caller (through OutParamRef) must Release() the old - * object contained in the tracked RefPtr. It's OK if the callee - * returns the same T* passed to it through the T** outparam, as long - * as the callee obeys the COM discipline. - * - * Prefer returning TemporaryRef from functions over creating T** - * outparams and passing OutParamRef to T**. Prefer RefPtr* - * outparams over T** outparams. - */ -template -class OutParamRef -{ - friend OutParamRef byRef(RefPtr&); - - public: - ~OutParamRef() { - RefPtr::unref(refPtr.ptr); - refPtr.ptr = tmp; - } - - operator T**() { return &tmp; } - - private: - OutParamRef(RefPtr& p) : refPtr(p), tmp(p.get()) {} - - RefPtr& refPtr; - T* tmp; - - OutParamRef() MOZ_DELETE; - OutParamRef& operator=(const OutParamRef&) MOZ_DELETE; -}; - -/** - * byRef cooperates with OutParamRef to implement COM outparam semantics. - */ -template -OutParamRef -byRef(RefPtr& ptr) -{ - return OutParamRef(ptr); -} - -} // namespace mozilla - -#endif // mozilla_RefPtr_h_ - - -#if 0 - -// Command line that builds these tests -// -// cp RefPtr.h test.cc && g++ -g -Wall -pedantic -DDEBUG -o test test.cc && ./test - -using namespace mozilla; - -struct Foo : public RefCounted -{ - Foo() : dead(false) { } - ~Foo() { - MOZ_ASSERT(!dead); - dead = true; - numDestroyed++; - } - - bool dead; - static int numDestroyed; -}; -int Foo::numDestroyed; - -struct Bar : public Foo { }; - -TemporaryRef -NewFoo() -{ - return RefPtr(new Foo()); -} - -TemporaryRef -NewBar() -{ - return new Bar(); -} - -void -GetNewFoo(Foo** f) -{ - *f = new Bar(); - // Kids, don't try this at home - (*f)->AddRef(); -} - -void -GetPassedFoo(Foo** f) -{ - // Kids, don't try this at home - (*f)->AddRef(); -} - -void -GetNewFoo(RefPtr* f) -{ - *f = new Bar(); -} - -void -GetPassedFoo(RefPtr* f) -{} - -TemporaryRef -GetNullFoo() -{ - return 0; -} - -int -main(int argc, char** argv) -{ - // This should blow up -// Foo* f = new Foo(); delete f; - - MOZ_ASSERT(0 == Foo::numDestroyed); - { - RefPtr f = new Foo(); - MOZ_ASSERT(f->refCount() == 1); - } - MOZ_ASSERT(1 == Foo::numDestroyed); - - { - RefPtr f1 = NewFoo(); - RefPtr f2(NewFoo()); - MOZ_ASSERT(1 == Foo::numDestroyed); - } - MOZ_ASSERT(3 == Foo::numDestroyed); - - { - RefPtr b = NewBar(); - MOZ_ASSERT(3 == Foo::numDestroyed); - } - MOZ_ASSERT(4 == Foo::numDestroyed); - - { - RefPtr f1; - { - f1 = new Foo(); - RefPtr f2(f1); - RefPtr f3 = f2; - MOZ_ASSERT(4 == Foo::numDestroyed); - } - MOZ_ASSERT(4 == Foo::numDestroyed); - } - MOZ_ASSERT(5 == Foo::numDestroyed); - - { - RefPtr f = new Foo(); - f.forget(); - MOZ_ASSERT(6 == Foo::numDestroyed); - } - - { - RefPtr f = new Foo(); - GetNewFoo(byRef(f)); - MOZ_ASSERT(7 == Foo::numDestroyed); - } - MOZ_ASSERT(8 == Foo::numDestroyed); - - { - RefPtr f = new Foo(); - GetPassedFoo(byRef(f)); - MOZ_ASSERT(8 == Foo::numDestroyed); - } - MOZ_ASSERT(9 == Foo::numDestroyed); - - { - RefPtr f = new Foo(); - GetNewFoo(&f); - MOZ_ASSERT(10 == Foo::numDestroyed); - } - MOZ_ASSERT(11 == Foo::numDestroyed); - - { - RefPtr f = new Foo(); - GetPassedFoo(&f); - MOZ_ASSERT(11 == Foo::numDestroyed); - } - MOZ_ASSERT(12 == Foo::numDestroyed); - - { - RefPtr f1 = new Bar(); - } - MOZ_ASSERT(13 == Foo::numDestroyed); - - { - RefPtr f = GetNullFoo(); - MOZ_ASSERT(13 == Foo::numDestroyed); - } - MOZ_ASSERT(13 == Foo::numDestroyed); - - return 0; -} - -#endif diff --git a/libazure/include/mozilla/Util.h b/libazure/include/mozilla/Util.h deleted file mode 100644 index 097c547..0000000 --- a/libazure/include/mozilla/Util.h +++ /dev/null @@ -1,283 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Miscellaneous uncategorized functionality. Please add new functionality to - * new headers, or to other appropriate existing headers, not here. - */ - -#ifndef mozilla_Util_h_ -#define mozilla_Util_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Types.h" - -#ifdef __cplusplus - -namespace mozilla { - -/* - * This class, and the corresponding macro MOZ_ALIGNOF, figure out how many - * bytes of alignment a given type needs. - */ -template -class AlignmentFinder -{ - struct Aligner - { - char c; - T t; - }; - - public: - static const size_t alignment = sizeof(Aligner) - sizeof(T); -}; - -#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder::alignment - -/* - * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types. - * - * For instance, - * - * MOZ_ALIGNED_DECL(char arr[2], 8); - * - * will declare a two-character array |arr| aligned to 8 bytes. - */ - -#if defined(__GNUC__) -# define MOZ_ALIGNED_DECL(_type, _align) \ - _type __attribute__((aligned(_align))) -#elif defined(_MSC_VER) -# define MOZ_ALIGNED_DECL(_type, _align) \ - __declspec(align(_align)) _type -#else -# warning "We don't know how to align variables on this compiler." -# define MOZ_ALIGNED_DECL(_type, _align) _type -#endif - -/* - * AlignedElem is a structure whose alignment is guaranteed to be at least N - * bytes. - * - * We support 1, 2, 4, 8, and 16-bit alignment. - */ -template -struct AlignedElem; - -/* - * We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where - * foo is a template parameter. - */ - -template<> -struct AlignedElem<1> -{ - MOZ_ALIGNED_DECL(uint8_t elem, 1); -}; - -template<> -struct AlignedElem<2> -{ - MOZ_ALIGNED_DECL(uint8_t elem, 2); -}; - -template<> -struct AlignedElem<4> -{ - MOZ_ALIGNED_DECL(uint8_t elem, 4); -}; - -template<> -struct AlignedElem<8> -{ - MOZ_ALIGNED_DECL(uint8_t elem, 8); -}; - -template<> -struct AlignedElem<16> -{ - MOZ_ALIGNED_DECL(uint8_t elem, 16); -}; - -/* - * This utility pales in comparison to Boost's aligned_storage. The utility - * simply assumes that uint64_t is enough alignment for anyone. This may need - * to be extended one day... - * - * As an important side effect, pulling the storage into this template is - * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving - * false negatives when we cast from the char buffer to whatever type we've - * constructed using the bytes. - */ -template -struct AlignedStorage -{ - union U { - char bytes[nbytes]; - uint64_t _; - } u; - - const void* addr() const { return u.bytes; } - void* addr() { return u.bytes; } -}; - -template -struct AlignedStorage2 -{ - union U { - char bytes[sizeof(T)]; - uint64_t _; - } u; - - const T* addr() const { return reinterpret_cast(u.bytes); } - T* addr() { return static_cast(static_cast(u.bytes)); } -}; - -/* - * Small utility for lazily constructing objects without using dynamic storage. - * When a Maybe is constructed, it is |empty()|, i.e., no value of T has - * been constructed and no T destructor will be called when the Maybe is - * destroyed. Upon calling |construct|, a T object will be constructed with the - * given arguments and that object will be destroyed when the owning Maybe - * is destroyed. - * - * N.B. GCC seems to miss some optimizations with Maybe and may generate extra - * branches/loads/stores. Use with caution on hot paths. - */ -template -class Maybe -{ - AlignedStorage2 storage; - bool constructed; - - T& asT() { return *storage.addr(); } - - public: - Maybe() { constructed = false; } - ~Maybe() { if (constructed) asT().~T(); } - - bool empty() const { return !constructed; } - - void construct() { - MOZ_ASSERT(!constructed); - ::new (storage.addr()) T(); - constructed = true; - } - - template - void construct(const T1& t1) { - MOZ_ASSERT(!constructed); - ::new (storage.addr()) T(t1); - constructed = true; - } - - template - void construct(const T1& t1, const T2& t2) { - MOZ_ASSERT(!constructed); - ::new (storage.addr()) T(t1, t2); - constructed = true; - } - - template - void construct(const T1& t1, const T2& t2, const T3& t3) { - MOZ_ASSERT(!constructed); - ::new (storage.addr()) T(t1, t2, t3); - constructed = true; - } - - template - void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4) { - MOZ_ASSERT(!constructed); - ::new (storage.addr()) T(t1, t2, t3, t4); - constructed = true; - } - - T* addr() { - MOZ_ASSERT(constructed); - return &asT(); - } - - T& ref() { - MOZ_ASSERT(constructed); - return asT(); - } - - const T& ref() const { - MOZ_ASSERT(constructed); - return const_cast(this)->asT(); - } - - void destroy() { - ref().~T(); - constructed = false; - } - - void destroyIfConstructed() { - if (!empty()) - destroy(); - } - - private: - Maybe(const Maybe& other) MOZ_DELETE; - const Maybe& operator=(const Maybe& other) MOZ_DELETE; -}; - -/* - * Safely subtract two pointers when it is known that end >= begin. This avoids - * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB - * set, the unsigned subtraction followed by right shift will produce -1, or - * size_t(-1), instead of the real difference. - */ -template -MOZ_ALWAYS_INLINE size_t -PointerRangeSize(T* begin, T* end) -{ - MOZ_ASSERT(end >= begin); - return (size_t(end) - size_t(begin)) / sizeof(T); -} - -/* - * Compute the length of an array with constant length. (Use of this method - * with a non-array pointer will not compile.) - * - * Beware of the implicit trailing '\0' when using this with string constants. - */ -template -MOZ_CONSTEXPR size_t -ArrayLength(T (&arr)[N]) -{ - return N; -} - -/* - * Compute the address one past the last element of a constant-length array. - * - * Beware of the implicit trailing '\0' when using this with string constants. - */ -template -MOZ_CONSTEXPR T* -ArrayEnd(T (&arr)[N]) -{ - return arr + ArrayLength(arr); -} - -} /* namespace mozilla */ - -#endif /* __cplusplus */ - -/* - * MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files - * that can't use C++ template functions and for MOZ_STATIC_ASSERT() calls that - * can't call ArrayLength() when it is not a C++11 constexpr function. - */ -#ifdef MOZ_HAVE_CXX11_CONSTEXPR -# define MOZ_ARRAY_LENGTH(array) mozilla::ArrayLength(array) -#else -# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) -#endif - -#endif /* mozilla_Util_h_ */ diff --git a/libazure/include/mozilla/fallible.h b/libazure/include/mozilla/fallible.h deleted file mode 100644 index 0eedd11..0000000 --- a/libazure/include/mozilla/fallible.h +++ /dev/null @@ -1,14 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_fallible_h -#define mozilla_fallible_h - -namespace mozilla { - -struct fallible_t { }; - -} // namespace mozilla - -#endif // mozilla_fallible_h diff --git a/libazure/include/mozilla/gfx/2D.h b/libazure/include/mozilla/gfx/2D.h deleted file mode 100644 index d936dba..0000000 --- a/libazure/include/mozilla/gfx/2D.h +++ /dev/null @@ -1,956 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef _MOZILLA_GFX_2D_H -#define _MOZILLA_GFX_2D_H - -#include "Types.h" -#include "Point.h" -#include "Rect.h" -#include "Matrix.h" -#include "UserData.h" -// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T** -// outparams using the &-operator. But it will have to do as there's no easy -// solution. -#include "mozilla/RefPtr.h" - -#ifdef MOZ_ENABLE_FREETYPE -#include -#endif - -struct _cairo_surface; -typedef _cairo_surface cairo_surface_t; - -struct _cairo_scaled_font; -typedef _cairo_scaled_font cairo_scaled_font_t; - -struct ID3D10Device1; -struct ID3D10Texture2D; -struct IDWriteRenderingParams; - -class GrContext; - -namespace mozilla { - -namespace gfx { - -class SourceSurface; -class DataSourceSurface; -class DrawTarget; -class DrawEventRecorder; - -struct NativeSurface { - NativeSurfaceType mType; - SurfaceFormat mFormat; - void *mSurface; -}; - -struct NativeFont { - NativeFontType mType; - void *mFont; -}; - -/* - * This structure is used to send draw options that are universal to all drawing - * operations. It consists of the following: - * - * mAlpha - Alpha value by which the mask generated by this operation is - * multiplied. - * mCompositionOp - The operator that indicates how the source and destination - * patterns are blended. - * mAntiAliasMode - The AntiAlias mode used for this drawing operation. - * mSnapping - Whether this operation is snapped to pixel boundaries. - */ -struct DrawOptions { - DrawOptions(Float aAlpha = 1.0f, - CompositionOp aCompositionOp = OP_OVER, - AntialiasMode aAntialiasMode = AA_DEFAULT, - Snapping aSnapping = SNAP_NONE) - : mAlpha(aAlpha) - , mCompositionOp(aCompositionOp) - , mAntialiasMode(aAntialiasMode) - , mSnapping(aSnapping) - {} - - Float mAlpha; - CompositionOp mCompositionOp : 8; - AntialiasMode mAntialiasMode : 3; - Snapping mSnapping : 1; -}; - -/* - * This structure is used to send stroke options that are used in stroking - * operations. It consists of the following: - * - * mLineWidth - Width of the stroke in userspace. - * mLineJoin - Join style used for joining lines. - * mLineCap - Cap style used for capping lines. - * mMiterLimit - Miter limit in units of linewidth - * mDashPattern - Series of on/off userspace lengths defining dash. - * Owned by the caller; must live at least as long as - * this StrokeOptions. - * mDashPattern != null <=> mDashLength > 0. - * mDashLength - Number of on/off lengths in mDashPattern. - * mDashOffset - Userspace offset within mDashPattern at which stroking - * begins. - */ -struct StrokeOptions { - StrokeOptions(Float aLineWidth = 1.0f, - JoinStyle aLineJoin = JOIN_MITER_OR_BEVEL, - CapStyle aLineCap = CAP_BUTT, - Float aMiterLimit = 10.0f, - size_t aDashLength = 0, - const Float* aDashPattern = 0, - Float aDashOffset = 0.f) - : mLineWidth(aLineWidth) - , mMiterLimit(aMiterLimit) - , mDashPattern(aDashLength > 0 ? aDashPattern : 0) - , mDashLength(aDashLength) - , mDashOffset(aDashOffset) - , mLineJoin(aLineJoin) - , mLineCap(aLineCap) - { - MOZ_ASSERT(aDashLength == 0 || aDashPattern); - } - - Float mLineWidth; - Float mMiterLimit; - const Float* mDashPattern; - size_t mDashLength; - Float mDashOffset; - JoinStyle mLineJoin : 4; - CapStyle mLineCap : 3; -}; - -/* - * This structure supplies additional options for calls to DrawSurface. - * - * mFilter - Filter used when resampling source surface region to the - * destination region. - * aSamplingBounds - This indicates whether the implementation is allowed - * to sample pixels outside the source rectangle as - * specified in DrawSurface on the surface. - */ -struct DrawSurfaceOptions { - DrawSurfaceOptions(Filter aFilter = FILTER_LINEAR, - SamplingBounds aSamplingBounds = SAMPLING_UNBOUNDED) - : mFilter(aFilter) - , mSamplingBounds(aSamplingBounds) - { } - - Filter mFilter : 3; - SamplingBounds mSamplingBounds : 1; -}; - -/* - * This class is used to store gradient stops, it can only be used with a - * matching DrawTarget. Not adhering to this condition will make a draw call - * fail. - */ -class GradientStops : public RefCounted -{ -public: - virtual ~GradientStops() {} - - virtual BackendType GetBackendType() const = 0; - -protected: - GradientStops() {} -}; - -/* - * This is the base class for 'patterns'. Patterns describe the pixels used as - * the source for a masked composition operation that is done by the different - * drawing commands. These objects are not backend specific, however for - * example the gradient stops on a gradient pattern can be backend specific. - */ -class Pattern -{ -public: - virtual ~Pattern() {} - - virtual PatternType GetType() const = 0; - -protected: - Pattern() {} -}; - -class ColorPattern : public Pattern -{ -public: - ColorPattern(const Color &aColor) - : mColor(aColor) - {} - - virtual PatternType GetType() const { return PATTERN_COLOR; } - - Color mColor; -}; - -/* - * This class is used for Linear Gradient Patterns, the gradient stops are - * stored in a separate object and are backend dependent. This class itself - * may be used on the stack. - */ -class LinearGradientPattern : public Pattern -{ -public: - /* - * aBegin Start of the linear gradient - * aEnd End of the linear gradient - NOTE: In the case of a zero length - * gradient it will act as the color of the last stop. - * aStops GradientStops object for this gradient, this should match the - * backend type of the draw target this pattern will be used with. - * aMatrix A matrix that transforms the pattern into user space - */ - LinearGradientPattern(const Point &aBegin, - const Point &aEnd, - GradientStops *aStops, - const Matrix &aMatrix = Matrix()) - : mBegin(aBegin) - , mEnd(aEnd) - , mStops(aStops) - , mMatrix(aMatrix) - { - } - - virtual PatternType GetType() const { return PATTERN_LINEAR_GRADIENT; } - - Point mBegin; - Point mEnd; - RefPtr mStops; - Matrix mMatrix; -}; - -/* - * This class is used for Radial Gradient Patterns, the gradient stops are - * stored in a separate object and are backend dependent. This class itself - * may be used on the stack. - */ -class RadialGradientPattern : public Pattern -{ -public: - /* - * aBegin Start of the linear gradient - * aEnd End of the linear gradient - * aStops GradientStops object for this gradient, this should match the - * backend type of the draw target this pattern will be used with. - * aMatrix A matrix that transforms the pattern into user space - */ - RadialGradientPattern(const Point &aCenter1, - const Point &aCenter2, - Float aRadius1, - Float aRadius2, - GradientStops *aStops, - const Matrix &aMatrix = Matrix()) - : mCenter1(aCenter1) - , mCenter2(aCenter2) - , mRadius1(aRadius1) - , mRadius2(aRadius2) - , mStops(aStops) - , mMatrix(aMatrix) - { - } - - virtual PatternType GetType() const { return PATTERN_RADIAL_GRADIENT; } - - Point mCenter1; - Point mCenter2; - Float mRadius1; - Float mRadius2; - RefPtr mStops; - Matrix mMatrix; -}; - -/* - * This class is used for Surface Patterns, they wrap a surface and a - * repetition mode for the surface. This may be used on the stack. - */ -class SurfacePattern : public Pattern -{ -public: - /* - * aSourceSurface Surface to use for drawing - * aExtendMode This determines how the image is extended outside the bounds - * of the image. - * aMatrix A matrix that transforms the pattern into user space - * aFilter Resampling filter used for resampling the image. - */ - SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode, - const Matrix &aMatrix = Matrix(), Filter aFilter = FILTER_LINEAR) - : mSurface(aSourceSurface) - , mExtendMode(aExtendMode) - , mFilter(aFilter) - , mMatrix(aMatrix) - {} - - virtual PatternType GetType() const { return PATTERN_SURFACE; } - - RefPtr mSurface; - ExtendMode mExtendMode; - Filter mFilter; - Matrix mMatrix; -}; - -/* - * This is the base class for source surfaces. These objects are surfaces - * which may be used as a source in a SurfacePattern of a DrawSurface call. - * They cannot be drawn to directly. - */ -class SourceSurface : public RefCounted -{ -public: - virtual ~SourceSurface() {} - - virtual SurfaceType GetType() const = 0; - virtual IntSize GetSize() const = 0; - virtual SurfaceFormat GetFormat() const = 0; - - /* This returns false if some event has made this source surface invalid for - * usage with current DrawTargets. For example in the case of Direct2D this - * could return false if we have switched devices since this surface was - * created. - */ - virtual bool IsValid() const { return true; } - - /* - * This function will get a DataSourceSurface for this surface, a - * DataSourceSurface's data can be accessed directly. - */ - virtual TemporaryRef GetDataSurface() = 0; -}; - -class DataSourceSurface : public SourceSurface -{ -public: - virtual SurfaceType GetType() const { return SURFACE_DATA; } - /* - * Get the raw bitmap data of the surface. - * Can return null if there was OOM allocating surface data. - */ - virtual uint8_t *GetData() = 0; - - /* - * Stride of the surface, distance in bytes between the start of the image - * data belonging to row y and row y+1. This may be negative. - * Can return 0 if there was OOM allocating surface data. - */ - virtual int32_t Stride() = 0; - - /* - * This function is called after modifying the data on the source surface - * directly through the data pointer. - */ - virtual void MarkDirty() {} - - virtual TemporaryRef GetDataSurface() { RefPtr temp = this; return temp.forget(); } -}; - -/* This is an abstract object that accepts path segments. */ -class PathSink : public RefCounted -{ -public: - virtual ~PathSink() {} - - /* Move the current point in the path, any figure currently being drawn will - * be considered closed during fill operations, however when stroking the - * closing line segment will not be drawn. - */ - virtual void MoveTo(const Point &aPoint) = 0; - /* Add a linesegment to the current figure */ - virtual void LineTo(const Point &aPoint) = 0; - /* Add a cubic bezier curve to the current figure */ - virtual void BezierTo(const Point &aCP1, - const Point &aCP2, - const Point &aCP3) = 0; - /* Add a quadratic bezier curve to the current figure */ - virtual void QuadraticBezierTo(const Point &aCP1, - const Point &aCP2) = 0; - /* Close the current figure, this will essentially generate a line segment - * from the current point to the starting point for the current figure - */ - virtual void Close() = 0; - /* Add an arc to the current figure */ - virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, - float aEndAngle, bool aAntiClockwise = false) = 0; - /* Point the current subpath is at - or where the next subpath will start - * if there is no active subpath. - */ - virtual Point CurrentPoint() const = 0; -}; - -class PathBuilder; - -/* The path class is used to create (sets of) figures of any shape that can be - * filled or stroked to a DrawTarget - */ -class Path : public RefCounted -{ -public: - virtual ~Path() {} - - virtual BackendType GetBackendType() const = 0; - - /* This returns a PathBuilder object that contains a copy of the contents of - * this path and is still writable. - */ - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const = 0; - virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const = 0; - - /* This function checks if a point lies within a path. It allows passing a - * transform that will transform the path to the coordinate space in which - * aPoint is given. - */ - virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0; - - - /* This function checks if a point lies within the stroke of a path using the - * specified strokeoptions. It allows passing a transform that will transform - * the path to the coordinate space in which aPoint is given. - */ - virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, - const Point &aPoint, - const Matrix &aTransform) const = 0; - - /* This functions gets the bounds of this path. These bounds are not - * guaranteed to be tight. A transform may be specified that gives the bounds - * after application of the transform. - */ - virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const = 0; - - /* This function gets the bounds of the stroke of this path using the - * specified strokeoptions. These bounds are not guaranteed to be tight. - * A transform may be specified that gives the bounds after application of - * the transform. - */ - virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, - const Matrix &aTransform = Matrix()) const = 0; - - /* This gets the fillrule this path's builder was created with. This is not - * mutable. - */ - virtual FillRule GetFillRule() const = 0; -}; - -/* The PathBuilder class allows path creation. Once finish is called on the - * pathbuilder it may no longer be written to. - */ -class PathBuilder : public PathSink -{ -public: - /* Finish writing to the path and return a Path object that can be used for - * drawing. Future use of the builder results in a crash! - */ - virtual TemporaryRef Finish() = 0; -}; - -struct Glyph -{ - uint32_t mIndex; - Point mPosition; -}; - -/* This class functions as a glyph buffer that can be drawn to a DrawTarget. - * XXX - This should probably contain the guts of gfxTextRun in the future as - * roc suggested. But for now it's a simple container for a glyph vector. - */ -struct GlyphBuffer -{ - // A pointer to a buffer of glyphs. Managed by the caller. - const Glyph *mGlyphs; - // Number of glyphs mGlyphs points to. - uint32_t mNumGlyphs; -}; - -/* This class is an abstraction of a backend/platform specific font object - * at a particular size. It is passed into text drawing calls to describe - * the font used for the drawing call. - */ -class ScaledFont : public RefCounted -{ -public: - virtual ~ScaledFont() {} - - typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton); - - virtual FontType GetType() const = 0; - - /* This allows getting a path that describes the outline of a set of glyphs. - * A target is passed in so that the guarantee is made the returned path - * can be used with any DrawTarget that has the same backend as the one - * passed in. - */ - virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0; - - /* This copies the path describing the glyphs into a PathBuilder. We use this - * API rather than a generic API to append paths because it allows easier - * implementation in some backends, and more efficient implementation in - * others. - */ - virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder) = 0; - - virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; } - - void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { - mUserData.Add(key, userData, destroy); - } - void *GetUserData(UserDataKey *key) { - return mUserData.Get(key); - } - -protected: - ScaledFont() {} - - UserData mUserData; -}; - -#ifdef MOZ_ENABLE_FREETYPE -/** - * Describes a font - * Used to pass the key informatin from a gfxFont into Azure - * XXX Should be replaced by a more long term solution, perhaps Bug 738014 - */ -struct FontOptions -{ - std::string mName; - FontStyle mStyle; - uint8_t *mData; - uint32_t mDataSize; -}; -#endif - - -/* This class is designed to allow passing additional glyph rendering - * parameters to the glyph drawing functions. This is an empty wrapper class - * merely used to allow holding on to and passing around platform specific - * parameters. This is because different platforms have unique rendering - * parameters. - */ -class GlyphRenderingOptions : public RefCounted -{ -public: - virtual ~GlyphRenderingOptions() {} - - virtual FontType GetType() const = 0; - -protected: - GlyphRenderingOptions() {} -}; - -/* This is the main class used for all the drawing. It is created through the - * factory and accepts drawing commands. The results of drawing to a target - * may be used either through a Snapshot or by flushing the target and directly - * accessing the backing store a DrawTarget was created with. - */ -class DrawTarget : public RefCounted -{ -public: - DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {} - virtual ~DrawTarget() {} - - virtual BackendType GetType() const = 0; - /** - * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget. - * Multiple calls to Snapshot() without any drawing operations in between will - * normally return the same SourceSurface object. - */ - virtual TemporaryRef Snapshot() = 0; - virtual IntSize GetSize() = 0; - - /* Ensure that the DrawTarget backend has flushed all drawing operations to - * this draw target. This must be called before using the backing surface of - * this draw target outside of GFX 2D code. - */ - virtual void Flush() = 0; - - /* - * Draw a surface to the draw target. Possibly doing partial drawing or - * applying scaling. No sampling happens outside the source. - * - * aSurface Source surface to draw - * aDest Destination rectangle that this drawing operation should draw to - * aSource Source rectangle in aSurface coordinates, this area of aSurface - * will be stretched to the size of aDest. - * aOptions General draw options that are applied to the operation - * aSurfOptions DrawSurface options that are applied - */ - virtual void DrawSurface(SourceSurface *aSurface, - const Rect &aDest, - const Rect &aSource, - const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Blend a surface to the draw target with a shadow. The shadow is drawn as a - * gaussian blur using a specified sigma. The shadow is clipped to the size - * of the input surface, so the input surface should contain a transparent - * border the size of the approximate coverage of the blur (3 * aSigma). - * NOTE: This function works in device space! - * - * aSurface Source surface to draw. - * aDest Destination point that this drawing operation should draw to. - * aColor Color of the drawn shadow - * aOffset Offset of the shadow - * aSigma Sigma used for the guassian filter kernel - * aOperator Composition operator used - */ - virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, - const Point &aDest, - const Color &aColor, - const Point &aOffset, - Float aSigma, - CompositionOp aOperator) = 0; - - /* - * Clear a rectangle on the draw target to transparent black. This will - * respect the clipping region and transform. - * - * aRect Rectangle to clear - */ - virtual void ClearRect(const Rect &aRect) = 0; - - /* - * This is essentially a 'memcpy' between two surfaces. It moves a pixel - * aligned area from the source surface unscaled directly onto the - * drawtarget. This ignores both transform and clip. - * - * aSurface Surface to copy from - * aSourceRect Source rectangle to be copied - * aDest Destination point to copy the surface to - */ - virtual void CopySurface(SourceSurface *aSurface, - const IntRect &aSourceRect, - const IntPoint &aDestination) = 0; - - /* - * Fill a rectangle on the DrawTarget with a certain source pattern. - * - * aRect Rectangle that forms the mask of this filling operation - * aPattern Pattern that forms the source of this filling operation - * aOptions Options that are applied to this operation - */ - virtual void FillRect(const Rect &aRect, - const Pattern &aPattern, - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Stroke a rectangle on the DrawTarget with a certain source pattern. - * - * aRect Rectangle that forms the mask of this stroking operation - * aPattern Pattern that forms the source of this stroking operation - * aOptions Options that are applied to this operation - */ - virtual void StrokeRect(const Rect &aRect, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions = StrokeOptions(), - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Stroke a line on the DrawTarget with a certain source pattern. - * - * aStart Starting point of the line - * aEnd End point of the line - * aPattern Pattern that forms the source of this stroking operation - * aOptions Options that are applied to this operation - */ - virtual void StrokeLine(const Point &aStart, - const Point &aEnd, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions = StrokeOptions(), - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Stroke a path on the draw target with a certain source pattern. - * - * aPath Path that is to be stroked - * aPattern Pattern that should be used for the stroke - * aStrokeOptions Stroke options used for this operation - * aOptions Draw options used for this operation - */ - virtual void Stroke(const Path *aPath, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions = StrokeOptions(), - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Fill a path on the draw target with a certain source pattern. - * - * aPath Path that is to be filled - * aPattern Pattern that should be used for the fill - * aOptions Draw options used for this operation - */ - virtual void Fill(const Path *aPath, - const Pattern &aPattern, - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Fill a series of clyphs on the draw target with a certain source pattern. - */ - virtual void FillGlyphs(ScaledFont *aFont, - const GlyphBuffer &aBuffer, - const Pattern &aPattern, - const DrawOptions &aOptions = DrawOptions(), - const GlyphRenderingOptions *aRenderingOptions = NULL) = 0; - - /* - * This takes a source pattern and a mask, and composites the source pattern - * onto the destination surface using the alpha channel of the mask pattern - * as a mask for the operation. - * - * aSource Source pattern - * aMask Mask pattern - * aOptions Drawing options - */ - virtual void Mask(const Pattern &aSource, - const Pattern &aMask, - const DrawOptions &aOptions = DrawOptions()) = 0; - - /* - * Push a clip to the DrawTarget. - * - * aPath The path to clip to - */ - virtual void PushClip(const Path *aPath) = 0; - - /* - * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle - * is specified in user space. - * - * aRect The rect to clip to - */ - virtual void PushClipRect(const Rect &aRect) = 0; - - /* Pop a clip from the DrawTarget. A pop without a corresponding push will - * be ignored. - */ - virtual void PopClip() = 0; - - /* - * Create a SourceSurface optimized for use with this DrawTarget from - * existing bitmap data in memory. - * - * The SourceSurface does not take ownership of aData, and may be freed at any time. - */ - virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) const = 0; - - /* - * Create a SourceSurface optimized for use with this DrawTarget from - * an arbitrary other SourceSurface. This may return aSourceSurface or some - * other existing surface. - */ - virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const = 0; - - /* - * Create a SourceSurface for a type of NativeSurface. This may fail if the - * draw target does not know how to deal with the type of NativeSurface passed - * in. - */ - virtual TemporaryRef - CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const = 0; - - /* - * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget. - */ - virtual TemporaryRef - CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0; - - /* - * Create a draw target optimized for drawing a shadow. - * - * Note that aSigma is the blur radius that must be used when we draw the - * shadow. Also note that this doesn't affect the size of the allocated - * surface, the caller is still responsible for including the shadow area in - * its size. - */ - virtual TemporaryRef - CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat, - float aSigma) const - { - return CreateSimilarDrawTarget(aSize, aFormat); - } - - /* - * Create a path builder with the specified fillmode. - * - * We need the fill mode up front because of Direct2D. - * ID2D1SimplifiedGeometrySink requires the fill mode - * to be set before calling BeginFigure(). - */ - virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const = 0; - - /* - * Create a GradientStops object that holds information about a set of - * gradient stops, this object is required for linear or radial gradient - * patterns to represent the color stops in the gradient. - * - * aStops An array of gradient stops - * aNumStops Number of stops in the array aStops - * aExtendNone This describes how to extend the stop color outside of the - * gradient area. - */ - virtual TemporaryRef - CreateGradientStops(GradientStop *aStops, - uint32_t aNumStops, - ExtendMode aExtendMode = EXTEND_CLAMP) const = 0; - - const Matrix &GetTransform() const { return mTransform; } - - /* - * Set a transform on the surface, this transform is applied at drawing time - * to both the mask and source of the operation. - */ - virtual void SetTransform(const Matrix &aTransform) - { mTransform = aTransform; mTransformDirty = true; } - - SurfaceFormat GetFormat() { return mFormat; } - - /* Tries to get a native surface for a DrawTarget, this may fail if the - * draw target cannot convert to this surface type. - */ - virtual void *GetNativeSurface(NativeSurfaceType aType) { return NULL; } - - void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { - mUserData.Add(key, userData, destroy); - } - void *GetUserData(UserDataKey *key) { - return mUserData.Get(key); - } - - /* Within this rectangle all pixels will be opaque by the time the result of - * this DrawTarget is first used for drawing. Either by the underlying surface - * being used as an input to external drawing, or Snapshot() being called. - * This rectangle is specified in device space. - */ - void SetOpaqueRect(const IntRect &aRect) { - mOpaqueRect = aRect; - } - - const IntRect &GetOpaqueRect() const { - return mOpaqueRect; - } - - void SetPermitSubpixelAA(bool aPermitSubpixelAA) { - mPermitSubpixelAA = aPermitSubpixelAA; - } - - bool GetPermitSubpixelAA() { - return mPermitSubpixelAA; - } - -protected: - UserData mUserData; - Matrix mTransform; - IntRect mOpaqueRect; - bool mTransformDirty : 1; - bool mPermitSubpixelAA : 1; - - SurfaceFormat mFormat; -}; - -class DrawEventRecorder : public RefCounted -{ -public: - virtual ~DrawEventRecorder() { } -}; - -class GFX2D_API Factory -{ -public: - static bool HasSSE2(); - - static TemporaryRef CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize); - - static TemporaryRef - CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); - - static TemporaryRef - CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT); - - static TemporaryRef - CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat); - - static TemporaryRef - CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize); - - /** - * This creates a ScaledFont from TrueType data. - * - * aData - Pointer to the data - * aSize - Size of the TrueType data - * aFaceIndex - Index of the font face in the truetype data this ScaledFont needs to represent. - * aGlyphSize - Size of the glyphs in this ScaledFont - * aType - Type of ScaledFont that should be created. - */ - static TemporaryRef - CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, uint32_t aFaceIndex, Float aGlyphSize, FontType aType); - - /* - * This creates a scaled font with an associated cairo_scaled_font_t, and - * must be used when using the Cairo backend. The NativeFont and - * cairo_scaled_font_t* parameters must correspond to the same font. - */ - static TemporaryRef - CreateScaledFontWithCairo(const NativeFont &aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont); - - /* - * This creates a simple data source surface for a certain size. It allocates - * new memory for the surface. This memory is freed when the surface is - * destroyed. - */ - static TemporaryRef - CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat); - - /* - * This creates a simple data source surface for some existing data. It will - * wrap this data and the data for this source surface. The caller is - * responsible for deallocating the memory only after destruction of the - * surface. - */ - static TemporaryRef - CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride, - const IntSize &aSize, SurfaceFormat aFormat); - - static TemporaryRef - CreateEventRecorderForFile(const char *aFilename); - - static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder); - -#ifdef USE_SKIA_GPU - static TemporaryRef - CreateSkiaDrawTargetForFBO(unsigned int aFBOID, GrContext *aContext, const IntSize &aSize, SurfaceFormat aFormat); -#endif - -#ifdef WIN32 - static TemporaryRef CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat); - static TemporaryRef - CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA, - ID3D10Texture2D *aTextureB, - SurfaceFormat aFormat); - - static void SetDirect3D10Device(ID3D10Device1 *aDevice); - static ID3D10Device1 *GetDirect3D10Device(); - - static TemporaryRef - CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams); - - static uint64_t GetD2DVRAMUsageDrawTarget(); - static uint64_t GetD2DVRAMUsageSourceSurface(); - static void D2DCleanup(); - -private: - static ID3D10Device1 *mD3D10Device; -#endif - - static DrawEventRecorder *mRecorder; -}; - -} -} - -#endif // _MOZILLA_GFX_2D_H diff --git a/libazure/include/mozilla/gfx/MacIOSurface.h b/libazure/include/mozilla/gfx/MacIOSurface.h deleted file mode 100644 index ff4a13a..0000000 --- a/libazure/include/mozilla/gfx/MacIOSurface.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -// vim:set ts=2 sts=2 sw=2 et cin: -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MacIOSurface_h__ -#define MacIOSurface_h__ -#ifdef XP_MACOSX - -#import -#include "2D.h" -#include "mozilla/RefPtr.h" - -class gfxASurface; -struct _CGLContextObject; - -typedef _CGLContextObject* CGLContextObj; -typedef struct CGContext* CGContextRef; -typedef struct CGImage* CGImageRef; -typedef uint32_t IOSurfaceID; - -class MacIOSurface : public mozilla::RefCounted { -public: - typedef mozilla::gfx::SourceSurface SourceSurface; - - static mozilla::TemporaryRef CreateIOSurface(int aWidth, int aHeight, - double aContentsScaleFactor = 1.0); - static void ReleaseIOSurface(MacIOSurface *aIOSurface); - static mozilla::TemporaryRef LookupSurface(IOSurfaceID aSurfaceID, - double aContentsScaleFactor = 1.0); - - MacIOSurface(const void *aIOSurfacePtr, double aContentsScaleFactor = 1.0) - : mIOSurfacePtr(aIOSurfacePtr), mContentsScaleFactor(aContentsScaleFactor) {} - ~MacIOSurface(); - IOSurfaceID GetIOSurfaceID(); - void *GetBaseAddress(); - // GetWidth() and GetHeight() return values in "display pixels". A - // "display pixel" is the smallest fully addressable part of a display. - // But in HiDPI modes each "display pixel" corresponds to more than one - // device pixel. Multiply display pixels by mContentsScaleFactor to - // get device pixels. - size_t GetWidth(); - size_t GetHeight(); - double GetContentsScaleFactor() { return mContentsScaleFactor; } - size_t GetBytesPerRow(); - void Lock(); - void Unlock(); - // We would like to forward declare NSOpenGLContext, but it is an @interface - // and this file is also used from c++, so we use a void *. - CGLError CGLTexImageIOSurface2D(void *ctxt, - GLenum internalFormat, GLenum format, - GLenum type, GLuint plane); - mozilla::TemporaryRef GetAsSurface(); - CGContextRef CreateIOSurfaceContext(); - - // FIXME This doesn't really belong here - static CGImageRef CreateImageFromIOSurfaceContext(CGContextRef aContext); - static mozilla::TemporaryRef IOSurfaceContextGetSurface(CGContextRef aContext, - double aContentsScaleFactor = 1.0); - -private: - friend class nsCARenderer; - const void* mIOSurfacePtr; - double mContentsScaleFactor; -}; - -#endif -#endif diff --git a/libazure/include/mozilla/gfx/Matrix.h b/libazure/include/mozilla/gfx/Matrix.h deleted file mode 100644 index 99431e0..0000000 --- a/libazure/include/mozilla/gfx/Matrix.h +++ /dev/null @@ -1,174 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_MATRIX_H_ -#define MOZILLA_GFX_MATRIX_H_ - -#include "Types.h" -#include "Rect.h" -#include "Point.h" -#include - -namespace mozilla { -namespace gfx { - -class Matrix -{ -public: - Matrix() - : _11(1.0f), _12(0) - , _21(0), _22(1.0f) - , _31(0), _32(0) - {} - Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32) - : _11(a11), _12(a12) - , _21(a21), _22(a22) - , _31(a31), _32(a32) - {} - Float _11, _12; - Float _21, _22; - Float _31, _32; - - Point operator *(const Point &aPoint) const - { - Point retPoint; - - retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31; - retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32; - - return retPoint; - } - - Size operator *(const Size &aSize) const - { - Size retSize; - - retSize.width = aSize.width * _11 + aSize.height * _21; - retSize.height = aSize.width * _12 + aSize.height * _22; - - return retSize; - } - - GFX2D_API Rect TransformBounds(const Rect& rect) const; - - // Apply a scale to this matrix. This scale will be applied -before- the - // existing transformation of the matrix. - Matrix &Scale(Float aX, Float aY) - { - _11 *= aX; - _12 *= aX; - _21 *= aY; - _22 *= aY; - - return *this; - } - - Matrix &Translate(Float aX, Float aY) - { - _31 += _11 * aX + _21 * aY; - _32 += _12 * aX + _22 * aY; - - return *this; - } - - bool Invert() - { - // Compute co-factors. - Float A = _22; - Float B = -_21; - Float C = _21 * _32 - _22 * _31; - Float D = -_12; - Float E = _11; - Float F = _31 * _12 - _11 * _32; - - Float det = Determinant(); - - if (!det) { - return false; - } - - Float inv_det = 1 / det; - - _11 = inv_det * A; - _12 = inv_det * D; - _21 = inv_det * B; - _22 = inv_det * E; - _31 = inv_det * C; - _32 = inv_det * F; - - return true; - } - - Float Determinant() const - { - return _11 * _22 - _12 * _21; - } - - GFX2D_API static Matrix Rotation(Float aAngle); - - Matrix operator*(const Matrix &aMatrix) const - { - Matrix resultMatrix; - - resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21; - resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22; - resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21; - resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22; - resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31; - resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32; - - return resultMatrix; - } - - /* Returns true if the other matrix is fuzzy-equal to this matrix. - * Note that this isn't a cheap comparison! - */ - bool operator==(const Matrix& other) const - { - return FuzzyEqual(_11, other._11) && FuzzyEqual(_12, other._12) && - FuzzyEqual(_21, other._21) && FuzzyEqual(_22, other._22) && - FuzzyEqual(_31, other._31) && FuzzyEqual(_32, other._32); - } - - bool operator!=(const Matrix& other) const - { - return !(*this == other); - } - - /* Returns true if the matrix is a rectilinear transformation (i.e. - * grid-aligned rectangles are transformed to grid-aligned rectangles) - */ - bool IsRectilinear() const { - if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) { - return true; - } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) { - return true; - } - - return false; - } - - /* Returns true if the matrix is an identity matrix. - */ - bool IsIdentity() const - { - return _11 == 1.0f && _12 == 0.0f && - _21 == 0.0f && _22 == 1.0f && - _31 == 0.0f && _32 == 0.0f; - } - - GFX2D_API void NudgeToIntegers(); - -private: - static bool FuzzyEqual(Float aV1, Float aV2) { - // XXX - Check if fabs does the smart thing and just negates the sign bit. - return fabs(aV2 - aV1) < 1e-6; - } -}; - -} -} - -#endif /* MOZILLA_GFX_MATRIX_H_ */ diff --git a/libazure/include/mozilla/gfx/Point.h b/libazure/include/mozilla/gfx/Point.h deleted file mode 100644 index 79b06eb..0000000 --- a/libazure/include/mozilla/gfx/Point.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_POINT_H_ -#define MOZILLA_GFX_POINT_H_ - -#include "Types.h" -#include "BasePoint.h" -#include "BaseSize.h" - -namespace mozilla { -namespace gfx { - -struct IntPoint : - public BasePoint { - typedef BasePoint Super; - - IntPoint() : Super() {} - IntPoint(int32_t aX, int32_t aY) : Super(aX, aY) {} -}; - -struct Point : - public BasePoint { - typedef BasePoint Super; - - Point() : Super() {} - Point(Float aX, Float aY) : Super(aX, aY) {} - Point(const IntPoint& point) : Super(float(point.x), float(point.y)) {} -}; - -struct IntSize : - public BaseSize { - typedef BaseSize Super; - - IntSize() : Super() {} - IntSize(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {} -}; - -struct Size : - public BaseSize { - typedef BaseSize Super; - - Size() : Super() {} - Size(Float aWidth, Float aHeight) : Super(aWidth, aHeight) {} - explicit Size(const IntSize& size) : - Super(float(size.width), float(size.height)) {} -}; - -} -} - -#endif /* MOZILLA_GFX_POINT_H_ */ diff --git a/libazure/include/mozilla/gfx/Rect.h b/libazure/include/mozilla/gfx/Rect.h deleted file mode 100644 index 8946222..0000000 --- a/libazure/include/mozilla/gfx/Rect.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_RECT_H_ -#define MOZILLA_GFX_RECT_H_ - -#include "BaseRect.h" -#include "BaseMargin.h" -#include "Point.h" - -namespace mozilla { -namespace gfx { - -struct Margin : - public BaseMargin { - typedef BaseMargin Super; - - // Constructors - Margin() : Super(0, 0, 0, 0) {} - Margin(const Margin& aMargin) : Super(aMargin) {} - Margin(Float aTop, Float aRight, Float aBottom, Float aLeft) - : Super(aTop, aRight, aBottom, aLeft) {} -}; - -struct IntRect : - public BaseRect { - typedef BaseRect Super; - - IntRect() : Super() {} - IntRect(IntPoint aPos, mozilla::gfx::IntSize aSize) : - Super(aPos, aSize) {} - IntRect(int32_t _x, int32_t _y, int32_t _width, int32_t _height) : - Super(_x, _y, _width, _height) {} - - // Rounding isn't meaningful on an integer rectangle. - void Round() {} - void RoundIn() {} - void RoundOut() {} -}; - -struct Rect : - public BaseRect { - typedef BaseRect Super; - - Rect() : Super() {} - Rect(Point aPos, mozilla::gfx::Size aSize) : - Super(aPos, aSize) {} - Rect(Float _x, Float _y, Float _width, Float _height) : - Super(_x, _y, _width, _height) {} - explicit Rect(const IntRect& rect) : - Super(float(rect.x), float(rect.y), - float(rect.width), float(rect.height)) {} - - GFX2D_API void NudgeToIntegers(); - - bool ToIntRect(IntRect *aOut) - { - *aOut = IntRect(int32_t(X()), int32_t(Y()), - int32_t(Width()), int32_t(Height())); - return Rect(Float(aOut->x), Float(aOut->y), - Float(aOut->width), Float(aOut->height)).IsEqualEdges(*this); - } -}; - -} -} - -#endif /* MOZILLA_GFX_RECT_H_ */ diff --git a/libazure/include/mozilla/gfx/Types.h b/libazure/include/mozilla/gfx/Types.h deleted file mode 100644 index 1d93246..0000000 --- a/libazure/include/mozilla/gfx/Types.h +++ /dev/null @@ -1,168 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_TYPES_H_ -#define MOZILLA_GFX_TYPES_H_ - -#include "mozilla/StandardInteger.h" -#include "mozilla/NullPtr.h" - -#include - -namespace mozilla { -namespace gfx { - -typedef float Float; - -enum SurfaceType -{ - SURFACE_DATA, /* Data surface - bitmap in memory */ - SURFACE_D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */ - SURFACE_D2D1_DRAWTARGET, /* Surface made from a D2D draw target */ - SURFACE_CAIRO, /* Surface wrapping a cairo surface */ - SURFACE_CAIRO_IMAGE, /* Data surface wrapping a cairo image surface */ - SURFACE_COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */ - SURFACE_COREGRAPHICS_CGCONTEXT, /* Surface wrapping a CG context */ - SURFACE_SKIA, /* Surface wrapping a Skia bitmap */ - SURFACE_DUAL_DT, /* Snapshot of a dual drawtarget */ - SURFACE_RECORDING /* Surface used for recording */ -}; - -enum SurfaceFormat -{ - FORMAT_B8G8R8A8, - FORMAT_B8G8R8X8, - FORMAT_R5G6B5, - FORMAT_A8 -}; - -enum BackendType -{ - BACKEND_NONE = 0, - BACKEND_DIRECT2D, - BACKEND_COREGRAPHICS, - BACKEND_COREGRAPHICS_ACCELERATED, - BACKEND_CAIRO, - BACKEND_SKIA, - BACKEND_RECORDING -}; - -enum FontType -{ - FONT_DWRITE, - FONT_GDI, - FONT_MAC, - FONT_SKIA, - FONT_CAIRO, - FONT_COREGRAPHICS -}; - -enum NativeSurfaceType -{ - NATIVE_SURFACE_D3D10_TEXTURE, - NATIVE_SURFACE_CAIRO_SURFACE, - NATIVE_SURFACE_CGCONTEXT, - NATIVE_SURFACE_CGCONTEXT_ACCELERATED -}; - -enum NativeFontType -{ - NATIVE_FONT_DWRITE_FONT_FACE, - NATIVE_FONT_GDI_FONT_FACE, - NATIVE_FONT_MAC_FONT_FACE, - NATIVE_FONT_SKIA_FONT_FACE, - NATIVE_FONT_CAIRO_FONT_FACE -}; - -enum FontStyle -{ - FONT_STYLE_NORMAL, - FONT_STYLE_ITALIC, - FONT_STYLE_BOLD, - FONT_STYLE_BOLD_ITALIC -}; - -enum CompositionOp { OP_OVER, OP_ADD, OP_ATOP, OP_OUT, OP_IN, OP_SOURCE, OP_DEST_IN, OP_DEST_OUT, OP_DEST_OVER, OP_DEST_ATOP, OP_XOR, - OP_MULTIPLY, OP_SCREEN, OP_OVERLAY, OP_DARKEN, OP_LIGHTEN, OP_COLOR_DODGE, OP_COLOR_BURN, OP_HARD_LIGHT, OP_SOFT_LIGHT, OP_DIFFERENCE, OP_EXCLUSION, OP_HUE, OP_SATURATION, OP_COLOR, OP_LUMINOSITY, OP_COUNT }; -enum ExtendMode { EXTEND_CLAMP, EXTEND_REPEAT, EXTEND_REFLECT }; -enum FillRule { FILL_WINDING, FILL_EVEN_ODD }; -enum AntialiasMode { AA_NONE, AA_GRAY, AA_SUBPIXEL, AA_DEFAULT }; -enum Snapping { SNAP_NONE, SNAP_ALIGNED }; -enum Filter { FILTER_LINEAR, FILTER_POINT }; -enum PatternType { PATTERN_COLOR, PATTERN_SURFACE, PATTERN_LINEAR_GRADIENT, PATTERN_RADIAL_GRADIENT }; -enum JoinStyle { JOIN_BEVEL, JOIN_ROUND, JOIN_MITER, JOIN_MITER_OR_BEVEL }; -enum CapStyle { CAP_BUTT, CAP_ROUND, CAP_SQUARE }; -enum SamplingBounds { SAMPLING_UNBOUNDED, SAMPLING_BOUNDED }; - -/* Color is stored in non-premultiplied form */ -struct Color -{ -public: - Color() - : r(0.0f), g(0.0f), b(0.0f), a(0.0f) - {} - Color(Float aR, Float aG, Float aB, Float aA) - : r(aR), g(aG), b(aB), a(aA) - {} - Color(Float aR, Float aG, Float aB) - : r(aR), g(aG), b(aB), a(1.0f) - {} - - static Color FromABGR(uint32_t aColor) - { - Color newColor(((aColor >> 0) & 0xff) * (1.0f / 255.0f), - ((aColor >> 8) & 0xff) * (1.0f / 255.0f), - ((aColor >> 16) & 0xff) * (1.0f / 255.0f), - ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); - - return newColor; - } - - uint32_t ToABGR() const - { - return uint32_t(r * 255.0f) | uint32_t(g * 255.0f) << 8 | - uint32_t(b * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; - } - - Float r, g, b, a; -}; - -struct GradientStop -{ - bool operator<(const GradientStop& aOther) const { - return offset < aOther.offset; - } - - Float offset; - Color color; -}; - -} -} - -#if defined(XP_WIN) && defined(MOZ_GFX) -#ifdef GFX2D_INTERNAL -#define GFX2D_API __declspec(dllexport) -#else -#define GFX2D_API __declspec(dllimport) -#endif -#else -#define GFX2D_API -#endif - -// Side constants for use in various places -namespace mozilla { - namespace css { - enum Side {eSideTop, eSideRight, eSideBottom, eSideLeft}; - } -} - -// XXX - These don't really belong here. But for now this is where they go. -#define NS_SIDE_TOP mozilla::css::eSideTop -#define NS_SIDE_RIGHT mozilla::css::eSideRight -#define NS_SIDE_BOTTOM mozilla::css::eSideBottom -#define NS_SIDE_LEFT mozilla::css::eSideLeft - -#endif /* MOZILLA_GFX_TYPES_H_ */ diff --git a/libazure/include/mozilla/gfx/gl/GLDefs.h b/libazure/include/mozilla/gfx/gl/GLDefs.h deleted file mode 100644 index 8e62c3d..0000000 --- a/libazure/include/mozilla/gfx/gl/GLDefs.h +++ /dev/null @@ -1,3325 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if !defined(LOCALGL_H_) -#define LOCALGL_H_ - -#if !defined(__gltypes_h_) && !defined(__gl_h_) -#define __gltypes_h_ -#define __gl_h_ - -#include - -typedef unsigned int GLenum; -typedef unsigned int GLbitfield; -typedef unsigned int GLuint; -typedef int GLint; -typedef int GLsizei; -typedef char realGLboolean; -typedef signed char GLbyte; -typedef short GLshort; -typedef unsigned char GLubyte; -typedef unsigned short GLushort; -typedef float GLfloat; -typedef float GLclampf; -#ifndef GLdouble_defined -typedef double GLdouble; -#endif -typedef double GLclampd; -typedef void GLvoid; - -typedef char GLchar; -#ifndef __gl2_h_ -typedef ptrdiff_t GLsizeiptr; -typedef ptrdiff_t GLintptr; -#endif - -#endif /* #if !defined(__gltypes_h_) && !defined(__gl_h_) */ - -#include "mozilla/StandardInteger.h" - -// ARB_sync -typedef struct __GLsync* GLsync; -typedef int64_t GLint64; -typedef uint64_t GLuint64; - -// OES_EGL_image (GLES) -typedef void* GLeglImage; - -// EGL types -typedef int EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; -typedef void *EGLConfig; -typedef void *EGLContext; -typedef void *EGLDisplay; -typedef void *EGLSurface; -typedef void *EGLClientBuffer; -typedef void *EGLCastToRelevantPtr; -typedef void *EGLImage; -typedef void *EGLSync; -typedef uint64_t EGLTime; - -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) -#define EGL_NO_CONFIG ((EGLConfig)nullptr) -#define EGL_NO_SYNC ((EGLSync)0) -#define EGL_NO_IMAGE ((EGLImage)0) - -#ifndef GLAPIENTRY -# ifdef WIN32 -# define GLAPIENTRY APIENTRY -# define GLAPI -# else -# define GLAPIENTRY -# define GLAPI -# endif -#endif - -#define LOCAL_GL_VERSION_1_1 1 -#define LOCAL_GL_ACCUM 0x0100 -#define LOCAL_GL_LOAD 0x0101 -#define LOCAL_GL_RETURN 0x0102 -#define LOCAL_GL_MULT 0x0103 -#define LOCAL_GL_ADD 0x0104 -#define LOCAL_GL_NEVER 0x0200 -#define LOCAL_GL_LESS 0x0201 -#define LOCAL_GL_EQUAL 0x0202 -#define LOCAL_GL_LEQUAL 0x0203 -#define LOCAL_GL_GREATER 0x0204 -#define LOCAL_GL_NOTEQUAL 0x0205 -#define LOCAL_GL_GEQUAL 0x0206 -#define LOCAL_GL_ALWAYS 0x0207 -#define LOCAL_GL_CURRENT_BIT 0x00000001 -#define LOCAL_GL_POINT_BIT 0x00000002 -#define LOCAL_GL_LINE_BIT 0x00000004 -#define LOCAL_GL_POLYGON_BIT 0x00000008 -#define LOCAL_GL_POLYGON_STIPPLE_BIT 0x00000010 -#define LOCAL_GL_PIXEL_MODE_BIT 0x00000020 -#define LOCAL_GL_LIGHTING_BIT 0x00000040 -#define LOCAL_GL_FOG_BIT 0x00000080 -#define LOCAL_GL_DEPTH_BUFFER_BIT 0x00000100 -#define LOCAL_GL_ACCUM_BUFFER_BIT 0x00000200 -#define LOCAL_GL_STENCIL_BUFFER_BIT 0x00000400 -#define LOCAL_GL_VIEWPORT_BIT 0x00000800 -#define LOCAL_GL_TRANSFORM_BIT 0x00001000 -#define LOCAL_GL_ENABLE_BIT 0x00002000 -#define LOCAL_GL_COLOR_BUFFER_BIT 0x00004000 -#define LOCAL_GL_HINT_BIT 0x00008000 -#define LOCAL_GL_EVAL_BIT 0x00010000 -#define LOCAL_GL_LIST_BIT 0x00020000 -#define LOCAL_GL_TEXTURE_BIT 0x00040000 -#define LOCAL_GL_SCISSOR_BIT 0x00080000 -#define LOCAL_GL_ALL_ATTRIB_BITS 0x000fffff -#define LOCAL_GL_POINTS 0x0000 -#define LOCAL_GL_LINES 0x0001 -#define LOCAL_GL_LINE_LOOP 0x0002 -#define LOCAL_GL_LINE_STRIP 0x0003 -#define LOCAL_GL_TRIANGLES 0x0004 -#define LOCAL_GL_TRIANGLE_STRIP 0x0005 -#define LOCAL_GL_TRIANGLE_FAN 0x0006 -#define LOCAL_GL_QUADS 0x0007 -#define LOCAL_GL_QUAD_STRIP 0x0008 -#define LOCAL_GL_POLYGON 0x0009 -#define LOCAL_GL_ZERO 0 -#define LOCAL_GL_ONE 1 -#define LOCAL_GL_SRC_COLOR 0x0300 -#define LOCAL_GL_ONE_MINUS_SRC_COLOR 0x0301 -#define LOCAL_GL_SRC_ALPHA 0x0302 -#define LOCAL_GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define LOCAL_GL_DST_ALPHA 0x0304 -#define LOCAL_GL_ONE_MINUS_DST_ALPHA 0x0305 -#define LOCAL_GL_DST_COLOR 0x0306 -#define LOCAL_GL_ONE_MINUS_DST_COLOR 0x0307 -#define LOCAL_GL_SRC_ALPHA_SATURATE 0x0308 -#define LOCAL_GL_TRUE 1 -#define LOCAL_GL_FALSE 0 -#define LOCAL_GL_CLIP_PLANE0 0x3000 -#define LOCAL_GL_CLIP_PLANE1 0x3001 -#define LOCAL_GL_CLIP_PLANE2 0x3002 -#define LOCAL_GL_CLIP_PLANE3 0x3003 -#define LOCAL_GL_CLIP_PLANE4 0x3004 -#define LOCAL_GL_CLIP_PLANE5 0x3005 -#define LOCAL_GL_BYTE 0x1400 -#define LOCAL_GL_UNSIGNED_BYTE 0x1401 -#define LOCAL_GL_SHORT 0x1402 -#define LOCAL_GL_UNSIGNED_SHORT 0x1403 -#define LOCAL_GL_INT 0x1404 -#define LOCAL_GL_UNSIGNED_INT 0x1405 -#define LOCAL_GL_FLOAT 0x1406 -#define LOCAL_GL_2_BYTES 0x1407 -#define LOCAL_GL_3_BYTES 0x1408 -#define LOCAL_GL_4_BYTES 0x1409 -#define LOCAL_GL_DOUBLE 0x140A -#define LOCAL_GL_NONE 0 -#define LOCAL_GL_FRONT_LEFT 0x0400 -#define LOCAL_GL_FRONT_RIGHT 0x0401 -#define LOCAL_GL_BACK_LEFT 0x0402 -#define LOCAL_GL_BACK_RIGHT 0x0403 -#define LOCAL_GL_FRONT 0x0404 -#define LOCAL_GL_BACK 0x0405 -#define LOCAL_GL_LEFT 0x0406 -#define LOCAL_GL_RIGHT 0x0407 -#define LOCAL_GL_FRONT_AND_BACK 0x0408 -#define LOCAL_GL_AUX0 0x0409 -#define LOCAL_GL_AUX1 0x040A -#define LOCAL_GL_AUX2 0x040B -#define LOCAL_GL_AUX3 0x040C -#define LOCAL_GL_NO_ERROR 0 -#define LOCAL_GL_INVALID_ENUM 0x0500 -#define LOCAL_GL_INVALID_VALUE 0x0501 -#define LOCAL_GL_INVALID_OPERATION 0x0502 -#define LOCAL_GL_STACK_OVERFLOW 0x0503 -#define LOCAL_GL_STACK_UNDERFLOW 0x0504 -#define LOCAL_GL_OUT_OF_MEMORY 0x0505 -#define LOCAL_GL_CONTEXT_LOST 0x9242 -#define LOCAL_GL_2D 0x0600 -#define LOCAL_GL_3D 0x0601 -#define LOCAL_GL_3D_COLOR 0x0602 -#define LOCAL_GL_3D_COLOR_TEXTURE 0x0603 -#define LOCAL_GL_4D_COLOR_TEXTURE 0x0604 -#define LOCAL_GL_PASS_THROUGH_TOKEN 0x0700 -#define LOCAL_GL_POINT_TOKEN 0x0701 -#define LOCAL_GL_LINE_TOKEN 0x0702 -#define LOCAL_GL_POLYGON_TOKEN 0x0703 -#define LOCAL_GL_BITMAP_TOKEN 0x0704 -#define LOCAL_GL_DRAW_PIXEL_TOKEN 0x0705 -#define LOCAL_GL_COPY_PIXEL_TOKEN 0x0706 -#define LOCAL_GL_LINE_RESET_TOKEN 0x0707 -#define LOCAL_GL_EXP 0x0800 -#define LOCAL_GL_EXP2 0x0801 -#define LOCAL_GL_CW 0x0900 -#define LOCAL_GL_CCW 0x0901 -#define LOCAL_GL_COEFF 0x0A00 -#define LOCAL_GL_ORDER 0x0A01 -#define LOCAL_GL_DOMAIN 0x0A02 -#define LOCAL_GL_CURRENT_COLOR 0x0B00 -#define LOCAL_GL_CURRENT_INDEX 0x0B01 -#define LOCAL_GL_CURRENT_NORMAL 0x0B02 -#define LOCAL_GL_CURRENT_TEXTURE_COORDS 0x0B03 -#define LOCAL_GL_CURRENT_RASTER_COLOR 0x0B04 -#define LOCAL_GL_CURRENT_RASTER_INDEX 0x0B05 -#define LOCAL_GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 -#define LOCAL_GL_CURRENT_RASTER_POSITION 0x0B07 -#define LOCAL_GL_CURRENT_RASTER_POSITION_VALID 0x0B08 -#define LOCAL_GL_CURRENT_RASTER_DISTANCE 0x0B09 -#define LOCAL_GL_POINT_SMOOTH 0x0B10 -#define LOCAL_GL_POINT_SIZE 0x0B11 -#define LOCAL_GL_POINT_SIZE_RANGE 0x0B12 -#define LOCAL_GL_POINT_SIZE_GRANULARITY 0x0B13 -#define LOCAL_GL_LINE_SMOOTH 0x0B20 -#define LOCAL_GL_LINE_WIDTH 0x0B21 -#define LOCAL_GL_LINE_WIDTH_RANGE 0x0B22 -#define LOCAL_GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define LOCAL_GL_LINE_STIPPLE 0x0B24 -#define LOCAL_GL_LINE_STIPPLE_PATTERN 0x0B25 -#define LOCAL_GL_LINE_STIPPLE_REPEAT 0x0B26 -#define LOCAL_GL_LIST_MODE 0x0B30 -#define LOCAL_GL_MAX_LIST_NESTING 0x0B31 -#define LOCAL_GL_LIST_BASE 0x0B32 -#define LOCAL_GL_LIST_INDEX 0x0B33 -#define LOCAL_GL_POLYGON_MODE 0x0B40 -#define LOCAL_GL_POLYGON_SMOOTH 0x0B41 -#define LOCAL_GL_POLYGON_STIPPLE 0x0B42 -#define LOCAL_GL_EDGE_FLAG 0x0B43 -#define LOCAL_GL_CULL_FACE 0x0B44 -#define LOCAL_GL_CULL_FACE_MODE 0x0B45 -#define LOCAL_GL_FRONT_FACE 0x0B46 -#define LOCAL_GL_LIGHTING 0x0B50 -#define LOCAL_GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 -#define LOCAL_GL_LIGHT_MODEL_TWO_SIDE 0x0B52 -#define LOCAL_GL_LIGHT_MODEL_AMBIENT 0x0B53 -#define LOCAL_GL_SHADE_MODEL 0x0B54 -#define LOCAL_GL_COLOR_MATERIAL_FACE 0x0B55 -#define LOCAL_GL_COLOR_MATERIAL_PARAMETER 0x0B56 -#define LOCAL_GL_COLOR_MATERIAL 0x0B57 -#define LOCAL_GL_FOG 0x0B60 -#define LOCAL_GL_FOG_INDEX 0x0B61 -#define LOCAL_GL_FOG_DENSITY 0x0B62 -#define LOCAL_GL_FOG_START 0x0B63 -#define LOCAL_GL_FOG_END 0x0B64 -#define LOCAL_GL_FOG_MODE 0x0B65 -#define LOCAL_GL_FOG_COLOR 0x0B66 -#define LOCAL_GL_DEPTH_RANGE 0x0B70 -#define LOCAL_GL_DEPTH_TEST 0x0B71 -#define LOCAL_GL_DEPTH_WRITEMASK 0x0B72 -#define LOCAL_GL_DEPTH_CLEAR_VALUE 0x0B73 -#define LOCAL_GL_DEPTH_FUNC 0x0B74 -#define LOCAL_GL_ACCUM_CLEAR_VALUE 0x0B80 -#define LOCAL_GL_STENCIL_TEST 0x0B90 -#define LOCAL_GL_STENCIL_CLEAR_VALUE 0x0B91 -#define LOCAL_GL_STENCIL_FUNC 0x0B92 -#define LOCAL_GL_STENCIL_VALUE_MASK 0x0B93 -#define LOCAL_GL_STENCIL_FAIL 0x0B94 -#define LOCAL_GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define LOCAL_GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define LOCAL_GL_STENCIL_REF 0x0B97 -#define LOCAL_GL_STENCIL_WRITEMASK 0x0B98 -#define LOCAL_GL_MATRIX_MODE 0x0BA0 -#define LOCAL_GL_NORMALIZE 0x0BA1 -#define LOCAL_GL_VIEWPORT 0x0BA2 -#define LOCAL_GL_MODELVIEW_STACK_DEPTH 0x0BA3 -#define LOCAL_GL_PROJECTION_STACK_DEPTH 0x0BA4 -#define LOCAL_GL_TEXTURE_STACK_DEPTH 0x0BA5 -#define LOCAL_GL_MODELVIEW_MATRIX 0x0BA6 -#define LOCAL_GL_PROJECTION_MATRIX 0x0BA7 -#define LOCAL_GL_TEXTURE_MATRIX 0x0BA8 -#define LOCAL_GL_ATTRIB_STACK_DEPTH 0x0BB0 -#define LOCAL_GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 -#define LOCAL_GL_ALPHA_TEST 0x0BC0 -#define LOCAL_GL_ALPHA_TEST_FUNC 0x0BC1 -#define LOCAL_GL_ALPHA_TEST_REF 0x0BC2 -#define LOCAL_GL_DITHER 0x0BD0 -#define LOCAL_GL_BLEND_DST 0x0BE0 -#define LOCAL_GL_BLEND_SRC 0x0BE1 -#define LOCAL_GL_BLEND 0x0BE2 -#define LOCAL_GL_LOGIC_OP_MODE 0x0BF0 -#define LOCAL_GL_INDEX_LOGIC_OP 0x0BF1 -#define LOCAL_GL_COLOR_LOGIC_OP 0x0BF2 -#define LOCAL_GL_AUX_BUFFERS 0x0C00 -#define LOCAL_GL_DRAW_BUFFER 0x0C01 -#define LOCAL_GL_READ_BUFFER 0x0C02 -#define LOCAL_GL_SCISSOR_BOX 0x0C10 -#define LOCAL_GL_SCISSOR_TEST 0x0C11 -#define LOCAL_GL_INDEX_CLEAR_VALUE 0x0C20 -#define LOCAL_GL_INDEX_WRITEMASK 0x0C21 -#define LOCAL_GL_COLOR_CLEAR_VALUE 0x0C22 -#define LOCAL_GL_COLOR_WRITEMASK 0x0C23 -#define LOCAL_GL_INDEX_MODE 0x0C30 -#define LOCAL_GL_RGBA_MODE 0x0C31 -#define LOCAL_GL_DOUBLEBUFFER 0x0C32 -#define LOCAL_GL_STEREO 0x0C33 -#define LOCAL_GL_RENDER_MODE 0x0C40 -#define LOCAL_GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 -#define LOCAL_GL_POINT_SMOOTH_HINT 0x0C51 -#define LOCAL_GL_LINE_SMOOTH_HINT 0x0C52 -#define LOCAL_GL_POLYGON_SMOOTH_HINT 0x0C53 -#define LOCAL_GL_FOG_HINT 0x0C54 -#define LOCAL_GL_TEXTURE_GEN_S 0x0C60 -#define LOCAL_GL_TEXTURE_GEN_T 0x0C61 -#define LOCAL_GL_TEXTURE_GEN_R 0x0C62 -#define LOCAL_GL_TEXTURE_GEN_Q 0x0C63 -#define LOCAL_GL_PIXEL_MAP_I_TO_I 0x0C70 -#define LOCAL_GL_PIXEL_MAP_S_TO_S 0x0C71 -#define LOCAL_GL_PIXEL_MAP_I_TO_R 0x0C72 -#define LOCAL_GL_PIXEL_MAP_I_TO_G 0x0C73 -#define LOCAL_GL_PIXEL_MAP_I_TO_B 0x0C74 -#define LOCAL_GL_PIXEL_MAP_I_TO_A 0x0C75 -#define LOCAL_GL_PIXEL_MAP_R_TO_R 0x0C76 -#define LOCAL_GL_PIXEL_MAP_G_TO_G 0x0C77 -#define LOCAL_GL_PIXEL_MAP_B_TO_B 0x0C78 -#define LOCAL_GL_PIXEL_MAP_A_TO_A 0x0C79 -#define LOCAL_GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 -#define LOCAL_GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 -#define LOCAL_GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 -#define LOCAL_GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 -#define LOCAL_GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 -#define LOCAL_GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 -#define LOCAL_GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 -#define LOCAL_GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 -#define LOCAL_GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 -#define LOCAL_GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 -#define LOCAL_GL_UNPACK_SWAP_BYTES 0x0CF0 -#define LOCAL_GL_UNPACK_LSB_FIRST 0x0CF1 -#define LOCAL_GL_UNPACK_ROW_LENGTH 0x0CF2 -#define LOCAL_GL_UNPACK_SKIP_ROWS 0x0CF3 -#define LOCAL_GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define LOCAL_GL_UNPACK_ALIGNMENT 0x0CF5 -#define LOCAL_GL_PACK_SWAP_BYTES 0x0D00 -#define LOCAL_GL_PACK_LSB_FIRST 0x0D01 -#define LOCAL_GL_PACK_ROW_LENGTH 0x0D02 -#define LOCAL_GL_PACK_SKIP_ROWS 0x0D03 -#define LOCAL_GL_PACK_SKIP_PIXELS 0x0D04 -#define LOCAL_GL_PACK_ALIGNMENT 0x0D05 -#define LOCAL_GL_MAP_COLOR 0x0D10 -#define LOCAL_GL_MAP_STENCIL 0x0D11 -#define LOCAL_GL_INDEX_SHIFT 0x0D12 -#define LOCAL_GL_INDEX_OFFSET 0x0D13 -#define LOCAL_GL_RED_SCALE 0x0D14 -#define LOCAL_GL_RED_BIAS 0x0D15 -#define LOCAL_GL_ZOOM_X 0x0D16 -#define LOCAL_GL_ZOOM_Y 0x0D17 -#define LOCAL_GL_GREEN_SCALE 0x0D18 -#define LOCAL_GL_GREEN_BIAS 0x0D19 -#define LOCAL_GL_BLUE_SCALE 0x0D1A -#define LOCAL_GL_BLUE_BIAS 0x0D1B -#define LOCAL_GL_ALPHA_SCALE 0x0D1C -#define LOCAL_GL_ALPHA_BIAS 0x0D1D -#define LOCAL_GL_DEPTH_SCALE 0x0D1E -#define LOCAL_GL_DEPTH_BIAS 0x0D1F -#define LOCAL_GL_MAX_EVAL_ORDER 0x0D30 -#define LOCAL_GL_MAX_LIGHTS 0x0D31 -#define LOCAL_GL_MAX_CLIP_PLANES 0x0D32 -#define LOCAL_GL_MAX_TEXTURE_SIZE 0x0D33 -#define LOCAL_GL_MAX_PIXEL_MAP_TABLE 0x0D34 -#define LOCAL_GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 -#define LOCAL_GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 -#define LOCAL_GL_MAX_NAME_STACK_DEPTH 0x0D37 -#define LOCAL_GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 -#define LOCAL_GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 -#define LOCAL_GL_MAX_VIEWPORT_DIMS 0x0D3A -#define LOCAL_GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B -#define LOCAL_GL_SUBPIXEL_BITS 0x0D50 -#define LOCAL_GL_INDEX_BITS 0x0D51 -#define LOCAL_GL_RED_BITS 0x0D52 -#define LOCAL_GL_GREEN_BITS 0x0D53 -#define LOCAL_GL_BLUE_BITS 0x0D54 -#define LOCAL_GL_ALPHA_BITS 0x0D55 -#define LOCAL_GL_DEPTH_BITS 0x0D56 -#define LOCAL_GL_STENCIL_BITS 0x0D57 -#define LOCAL_GL_ACCUM_RED_BITS 0x0D58 -#define LOCAL_GL_ACCUM_GREEN_BITS 0x0D59 -#define LOCAL_GL_ACCUM_BLUE_BITS 0x0D5A -#define LOCAL_GL_ACCUM_ALPHA_BITS 0x0D5B -#define LOCAL_GL_NAME_STACK_DEPTH 0x0D70 -#define LOCAL_GL_AUTO_NORMAL 0x0D80 -#define LOCAL_GL_MAP1_COLOR_4 0x0D90 -#define LOCAL_GL_MAP1_INDEX 0x0D91 -#define LOCAL_GL_MAP1_NORMAL 0x0D92 -#define LOCAL_GL_MAP1_TEXTURE_COORD_1 0x0D93 -#define LOCAL_GL_MAP1_TEXTURE_COORD_2 0x0D94 -#define LOCAL_GL_MAP1_TEXTURE_COORD_3 0x0D95 -#define LOCAL_GL_MAP1_TEXTURE_COORD_4 0x0D96 -#define LOCAL_GL_MAP1_VERTEX_3 0x0D97 -#define LOCAL_GL_MAP1_VERTEX_4 0x0D98 -#define LOCAL_GL_MAP2_COLOR_4 0x0DB0 -#define LOCAL_GL_MAP2_INDEX 0x0DB1 -#define LOCAL_GL_MAP2_NORMAL 0x0DB2 -#define LOCAL_GL_MAP2_TEXTURE_COORD_1 0x0DB3 -#define LOCAL_GL_MAP2_TEXTURE_COORD_2 0x0DB4 -#define LOCAL_GL_MAP2_TEXTURE_COORD_3 0x0DB5 -#define LOCAL_GL_MAP2_TEXTURE_COORD_4 0x0DB6 -#define LOCAL_GL_MAP2_VERTEX_3 0x0DB7 -#define LOCAL_GL_MAP2_VERTEX_4 0x0DB8 -#define LOCAL_GL_MAP1_GRID_DOMAIN 0x0DD0 -#define LOCAL_GL_MAP1_GRID_SEGMENTS 0x0DD1 -#define LOCAL_GL_MAP2_GRID_DOMAIN 0x0DD2 -#define LOCAL_GL_MAP2_GRID_SEGMENTS 0x0DD3 -#define LOCAL_GL_TEXTURE_1D 0x0DE0 -#define LOCAL_GL_TEXTURE_2D 0x0DE1 -#define LOCAL_GL_FEEDBACK_BUFFER_POINTER 0x0DF0 -#define LOCAL_GL_FEEDBACK_BUFFER_SIZE 0x0DF1 -#define LOCAL_GL_FEEDBACK_BUFFER_TYPE 0x0DF2 -#define LOCAL_GL_SELECTION_BUFFER_POINTER 0x0DF3 -#define LOCAL_GL_SELECTION_BUFFER_SIZE 0x0DF4 -#define LOCAL_GL_TEXTURE_WIDTH 0x1000 -#define LOCAL_GL_TEXTURE_HEIGHT 0x1001 -#define LOCAL_GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define LOCAL_GL_TEXTURE_BORDER_COLOR 0x1004 -#define LOCAL_GL_TEXTURE_BORDER 0x1005 -#define LOCAL_GL_DONT_CARE 0x1100 -#define LOCAL_GL_FASTEST 0x1101 -#define LOCAL_GL_NICEST 0x1102 -#define LOCAL_GL_LIGHT0 0x4000 -#define LOCAL_GL_LIGHT1 0x4001 -#define LOCAL_GL_LIGHT2 0x4002 -#define LOCAL_GL_LIGHT3 0x4003 -#define LOCAL_GL_LIGHT4 0x4004 -#define LOCAL_GL_LIGHT5 0x4005 -#define LOCAL_GL_LIGHT6 0x4006 -#define LOCAL_GL_LIGHT7 0x4007 -#define LOCAL_GL_AMBIENT 0x1200 -#define LOCAL_GL_DIFFUSE 0x1201 -#define LOCAL_GL_SPECULAR 0x1202 -#define LOCAL_GL_POSITION 0x1203 -#define LOCAL_GL_SPOT_DIRECTION 0x1204 -#define LOCAL_GL_SPOT_EXPONENT 0x1205 -#define LOCAL_GL_SPOT_CUTOFF 0x1206 -#define LOCAL_GL_CONSTANT_ATTENUATION 0x1207 -#define LOCAL_GL_LINEAR_ATTENUATION 0x1208 -#define LOCAL_GL_QUADRATIC_ATTENUATION 0x1209 -#define LOCAL_GL_COMPILE 0x1300 -#define LOCAL_GL_COMPILE_AND_EXECUTE 0x1301 -#define LOCAL_GL_CLEAR 0x1500 -#define LOCAL_GL_AND 0x1501 -#define LOCAL_GL_AND_REVERSE 0x1502 -#define LOCAL_GL_COPY 0x1503 -#define LOCAL_GL_AND_INVERTED 0x1504 -#define LOCAL_GL_NOOP 0x1505 -#define LOCAL_GL_XOR 0x1506 -#define LOCAL_GL_OR 0x1507 -#define LOCAL_GL_NOR 0x1508 -#define LOCAL_GL_EQUIV 0x1509 -#define LOCAL_GL_INVERT 0x150A -#define LOCAL_GL_OR_REVERSE 0x150B -#define LOCAL_GL_COPY_INVERTED 0x150C -#define LOCAL_GL_OR_INVERTED 0x150D -#define LOCAL_GL_NAND 0x150E -#define LOCAL_GL_SET 0x150F -#define LOCAL_GL_EMISSION 0x1600 -#define LOCAL_GL_SHININESS 0x1601 -#define LOCAL_GL_AMBIENT_AND_DIFFUSE 0x1602 -#define LOCAL_GL_COLOR_INDEXES 0x1603 -#define LOCAL_GL_MODELVIEW 0x1700 -#define LOCAL_GL_PROJECTION 0x1701 -#define LOCAL_GL_TEXTURE 0x1702 -#define LOCAL_GL_COLOR 0x1800 -#define LOCAL_GL_DEPTH 0x1801 -#define LOCAL_GL_STENCIL 0x1802 -#define LOCAL_GL_COLOR_INDEX 0x1900 -#define LOCAL_GL_STENCIL_INDEX 0x1901 -#define LOCAL_GL_DEPTH_COMPONENT 0x1902 -#define LOCAL_GL_RED 0x1903 -#define LOCAL_GL_GREEN 0x1904 -#define LOCAL_GL_BLUE 0x1905 -#define LOCAL_GL_ALPHA 0x1906 -#define LOCAL_GL_RGB 0x1907 -#define LOCAL_GL_RGBA 0x1908 -#define LOCAL_GL_LUMINANCE 0x1909 -#define LOCAL_GL_LUMINANCE_ALPHA 0x190A -#define LOCAL_GL_BITMAP 0x1A00 -#define LOCAL_GL_POINT 0x1B00 -#define LOCAL_GL_LINE 0x1B01 -#define LOCAL_GL_FILL 0x1B02 -#define LOCAL_GL_RENDER 0x1C00 -#define LOCAL_GL_FEEDBACK 0x1C01 -#define LOCAL_GL_SELECT 0x1C02 -#define LOCAL_GL_FLAT 0x1D00 -#define LOCAL_GL_SMOOTH 0x1D01 -#define LOCAL_GL_KEEP 0x1E00 -#define LOCAL_GL_REPLACE 0x1E01 -#define LOCAL_GL_INCR 0x1E02 -#define LOCAL_GL_DECR 0x1E03 -#define LOCAL_GL_VENDOR 0x1F00 -#define LOCAL_GL_RENDERER 0x1F01 -#define LOCAL_GL_VERSION 0x1F02 -#define LOCAL_GL_EXTENSIONS 0x1F03 -#define LOCAL_GL_S 0x2000 -#define LOCAL_GL_T 0x2001 -#define LOCAL_GL_R 0x2002 -#define LOCAL_GL_Q 0x2003 -#define LOCAL_GL_MODULATE 0x2100 -#define LOCAL_GL_DECAL 0x2101 -#define LOCAL_GL_TEXTURE_ENV_MODE 0x2200 -#define LOCAL_GL_TEXTURE_ENV_COLOR 0x2201 -#define LOCAL_GL_TEXTURE_ENV 0x2300 -#define LOCAL_GL_EYE_LINEAR 0x2400 -#define LOCAL_GL_OBJECT_LINEAR 0x2401 -#define LOCAL_GL_SPHERE_MAP 0x2402 -#define LOCAL_GL_TEXTURE_GEN_MODE 0x2500 -#define LOCAL_GL_OBJECT_PLANE 0x2501 -#define LOCAL_GL_EYE_PLANE 0x2502 -#define LOCAL_GL_NEAREST 0x2600 -#define LOCAL_GL_LINEAR 0x2601 -#define LOCAL_GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define LOCAL_GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define LOCAL_GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define LOCAL_GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define LOCAL_GL_TEXTURE_MAG_FILTER 0x2800 -#define LOCAL_GL_TEXTURE_MIN_FILTER 0x2801 -#define LOCAL_GL_TEXTURE_WRAP_S 0x2802 -#define LOCAL_GL_TEXTURE_WRAP_T 0x2803 -#define LOCAL_GL_CLAMP 0x2900 -#define LOCAL_GL_REPEAT 0x2901 -#define LOCAL_GL_CLIENT_PIXEL_STORE_BIT 0x00000001 -#define LOCAL_GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 -#define LOCAL_GL_CLIENT_ALL_ATTRIB_BITS 0xffffffff -#define LOCAL_GL_POLYGON_OFFSET_FACTOR 0x8038 -#define LOCAL_GL_POLYGON_OFFSET_UNITS 0x2A00 -#define LOCAL_GL_POLYGON_OFFSET_POINT 0x2A01 -#define LOCAL_GL_POLYGON_OFFSET_LINE 0x2A02 -#define LOCAL_GL_POLYGON_OFFSET_FILL 0x8037 -#define LOCAL_GL_ALPHA4 0x803B -#define LOCAL_GL_ALPHA8 0x803C -#define LOCAL_GL_ALPHA12 0x803D -#define LOCAL_GL_ALPHA16 0x803E -#define LOCAL_GL_LUMINANCE4 0x803F -#define LOCAL_GL_LUMINANCE8 0x8040 -#define LOCAL_GL_LUMINANCE12 0x8041 -#define LOCAL_GL_LUMINANCE16 0x8042 -#define LOCAL_GL_LUMINANCE4_ALPHA4 0x8043 -#define LOCAL_GL_LUMINANCE6_ALPHA2 0x8044 -#define LOCAL_GL_LUMINANCE8_ALPHA8 0x8045 -#define LOCAL_GL_LUMINANCE12_ALPHA4 0x8046 -#define LOCAL_GL_LUMINANCE12_ALPHA12 0x8047 -#define LOCAL_GL_LUMINANCE16_ALPHA16 0x8048 -#define LOCAL_GL_INTENSITY 0x8049 -#define LOCAL_GL_INTENSITY4 0x804A -#define LOCAL_GL_INTENSITY8 0x804B -#define LOCAL_GL_INTENSITY12 0x804C -#define LOCAL_GL_INTENSITY16 0x804D -#define LOCAL_GL_R3_G3_B2 0x2A10 -#define LOCAL_GL_RGB4 0x804F -#define LOCAL_GL_RGB5 0x8050 -#define LOCAL_GL_RGB8 0x8051 -#define LOCAL_GL_RGB10 0x8052 -#define LOCAL_GL_RGB12 0x8053 -#define LOCAL_GL_RGB16 0x8054 -#define LOCAL_GL_RGBA2 0x8055 -#define LOCAL_GL_RGBA4 0x8056 -#define LOCAL_GL_RGB5_A1 0x8057 -#define LOCAL_GL_RGB565 0x8D62 -#define LOCAL_GL_RGBA8 0x8058 -#define LOCAL_GL_RGB10_A2 0x8059 -#define LOCAL_GL_RGBA12 0x805A -#define LOCAL_GL_RGBA16 0x805B -#define LOCAL_GL_TEXTURE_RED_SIZE 0x805C -#define LOCAL_GL_TEXTURE_GREEN_SIZE 0x805D -#define LOCAL_GL_TEXTURE_BLUE_SIZE 0x805E -#define LOCAL_GL_TEXTURE_ALPHA_SIZE 0x805F -#define LOCAL_GL_TEXTURE_LUMINANCE_SIZE 0x8060 -#define LOCAL_GL_TEXTURE_INTENSITY_SIZE 0x8061 -#define LOCAL_GL_PROXY_TEXTURE_1D 0x8063 -#define LOCAL_GL_PROXY_TEXTURE_2D 0x8064 -#define LOCAL_GL_TEXTURE_PRIORITY 0x8066 -#define LOCAL_GL_TEXTURE_RESIDENT 0x8067 -#define LOCAL_GL_TEXTURE_BINDING_1D 0x8068 -#define LOCAL_GL_TEXTURE_BINDING_2D 0x8069 -#define LOCAL_GL_VERTEX_ARRAY 0x8074 -#define LOCAL_GL_NORMAL_ARRAY 0x8075 -#define LOCAL_GL_COLOR_ARRAY 0x8076 -#define LOCAL_GL_INDEX_ARRAY 0x8077 -#define LOCAL_GL_TEXTURE_COORD_ARRAY 0x8078 -#define LOCAL_GL_EDGE_FLAG_ARRAY 0x8079 -#define LOCAL_GL_VERTEX_ARRAY_SIZE 0x807A -#define LOCAL_GL_VERTEX_ARRAY_TYPE 0x807B -#define LOCAL_GL_VERTEX_ARRAY_STRIDE 0x807C -#define LOCAL_GL_NORMAL_ARRAY_TYPE 0x807E -#define LOCAL_GL_NORMAL_ARRAY_STRIDE 0x807F -#define LOCAL_GL_COLOR_ARRAY_SIZE 0x8081 -#define LOCAL_GL_COLOR_ARRAY_TYPE 0x8082 -#define LOCAL_GL_COLOR_ARRAY_STRIDE 0x8083 -#define LOCAL_GL_INDEX_ARRAY_TYPE 0x8085 -#define LOCAL_GL_INDEX_ARRAY_STRIDE 0x8086 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A -#define LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE 0x808C -#define LOCAL_GL_VERTEX_ARRAY_POINTER 0x808E -#define LOCAL_GL_NORMAL_ARRAY_POINTER 0x808F -#define LOCAL_GL_COLOR_ARRAY_POINTER 0x8090 -#define LOCAL_GL_INDEX_ARRAY_POINTER 0x8091 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 -#define LOCAL_GL_EDGE_FLAG_ARRAY_POINTER 0x8093 -#define LOCAL_GL_V2F 0x2A20 -#define LOCAL_GL_V3F 0x2A21 -#define LOCAL_GL_C4UB_V2F 0x2A22 -#define LOCAL_GL_C4UB_V3F 0x2A23 -#define LOCAL_GL_C3F_V3F 0x2A24 -#define LOCAL_GL_N3F_V3F 0x2A25 -#define LOCAL_GL_C4F_N3F_V3F 0x2A26 -#define LOCAL_GL_T2F_V3F 0x2A27 -#define LOCAL_GL_T4F_V4F 0x2A28 -#define LOCAL_GL_T2F_C4UB_V3F 0x2A29 -#define LOCAL_GL_T2F_C3F_V3F 0x2A2A -#define LOCAL_GL_T2F_N3F_V3F 0x2A2B -#define LOCAL_GL_T2F_C4F_N3F_V3F 0x2A2C -#define LOCAL_GL_T4F_C4F_N3F_V4F 0x2A2D -#define LOCAL_GL_LOGIC_OP GL_INDEX_LOGIC_OP -#define LOCAL_GL_TEXTURE_COMPONENTS GL_TEXTURE_INTERNAL_FORMAT -#define LOCAL_GL_COLOR_INDEX1_EXT 0x80E2 -#define LOCAL_GL_COLOR_INDEX2_EXT 0x80E3 -#define LOCAL_GL_COLOR_INDEX4_EXT 0x80E4 -#define LOCAL_GL_COLOR_INDEX8_EXT 0x80E5 -#define LOCAL_GL_COLOR_INDEX12_EXT 0x80E6 -#define LOCAL_GL_COLOR_INDEX16_EXT 0x80E7 -#define LOCAL_GL_VERSION_1_2 1 -#define LOCAL_GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define LOCAL_GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define LOCAL_GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define LOCAL_GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define LOCAL_GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define LOCAL_GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define LOCAL_GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define LOCAL_GL_RESCALE_NORMAL 0x803A -#define LOCAL_GL_TEXTURE_BINDING_3D 0x806A -#define LOCAL_GL_PACK_SKIP_IMAGES 0x806B -#define LOCAL_GL_PACK_IMAGE_HEIGHT 0x806C -#define LOCAL_GL_UNPACK_SKIP_IMAGES 0x806D -#define LOCAL_GL_UNPACK_IMAGE_HEIGHT 0x806E -#define LOCAL_GL_TEXTURE_3D 0x806F -#define LOCAL_GL_PROXY_TEXTURE_3D 0x8070 -#define LOCAL_GL_TEXTURE_DEPTH 0x8071 -#define LOCAL_GL_TEXTURE_WRAP_R 0x8072 -#define LOCAL_GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define LOCAL_GL_BGR 0x80E0 -#define LOCAL_GL_BGRA 0x80E1 -#define LOCAL_GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define LOCAL_GL_MAX_ELEMENTS_INDICES 0x80E9 -#define LOCAL_GL_CLAMP_TO_EDGE 0x812F -#define LOCAL_GL_TEXTURE_MIN_LOD 0x813A -#define LOCAL_GL_TEXTURE_MAX_LOD 0x813B -#define LOCAL_GL_TEXTURE_BASE_LEVEL 0x813C -#define LOCAL_GL_TEXTURE_MAX_LEVEL 0x813D -#define LOCAL_GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define LOCAL_GL_SINGLE_COLOR 0x81F9 -#define LOCAL_GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define LOCAL_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define LOCAL_GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define LOCAL_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define LOCAL_GL_ALIASED_POINT_SIZE_RANGE 0x846D -#define LOCAL_GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define LOCAL_GL_VERSION_1_3 1 -#define LOCAL_GL_MULTISAMPLE 0x809D -#define LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define LOCAL_GL_SAMPLE_COVERAGE 0x80A0 -#define LOCAL_GL_SAMPLE_BUFFERS 0x80A8 -#define LOCAL_GL_SAMPLES 0x80A9 -#define LOCAL_GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define LOCAL_GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define LOCAL_GL_CLAMP_TO_BORDER 0x812D -#define LOCAL_GL_TEXTURE0 0x84C0 -#define LOCAL_GL_TEXTURE1 0x84C1 -#define LOCAL_GL_TEXTURE2 0x84C2 -#define LOCAL_GL_TEXTURE3 0x84C3 -#define LOCAL_GL_TEXTURE4 0x84C4 -#define LOCAL_GL_TEXTURE5 0x84C5 -#define LOCAL_GL_TEXTURE6 0x84C6 -#define LOCAL_GL_TEXTURE7 0x84C7 -#define LOCAL_GL_TEXTURE8 0x84C8 -#define LOCAL_GL_TEXTURE9 0x84C9 -#define LOCAL_GL_TEXTURE10 0x84CA -#define LOCAL_GL_TEXTURE11 0x84CB -#define LOCAL_GL_TEXTURE12 0x84CC -#define LOCAL_GL_TEXTURE13 0x84CD -#define LOCAL_GL_TEXTURE14 0x84CE -#define LOCAL_GL_TEXTURE15 0x84CF -#define LOCAL_GL_TEXTURE16 0x84D0 -#define LOCAL_GL_TEXTURE17 0x84D1 -#define LOCAL_GL_TEXTURE18 0x84D2 -#define LOCAL_GL_TEXTURE19 0x84D3 -#define LOCAL_GL_TEXTURE20 0x84D4 -#define LOCAL_GL_TEXTURE21 0x84D5 -#define LOCAL_GL_TEXTURE22 0x84D6 -#define LOCAL_GL_TEXTURE23 0x84D7 -#define LOCAL_GL_TEXTURE24 0x84D8 -#define LOCAL_GL_TEXTURE25 0x84D9 -#define LOCAL_GL_TEXTURE26 0x84DA -#define LOCAL_GL_TEXTURE27 0x84DB -#define LOCAL_GL_TEXTURE28 0x84DC -#define LOCAL_GL_TEXTURE29 0x84DD -#define LOCAL_GL_TEXTURE30 0x84DE -#define LOCAL_GL_TEXTURE31 0x84DF -#define LOCAL_GL_ACTIVE_TEXTURE 0x84E0 -#define LOCAL_GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define LOCAL_GL_MAX_TEXTURE_UNITS 0x84E2 -#define LOCAL_GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define LOCAL_GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define LOCAL_GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define LOCAL_GL_TRANSPOSE_COLOR_MATRIX 0x84E6 -#define LOCAL_GL_SUBTRACT 0x84E7 -#define LOCAL_GL_COMPRESSED_ALPHA 0x84E9 -#define LOCAL_GL_COMPRESSED_LUMINANCE 0x84EA -#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define LOCAL_GL_COMPRESSED_INTENSITY 0x84EC -#define LOCAL_GL_COMPRESSED_RGB 0x84ED -#define LOCAL_GL_COMPRESSED_RGBA 0x84EE -#define LOCAL_GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define LOCAL_GL_NORMAL_MAP 0x8511 -#define LOCAL_GL_REFLECTION_MAP 0x8512 -#define LOCAL_GL_TEXTURE_CUBE_MAP 0x8513 -#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define LOCAL_GL_COMBINE 0x8570 -#define LOCAL_GL_COMBINE_RGB 0x8571 -#define LOCAL_GL_COMBINE_ALPHA 0x8572 -#define LOCAL_GL_RGB_SCALE 0x8573 -#define LOCAL_GL_ADD_SIGNED 0x8574 -#define LOCAL_GL_INTERPOLATE 0x8575 -#define LOCAL_GL_CONSTANT 0x8576 -#define LOCAL_GL_PRIMARY_COLOR 0x8577 -#define LOCAL_GL_PREVIOUS 0x8578 -#define LOCAL_GL_SOURCE0_RGB 0x8580 -#define LOCAL_GL_SOURCE1_RGB 0x8581 -#define LOCAL_GL_SOURCE2_RGB 0x8582 -#define LOCAL_GL_SOURCE0_ALPHA 0x8588 -#define LOCAL_GL_SOURCE1_ALPHA 0x8589 -#define LOCAL_GL_SOURCE2_ALPHA 0x858A -#define LOCAL_GL_OPERAND0_RGB 0x8590 -#define LOCAL_GL_OPERAND1_RGB 0x8591 -#define LOCAL_GL_OPERAND2_RGB 0x8592 -#define LOCAL_GL_OPERAND0_ALPHA 0x8598 -#define LOCAL_GL_OPERAND1_ALPHA 0x8599 -#define LOCAL_GL_OPERAND2_ALPHA 0x859A -#define LOCAL_GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define LOCAL_GL_TEXTURE_COMPRESSED 0x86A1 -#define LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define LOCAL_GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define LOCAL_GL_DOT3_RGB 0x86AE -#define LOCAL_GL_DOT3_RGBA 0x86AF -#define LOCAL_GL_MULTISAMPLE_BIT 0x20000000 -#define LOCAL_GL_VERSION_1_4 1 -#define LOCAL_GL_BLEND_DST_RGB 0x80C8 -#define LOCAL_GL_BLEND_SRC_RGB 0x80C9 -#define LOCAL_GL_BLEND_DST_ALPHA 0x80CA -#define LOCAL_GL_BLEND_SRC_ALPHA 0x80CB -#define LOCAL_GL_POINT_SIZE_MIN 0x8126 -#define LOCAL_GL_POINT_SIZE_MAX 0x8127 -#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define LOCAL_GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define LOCAL_GL_GENERATE_MIPMAP 0x8191 -#define LOCAL_GL_GENERATE_MIPMAP_HINT 0x8192 -#define LOCAL_GL_DEPTH_COMPONENT16 0x81A5 -#define LOCAL_GL_DEPTH_COMPONENT24 0x81A6 -#define LOCAL_GL_DEPTH_COMPONENT32 0x81A7 -#define LOCAL_GL_MIRRORED_REPEAT 0x8370 -#define LOCAL_GL_FOG_COORDINATE_SOURCE 0x8450 -#define LOCAL_GL_FOG_COORDINATE 0x8451 -#define LOCAL_GL_FRAGMENT_DEPTH 0x8452 -#define LOCAL_GL_CURRENT_FOG_COORDINATE 0x8453 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define LOCAL_GL_FOG_COORDINATE_ARRAY 0x8457 -#define LOCAL_GL_COLOR_SUM 0x8458 -#define LOCAL_GL_CURRENT_SECONDARY_COLOR 0x8459 -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define LOCAL_GL_SECONDARY_COLOR_ARRAY 0x845E -#define LOCAL_GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define LOCAL_GL_TEXTURE_FILTER_CONTROL 0x8500 -#define LOCAL_GL_TEXTURE_LOD_BIAS 0x8501 -#define LOCAL_GL_INCR_WRAP 0x8507 -#define LOCAL_GL_DECR_WRAP 0x8508 -#define LOCAL_GL_TEXTURE_DEPTH_SIZE 0x884A -#define LOCAL_GL_DEPTH_TEXTURE_MODE 0x884B -#define LOCAL_GL_TEXTURE_COMPARE_MODE 0x884C -#define LOCAL_GL_TEXTURE_COMPARE_FUNC 0x884D -#define LOCAL_GL_COMPARE_R_TO_TEXTURE 0x884E -#define LOCAL_GL_VERSION_1_5 1 -#define LOCAL_GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE -#define LOCAL_GL_FOG_COORD GL_FOG_COORDINATE -#define LOCAL_GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY -#define LOCAL_GL_SRC0_RGB GL_SOURCE0_RGB -#define LOCAL_GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER -#define LOCAL_GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE -#define LOCAL_GL_SRC1_ALPHA GL_SOURCE1_ALPHA -#define LOCAL_GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE -#define LOCAL_GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE -#define LOCAL_GL_SRC0_ALPHA GL_SOURCE0_ALPHA -#define LOCAL_GL_SRC1_RGB GL_SOURCE1_RGB -#define LOCAL_GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING -#define LOCAL_GL_SRC2_ALPHA GL_SOURCE2_ALPHA -#define LOCAL_GL_SRC2_RGB GL_SOURCE2_RGB -#define LOCAL_GL_BUFFER_SIZE 0x8764 -#define LOCAL_GL_BUFFER_USAGE 0x8765 -#define LOCAL_GL_QUERY_COUNTER_BITS 0x8864 -#define LOCAL_GL_CURRENT_QUERY 0x8865 -#define LOCAL_GL_QUERY_RESULT 0x8866 -#define LOCAL_GL_QUERY_RESULT_AVAILABLE 0x8867 -#define LOCAL_GL_ARRAY_BUFFER 0x8892 -#define LOCAL_GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define LOCAL_GL_ARRAY_BUFFER_BINDING 0x8894 -#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define LOCAL_GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define LOCAL_GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define LOCAL_GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define LOCAL_GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A -#define LOCAL_GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C -#define LOCAL_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define LOCAL_GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define LOCAL_GL_READ_ONLY 0x88B8 -#define LOCAL_GL_WRITE_ONLY 0x88B9 -#define LOCAL_GL_READ_WRITE 0x88BA -#define LOCAL_GL_BUFFER_ACCESS 0x88BB -#define LOCAL_GL_BUFFER_MAPPED 0x88BC -#define LOCAL_GL_BUFFER_MAP_POINTER 0x88BD -#define LOCAL_GL_STREAM_DRAW 0x88E0 -#define LOCAL_GL_STREAM_READ 0x88E1 -#define LOCAL_GL_STREAM_COPY 0x88E2 -#define LOCAL_GL_STATIC_DRAW 0x88E4 -#define LOCAL_GL_STATIC_READ 0x88E5 -#define LOCAL_GL_STATIC_COPY 0x88E6 -#define LOCAL_GL_DYNAMIC_DRAW 0x88E8 -#define LOCAL_GL_DYNAMIC_READ 0x88E9 -#define LOCAL_GL_DYNAMIC_COPY 0x88EA -#define LOCAL_GL_PIXEL_UNPACK_BUFFER 0x88EC -#define LOCAL_GL_SAMPLES_PASSED 0x8914 -#define LOCAL_GL_VERSION_2_0 1 -#define LOCAL_GL_BLEND_EQUATION_RGB 0x8009 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define LOCAL_GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define LOCAL_GL_STENCIL_BACK_FUNC 0x8800 -#define LOCAL_GL_STENCIL_BACK_FAIL 0x8801 -#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define LOCAL_GL_MAX_DRAW_BUFFERS 0x8824 -#define LOCAL_GL_DRAW_BUFFER0 0x8825 -#define LOCAL_GL_DRAW_BUFFER1 0x8826 -#define LOCAL_GL_DRAW_BUFFER2 0x8827 -#define LOCAL_GL_DRAW_BUFFER3 0x8828 -#define LOCAL_GL_DRAW_BUFFER4 0x8829 -#define LOCAL_GL_DRAW_BUFFER5 0x882A -#define LOCAL_GL_DRAW_BUFFER6 0x882B -#define LOCAL_GL_DRAW_BUFFER7 0x882C -#define LOCAL_GL_DRAW_BUFFER8 0x882D -#define LOCAL_GL_DRAW_BUFFER9 0x882E -#define LOCAL_GL_DRAW_BUFFER10 0x882F -#define LOCAL_GL_DRAW_BUFFER11 0x8830 -#define LOCAL_GL_DRAW_BUFFER12 0x8831 -#define LOCAL_GL_DRAW_BUFFER13 0x8832 -#define LOCAL_GL_DRAW_BUFFER14 0x8833 -#define LOCAL_GL_DRAW_BUFFER15 0x8834 -#define LOCAL_GL_BLEND_EQUATION_ALPHA 0x883D -#define LOCAL_GL_POINT_SPRITE 0x8861 -#define LOCAL_GL_COORD_REPLACE 0x8862 -#define LOCAL_GL_MAX_VERTEX_ATTRIBS 0x8869 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define LOCAL_GL_MAX_TEXTURE_COORDS 0x8871 -#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define LOCAL_GL_FRAGMENT_SHADER 0x8B30 -#define LOCAL_GL_VERTEX_SHADER 0x8B31 -#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define LOCAL_GL_MAX_VARYING_FLOATS 0x8B4B -#define LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define LOCAL_GL_SHADER_TYPE 0x8B4F -#define LOCAL_GL_FLOAT_VEC2 0x8B50 -#define LOCAL_GL_FLOAT_VEC3 0x8B51 -#define LOCAL_GL_FLOAT_VEC4 0x8B52 -#define LOCAL_GL_INT_VEC2 0x8B53 -#define LOCAL_GL_INT_VEC3 0x8B54 -#define LOCAL_GL_INT_VEC4 0x8B55 -#define LOCAL_GL_BOOL 0x8B56 -#define LOCAL_GL_BOOL_VEC2 0x8B57 -#define LOCAL_GL_BOOL_VEC3 0x8B58 -#define LOCAL_GL_BOOL_VEC4 0x8B59 -#define LOCAL_GL_FLOAT_MAT2 0x8B5A -#define LOCAL_GL_FLOAT_MAT3 0x8B5B -#define LOCAL_GL_FLOAT_MAT4 0x8B5C -#define LOCAL_GL_SAMPLER_1D 0x8B5D -#define LOCAL_GL_SAMPLER_2D 0x8B5E -#define LOCAL_GL_SAMPLER_3D 0x8B5F -#define LOCAL_GL_SAMPLER_CUBE 0x8B60 -#define LOCAL_GL_SAMPLER_1D_SHADOW 0x8B61 -#define LOCAL_GL_SAMPLER_2D_SHADOW 0x8B62 -#define LOCAL_GL_DELETE_STATUS 0x8B80 -#define LOCAL_GL_COMPILE_STATUS 0x8B81 -#define LOCAL_GL_LINK_STATUS 0x8B82 -#define LOCAL_GL_VALIDATE_STATUS 0x8B83 -#define LOCAL_GL_INFO_LOG_LENGTH 0x8B84 -#define LOCAL_GL_ATTACHED_SHADERS 0x8B85 -#define LOCAL_GL_ACTIVE_UNIFORMS 0x8B86 -#define LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define LOCAL_GL_SHADER_SOURCE_LENGTH 0x8B88 -#define LOCAL_GL_ACTIVE_ATTRIBUTES 0x8B89 -#define LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define LOCAL_GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define LOCAL_GL_CURRENT_PROGRAM 0x8B8D -#define LOCAL_GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define LOCAL_GL_LOWER_LEFT 0x8CA1 -#define LOCAL_GL_UPPER_LEFT 0x8CA2 -#define LOCAL_GL_STENCIL_BACK_REF 0x8CA3 -#define LOCAL_GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define LOCAL_GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define LOCAL_GL_3DFX_multisample 1 -#define LOCAL_GL_MULTISAMPLE_3DFX 0x86B2 -#define LOCAL_GL_SAMPLE_BUFFERS_3DFX 0x86B3 -#define LOCAL_GL_SAMPLES_3DFX 0x86B4 -#define LOCAL_GL_MULTISAMPLE_BIT_3DFX 0x20000000 -#define LOCAL_GL_3DFX_tbuffer 1 -#define LOCAL_GL_3DFX_texture_compression_FXT1 1 -#define LOCAL_GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 -#define LOCAL_GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 -#define LOCAL_GL_APPLE_client_storage 1 -#define LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 -#define LOCAL_GL_APPLE_element_array 1 -#define LOCAL_GL_ELEMENT_ARRAY_APPLE 0x8768 -#define LOCAL_GL_ELEMENT_ARRAY_TYPE_APPLE 0x8769 -#define LOCAL_GL_ELEMENT_ARRAY_POINTER_APPLE 0x876A -#define LOCAL_GL_APPLE_fence 1 -#define LOCAL_GL_DRAW_PIXELS_APPLE 0x8A0A -#define LOCAL_GL_FENCE_APPLE 0x8A0B -#define LOCAL_GL_APPLE_float_pixels 1 -#define LOCAL_GL_HALF_APPLE 0x140B -#define LOCAL_GL_RGBA_FLOAT32_APPLE 0x8814 -#define LOCAL_GL_RGB_FLOAT32_APPLE 0x8815 -#define LOCAL_GL_ALPHA_FLOAT32_APPLE 0x8816 -#define LOCAL_GL_INTENSITY_FLOAT32_APPLE 0x8817 -#define LOCAL_GL_LUMINANCE_FLOAT32_APPLE 0x8818 -#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 -#define LOCAL_GL_RGBA_FLOAT16_APPLE 0x881A -#define LOCAL_GL_RGB_FLOAT16_APPLE 0x881B -#define LOCAL_GL_ALPHA_FLOAT16_APPLE 0x881C -#define LOCAL_GL_INTENSITY_FLOAT16_APPLE 0x881D -#define LOCAL_GL_LUMINANCE_FLOAT16_APPLE 0x881E -#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F -#define LOCAL_GL_COLOR_FLOAT_APPLE 0x8A0F -#define LOCAL_GL_APPLE_pixel_buffer 1 -#define LOCAL_GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE 0x8A10 -#define LOCAL_GL_APPLE_specular_vector 1 -#define LOCAL_GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 -#define LOCAL_GL_APPLE_texture_range 1 -#define LOCAL_GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 -#define LOCAL_GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 -#define LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC -#define LOCAL_GL_STORAGE_PRIVATE_APPLE 0x85BD -#define LOCAL_GL_STORAGE_CACHED_APPLE 0x85BE -#define LOCAL_GL_STORAGE_SHARED_APPLE 0x85BF -#define LOCAL_GL_APPLE_transform_hint 1 -#define LOCAL_GL_TRANSFORM_HINT_APPLE 0x85B1 -#define LOCAL_GL_APPLE_vertex_array_object 1 -#define LOCAL_GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 -#define LOCAL_GL_APPLE_vertex_array_range 1 -#define LOCAL_GL_VERTEX_ARRAY_RANGE_APPLE 0x851D -#define LOCAL_GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E -#define LOCAL_GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F -#define LOCAL_GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE 0x8520 -#define LOCAL_GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 -#define LOCAL_GL_STORAGE_CACHED_APPLE 0x85BE -#define LOCAL_GL_STORAGE_SHARED_APPLE 0x85BF -#define LOCAL_GL_APPLE_ycbcr_422 1 -#define LOCAL_GL_YCBCR_422_APPLE 0x85B9 -#define LOCAL_GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA -#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB -#define LOCAL_GL_ARB_color_buffer_float 1 -#define LOCAL_GL_RGBA_FLOAT_MODE_ARB 0x8820 -#define LOCAL_GL_CLAMP_VERTEX_COLOR_ARB 0x891A -#define LOCAL_GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B -#define LOCAL_GL_CLAMP_READ_COLOR_ARB 0x891C -#define LOCAL_GL_FIXED_ONLY_ARB 0x891D -#define LOCAL_GL_ARB_depth_texture 1 -#define LOCAL_GL_DEPTH_COMPONENT16_ARB 0x81A5 -#define LOCAL_GL_DEPTH_COMPONENT24_ARB 0x81A6 -#define LOCAL_GL_DEPTH_COMPONENT32_ARB 0x81A7 -#define LOCAL_GL_TEXTURE_DEPTH_SIZE_ARB 0x884A -#define LOCAL_GL_DEPTH_TEXTURE_MODE_ARB 0x884B -#define LOCAL_GL_ARB_draw_buffers 1 -#define LOCAL_GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define LOCAL_GL_DRAW_BUFFER0_ARB 0x8825 -#define LOCAL_GL_DRAW_BUFFER1_ARB 0x8826 -#define LOCAL_GL_DRAW_BUFFER2_ARB 0x8827 -#define LOCAL_GL_DRAW_BUFFER3_ARB 0x8828 -#define LOCAL_GL_DRAW_BUFFER4_ARB 0x8829 -#define LOCAL_GL_DRAW_BUFFER5_ARB 0x882A -#define LOCAL_GL_DRAW_BUFFER6_ARB 0x882B -#define LOCAL_GL_DRAW_BUFFER7_ARB 0x882C -#define LOCAL_GL_DRAW_BUFFER8_ARB 0x882D -#define LOCAL_GL_DRAW_BUFFER9_ARB 0x882E -#define LOCAL_GL_DRAW_BUFFER10_ARB 0x882F -#define LOCAL_GL_DRAW_BUFFER11_ARB 0x8830 -#define LOCAL_GL_DRAW_BUFFER12_ARB 0x8831 -#define LOCAL_GL_DRAW_BUFFER13_ARB 0x8832 -#define LOCAL_GL_DRAW_BUFFER14_ARB 0x8833 -#define LOCAL_GL_DRAW_BUFFER15_ARB 0x8834 -#define LOCAL_GL_ARB_fragment_program 1 -#define LOCAL_GL_FRAGMENT_PROGRAM_ARB 0x8804 -#define LOCAL_GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 -#define LOCAL_GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 -#define LOCAL_GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 -#define LOCAL_GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 -#define LOCAL_GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 -#define LOCAL_GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A -#define LOCAL_GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B -#define LOCAL_GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C -#define LOCAL_GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D -#define LOCAL_GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E -#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F -#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 -#define LOCAL_GL_MAX_TEXTURE_COORDS_ARB 0x8871 -#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 -#define LOCAL_GL_ARB_fragment_program_shadow 1 -#define LOCAL_GL_ARB_fragment_shader 1 -#define LOCAL_GL_FRAGMENT_SHADER_ARB 0x8B30 -#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B -#define LOCAL_GL_ARB_half_float_pixel 1 -#define LOCAL_GL_HALF_FLOAT_ARB 0x140B -#define LOCAL_GL_ARB_imaging 1 -#define LOCAL_GL_CONSTANT_COLOR 0x8001 -#define LOCAL_GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define LOCAL_GL_CONSTANT_ALPHA 0x8003 -#define LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define LOCAL_GL_BLEND_COLOR 0x8005 -#define LOCAL_GL_FUNC_ADD 0x8006 -#define LOCAL_GL_MIN 0x8007 -#define LOCAL_GL_MAX 0x8008 -#define LOCAL_GL_BLEND_EQUATION 0x8009 -#define LOCAL_GL_FUNC_SUBTRACT 0x800A -#define LOCAL_GL_FUNC_REVERSE_SUBTRACT 0x800B -#define LOCAL_GL_CONVOLUTION_1D 0x8010 -#define LOCAL_GL_CONVOLUTION_2D 0x8011 -#define LOCAL_GL_SEPARABLE_2D 0x8012 -#define LOCAL_GL_CONVOLUTION_BORDER_MODE 0x8013 -#define LOCAL_GL_CONVOLUTION_FILTER_SCALE 0x8014 -#define LOCAL_GL_CONVOLUTION_FILTER_BIAS 0x8015 -#define LOCAL_GL_REDUCE 0x8016 -#define LOCAL_GL_CONVOLUTION_FORMAT 0x8017 -#define LOCAL_GL_CONVOLUTION_WIDTH 0x8018 -#define LOCAL_GL_CONVOLUTION_HEIGHT 0x8019 -#define LOCAL_GL_MAX_CONVOLUTION_WIDTH 0x801A -#define LOCAL_GL_MAX_CONVOLUTION_HEIGHT 0x801B -#define LOCAL_GL_POST_CONVOLUTION_RED_SCALE 0x801C -#define LOCAL_GL_POST_CONVOLUTION_GREEN_SCALE 0x801D -#define LOCAL_GL_POST_CONVOLUTION_BLUE_SCALE 0x801E -#define LOCAL_GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F -#define LOCAL_GL_POST_CONVOLUTION_RED_BIAS 0x8020 -#define LOCAL_GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 -#define LOCAL_GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 -#define LOCAL_GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 -#define LOCAL_GL_HISTOGRAM 0x8024 -#define LOCAL_GL_PROXY_HISTOGRAM 0x8025 -#define LOCAL_GL_HISTOGRAM_WIDTH 0x8026 -#define LOCAL_GL_HISTOGRAM_FORMAT 0x8027 -#define LOCAL_GL_HISTOGRAM_RED_SIZE 0x8028 -#define LOCAL_GL_HISTOGRAM_GREEN_SIZE 0x8029 -#define LOCAL_GL_HISTOGRAM_BLUE_SIZE 0x802A -#define LOCAL_GL_HISTOGRAM_ALPHA_SIZE 0x802B -#define LOCAL_GL_HISTOGRAM_LUMINANCE_SIZE 0x802C -#define LOCAL_GL_HISTOGRAM_SINK 0x802D -#define LOCAL_GL_MINMAX 0x802E -#define LOCAL_GL_MINMAX_FORMAT 0x802F -#define LOCAL_GL_MINMAX_SINK 0x8030 -#define LOCAL_GL_TABLE_TOO_LARGE 0x8031 -#define LOCAL_GL_COLOR_MATRIX 0x80B1 -#define LOCAL_GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 -#define LOCAL_GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 -#define LOCAL_GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 -#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 -#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 -#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 -#define LOCAL_GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 -#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 -#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA -#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB -#define LOCAL_GL_COLOR_TABLE 0x80D0 -#define LOCAL_GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 -#define LOCAL_GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 -#define LOCAL_GL_PROXY_COLOR_TABLE 0x80D3 -#define LOCAL_GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 -#define LOCAL_GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 -#define LOCAL_GL_COLOR_TABLE_SCALE 0x80D6 -#define LOCAL_GL_COLOR_TABLE_BIAS 0x80D7 -#define LOCAL_GL_COLOR_TABLE_FORMAT 0x80D8 -#define LOCAL_GL_COLOR_TABLE_WIDTH 0x80D9 -#define LOCAL_GL_COLOR_TABLE_RED_SIZE 0x80DA -#define LOCAL_GL_COLOR_TABLE_GREEN_SIZE 0x80DB -#define LOCAL_GL_COLOR_TABLE_BLUE_SIZE 0x80DC -#define LOCAL_GL_COLOR_TABLE_ALPHA_SIZE 0x80DD -#define LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE -#define LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF -#define LOCAL_GL_IGNORE_BORDER 0x8150 -#define LOCAL_GL_CONSTANT_BORDER 0x8151 -#define LOCAL_GL_WRAP_BORDER 0x8152 -#define LOCAL_GL_REPLICATE_BORDER 0x8153 -#define LOCAL_GL_CONVOLUTION_BORDER_COLOR 0x8154 -#define LOCAL_GL_ARB_matrix_palette 1 -#define LOCAL_GL_MATRIX_PALETTE_ARB 0x8840 -#define LOCAL_GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 -#define LOCAL_GL_MAX_PALETTE_MATRICES_ARB 0x8842 -#define LOCAL_GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 -#define LOCAL_GL_MATRIX_INDEX_ARRAY_ARB 0x8844 -#define LOCAL_GL_CURRENT_MATRIX_INDEX_ARB 0x8845 -#define LOCAL_GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 -#define LOCAL_GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 -#define LOCAL_GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 -#define LOCAL_GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 -#define LOCAL_GL_ARB_multisample 1 -#define LOCAL_GL_MULTISAMPLE_ARB 0x809D -#define LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define LOCAL_GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define LOCAL_GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define LOCAL_GL_SAMPLES_ARB 0x80A9 -#define LOCAL_GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define LOCAL_GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define LOCAL_GL_MULTISAMPLE_BIT_ARB 0x20000000 -#define LOCAL_GL_ARB_multitexture 1 -#define LOCAL_GL_TEXTURE0_ARB 0x84C0 -#define LOCAL_GL_TEXTURE1_ARB 0x84C1 -#define LOCAL_GL_TEXTURE2_ARB 0x84C2 -#define LOCAL_GL_TEXTURE3_ARB 0x84C3 -#define LOCAL_GL_TEXTURE4_ARB 0x84C4 -#define LOCAL_GL_TEXTURE5_ARB 0x84C5 -#define LOCAL_GL_TEXTURE6_ARB 0x84C6 -#define LOCAL_GL_TEXTURE7_ARB 0x84C7 -#define LOCAL_GL_TEXTURE8_ARB 0x84C8 -#define LOCAL_GL_TEXTURE9_ARB 0x84C9 -#define LOCAL_GL_TEXTURE10_ARB 0x84CA -#define LOCAL_GL_TEXTURE11_ARB 0x84CB -#define LOCAL_GL_TEXTURE12_ARB 0x84CC -#define LOCAL_GL_TEXTURE13_ARB 0x84CD -#define LOCAL_GL_TEXTURE14_ARB 0x84CE -#define LOCAL_GL_TEXTURE15_ARB 0x84CF -#define LOCAL_GL_TEXTURE16_ARB 0x84D0 -#define LOCAL_GL_TEXTURE17_ARB 0x84D1 -#define LOCAL_GL_TEXTURE18_ARB 0x84D2 -#define LOCAL_GL_TEXTURE19_ARB 0x84D3 -#define LOCAL_GL_TEXTURE20_ARB 0x84D4 -#define LOCAL_GL_TEXTURE21_ARB 0x84D5 -#define LOCAL_GL_TEXTURE22_ARB 0x84D6 -#define LOCAL_GL_TEXTURE23_ARB 0x84D7 -#define LOCAL_GL_TEXTURE24_ARB 0x84D8 -#define LOCAL_GL_TEXTURE25_ARB 0x84D9 -#define LOCAL_GL_TEXTURE26_ARB 0x84DA -#define LOCAL_GL_TEXTURE27_ARB 0x84DB -#define LOCAL_GL_TEXTURE28_ARB 0x84DC -#define LOCAL_GL_TEXTURE29_ARB 0x84DD -#define LOCAL_GL_TEXTURE30_ARB 0x84DE -#define LOCAL_GL_TEXTURE31_ARB 0x84DF -#define LOCAL_GL_ACTIVE_TEXTURE_ARB 0x84E0 -#define LOCAL_GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 -#define LOCAL_GL_MAX_TEXTURE_UNITS_ARB 0x84E2 -#define LOCAL_GL_ARB_occlusion_query 1 -#define LOCAL_GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define LOCAL_GL_CURRENT_QUERY_ARB 0x8865 -#define LOCAL_GL_QUERY_RESULT_ARB 0x8866 -#define LOCAL_GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#define LOCAL_GL_SAMPLES_PASSED_ARB 0x8914 -#define LOCAL_GL_ARB_pixel_buffer_object 1 -#define LOCAL_GL_PIXEL_PACK_BUFFER_ARB 0x88EB -#define LOCAL_GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED -#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF -#define LOCAL_GL_ARB_point_parameters 1 -#define LOCAL_GL_POINT_SIZE_MIN_ARB 0x8126 -#define LOCAL_GL_POINT_SIZE_MAX_ARB 0x8127 -#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 -#define LOCAL_GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 -#define LOCAL_GL_ARB_point_sprite 1 -#define LOCAL_GL_POINT_SPRITE_ARB 0x8861 -#define LOCAL_GL_COORD_REPLACE_ARB 0x8862 -#define LOCAL_GL_ARB_shader_objects 1 -#define LOCAL_GL_PROGRAM_OBJECT_ARB 0x8B40 -#define LOCAL_GL_SHADER_OBJECT_ARB 0x8B48 -#define LOCAL_GL_OBJECT_TYPE_ARB 0x8B4E -#define LOCAL_GL_OBJECT_SUBTYPE_ARB 0x8B4F -#define LOCAL_GL_FLOAT_VEC2_ARB 0x8B50 -#define LOCAL_GL_FLOAT_VEC3_ARB 0x8B51 -#define LOCAL_GL_FLOAT_VEC4_ARB 0x8B52 -#define LOCAL_GL_INT_VEC2_ARB 0x8B53 -#define LOCAL_GL_INT_VEC3_ARB 0x8B54 -#define LOCAL_GL_INT_VEC4_ARB 0x8B55 -#define LOCAL_GL_BOOL_ARB 0x8B56 -#define LOCAL_GL_BOOL_VEC2_ARB 0x8B57 -#define LOCAL_GL_BOOL_VEC3_ARB 0x8B58 -#define LOCAL_GL_BOOL_VEC4_ARB 0x8B59 -#define LOCAL_GL_FLOAT_MAT2_ARB 0x8B5A -#define LOCAL_GL_FLOAT_MAT3_ARB 0x8B5B -#define LOCAL_GL_FLOAT_MAT4_ARB 0x8B5C -#define LOCAL_GL_SAMPLER_1D_ARB 0x8B5D -#define LOCAL_GL_SAMPLER_2D_ARB 0x8B5E -#define LOCAL_GL_SAMPLER_3D_ARB 0x8B5F -#define LOCAL_GL_SAMPLER_CUBE_ARB 0x8B60 -#define LOCAL_GL_SAMPLER_1D_SHADOW_ARB 0x8B61 -#define LOCAL_GL_SAMPLER_2D_SHADOW_ARB 0x8B62 -#define LOCAL_GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define LOCAL_GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define LOCAL_GL_OBJECT_DELETE_STATUS_ARB 0x8B80 -#define LOCAL_GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define LOCAL_GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define LOCAL_GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 -#define LOCAL_GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#define LOCAL_GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 -#define LOCAL_GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 -#define LOCAL_GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 -#define LOCAL_GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 -#define LOCAL_GL_ARB_shading_language_100 1 -#define LOCAL_GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#define LOCAL_GL_ARB_shadow 1 -#define LOCAL_GL_TEXTURE_COMPARE_MODE_ARB 0x884C -#define LOCAL_GL_TEXTURE_COMPARE_FUNC_ARB 0x884D -#define LOCAL_GL_COMPARE_R_TO_TEXTURE_ARB 0x884E -#define LOCAL_GL_ARB_shadow_ambient 1 -#define LOCAL_GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF -#define LOCAL_GL_ARB_texture_border_clamp 1 -#define LOCAL_GL_CLAMP_TO_BORDER_ARB 0x812D -#define LOCAL_GL_ARB_texture_compression 1 -#define LOCAL_GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define LOCAL_GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define LOCAL_GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define LOCAL_GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define LOCAL_GL_COMPRESSED_RGB_ARB 0x84ED -#define LOCAL_GL_COMPRESSED_RGBA_ARB 0x84EE -#define LOCAL_GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF -#define LOCAL_GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define LOCAL_GL_TEXTURE_COMPRESSED_ARB 0x86A1 -#define LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 -#define LOCAL_GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -#define LOCAL_GL_ARB_texture_cube_map 1 -#define LOCAL_GL_NORMAL_MAP_ARB 0x8511 -#define LOCAL_GL_REFLECTION_MAP_ARB 0x8512 -#define LOCAL_GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A -#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C -#define LOCAL_GL_ARB_texture_env_add 1 -#define LOCAL_GL_ARB_texture_env_combine 1 -#define LOCAL_GL_SUBTRACT_ARB 0x84E7 -#define LOCAL_GL_COMBINE_ARB 0x8570 -#define LOCAL_GL_COMBINE_RGB_ARB 0x8571 -#define LOCAL_GL_COMBINE_ALPHA_ARB 0x8572 -#define LOCAL_GL_RGB_SCALE_ARB 0x8573 -#define LOCAL_GL_ADD_SIGNED_ARB 0x8574 -#define LOCAL_GL_INTERPOLATE_ARB 0x8575 -#define LOCAL_GL_CONSTANT_ARB 0x8576 -#define LOCAL_GL_PRIMARY_COLOR_ARB 0x8577 -#define LOCAL_GL_PREVIOUS_ARB 0x8578 -#define LOCAL_GL_SOURCE0_RGB_ARB 0x8580 -#define LOCAL_GL_SOURCE1_RGB_ARB 0x8581 -#define LOCAL_GL_SOURCE2_RGB_ARB 0x8582 -#define LOCAL_GL_SOURCE0_ALPHA_ARB 0x8588 -#define LOCAL_GL_SOURCE1_ALPHA_ARB 0x8589 -#define LOCAL_GL_SOURCE2_ALPHA_ARB 0x858A -#define LOCAL_GL_OPERAND0_RGB_ARB 0x8590 -#define LOCAL_GL_OPERAND1_RGB_ARB 0x8591 -#define LOCAL_GL_OPERAND2_RGB_ARB 0x8592 -#define LOCAL_GL_OPERAND0_ALPHA_ARB 0x8598 -#define LOCAL_GL_OPERAND1_ALPHA_ARB 0x8599 -#define LOCAL_GL_OPERAND2_ALPHA_ARB 0x859A -#define LOCAL_GL_ARB_texture_env_crossbar 1 -#define LOCAL_GL_ARB_texture_env_dot3 1 -#define LOCAL_GL_DOT3_RGB_ARB 0x86AE -#define LOCAL_GL_DOT3_RGBA_ARB 0x86AF -#define LOCAL_GL_ARB_texture_float 1 -#define LOCAL_GL_RGBA32F_ARB 0x8814 -#define LOCAL_GL_RGB32F_ARB 0x8815 -#define LOCAL_GL_ALPHA32F_ARB 0x8816 -#define LOCAL_GL_INTENSITY32F_ARB 0x8817 -#define LOCAL_GL_LUMINANCE32F_ARB 0x8818 -#define LOCAL_GL_LUMINANCE_ALPHA32F_ARB 0x8819 -#define LOCAL_GL_RGBA16F_ARB 0x881A -#define LOCAL_GL_RGB16F_ARB 0x881B -#define LOCAL_GL_ALPHA16F_ARB 0x881C -#define LOCAL_GL_INTENSITY16F_ARB 0x881D -#define LOCAL_GL_LUMINANCE16F_ARB 0x881E -#define LOCAL_GL_LUMINANCE_ALPHA16F_ARB 0x881F -#define LOCAL_GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#define LOCAL_GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 -#define LOCAL_GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 -#define LOCAL_GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 -#define LOCAL_GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 -#define LOCAL_GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 -#define LOCAL_GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 -#define LOCAL_GL_UNSIGNED_NORMALIZED_ARB 0x8C17 -#define LOCAL_GL_ARB_texture_mirrored_repeat 1 -#define LOCAL_GL_MIRRORED_REPEAT_ARB 0x8370 -#define LOCAL_GL_ARB_texture_non_power_of_two 1 -#define LOCAL_GL_ARB_texture_rectangle 1 -#define LOCAL_GL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 -#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 -#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -#define LOCAL_GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define LOCAL_GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define LOCAL_GL_ARB_transpose_matrix 1 -#define LOCAL_GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 -#define LOCAL_GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 -#define LOCAL_GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 -#define LOCAL_GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#define LOCAL_GL_ARB_vertex_blend 1 -#define LOCAL_GL_MODELVIEW0_ARB 0x1700 -#define LOCAL_GL_MODELVIEW1_ARB 0x850A -#define LOCAL_GL_MAX_VERTEX_UNITS_ARB 0x86A4 -#define LOCAL_GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 -#define LOCAL_GL_WEIGHT_SUM_UNITY_ARB 0x86A6 -#define LOCAL_GL_VERTEX_BLEND_ARB 0x86A7 -#define LOCAL_GL_CURRENT_WEIGHT_ARB 0x86A8 -#define LOCAL_GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 -#define LOCAL_GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA -#define LOCAL_GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB -#define LOCAL_GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC -#define LOCAL_GL_WEIGHT_ARRAY_ARB 0x86AD -#define LOCAL_GL_MODELVIEW2_ARB 0x8722 -#define LOCAL_GL_MODELVIEW3_ARB 0x8723 -#define LOCAL_GL_MODELVIEW4_ARB 0x8724 -#define LOCAL_GL_MODELVIEW5_ARB 0x8725 -#define LOCAL_GL_MODELVIEW6_ARB 0x8726 -#define LOCAL_GL_MODELVIEW7_ARB 0x8727 -#define LOCAL_GL_MODELVIEW8_ARB 0x8728 -#define LOCAL_GL_MODELVIEW9_ARB 0x8729 -#define LOCAL_GL_MODELVIEW10_ARB 0x872A -#define LOCAL_GL_MODELVIEW11_ARB 0x872B -#define LOCAL_GL_MODELVIEW12_ARB 0x872C -#define LOCAL_GL_MODELVIEW13_ARB 0x872D -#define LOCAL_GL_MODELVIEW14_ARB 0x872E -#define LOCAL_GL_MODELVIEW15_ARB 0x872F -#define LOCAL_GL_MODELVIEW16_ARB 0x8730 -#define LOCAL_GL_MODELVIEW17_ARB 0x8731 -#define LOCAL_GL_MODELVIEW18_ARB 0x8732 -#define LOCAL_GL_MODELVIEW19_ARB 0x8733 -#define LOCAL_GL_MODELVIEW20_ARB 0x8734 -#define LOCAL_GL_MODELVIEW21_ARB 0x8735 -#define LOCAL_GL_MODELVIEW22_ARB 0x8736 -#define LOCAL_GL_MODELVIEW23_ARB 0x8737 -#define LOCAL_GL_MODELVIEW24_ARB 0x8738 -#define LOCAL_GL_MODELVIEW25_ARB 0x8739 -#define LOCAL_GL_MODELVIEW26_ARB 0x873A -#define LOCAL_GL_MODELVIEW27_ARB 0x873B -#define LOCAL_GL_MODELVIEW28_ARB 0x873C -#define LOCAL_GL_MODELVIEW29_ARB 0x873D -#define LOCAL_GL_MODELVIEW30_ARB 0x873E -#define LOCAL_GL_MODELVIEW31_ARB 0x873F -#define LOCAL_GL_ARB_vertex_buffer_object 1 -#define LOCAL_GL_BUFFER_SIZE_ARB 0x8764 -#define LOCAL_GL_BUFFER_USAGE_ARB 0x8765 -#define LOCAL_GL_ARRAY_BUFFER_ARB 0x8892 -#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 -#define LOCAL_GL_ARRAY_BUFFER_BINDING_ARB 0x8894 -#define LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 -#define LOCAL_GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 -#define LOCAL_GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 -#define LOCAL_GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 -#define LOCAL_GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A -#define LOCAL_GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C -#define LOCAL_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D -#define LOCAL_GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F -#define LOCAL_GL_READ_ONLY_ARB 0x88B8 -#define LOCAL_GL_WRITE_ONLY_ARB 0x88B9 -#define LOCAL_GL_READ_WRITE_ARB 0x88BA -#define LOCAL_GL_BUFFER_ACCESS_ARB 0x88BB -#define LOCAL_GL_BUFFER_MAPPED_ARB 0x88BC -#define LOCAL_GL_BUFFER_MAP_POINTER_ARB 0x88BD -#define LOCAL_GL_STREAM_DRAW_ARB 0x88E0 -#define LOCAL_GL_STREAM_READ_ARB 0x88E1 -#define LOCAL_GL_STREAM_COPY_ARB 0x88E2 -#define LOCAL_GL_STATIC_DRAW_ARB 0x88E4 -#define LOCAL_GL_STATIC_READ_ARB 0x88E5 -#define LOCAL_GL_STATIC_COPY_ARB 0x88E6 -#define LOCAL_GL_DYNAMIC_DRAW_ARB 0x88E8 -#define LOCAL_GL_DYNAMIC_READ_ARB 0x88E9 -#define LOCAL_GL_DYNAMIC_COPY_ARB 0x88EA -#define LOCAL_GL_ARB_vertex_program 1 -#define LOCAL_GL_COLOR_SUM_ARB 0x8458 -#define LOCAL_GL_VERTEX_PROGRAM_ARB 0x8620 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 -#define LOCAL_GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 -#define LOCAL_GL_PROGRAM_LENGTH_ARB 0x8627 -#define LOCAL_GL_PROGRAM_STRING_ARB 0x8628 -#define LOCAL_GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E -#define LOCAL_GL_MAX_PROGRAM_MATRICES_ARB 0x862F -#define LOCAL_GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 -#define LOCAL_GL_CURRENT_MATRIX_ARB 0x8641 -#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 -#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 -#define LOCAL_GL_PROGRAM_ERROR_POSITION_ARB 0x864B -#define LOCAL_GL_PROGRAM_BINDING_ARB 0x8677 -#define LOCAL_GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A -#define LOCAL_GL_PROGRAM_ERROR_STRING_ARB 0x8874 -#define LOCAL_GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 -#define LOCAL_GL_PROGRAM_FORMAT_ARB 0x8876 -#define LOCAL_GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 -#define LOCAL_GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 -#define LOCAL_GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 -#define LOCAL_GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 -#define LOCAL_GL_PROGRAM_TEMPORARIES_ARB 0x88A4 -#define LOCAL_GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 -#define LOCAL_GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 -#define LOCAL_GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 -#define LOCAL_GL_PROGRAM_PARAMETERS_ARB 0x88A8 -#define LOCAL_GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 -#define LOCAL_GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA -#define LOCAL_GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB -#define LOCAL_GL_PROGRAM_ATTRIBS_ARB 0x88AC -#define LOCAL_GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD -#define LOCAL_GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE -#define LOCAL_GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF -#define LOCAL_GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 -#define LOCAL_GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 -#define LOCAL_GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 -#define LOCAL_GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 -#define LOCAL_GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 -#define LOCAL_GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 -#define LOCAL_GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 -#define LOCAL_GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 -#define LOCAL_GL_MATRIX0_ARB 0x88C0 -#define LOCAL_GL_MATRIX1_ARB 0x88C1 -#define LOCAL_GL_MATRIX2_ARB 0x88C2 -#define LOCAL_GL_MATRIX3_ARB 0x88C3 -#define LOCAL_GL_MATRIX4_ARB 0x88C4 -#define LOCAL_GL_MATRIX5_ARB 0x88C5 -#define LOCAL_GL_MATRIX6_ARB 0x88C6 -#define LOCAL_GL_MATRIX7_ARB 0x88C7 -#define LOCAL_GL_MATRIX8_ARB 0x88C8 -#define LOCAL_GL_MATRIX9_ARB 0x88C9 -#define LOCAL_GL_MATRIX10_ARB 0x88CA -#define LOCAL_GL_MATRIX11_ARB 0x88CB -#define LOCAL_GL_MATRIX12_ARB 0x88CC -#define LOCAL_GL_MATRIX13_ARB 0x88CD -#define LOCAL_GL_MATRIX14_ARB 0x88CE -#define LOCAL_GL_MATRIX15_ARB 0x88CF -#define LOCAL_GL_MATRIX16_ARB 0x88D0 -#define LOCAL_GL_MATRIX17_ARB 0x88D1 -#define LOCAL_GL_MATRIX18_ARB 0x88D2 -#define LOCAL_GL_MATRIX19_ARB 0x88D3 -#define LOCAL_GL_MATRIX20_ARB 0x88D4 -#define LOCAL_GL_MATRIX21_ARB 0x88D5 -#define LOCAL_GL_MATRIX22_ARB 0x88D6 -#define LOCAL_GL_MATRIX23_ARB 0x88D7 -#define LOCAL_GL_MATRIX24_ARB 0x88D8 -#define LOCAL_GL_MATRIX25_ARB 0x88D9 -#define LOCAL_GL_MATRIX26_ARB 0x88DA -#define LOCAL_GL_MATRIX27_ARB 0x88DB -#define LOCAL_GL_MATRIX28_ARB 0x88DC -#define LOCAL_GL_MATRIX29_ARB 0x88DD -#define LOCAL_GL_MATRIX30_ARB 0x88DE -#define LOCAL_GL_MATRIX31_ARB 0x88DF -#define LOCAL_GL_ARB_vertex_shader 1 -#define LOCAL_GL_VERTEX_SHADER_ARB 0x8B31 -#define LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A -#define LOCAL_GL_MAX_VARYING_FLOATS_ARB 0x8B4B -#define LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C -#define LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D -#define LOCAL_GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 -#define LOCAL_GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A -#define LOCAL_GL_ARB_window_pos 1 -#define LOCAL_GL_ATIX_point_sprites 1 -#define LOCAL_GL_ATIX_texture_env_combine3 1 -#define LOCAL_GL_MODULATE_ADD_ATIX 0x8744 -#define LOCAL_GL_MODULATE_SIGNED_ADD_ATIX 0x8745 -#define LOCAL_GL_MODULATE_SUBTRACT_ATIX 0x8746 -#define LOCAL_GL_ATIX_texture_env_route 1 -#define LOCAL_GL_SECONDARY_COLOR_ATIX 0x8747 -#define LOCAL_GL_TEXTURE_OUTPUT_RGB_ATIX 0x8748 -#define LOCAL_GL_TEXTURE_OUTPUT_ALPHA_ATIX 0x8749 -#define LOCAL_GL_ATIX_vertex_shader_output_point_size 1 -#define LOCAL_GL_OUTPUT_POINT_SIZE_ATIX 0x610E -#define LOCAL_GL_ATI_draw_buffers 1 -#define LOCAL_GL_MAX_DRAW_BUFFERS_ATI 0x8824 -#define LOCAL_GL_DRAW_BUFFER0_ATI 0x8825 -#define LOCAL_GL_DRAW_BUFFER1_ATI 0x8826 -#define LOCAL_GL_DRAW_BUFFER2_ATI 0x8827 -#define LOCAL_GL_DRAW_BUFFER3_ATI 0x8828 -#define LOCAL_GL_DRAW_BUFFER4_ATI 0x8829 -#define LOCAL_GL_DRAW_BUFFER5_ATI 0x882A -#define LOCAL_GL_DRAW_BUFFER6_ATI 0x882B -#define LOCAL_GL_DRAW_BUFFER7_ATI 0x882C -#define LOCAL_GL_DRAW_BUFFER8_ATI 0x882D -#define LOCAL_GL_DRAW_BUFFER9_ATI 0x882E -#define LOCAL_GL_DRAW_BUFFER10_ATI 0x882F -#define LOCAL_GL_DRAW_BUFFER11_ATI 0x8830 -#define LOCAL_GL_DRAW_BUFFER12_ATI 0x8831 -#define LOCAL_GL_DRAW_BUFFER13_ATI 0x8832 -#define LOCAL_GL_DRAW_BUFFER14_ATI 0x8833 -#define LOCAL_GL_DRAW_BUFFER15_ATI 0x8834 -#define LOCAL_GL_ATI_element_array 1 -#define LOCAL_GL_ELEMENT_ARRAY_ATI 0x8768 -#define LOCAL_GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 -#define LOCAL_GL_ELEMENT_ARRAY_POINTER_ATI 0x876A -#define LOCAL_GL_ATI_envmap_bumpmap 1 -#define LOCAL_GL_BUMP_ROT_MATRIX_ATI 0x8775 -#define LOCAL_GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 -#define LOCAL_GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 -#define LOCAL_GL_BUMP_TEX_UNITS_ATI 0x8778 -#define LOCAL_GL_DUDV_ATI 0x8779 -#define LOCAL_GL_DU8DV8_ATI 0x877A -#define LOCAL_GL_BUMP_ENVMAP_ATI 0x877B -#define LOCAL_GL_BUMP_TARGET_ATI 0x877C -#define LOCAL_GL_ATI_fragment_shader 1 -#define LOCAL_GL_RED_BIT_ATI 0x00000001 -#define LOCAL_GL_2X_BIT_ATI 0x00000001 -#define LOCAL_GL_4X_BIT_ATI 0x00000002 -#define LOCAL_GL_GREEN_BIT_ATI 0x00000002 -#define LOCAL_GL_COMP_BIT_ATI 0x00000002 -#define LOCAL_GL_BLUE_BIT_ATI 0x00000004 -#define LOCAL_GL_8X_BIT_ATI 0x00000004 -#define LOCAL_GL_NEGATE_BIT_ATI 0x00000004 -#define LOCAL_GL_BIAS_BIT_ATI 0x00000008 -#define LOCAL_GL_HALF_BIT_ATI 0x00000008 -#define LOCAL_GL_QUARTER_BIT_ATI 0x00000010 -#define LOCAL_GL_EIGHTH_BIT_ATI 0x00000020 -#define LOCAL_GL_SATURATE_BIT_ATI 0x00000040 -#define LOCAL_GL_FRAGMENT_SHADER_ATI 0x8920 -#define LOCAL_GL_REG_0_ATI 0x8921 -#define LOCAL_GL_REG_1_ATI 0x8922 -#define LOCAL_GL_REG_2_ATI 0x8923 -#define LOCAL_GL_REG_3_ATI 0x8924 -#define LOCAL_GL_REG_4_ATI 0x8925 -#define LOCAL_GL_REG_5_ATI 0x8926 -#define LOCAL_GL_CON_0_ATI 0x8941 -#define LOCAL_GL_CON_1_ATI 0x8942 -#define LOCAL_GL_CON_2_ATI 0x8943 -#define LOCAL_GL_CON_3_ATI 0x8944 -#define LOCAL_GL_CON_4_ATI 0x8945 -#define LOCAL_GL_CON_5_ATI 0x8946 -#define LOCAL_GL_CON_6_ATI 0x8947 -#define LOCAL_GL_CON_7_ATI 0x8948 -#define LOCAL_GL_MOV_ATI 0x8961 -#define LOCAL_GL_ADD_ATI 0x8963 -#define LOCAL_GL_MUL_ATI 0x8964 -#define LOCAL_GL_SUB_ATI 0x8965 -#define LOCAL_GL_DOT3_ATI 0x8966 -#define LOCAL_GL_DOT4_ATI 0x8967 -#define LOCAL_GL_MAD_ATI 0x8968 -#define LOCAL_GL_LERP_ATI 0x8969 -#define LOCAL_GL_CND_ATI 0x896A -#define LOCAL_GL_CND0_ATI 0x896B -#define LOCAL_GL_DOT2_ADD_ATI 0x896C -#define LOCAL_GL_SECONDARY_INTERPOLATOR_ATI 0x896D -#define LOCAL_GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E -#define LOCAL_GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F -#define LOCAL_GL_NUM_PASSES_ATI 0x8970 -#define LOCAL_GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 -#define LOCAL_GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 -#define LOCAL_GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 -#define LOCAL_GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 -#define LOCAL_GL_COLOR_ALPHA_PAIRING_ATI 0x8975 -#define LOCAL_GL_SWIZZLE_STR_ATI 0x8976 -#define LOCAL_GL_SWIZZLE_STQ_ATI 0x8977 -#define LOCAL_GL_SWIZZLE_STR_DR_ATI 0x8978 -#define LOCAL_GL_SWIZZLE_STQ_DQ_ATI 0x8979 -#define LOCAL_GL_SWIZZLE_STRQ_ATI 0x897A -#define LOCAL_GL_SWIZZLE_STRQ_DQ_ATI 0x897B -#define LOCAL_GL_ATI_map_object_buffer 1 -#define LOCAL_GL_ATI_pn_triangles 1 -#define LOCAL_GL_PN_TRIANGLES_ATI 0x87F0 -#define LOCAL_GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 -#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 -#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 -#define LOCAL_GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 -#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 -#define LOCAL_GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 -#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 -#define LOCAL_GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 -#define LOCAL_GL_ATI_separate_stencil 1 -#define LOCAL_GL_STENCIL_BACK_FUNC_ATI 0x8800 -#define LOCAL_GL_STENCIL_BACK_FAIL_ATI 0x8801 -#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 -#define LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 -#define LOCAL_GL_ATI_text_fragment_shader 1 -#define LOCAL_GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 -#define LOCAL_GL_ATI_texture_compression_3dc 1 -#define LOCAL_GL_COMPRESSED_RGB_3DC_ATI 0x8837 -#define LOCAL_GL_ATI_texture_env_combine3 1 -#define LOCAL_GL_MODULATE_ADD_ATI 0x8744 -#define LOCAL_GL_MODULATE_SIGNED_ADD_ATI 0x8745 -#define LOCAL_GL_MODULATE_SUBTRACT_ATI 0x8746 -#define LOCAL_GL_ATI_texture_float 1 -#define LOCAL_GL_RGBA_FLOAT32_ATI 0x8814 -#define LOCAL_GL_RGB_FLOAT32_ATI 0x8815 -#define LOCAL_GL_ALPHA_FLOAT32_ATI 0x8816 -#define LOCAL_GL_INTENSITY_FLOAT32_ATI 0x8817 -#define LOCAL_GL_LUMINANCE_FLOAT32_ATI 0x8818 -#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 -#define LOCAL_GL_RGBA_FLOAT16_ATI 0x881A -#define LOCAL_GL_RGB_FLOAT16_ATI 0x881B -#define LOCAL_GL_ALPHA_FLOAT16_ATI 0x881C -#define LOCAL_GL_INTENSITY_FLOAT16_ATI 0x881D -#define LOCAL_GL_LUMINANCE_FLOAT16_ATI 0x881E -#define LOCAL_GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F -#define LOCAL_GL_ATI_texture_mirror_once 1 -#define LOCAL_GL_MIRROR_CLAMP_ATI 0x8742 -#define LOCAL_GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 -#define LOCAL_GL_ATI_vertex_array_object 1 -#define LOCAL_GL_STATIC_ATI 0x8760 -#define LOCAL_GL_DYNAMIC_ATI 0x8761 -#define LOCAL_GL_PRESERVE_ATI 0x8762 -#define LOCAL_GL_DISCARD_ATI 0x8763 -#define LOCAL_GL_OBJECT_BUFFER_SIZE_ATI 0x8764 -#define LOCAL_GL_OBJECT_BUFFER_USAGE_ATI 0x8765 -#define LOCAL_GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 -#define LOCAL_GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 -#define LOCAL_GL_ATI_vertex_attrib_array_object 1 -#define LOCAL_GL_ATI_vertex_streams 1 -#define LOCAL_GL_MAX_VERTEX_STREAMS_ATI 0x876B -#define LOCAL_GL_VERTEX_SOURCE_ATI 0x876C -#define LOCAL_GL_VERTEX_STREAM0_ATI 0x876D -#define LOCAL_GL_VERTEX_STREAM1_ATI 0x876E -#define LOCAL_GL_VERTEX_STREAM2_ATI 0x876F -#define LOCAL_GL_VERTEX_STREAM3_ATI 0x8770 -#define LOCAL_GL_VERTEX_STREAM4_ATI 0x8771 -#define LOCAL_GL_VERTEX_STREAM5_ATI 0x8772 -#define LOCAL_GL_VERTEX_STREAM6_ATI 0x8773 -#define LOCAL_GL_VERTEX_STREAM7_ATI 0x8774 -#define LOCAL_GL_EXT_422_pixels 1 -#define LOCAL_GL_422_EXT 0x80CC -#define LOCAL_GL_422_REV_EXT 0x80CD -#define LOCAL_GL_422_AVERAGE_EXT 0x80CE -#define LOCAL_GL_422_REV_AVERAGE_EXT 0x80CF -#define LOCAL_GL_EXT_Cg_shader 1 -#define LOCAL_GL_CG_VERTEX_SHADER_EXT 0x890E -#define LOCAL_GL_CG_FRAGMENT_SHADER_EXT 0x890F -#define LOCAL_GL_EXT_abgr 1 -#define LOCAL_GL_ABGR_EXT 0x8000 -#define LOCAL_GL_EXT_bgra 1 -#define LOCAL_GL_BGR_EXT 0x80E0 -#define LOCAL_GL_BGRA_EXT 0x80E1 -#define LOCAL_GL_EXT_blend_color 1 -#define LOCAL_GL_CONSTANT_COLOR_EXT 0x8001 -#define LOCAL_GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 -#define LOCAL_GL_CONSTANT_ALPHA_EXT 0x8003 -#define LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 -#define LOCAL_GL_BLEND_COLOR_EXT 0x8005 -#define LOCAL_GL_EXT_blend_equation_separate 1 -#define LOCAL_GL_BLEND_EQUATION_RGB_EXT 0x8009 -#define LOCAL_GL_BLEND_EQUATION_ALPHA_EXT 0x883D -#define LOCAL_GL_EXT_blend_func_separate 1 -#define LOCAL_GL_BLEND_DST_RGB_EXT 0x80C8 -#define LOCAL_GL_BLEND_SRC_RGB_EXT 0x80C9 -#define LOCAL_GL_BLEND_DST_ALPHA_EXT 0x80CA -#define LOCAL_GL_BLEND_SRC_ALPHA_EXT 0x80CB -#define LOCAL_GL_EXT_blend_logic_op 1 -#define LOCAL_GL_EXT_blend_minmax 1 -#define LOCAL_GL_FUNC_ADD_EXT 0x8006 -#define LOCAL_GL_MIN_EXT 0x8007 -#define LOCAL_GL_MAX_EXT 0x8008 -#define LOCAL_GL_BLEND_EQUATION_EXT 0x8009 -#define LOCAL_GL_EXT_blend_subtract 1 -#define LOCAL_GL_FUNC_SUBTRACT_EXT 0x800A -#define LOCAL_GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B -#define LOCAL_GL_EXT_clip_volume_hint 1 -#define LOCAL_GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 -#define LOCAL_GL_EXT_cmyka 1 -#define LOCAL_GL_CMYK_EXT 0x800C -#define LOCAL_GL_CMYKA_EXT 0x800D -#define LOCAL_GL_PACK_CMYK_HINT_EXT 0x800E -#define LOCAL_GL_UNPACK_CMYK_HINT_EXT 0x800F -#define LOCAL_GL_EXT_color_subtable 1 -#define LOCAL_GL_EXT_compiled_vertex_array 1 -#define LOCAL_GL_EXT_convolution 1 -#define LOCAL_GL_CONVOLUTION_1D_EXT 0x8010 -#define LOCAL_GL_CONVOLUTION_2D_EXT 0x8011 -#define LOCAL_GL_SEPARABLE_2D_EXT 0x8012 -#define LOCAL_GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 -#define LOCAL_GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 -#define LOCAL_GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 -#define LOCAL_GL_REDUCE_EXT 0x8016 -#define LOCAL_GL_CONVOLUTION_FORMAT_EXT 0x8017 -#define LOCAL_GL_CONVOLUTION_WIDTH_EXT 0x8018 -#define LOCAL_GL_CONVOLUTION_HEIGHT_EXT 0x8019 -#define LOCAL_GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A -#define LOCAL_GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B -#define LOCAL_GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C -#define LOCAL_GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D -#define LOCAL_GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E -#define LOCAL_GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F -#define LOCAL_GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 -#define LOCAL_GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 -#define LOCAL_GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 -#define LOCAL_GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -#define LOCAL_GL_EXT_coordinate_frame 1 -#define LOCAL_GL_TANGENT_ARRAY_EXT 0x8439 -#define LOCAL_GL_BINORMAL_ARRAY_EXT 0x843A -#define LOCAL_GL_CURRENT_TANGENT_EXT 0x843B -#define LOCAL_GL_CURRENT_BINORMAL_EXT 0x843C -#define LOCAL_GL_TANGENT_ARRAY_TYPE_EXT 0x843E -#define LOCAL_GL_TANGENT_ARRAY_STRIDE_EXT 0x843F -#define LOCAL_GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 -#define LOCAL_GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 -#define LOCAL_GL_TANGENT_ARRAY_POINTER_EXT 0x8442 -#define LOCAL_GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 -#define LOCAL_GL_MAP1_TANGENT_EXT 0x8444 -#define LOCAL_GL_MAP2_TANGENT_EXT 0x8445 -#define LOCAL_GL_MAP1_BINORMAL_EXT 0x8446 -#define LOCAL_GL_MAP2_BINORMAL_EXT 0x8447 -#define LOCAL_GL_EXT_copy_texture 1 -#define LOCAL_GL_EXT_cull_vertex 1 -#define LOCAL_GL_EXT_depth_bounds_test 1 -#define LOCAL_GL_DEPTH_BOUNDS_TEST_EXT 0x8890 -#define LOCAL_GL_DEPTH_BOUNDS_EXT 0x8891 -#define LOCAL_GL_EXT_draw_range_elements 1 -#define LOCAL_GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define LOCAL_GL_MAX_ELEMENTS_INDICES 0x80E9 -#define LOCAL_GL_EXT_fog_coord 1 -#define LOCAL_GL_FOG_COORDINATE_SOURCE_EXT 0x8450 -#define LOCAL_GL_FOG_COORDINATE_EXT 0x8451 -#define LOCAL_GL_FRAGMENT_DEPTH_EXT 0x8452 -#define LOCAL_GL_CURRENT_FOG_COORDINATE_EXT 0x8453 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_EXT 0x8457 -#define LOCAL_GL_EXT_fragment_lighting 1 -#define LOCAL_GL_FRAGMENT_LIGHTING_EXT 0x8400 -#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_EXT 0x8401 -#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_FACE_EXT 0x8402 -#define LOCAL_GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_EXT 0x8403 -#define LOCAL_GL_MAX_FRAGMENT_LIGHTS_EXT 0x8404 -#define LOCAL_GL_MAX_ACTIVE_LIGHTS_EXT 0x8405 -#define LOCAL_GL_CURRENT_RASTER_NORMAL_EXT 0x8406 -#define LOCAL_GL_LIGHT_ENV_MODE_EXT 0x8407 -#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_EXT 0x8408 -#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_EXT 0x8409 -#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_AMBIENT_EXT 0x840A -#define LOCAL_GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_EXT 0x840B -#define LOCAL_GL_FRAGMENT_LIGHT0_EXT 0x840C -#define LOCAL_GL_FRAGMENT_LIGHT7_EXT 0x8413 -#define LOCAL_GL_EXT_framebuffer_blit 1 -#define LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define LOCAL_GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define LOCAL_GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -#define LOCAL_GL_EXT_framebuffer_multisample 1 -#define LOCAL_GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define LOCAL_GL_EXT_framebuffer_object 1 -#define LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define LOCAL_GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define LOCAL_GL_FRAMEBUFFER_BINDING 0x8CA6 -#define LOCAL_GL_RENDERBUFFER_BINDING 0x8CA7 -#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET 0x8CD4 -#define LOCAL_GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_FORMATS 0x8CDA -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define LOCAL_GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define LOCAL_GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define LOCAL_GL_COLOR_ATTACHMENT0 0x8CE0 -#define LOCAL_GL_COLOR_ATTACHMENT1 0x8CE1 -#define LOCAL_GL_COLOR_ATTACHMENT2 0x8CE2 -#define LOCAL_GL_COLOR_ATTACHMENT3 0x8CE3 -#define LOCAL_GL_COLOR_ATTACHMENT4 0x8CE4 -#define LOCAL_GL_COLOR_ATTACHMENT5 0x8CE5 -#define LOCAL_GL_COLOR_ATTACHMENT6 0x8CE6 -#define LOCAL_GL_COLOR_ATTACHMENT7 0x8CE7 -#define LOCAL_GL_COLOR_ATTACHMENT8 0x8CE8 -#define LOCAL_GL_COLOR_ATTACHMENT9 0x8CE9 -#define LOCAL_GL_COLOR_ATTACHMENT10 0x8CEA -#define LOCAL_GL_COLOR_ATTACHMENT11 0x8CEB -#define LOCAL_GL_COLOR_ATTACHMENT12 0x8CEC -#define LOCAL_GL_COLOR_ATTACHMENT13 0x8CED -#define LOCAL_GL_COLOR_ATTACHMENT14 0x8CEE -#define LOCAL_GL_COLOR_ATTACHMENT15 0x8CEF -#define LOCAL_GL_DEPTH_ATTACHMENT 0x8D00 -#define LOCAL_GL_STENCIL_ATTACHMENT 0x8D20 -#define LOCAL_GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define LOCAL_GL_FRAMEBUFFER 0x8D40 -#define LOCAL_GL_RENDERBUFFER 0x8D41 -#define LOCAL_GL_RENDERBUFFER_WIDTH 0x8D42 -#define LOCAL_GL_RENDERBUFFER_HEIGHT 0x8D43 -#define LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define LOCAL_GL_STENCIL_INDEX1 0x8D46 -#define LOCAL_GL_STENCIL_INDEX4 0x8D47 -#define LOCAL_GL_STENCIL_INDEX8 0x8D48 -#define LOCAL_GL_STENCIL_INDEX16 0x8D49 -#define LOCAL_GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define LOCAL_GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define LOCAL_GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define LOCAL_GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define LOCAL_GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define LOCAL_GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define LOCAL_GL_EXT_histogram 1 -#define LOCAL_GL_HISTOGRAM_EXT 0x8024 -#define LOCAL_GL_PROXY_HISTOGRAM_EXT 0x8025 -#define LOCAL_GL_HISTOGRAM_WIDTH_EXT 0x8026 -#define LOCAL_GL_HISTOGRAM_FORMAT_EXT 0x8027 -#define LOCAL_GL_HISTOGRAM_RED_SIZE_EXT 0x8028 -#define LOCAL_GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 -#define LOCAL_GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A -#define LOCAL_GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B -#define LOCAL_GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C -#define LOCAL_GL_HISTOGRAM_SINK_EXT 0x802D -#define LOCAL_GL_MINMAX_EXT 0x802E -#define LOCAL_GL_MINMAX_FORMAT_EXT 0x802F -#define LOCAL_GL_MINMAX_SINK_EXT 0x8030 -#define LOCAL_GL_EXT_index_array_formats 1 -#define LOCAL_GL_EXT_index_func 1 -#define LOCAL_GL_EXT_index_material 1 -#define LOCAL_GL_EXT_index_texture 1 -#define LOCAL_GL_EXT_light_texture 1 -#define LOCAL_GL_FRAGMENT_MATERIAL_EXT 0x8349 -#define LOCAL_GL_FRAGMENT_NORMAL_EXT 0x834A -#define LOCAL_GL_FRAGMENT_COLOR_EXT 0x834C -#define LOCAL_GL_ATTENUATION_EXT 0x834D -#define LOCAL_GL_SHADOW_ATTENUATION_EXT 0x834E -#define LOCAL_GL_TEXTURE_APPLICATION_MODE_EXT 0x834F -#define LOCAL_GL_TEXTURE_LIGHT_EXT 0x8350 -#define LOCAL_GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 -#define LOCAL_GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 -#define LOCAL_GL_FRAGMENT_DEPTH_EXT 0x8452 -#define LOCAL_GL_EXT_misc_attribute 1 -#define LOCAL_GL_EXT_multi_draw_arrays 1 -#define LOCAL_GL_EXT_multisample 1 -#define LOCAL_GL_MULTISAMPLE_EXT 0x809D -#define LOCAL_GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E -#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F -#define LOCAL_GL_SAMPLE_MASK_EXT 0x80A0 -#define LOCAL_GL_1PASS_EXT 0x80A1 -#define LOCAL_GL_2PASS_0_EXT 0x80A2 -#define LOCAL_GL_2PASS_1_EXT 0x80A3 -#define LOCAL_GL_4PASS_0_EXT 0x80A4 -#define LOCAL_GL_4PASS_1_EXT 0x80A5 -#define LOCAL_GL_4PASS_2_EXT 0x80A6 -#define LOCAL_GL_4PASS_3_EXT 0x80A7 -#define LOCAL_GL_SAMPLE_BUFFERS_EXT 0x80A8 -#define LOCAL_GL_SAMPLES_EXT 0x80A9 -#define LOCAL_GL_SAMPLE_MASK_VALUE_EXT 0x80AA -#define LOCAL_GL_SAMPLE_MASK_INVERT_EXT 0x80AB -#define LOCAL_GL_SAMPLE_PATTERN_EXT 0x80AC -#define LOCAL_GL_MULTISAMPLE_BIT_EXT 0x20000000 -#define LOCAL_GL_EXT_packed_depth_stencil 1 -#define LOCAL_GL_DEPTH_STENCIL_EXT 0x84F9 -#define LOCAL_GL_DEPTH_STENCIL 0x84F9 -#define LOCAL_GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define LOCAL_GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define LOCAL_GL_DEPTH24_STENCIL8 0x88F0 -#define LOCAL_GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#define LOCAL_GL_EXT_packed_pixels 1 -#define LOCAL_GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 -#define LOCAL_GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 -#define LOCAL_GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 -#define LOCAL_GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 -#define LOCAL_GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 -#define LOCAL_GL_EXT_paletted_texture 1 -#define LOCAL_GL_TEXTURE_1D 0x0DE0 -#define LOCAL_GL_TEXTURE_2D 0x0DE1 -#define LOCAL_GL_PROXY_TEXTURE_1D 0x8063 -#define LOCAL_GL_PROXY_TEXTURE_2D 0x8064 -#define LOCAL_GL_TEXTURE_3D_EXT 0x806F -#define LOCAL_GL_PROXY_TEXTURE_3D_EXT 0x8070 -#define LOCAL_GL_COLOR_TABLE_FORMAT_EXT 0x80D8 -#define LOCAL_GL_COLOR_TABLE_WIDTH_EXT 0x80D9 -#define LOCAL_GL_COLOR_TABLE_RED_SIZE_EXT 0x80DA -#define LOCAL_GL_COLOR_TABLE_GREEN_SIZE_EXT 0x80DB -#define LOCAL_GL_COLOR_TABLE_BLUE_SIZE_EXT 0x80DC -#define LOCAL_GL_COLOR_TABLE_ALPHA_SIZE_EXT 0x80DD -#define LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE_EXT 0x80DE -#define LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE_EXT 0x80DF -#define LOCAL_GL_COLOR_INDEX1_EXT 0x80E2 -#define LOCAL_GL_COLOR_INDEX2_EXT 0x80E3 -#define LOCAL_GL_COLOR_INDEX4_EXT 0x80E4 -#define LOCAL_GL_COLOR_INDEX8_EXT 0x80E5 -#define LOCAL_GL_COLOR_INDEX12_EXT 0x80E6 -#define LOCAL_GL_COLOR_INDEX16_EXT 0x80E7 -#define LOCAL_GL_TEXTURE_INDEX_SIZE_EXT 0x80ED -#define LOCAL_GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define LOCAL_GL_EXT_pixel_buffer_object 1 -#define LOCAL_GL_PIXEL_PACK_BUFFER_EXT 0x88EB -#define LOCAL_GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC -#define LOCAL_GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED -#define LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF -#define LOCAL_GL_EXT_pixel_transform 1 -#define LOCAL_GL_PIXEL_TRANSFORM_2D_EXT 0x8330 -#define LOCAL_GL_PIXEL_MAG_FILTER_EXT 0x8331 -#define LOCAL_GL_PIXEL_MIN_FILTER_EXT 0x8332 -#define LOCAL_GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 -#define LOCAL_GL_CUBIC_EXT 0x8334 -#define LOCAL_GL_AVERAGE_EXT 0x8335 -#define LOCAL_GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 -#define LOCAL_GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 -#define LOCAL_GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 -#define LOCAL_GL_EXT_pixel_transform_color_table 1 -#define LOCAL_GL_EXT_point_parameters 1 -#define LOCAL_GL_POINT_SIZE_MIN_EXT 0x8126 -#define LOCAL_GL_POINT_SIZE_MAX_EXT 0x8127 -#define LOCAL_GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 -#define LOCAL_GL_DISTANCE_ATTENUATION_EXT 0x8129 -#define LOCAL_GL_EXT_polygon_offset 1 -#define LOCAL_GL_POLYGON_OFFSET_EXT 0x8037 -#define LOCAL_GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 -#define LOCAL_GL_POLYGON_OFFSET_BIAS_EXT 0x8039 -#define LOCAL_GL_EXT_rescale_normal 1 -#define LOCAL_GL_EXT_scene_marker 1 -#define LOCAL_GL_EXT_secondary_color 1 -#define LOCAL_GL_COLOR_SUM_EXT 0x8458 -#define LOCAL_GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_EXT 0x845E -#define LOCAL_GL_EXT_separate_specular_color 1 -#define LOCAL_GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define LOCAL_GL_SINGLE_COLOR_EXT 0x81F9 -#define LOCAL_GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#define LOCAL_GL_EXT_shadow_funcs 1 -#define LOCAL_GL_EXT_shared_texture_palette 1 -#define LOCAL_GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB -#define LOCAL_GL_EXT_stencil_clear_tag 1 -#define LOCAL_GL_STENCIL_TAG_BITS_EXT 0x88F2 -#define LOCAL_GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 -#define LOCAL_GL_EXT_stencil_two_side 1 -#define LOCAL_GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 -#define LOCAL_GL_ACTIVE_STENCIL_FACE_EXT 0x8911 -#define LOCAL_GL_EXT_stencil_wrap 1 -#define LOCAL_GL_INCR_WRAP_EXT 0x8507 -#define LOCAL_GL_DECR_WRAP_EXT 0x8508 -#define LOCAL_GL_EXT_subtexture 1 -#define LOCAL_GL_EXT_texture 1 -#define LOCAL_GL_ALPHA4_EXT 0x803B -#define LOCAL_GL_ALPHA8_EXT 0x803C -#define LOCAL_GL_ALPHA12_EXT 0x803D -#define LOCAL_GL_ALPHA16_EXT 0x803E -#define LOCAL_GL_LUMINANCE4_EXT 0x803F -#define LOCAL_GL_LUMINANCE8_EXT 0x8040 -#define LOCAL_GL_LUMINANCE12_EXT 0x8041 -#define LOCAL_GL_LUMINANCE16_EXT 0x8042 -#define LOCAL_GL_LUMINANCE4_ALPHA4_EXT 0x8043 -#define LOCAL_GL_LUMINANCE6_ALPHA2_EXT 0x8044 -#define LOCAL_GL_LUMINANCE8_ALPHA8_EXT 0x8045 -#define LOCAL_GL_LUMINANCE12_ALPHA4_EXT 0x8046 -#define LOCAL_GL_LUMINANCE12_ALPHA12_EXT 0x8047 -#define LOCAL_GL_LUMINANCE16_ALPHA16_EXT 0x8048 -#define LOCAL_GL_INTENSITY_EXT 0x8049 -#define LOCAL_GL_INTENSITY4_EXT 0x804A -#define LOCAL_GL_INTENSITY8_EXT 0x804B -#define LOCAL_GL_INTENSITY12_EXT 0x804C -#define LOCAL_GL_INTENSITY16_EXT 0x804D -#define LOCAL_GL_RGB2_EXT 0x804E -#define LOCAL_GL_RGB4_EXT 0x804F -#define LOCAL_GL_RGB5_EXT 0x8050 -#define LOCAL_GL_RGB8_EXT 0x8051 -#define LOCAL_GL_RGB10_EXT 0x8052 -#define LOCAL_GL_RGB12_EXT 0x8053 -#define LOCAL_GL_RGB16_EXT 0x8054 -#define LOCAL_GL_RGBA2_EXT 0x8055 -#define LOCAL_GL_RGBA4_EXT 0x8056 -#define LOCAL_GL_RGB5_A1_EXT 0x8057 -#define LOCAL_GL_RGBA8_EXT 0x8058 -#define LOCAL_GL_RGB10_A2_EXT 0x8059 -#define LOCAL_GL_RGBA12_EXT 0x805A -#define LOCAL_GL_RGBA16_EXT 0x805B -#define LOCAL_GL_TEXTURE_RED_SIZE_EXT 0x805C -#define LOCAL_GL_TEXTURE_GREEN_SIZE_EXT 0x805D -#define LOCAL_GL_TEXTURE_BLUE_SIZE_EXT 0x805E -#define LOCAL_GL_TEXTURE_ALPHA_SIZE_EXT 0x805F -#define LOCAL_GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 -#define LOCAL_GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 -#define LOCAL_GL_REPLACE_EXT 0x8062 -#define LOCAL_GL_PROXY_TEXTURE_1D_EXT 0x8063 -#define LOCAL_GL_PROXY_TEXTURE_2D_EXT 0x8064 -#define LOCAL_GL_EXT_texture3D 1 -#define LOCAL_GL_PACK_SKIP_IMAGES_EXT 0x806B -#define LOCAL_GL_PACK_IMAGE_HEIGHT_EXT 0x806C -#define LOCAL_GL_UNPACK_SKIP_IMAGES_EXT 0x806D -#define LOCAL_GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E -#define LOCAL_GL_TEXTURE_3D_EXT 0x806F -#define LOCAL_GL_PROXY_TEXTURE_3D_EXT 0x8070 -#define LOCAL_GL_TEXTURE_DEPTH_EXT 0x8071 -#define LOCAL_GL_TEXTURE_WRAP_R_EXT 0x8072 -#define LOCAL_GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -#define LOCAL_GL_EXT_texture_compression_dxt1 1 -#define LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define LOCAL_GL_EXT_texture_compression_s3tc 1 -#define LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#define LOCAL_GL_EXT_texture_cube_map 1 -#define LOCAL_GL_NORMAL_MAP_EXT 0x8511 -#define LOCAL_GL_REFLECTION_MAP_EXT 0x8512 -#define LOCAL_GL_TEXTURE_CUBE_MAP_EXT 0x8513 -#define LOCAL_GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 -#define LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 -#define LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A -#define LOCAL_GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B -#define LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C -#define LOCAL_GL_EXT_texture_edge_clamp 1 -#define LOCAL_GL_CLAMP_TO_EDGE_EXT 0x812F -#define LOCAL_GL_EXT_texture_env 1 -#define LOCAL_GL_TEXTURE_ENV0_EXT 0 -#define LOCAL_GL_ENV_BLEND_EXT 0 -#define LOCAL_GL_TEXTURE_ENV_SHIFT_EXT 0 -#define LOCAL_GL_ENV_REPLACE_EXT 0 -#define LOCAL_GL_ENV_ADD_EXT 0 -#define LOCAL_GL_ENV_SUBTRACT_EXT 0 -#define LOCAL_GL_TEXTURE_ENV_MODE_ALPHA_EXT 0 -#define LOCAL_GL_ENV_REVERSE_SUBTRACT_EXT 0 -#define LOCAL_GL_ENV_REVERSE_BLEND_EXT 0 -#define LOCAL_GL_ENV_COPY_EXT 0 -#define LOCAL_GL_ENV_MODULATE_EXT 0 -#define LOCAL_GL_EXT_texture_env_add 1 -#define LOCAL_GL_EXT_texture_env_combine 1 -#define LOCAL_GL_COMBINE_EXT 0x8570 -#define LOCAL_GL_COMBINE_RGB_EXT 0x8571 -#define LOCAL_GL_COMBINE_ALPHA_EXT 0x8572 -#define LOCAL_GL_RGB_SCALE_EXT 0x8573 -#define LOCAL_GL_ADD_SIGNED_EXT 0x8574 -#define LOCAL_GL_INTERPOLATE_EXT 0x8575 -#define LOCAL_GL_CONSTANT_EXT 0x8576 -#define LOCAL_GL_PRIMARY_COLOR_EXT 0x8577 -#define LOCAL_GL_PREVIOUS_EXT 0x8578 -#define LOCAL_GL_SOURCE0_RGB_EXT 0x8580 -#define LOCAL_GL_SOURCE1_RGB_EXT 0x8581 -#define LOCAL_GL_SOURCE2_RGB_EXT 0x8582 -#define LOCAL_GL_SOURCE0_ALPHA_EXT 0x8588 -#define LOCAL_GL_SOURCE1_ALPHA_EXT 0x8589 -#define LOCAL_GL_SOURCE2_ALPHA_EXT 0x858A -#define LOCAL_GL_OPERAND0_RGB_EXT 0x8590 -#define LOCAL_GL_OPERAND1_RGB_EXT 0x8591 -#define LOCAL_GL_OPERAND2_RGB_EXT 0x8592 -#define LOCAL_GL_OPERAND0_ALPHA_EXT 0x8598 -#define LOCAL_GL_OPERAND1_ALPHA_EXT 0x8599 -#define LOCAL_GL_OPERAND2_ALPHA_EXT 0x859A -#define LOCAL_GL_EXT_texture_env_dot3 1 -#define LOCAL_GL_DOT3_RGB_EXT 0x8740 -#define LOCAL_GL_DOT3_RGBA_EXT 0x8741 -#define LOCAL_GL_EXT_texture_filter_anisotropic 1 -#define LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#define LOCAL_GL_EXT_texture_lod_bias 1 -#define LOCAL_GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD -#define LOCAL_GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define LOCAL_GL_TEXTURE_LOD_BIAS_EXT 0x8501 -#define LOCAL_GL_EXT_texture_mirror_clamp 1 -#define LOCAL_GL_MIRROR_CLAMP_EXT 0x8742 -#define LOCAL_GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define LOCAL_GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 -#define LOCAL_GL_EXT_texture_object 1 -#define LOCAL_GL_TEXTURE_PRIORITY_EXT 0x8066 -#define LOCAL_GL_TEXTURE_RESIDENT_EXT 0x8067 -#define LOCAL_GL_TEXTURE_1D_BINDING_EXT 0x8068 -#define LOCAL_GL_TEXTURE_2D_BINDING_EXT 0x8069 -#define LOCAL_GL_TEXTURE_3D_BINDING_EXT 0x806A -#define LOCAL_GL_EXT_texture_perturb_normal 1 -#define LOCAL_GL_PERTURB_EXT 0x85AE -#define LOCAL_GL_TEXTURE_NORMAL_EXT 0x85AF -#define LOCAL_GL_EXT_texture_rectangle 1 -#define LOCAL_GL_TEXTURE_RECTANGLE_EXT 0x84F5 -#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE_EXT 0x84F6 -#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE_EXT 0x84F7 -#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT 0x84F8 -#define LOCAL_GL_EXT_texture_sRGB 1 -#define LOCAL_GL_SRGB_EXT 0x8C40 -#define LOCAL_GL_SRGB8_EXT 0x8C41 -#define LOCAL_GL_SRGB_ALPHA_EXT 0x8C42 -#define LOCAL_GL_SRGB8_ALPHA8_EXT 0x8C43 -#define LOCAL_GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define LOCAL_GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define LOCAL_GL_SLUMINANCE_EXT 0x8C46 -#define LOCAL_GL_SLUMINANCE8_EXT 0x8C47 -#define LOCAL_GL_COMPRESSED_SRGB_EXT 0x8C48 -#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 -#define LOCAL_GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A -#define LOCAL_GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B -#define LOCAL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define LOCAL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#define LOCAL_GL_EXT_vertex_array 1 -#define LOCAL_GL_DOUBLE_EXT 0x140A -#define LOCAL_GL_VERTEX_ARRAY_EXT 0x8074 -#define LOCAL_GL_NORMAL_ARRAY_EXT 0x8075 -#define LOCAL_GL_COLOR_ARRAY_EXT 0x8076 -#define LOCAL_GL_INDEX_ARRAY_EXT 0x8077 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_EXT 0x8078 -#define LOCAL_GL_EDGE_FLAG_ARRAY_EXT 0x8079 -#define LOCAL_GL_VERTEX_ARRAY_SIZE_EXT 0x807A -#define LOCAL_GL_VERTEX_ARRAY_TYPE_EXT 0x807B -#define LOCAL_GL_VERTEX_ARRAY_STRIDE_EXT 0x807C -#define LOCAL_GL_VERTEX_ARRAY_COUNT_EXT 0x807D -#define LOCAL_GL_NORMAL_ARRAY_TYPE_EXT 0x807E -#define LOCAL_GL_NORMAL_ARRAY_STRIDE_EXT 0x807F -#define LOCAL_GL_NORMAL_ARRAY_COUNT_EXT 0x8080 -#define LOCAL_GL_COLOR_ARRAY_SIZE_EXT 0x8081 -#define LOCAL_GL_COLOR_ARRAY_TYPE_EXT 0x8082 -#define LOCAL_GL_COLOR_ARRAY_STRIDE_EXT 0x8083 -#define LOCAL_GL_COLOR_ARRAY_COUNT_EXT 0x8084 -#define LOCAL_GL_INDEX_ARRAY_TYPE_EXT 0x8085 -#define LOCAL_GL_INDEX_ARRAY_STRIDE_EXT 0x8086 -#define LOCAL_GL_INDEX_ARRAY_COUNT_EXT 0x8087 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A -#define LOCAL_GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B -#define LOCAL_GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C -#define LOCAL_GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D -#define LOCAL_GL_VERTEX_ARRAY_POINTER_EXT 0x808E -#define LOCAL_GL_NORMAL_ARRAY_POINTER_EXT 0x808F -#define LOCAL_GL_COLOR_ARRAY_POINTER_EXT 0x8090 -#define LOCAL_GL_INDEX_ARRAY_POINTER_EXT 0x8091 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 -#define LOCAL_GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 -#define LOCAL_GL_EXT_vertex_shader 1 -#define LOCAL_GL_VERTEX_SHADER_EXT 0x8780 -#define LOCAL_GL_VERTEX_SHADER_BINDING_EXT 0x8781 -#define LOCAL_GL_OP_INDEX_EXT 0x8782 -#define LOCAL_GL_OP_NEGATE_EXT 0x8783 -#define LOCAL_GL_OP_DOT3_EXT 0x8784 -#define LOCAL_GL_OP_DOT4_EXT 0x8785 -#define LOCAL_GL_OP_MUL_EXT 0x8786 -#define LOCAL_GL_OP_ADD_EXT 0x8787 -#define LOCAL_GL_OP_MADD_EXT 0x8788 -#define LOCAL_GL_OP_FRAC_EXT 0x8789 -#define LOCAL_GL_OP_MAX_EXT 0x878A -#define LOCAL_GL_OP_MIN_EXT 0x878B -#define LOCAL_GL_OP_SET_GE_EXT 0x878C -#define LOCAL_GL_OP_SET_LT_EXT 0x878D -#define LOCAL_GL_OP_CLAMP_EXT 0x878E -#define LOCAL_GL_OP_FLOOR_EXT 0x878F -#define LOCAL_GL_OP_ROUND_EXT 0x8790 -#define LOCAL_GL_OP_EXP_BASE_2_EXT 0x8791 -#define LOCAL_GL_OP_LOG_BASE_2_EXT 0x8792 -#define LOCAL_GL_OP_POWER_EXT 0x8793 -#define LOCAL_GL_OP_RECIP_EXT 0x8794 -#define LOCAL_GL_OP_RECIP_SQRT_EXT 0x8795 -#define LOCAL_GL_OP_SUB_EXT 0x8796 -#define LOCAL_GL_OP_CROSS_PRODUCT_EXT 0x8797 -#define LOCAL_GL_OP_MULTIPLY_MATRIX_EXT 0x8798 -#define LOCAL_GL_OP_MOV_EXT 0x8799 -#define LOCAL_GL_OUTPUT_VERTEX_EXT 0x879A -#define LOCAL_GL_OUTPUT_COLOR0_EXT 0x879B -#define LOCAL_GL_OUTPUT_COLOR1_EXT 0x879C -#define LOCAL_GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D -#define LOCAL_GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E -#define LOCAL_GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F -#define LOCAL_GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA -#define LOCAL_GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB -#define LOCAL_GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC -#define LOCAL_GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD -#define LOCAL_GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE -#define LOCAL_GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF -#define LOCAL_GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 -#define LOCAL_GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA -#define LOCAL_GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB -#define LOCAL_GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC -#define LOCAL_GL_OUTPUT_FOG_EXT 0x87BD -#define LOCAL_GL_SCALAR_EXT 0x87BE -#define LOCAL_GL_VECTOR_EXT 0x87BF -#define LOCAL_GL_MATRIX_EXT 0x87C0 -#define LOCAL_GL_VARIANT_EXT 0x87C1 -#define LOCAL_GL_INVARIANT_EXT 0x87C2 -#define LOCAL_GL_LOCAL_CONSTANT_EXT 0x87C3 -#define LOCAL_GL_LOCAL_EXT 0x87C4 -#define LOCAL_GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 -#define LOCAL_GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 -#define LOCAL_GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 -#define LOCAL_GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 -#define LOCAL_GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 -#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA -#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB -#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CC -#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CD -#define LOCAL_GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE -#define LOCAL_GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF -#define LOCAL_GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 -#define LOCAL_GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 -#define LOCAL_GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 -#define LOCAL_GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 -#define LOCAL_GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 -#define LOCAL_GL_X_EXT 0x87D5 -#define LOCAL_GL_Y_EXT 0x87D6 -#define LOCAL_GL_Z_EXT 0x87D7 -#define LOCAL_GL_W_EXT 0x87D8 -#define LOCAL_GL_NEGATIVE_X_EXT 0x87D9 -#define LOCAL_GL_NEGATIVE_Y_EXT 0x87DA -#define LOCAL_GL_NEGATIVE_Z_EXT 0x87DB -#define LOCAL_GL_NEGATIVE_W_EXT 0x87DC -#define LOCAL_GL_ZERO_EXT 0x87DD -#define LOCAL_GL_ONE_EXT 0x87DE -#define LOCAL_GL_NEGATIVE_ONE_EXT 0x87DF -#define LOCAL_GL_NORMALIZED_RANGE_EXT 0x87E0 -#define LOCAL_GL_FULL_RANGE_EXT 0x87E1 -#define LOCAL_GL_CURRENT_VERTEX_EXT 0x87E2 -#define LOCAL_GL_MVP_MATRIX_EXT 0x87E3 -#define LOCAL_GL_VARIANT_VALUE_EXT 0x87E4 -#define LOCAL_GL_VARIANT_DATATYPE_EXT 0x87E5 -#define LOCAL_GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 -#define LOCAL_GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 -#define LOCAL_GL_VARIANT_ARRAY_EXT 0x87E8 -#define LOCAL_GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 -#define LOCAL_GL_INVARIANT_VALUE_EXT 0x87EA -#define LOCAL_GL_INVARIANT_DATATYPE_EXT 0x87EB -#define LOCAL_GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC -#define LOCAL_GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED -#define LOCAL_GL_EXT_vertex_weighting 1 -#define LOCAL_GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 -#define LOCAL_GL_MODELVIEW0_MATRIX_EXT 0x0BA6 -#define LOCAL_GL_MODELVIEW0_EXT 0x1700 -#define LOCAL_GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 -#define LOCAL_GL_MODELVIEW1_MATRIX_EXT 0x8506 -#define LOCAL_GL_VERTEX_WEIGHTING_EXT 0x8509 -#define LOCAL_GL_MODELVIEW1_EXT 0x850A -#define LOCAL_GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B -#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C -#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D -#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E -#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F -#define LOCAL_GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 -#define LOCAL_GL_GREMEDY_string_marker 1 -#define LOCAL_GL_HP_convolution_border_modes 1 -#define LOCAL_GL_HP_image_transform 1 -#define LOCAL_GL_HP_occlusion_test 1 -#define LOCAL_GL_OCCLUSION_TEST_HP 0x8165 -#define LOCAL_GL_OCCLUSION_TEST_RESULT_HP 0x8166 -#define LOCAL_GL_HP_texture_lighting 1 -#define LOCAL_GL_IBM_cull_vertex 1 -#define LOCAL_GL_CULL_VERTEX_IBM 103050 -#define LOCAL_GL_IBM_multimode_draw_arrays 1 -#define LOCAL_GL_IBM_rasterpos_clip 1 -#define LOCAL_GL_RASTER_POSITION_UNCLIPPED_IBM 103010 -#define LOCAL_GL_IBM_static_data 1 -#define LOCAL_GL_ALL_STATIC_DATA_IBM 103060 -#define LOCAL_GL_STATIC_VERTEX_ARRAY_IBM 103061 -#define LOCAL_GL_IBM_texture_mirrored_repeat 1 -#define LOCAL_GL_MIRRORED_REPEAT_IBM 0x8370 -#define LOCAL_GL_IBM_vertex_array_lists 1 -#define LOCAL_GL_VERTEX_ARRAY_LIST_IBM 103070 -#define LOCAL_GL_NORMAL_ARRAY_LIST_IBM 103071 -#define LOCAL_GL_COLOR_ARRAY_LIST_IBM 103072 -#define LOCAL_GL_INDEX_ARRAY_LIST_IBM 103073 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 -#define LOCAL_GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 -#define LOCAL_GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 -#define LOCAL_GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 -#define LOCAL_GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 -#define LOCAL_GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 -#define LOCAL_GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 -#define LOCAL_GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 -#define LOCAL_GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 -#define LOCAL_GL_INGR_color_clamp 1 -#define LOCAL_GL_RED_MIN_CLAMP_INGR 0x8560 -#define LOCAL_GL_GREEN_MIN_CLAMP_INGR 0x8561 -#define LOCAL_GL_BLUE_MIN_CLAMP_INGR 0x8562 -#define LOCAL_GL_ALPHA_MIN_CLAMP_INGR 0x8563 -#define LOCAL_GL_RED_MAX_CLAMP_INGR 0x8564 -#define LOCAL_GL_GREEN_MAX_CLAMP_INGR 0x8565 -#define LOCAL_GL_BLUE_MAX_CLAMP_INGR 0x8566 -#define LOCAL_GL_ALPHA_MAX_CLAMP_INGR 0x8567 -#define LOCAL_GL_INGR_interlace_read 1 -#define LOCAL_GL_INTERLACE_READ_INGR 0x8568 -#define LOCAL_GL_INTEL_parallel_arrays 1 -#define LOCAL_GL_PARALLEL_ARRAYS_INTEL 0x83F4 -#define LOCAL_GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 -#define LOCAL_GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 -#define LOCAL_GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 -#define LOCAL_GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 -#define LOCAL_GL_INTEL_texture_scissor 1 -#define LOCAL_GL_KTX_buffer_region 1 -#define LOCAL_GL_KTX_FRONT_REGION 0x0 -#define LOCAL_GL_KTX_BACK_REGION 0x1 -#define LOCAL_GL_KTX_Z_REGION 0x2 -#define LOCAL_GL_KTX_STENCIL_REGION 0x3 -#define LOCAL_GL_MESAX_texture_stack 1 -#define LOCAL_GL_TEXTURE_1D_STACK_MESAX 0x8759 -#define LOCAL_GL_TEXTURE_2D_STACK_MESAX 0x875A -#define LOCAL_GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B -#define LOCAL_GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C -#define LOCAL_GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D -#define LOCAL_GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E -#define LOCAL_GL_MESA_pack_invert 1 -#define LOCAL_GL_PACK_INVERT_MESA 0x8758 -#define LOCAL_GL_MESA_resize_buffers 1 -#define LOCAL_GL_MESA_window_pos 1 -#define LOCAL_GL_MESA_ycbcr_texture 1 -#define LOCAL_GL_UNSIGNED_SHORT_8_8_MESA 0x85BA -#define LOCAL_GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB -#define LOCAL_GL_YCBCR_MESA 0x8757 -#define LOCAL_GL_NV_blend_square 1 -#define LOCAL_GL_NV_copy_depth_to_color 1 -#define LOCAL_GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E -#define LOCAL_GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F -#define LOCAL_GL_NV_depth_clamp 1 -#define LOCAL_GL_DEPTH_CLAMP_NV 0x864F -#define LOCAL_GL_NV_evaluators 1 -#define LOCAL_GL_EVAL_2D_NV 0x86C0 -#define LOCAL_GL_EVAL_TRIANGULAR_2D_NV 0x86C1 -#define LOCAL_GL_MAP_TESSELLATION_NV 0x86C2 -#define LOCAL_GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 -#define LOCAL_GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 -#define LOCAL_GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA -#define LOCAL_GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB -#define LOCAL_GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC -#define LOCAL_GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD -#define LOCAL_GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE -#define LOCAL_GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF -#define LOCAL_GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 -#define LOCAL_GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 -#define LOCAL_GL_MAX_MAP_TESSELLATION_NV 0x86D6 -#define LOCAL_GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 -#define LOCAL_GL_NV_fence 1 -#define LOCAL_GL_ALL_COMPLETED_NV 0x84F2 -#define LOCAL_GL_FENCE_STATUS_NV 0x84F3 -#define LOCAL_GL_FENCE_CONDITION_NV 0x84F4 -#define LOCAL_GL_NV_float_buffer 1 -#define LOCAL_GL_FLOAT_R_NV 0x8880 -#define LOCAL_GL_FLOAT_RG_NV 0x8881 -#define LOCAL_GL_FLOAT_RGB_NV 0x8882 -#define LOCAL_GL_FLOAT_RGBA_NV 0x8883 -#define LOCAL_GL_FLOAT_R16_NV 0x8884 -#define LOCAL_GL_FLOAT_R32_NV 0x8885 -#define LOCAL_GL_FLOAT_RG16_NV 0x8886 -#define LOCAL_GL_FLOAT_RG32_NV 0x8887 -#define LOCAL_GL_FLOAT_RGB16_NV 0x8888 -#define LOCAL_GL_FLOAT_RGB32_NV 0x8889 -#define LOCAL_GL_FLOAT_RGBA16_NV 0x888A -#define LOCAL_GL_FLOAT_RGBA32_NV 0x888B -#define LOCAL_GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C -#define LOCAL_GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D -#define LOCAL_GL_FLOAT_RGBA_MODE_NV 0x888E -#define LOCAL_GL_NV_fog_distance 1 -#define LOCAL_GL_FOG_DISTANCE_MODE_NV 0x855A -#define LOCAL_GL_EYE_RADIAL_NV 0x855B -#define LOCAL_GL_EYE_PLANE_ABSOLUTE_NV 0x855C -#define LOCAL_GL_NV_fragment_program 1 -#define LOCAL_GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 -#define LOCAL_GL_FRAGMENT_PROGRAM_NV 0x8870 -#define LOCAL_GL_MAX_TEXTURE_COORDS_NV 0x8871 -#define LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 -#define LOCAL_GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 -#define LOCAL_GL_PROGRAM_ERROR_STRING_NV 0x8874 -#define LOCAL_GL_NV_fragment_program2 1 -#define LOCAL_GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 -#define LOCAL_GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 -#define LOCAL_GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 -#define LOCAL_GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 -#define LOCAL_GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 -#define LOCAL_GL_NV_fragment_program_option 1 -#define LOCAL_GL_NV_half_float 1 -#define LOCAL_GL_HALF_FLOAT_NV 0x140B -#define LOCAL_GL_NV_light_max_exponent 1 -#define LOCAL_GL_MAX_SHININESS_NV 0x8504 -#define LOCAL_GL_MAX_SPOT_EXPONENT_NV 0x8505 -#define LOCAL_GL_NV_multisample_filter_hint 1 -#define LOCAL_GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 -#define LOCAL_GL_NV_occlusion_query 1 -#define LOCAL_GL_PIXEL_COUNTER_BITS_NV 0x8864 -#define LOCAL_GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 -#define LOCAL_GL_PIXEL_COUNT_NV 0x8866 -#define LOCAL_GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 -#define LOCAL_GL_NV_packed_depth_stencil 1 -#define LOCAL_GL_DEPTH_STENCIL_NV 0x84F9 -#define LOCAL_GL_UNSIGNED_INT_24_8_NV 0x84FA -#define LOCAL_GL_NV_pixel_data_range 1 -#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 -#define LOCAL_GL_READ_PIXEL_DATA_RANGE_NV 0x8879 -#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A -#define LOCAL_GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B -#define LOCAL_GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C -#define LOCAL_GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D -#define LOCAL_GL_NV_point_sprite 1 -#define LOCAL_GL_POINT_SPRITE_NV 0x8861 -#define LOCAL_GL_COORD_REPLACE_NV 0x8862 -#define LOCAL_GL_POINT_SPRITE_R_MODE_NV 0x8863 -#define LOCAL_GL_NV_primitive_restart 1 -#define LOCAL_GL_PRIMITIVE_RESTART_NV 0x8558 -#define LOCAL_GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 -#define LOCAL_GL_NV_register_combiners 1 -#define LOCAL_GL_REGISTER_COMBINERS_NV 0x8522 -#define LOCAL_GL_VARIABLE_A_NV 0x8523 -#define LOCAL_GL_VARIABLE_B_NV 0x8524 -#define LOCAL_GL_VARIABLE_C_NV 0x8525 -#define LOCAL_GL_VARIABLE_D_NV 0x8526 -#define LOCAL_GL_VARIABLE_E_NV 0x8527 -#define LOCAL_GL_VARIABLE_F_NV 0x8528 -#define LOCAL_GL_VARIABLE_G_NV 0x8529 -#define LOCAL_GL_CONSTANT_COLOR0_NV 0x852A -#define LOCAL_GL_CONSTANT_COLOR1_NV 0x852B -#define LOCAL_GL_PRIMARY_COLOR_NV 0x852C -#define LOCAL_GL_SECONDARY_COLOR_NV 0x852D -#define LOCAL_GL_SPARE0_NV 0x852E -#define LOCAL_GL_SPARE1_NV 0x852F -#define LOCAL_GL_DISCARD_NV 0x8530 -#define LOCAL_GL_E_TIMES_F_NV 0x8531 -#define LOCAL_GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 -#define LOCAL_GL_UNSIGNED_IDENTITY_NV 0x8536 -#define LOCAL_GL_UNSIGNED_INVERT_NV 0x8537 -#define LOCAL_GL_EXPAND_NORMAL_NV 0x8538 -#define LOCAL_GL_EXPAND_NEGATE_NV 0x8539 -#define LOCAL_GL_HALF_BIAS_NORMAL_NV 0x853A -#define LOCAL_GL_HALF_BIAS_NEGATE_NV 0x853B -#define LOCAL_GL_SIGNED_IDENTITY_NV 0x853C -#define LOCAL_GL_SIGNED_NEGATE_NV 0x853D -#define LOCAL_GL_SCALE_BY_TWO_NV 0x853E -#define LOCAL_GL_SCALE_BY_FOUR_NV 0x853F -#define LOCAL_GL_SCALE_BY_ONE_HALF_NV 0x8540 -#define LOCAL_GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 -#define LOCAL_GL_COMBINER_INPUT_NV 0x8542 -#define LOCAL_GL_COMBINER_MAPPING_NV 0x8543 -#define LOCAL_GL_COMBINER_COMPONENT_USAGE_NV 0x8544 -#define LOCAL_GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 -#define LOCAL_GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 -#define LOCAL_GL_COMBINER_MUX_SUM_NV 0x8547 -#define LOCAL_GL_COMBINER_SCALE_NV 0x8548 -#define LOCAL_GL_COMBINER_BIAS_NV 0x8549 -#define LOCAL_GL_COMBINER_AB_OUTPUT_NV 0x854A -#define LOCAL_GL_COMBINER_CD_OUTPUT_NV 0x854B -#define LOCAL_GL_COMBINER_SUM_OUTPUT_NV 0x854C -#define LOCAL_GL_MAX_GENERAL_COMBINERS_NV 0x854D -#define LOCAL_GL_NUM_GENERAL_COMBINERS_NV 0x854E -#define LOCAL_GL_COLOR_SUM_CLAMP_NV 0x854F -#define LOCAL_GL_COMBINER0_NV 0x8550 -#define LOCAL_GL_COMBINER1_NV 0x8551 -#define LOCAL_GL_COMBINER2_NV 0x8552 -#define LOCAL_GL_COMBINER3_NV 0x8553 -#define LOCAL_GL_COMBINER4_NV 0x8554 -#define LOCAL_GL_COMBINER5_NV 0x8555 -#define LOCAL_GL_COMBINER6_NV 0x8556 -#define LOCAL_GL_COMBINER7_NV 0x8557 -#define LOCAL_GL_NV_register_combiners2 1 -#define LOCAL_GL_PER_STAGE_CONSTANTS_NV 0x8535 -#define LOCAL_GL_NV_texgen_emboss 1 -#define LOCAL_GL_EMBOSS_LIGHT_NV 0x855D -#define LOCAL_GL_EMBOSS_CONSTANT_NV 0x855E -#define LOCAL_GL_EMBOSS_MAP_NV 0x855F -#define LOCAL_GL_NV_texgen_reflection 1 -#define LOCAL_GL_NORMAL_MAP_NV 0x8511 -#define LOCAL_GL_REFLECTION_MAP_NV 0x8512 -#define LOCAL_GL_NV_texture_compression_vtc 1 -#define LOCAL_GL_NV_texture_env_combine4 1 -#define LOCAL_GL_COMBINE4_NV 0x8503 -#define LOCAL_GL_SOURCE3_RGB_NV 0x8583 -#define LOCAL_GL_SOURCE3_ALPHA_NV 0x858B -#define LOCAL_GL_OPERAND3_RGB_NV 0x8593 -#define LOCAL_GL_OPERAND3_ALPHA_NV 0x859B -#define LOCAL_GL_NV_texture_expand_normal 1 -#define LOCAL_GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F -#define LOCAL_GL_NV_texture_rectangle 1 -#define LOCAL_GL_TEXTURE_RECTANGLE_NV 0x84F5 -#define LOCAL_GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 -#define LOCAL_GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 -#define LOCAL_GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 -#define LOCAL_GL_NV_texture_shader 1 -#define LOCAL_GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C -#define LOCAL_GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D -#define LOCAL_GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E -#define LOCAL_GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 -#define LOCAL_GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA -#define LOCAL_GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB -#define LOCAL_GL_DSDT_MAG_INTENSITY_NV 0x86DC -#define LOCAL_GL_SHADER_CONSISTENT_NV 0x86DD -#define LOCAL_GL_TEXTURE_SHADER_NV 0x86DE -#define LOCAL_GL_SHADER_OPERATION_NV 0x86DF -#define LOCAL_GL_CULL_MODES_NV 0x86E0 -#define LOCAL_GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 -#define LOCAL_GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 -#define LOCAL_GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 -#define LOCAL_GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 -#define LOCAL_GL_CONST_EYE_NV 0x86E5 -#define LOCAL_GL_PASS_THROUGH_NV 0x86E6 -#define LOCAL_GL_CULL_FRAGMENT_NV 0x86E7 -#define LOCAL_GL_OFFSET_TEXTURE_2D_NV 0x86E8 -#define LOCAL_GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 -#define LOCAL_GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA -#define LOCAL_GL_DOT_PRODUCT_NV 0x86EC -#define LOCAL_GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED -#define LOCAL_GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE -#define LOCAL_GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 -#define LOCAL_GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 -#define LOCAL_GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 -#define LOCAL_GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 -#define LOCAL_GL_HILO_NV 0x86F4 -#define LOCAL_GL_DSDT_NV 0x86F5 -#define LOCAL_GL_DSDT_MAG_NV 0x86F6 -#define LOCAL_GL_DSDT_MAG_VIB_NV 0x86F7 -#define LOCAL_GL_HILO16_NV 0x86F8 -#define LOCAL_GL_SIGNED_HILO_NV 0x86F9 -#define LOCAL_GL_SIGNED_HILO16_NV 0x86FA -#define LOCAL_GL_SIGNED_RGBA_NV 0x86FB -#define LOCAL_GL_SIGNED_RGBA8_NV 0x86FC -#define LOCAL_GL_SIGNED_RGB_NV 0x86FE -#define LOCAL_GL_SIGNED_RGB8_NV 0x86FF -#define LOCAL_GL_SIGNED_LUMINANCE_NV 0x8701 -#define LOCAL_GL_SIGNED_LUMINANCE8_NV 0x8702 -#define LOCAL_GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 -#define LOCAL_GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 -#define LOCAL_GL_SIGNED_ALPHA_NV 0x8705 -#define LOCAL_GL_SIGNED_ALPHA8_NV 0x8706 -#define LOCAL_GL_SIGNED_INTENSITY_NV 0x8707 -#define LOCAL_GL_SIGNED_INTENSITY8_NV 0x8708 -#define LOCAL_GL_DSDT8_NV 0x8709 -#define LOCAL_GL_DSDT8_MAG8_NV 0x870A -#define LOCAL_GL_DSDT8_MAG8_INTENSITY8_NV 0x870B -#define LOCAL_GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C -#define LOCAL_GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D -#define LOCAL_GL_HI_SCALE_NV 0x870E -#define LOCAL_GL_LO_SCALE_NV 0x870F -#define LOCAL_GL_DS_SCALE_NV 0x8710 -#define LOCAL_GL_DT_SCALE_NV 0x8711 -#define LOCAL_GL_MAGNITUDE_SCALE_NV 0x8712 -#define LOCAL_GL_VIBRANCE_SCALE_NV 0x8713 -#define LOCAL_GL_HI_BIAS_NV 0x8714 -#define LOCAL_GL_LO_BIAS_NV 0x8715 -#define LOCAL_GL_DS_BIAS_NV 0x8716 -#define LOCAL_GL_DT_BIAS_NV 0x8717 -#define LOCAL_GL_MAGNITUDE_BIAS_NV 0x8718 -#define LOCAL_GL_VIBRANCE_BIAS_NV 0x8719 -#define LOCAL_GL_TEXTURE_BORDER_VALUES_NV 0x871A -#define LOCAL_GL_TEXTURE_HI_SIZE_NV 0x871B -#define LOCAL_GL_TEXTURE_LO_SIZE_NV 0x871C -#define LOCAL_GL_TEXTURE_DS_SIZE_NV 0x871D -#define LOCAL_GL_TEXTURE_DT_SIZE_NV 0x871E -#define LOCAL_GL_TEXTURE_MAG_SIZE_NV 0x871F -#define LOCAL_GL_NV_texture_shader2 1 -#define LOCAL_GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA -#define LOCAL_GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB -#define LOCAL_GL_DSDT_MAG_INTENSITY_NV 0x86DC -#define LOCAL_GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF -#define LOCAL_GL_HILO_NV 0x86F4 -#define LOCAL_GL_DSDT_NV 0x86F5 -#define LOCAL_GL_DSDT_MAG_NV 0x86F6 -#define LOCAL_GL_DSDT_MAG_VIB_NV 0x86F7 -#define LOCAL_GL_HILO16_NV 0x86F8 -#define LOCAL_GL_SIGNED_HILO_NV 0x86F9 -#define LOCAL_GL_SIGNED_HILO16_NV 0x86FA -#define LOCAL_GL_SIGNED_RGBA_NV 0x86FB -#define LOCAL_GL_SIGNED_RGBA8_NV 0x86FC -#define LOCAL_GL_SIGNED_RGB_NV 0x86FE -#define LOCAL_GL_SIGNED_RGB8_NV 0x86FF -#define LOCAL_GL_SIGNED_LUMINANCE_NV 0x8701 -#define LOCAL_GL_SIGNED_LUMINANCE8_NV 0x8702 -#define LOCAL_GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 -#define LOCAL_GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 -#define LOCAL_GL_SIGNED_ALPHA_NV 0x8705 -#define LOCAL_GL_SIGNED_ALPHA8_NV 0x8706 -#define LOCAL_GL_SIGNED_INTENSITY_NV 0x8707 -#define LOCAL_GL_SIGNED_INTENSITY8_NV 0x8708 -#define LOCAL_GL_DSDT8_NV 0x8709 -#define LOCAL_GL_DSDT8_MAG8_NV 0x870A -#define LOCAL_GL_DSDT8_MAG8_INTENSITY8_NV 0x870B -#define LOCAL_GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C -#define LOCAL_GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D -#define LOCAL_GL_NV_texture_shader3 1 -#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 -#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 -#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 -#define LOCAL_GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 -#define LOCAL_GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 -#define LOCAL_GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 -#define LOCAL_GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 -#define LOCAL_GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 -#define LOCAL_GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 -#define LOCAL_GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 -#define LOCAL_GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A -#define LOCAL_GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B -#define LOCAL_GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C -#define LOCAL_GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D -#define LOCAL_GL_HILO8_NV 0x885E -#define LOCAL_GL_SIGNED_HILO8_NV 0x885F -#define LOCAL_GL_FORCE_BLUE_TO_ONE_NV 0x8860 -#define LOCAL_GL_NV_vertex_array_range 1 -#define LOCAL_GL_VERTEX_ARRAY_RANGE_NV 0x851D -#define LOCAL_GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E -#define LOCAL_GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F -#define LOCAL_GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 -#define LOCAL_GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 -#define LOCAL_GL_NV_vertex_array_range2 1 -#define LOCAL_GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 -#define LOCAL_GL_NV_vertex_program 1 -#define LOCAL_GL_VERTEX_PROGRAM_NV 0x8620 -#define LOCAL_GL_VERTEX_STATE_PROGRAM_NV 0x8621 -#define LOCAL_GL_ATTRIB_ARRAY_SIZE_NV 0x8623 -#define LOCAL_GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 -#define LOCAL_GL_ATTRIB_ARRAY_TYPE_NV 0x8625 -#define LOCAL_GL_CURRENT_ATTRIB_NV 0x8626 -#define LOCAL_GL_PROGRAM_LENGTH_NV 0x8627 -#define LOCAL_GL_PROGRAM_STRING_NV 0x8628 -#define LOCAL_GL_MODELVIEW_PROJECTION_NV 0x8629 -#define LOCAL_GL_IDENTITY_NV 0x862A -#define LOCAL_GL_INVERSE_NV 0x862B -#define LOCAL_GL_TRANSPOSE_NV 0x862C -#define LOCAL_GL_INVERSE_TRANSPOSE_NV 0x862D -#define LOCAL_GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E -#define LOCAL_GL_MAX_TRACK_MATRICES_NV 0x862F -#define LOCAL_GL_MATRIX0_NV 0x8630 -#define LOCAL_GL_MATRIX1_NV 0x8631 -#define LOCAL_GL_MATRIX2_NV 0x8632 -#define LOCAL_GL_MATRIX3_NV 0x8633 -#define LOCAL_GL_MATRIX4_NV 0x8634 -#define LOCAL_GL_MATRIX5_NV 0x8635 -#define LOCAL_GL_MATRIX6_NV 0x8636 -#define LOCAL_GL_MATRIX7_NV 0x8637 -#define LOCAL_GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 -#define LOCAL_GL_CURRENT_MATRIX_NV 0x8641 -#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 -#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 -#define LOCAL_GL_PROGRAM_PARAMETER_NV 0x8644 -#define LOCAL_GL_ATTRIB_ARRAY_POINTER_NV 0x8645 -#define LOCAL_GL_PROGRAM_TARGET_NV 0x8646 -#define LOCAL_GL_PROGRAM_RESIDENT_NV 0x8647 -#define LOCAL_GL_TRACK_MATRIX_NV 0x8648 -#define LOCAL_GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 -#define LOCAL_GL_VERTEX_PROGRAM_BINDING_NV 0x864A -#define LOCAL_GL_PROGRAM_ERROR_POSITION_NV 0x864B -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E -#define LOCAL_GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F -#define LOCAL_GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 -#define LOCAL_GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A -#define LOCAL_GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B -#define LOCAL_GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C -#define LOCAL_GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D -#define LOCAL_GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E -#define LOCAL_GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F -#define LOCAL_GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 -#define LOCAL_GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A -#define LOCAL_GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B -#define LOCAL_GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C -#define LOCAL_GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D -#define LOCAL_GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E -#define LOCAL_GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F -#define LOCAL_GL_NV_vertex_program1_1 1 -#define LOCAL_GL_NV_vertex_program2 1 -#define LOCAL_GL_NV_vertex_program2_option 1 -#define LOCAL_GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 -#define LOCAL_GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 -#define LOCAL_GL_NV_vertex_program3 1 -#define LOCAL_GL_OML_interlace 1 -#define LOCAL_GL_INTERLACE_OML 0x8980 -#define LOCAL_GL_INTERLACE_READ_OML 0x8981 -#define LOCAL_GL_OML_resample 1 -#define LOCAL_GL_PACK_RESAMPLE_OML 0x8984 -#define LOCAL_GL_UNPACK_RESAMPLE_OML 0x8985 -#define LOCAL_GL_RESAMPLE_REPLICATE_OML 0x8986 -#define LOCAL_GL_RESAMPLE_ZERO_FILL_OML 0x8987 -#define LOCAL_GL_RESAMPLE_AVERAGE_OML 0x8988 -#define LOCAL_GL_RESAMPLE_DECIMATE_OML 0x8989 -#define LOCAL_GL_OML_subsample 1 -#define LOCAL_GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 -#define LOCAL_GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 -#define LOCAL_GL_PGI_misc_hints 1 -#define LOCAL_GL_PREFER_DOUBLEBUFFER_HINT_PGI 107000 -#define LOCAL_GL_CONSERVE_MEMORY_HINT_PGI 107005 -#define LOCAL_GL_RECLAIM_MEMORY_HINT_PGI 107006 -#define LOCAL_GL_NATIVE_GRAPHICS_HANDLE_PGI 107010 -#define LOCAL_GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 107011 -#define LOCAL_GL_NATIVE_GRAPHICS_END_HINT_PGI 107012 -#define LOCAL_GL_ALWAYS_FAST_HINT_PGI 107020 -#define LOCAL_GL_ALWAYS_SOFT_HINT_PGI 107021 -#define LOCAL_GL_ALLOW_DRAW_OBJ_HINT_PGI 107022 -#define LOCAL_GL_ALLOW_DRAW_WIN_HINT_PGI 107023 -#define LOCAL_GL_ALLOW_DRAW_FRG_HINT_PGI 107024 -#define LOCAL_GL_ALLOW_DRAW_MEM_HINT_PGI 107025 -#define LOCAL_GL_STRICT_DEPTHFUNC_HINT_PGI 107030 -#define LOCAL_GL_STRICT_LIGHTING_HINT_PGI 107031 -#define LOCAL_GL_STRICT_SCISSOR_HINT_PGI 107032 -#define LOCAL_GL_FULL_STIPPLE_HINT_PGI 107033 -#define LOCAL_GL_CLIP_NEAR_HINT_PGI 107040 -#define LOCAL_GL_CLIP_FAR_HINT_PGI 107041 -#define LOCAL_GL_WIDE_LINE_HINT_PGI 107042 -#define LOCAL_GL_BACK_NORMALS_HINT_PGI 107043 -#define LOCAL_GL_PGI_vertex_hints 1 -#define LOCAL_GL_VERTEX23_BIT_PGI 0x00000004 -#define LOCAL_GL_VERTEX4_BIT_PGI 0x00000008 -#define LOCAL_GL_COLOR3_BIT_PGI 0x00010000 -#define LOCAL_GL_COLOR4_BIT_PGI 0x00020000 -#define LOCAL_GL_EDGEFLAG_BIT_PGI 0x00040000 -#define LOCAL_GL_INDEX_BIT_PGI 0x00080000 -#define LOCAL_GL_MAT_AMBIENT_BIT_PGI 0x00100000 -#define LOCAL_GL_VERTEX_DATA_HINT_PGI 107050 -#define LOCAL_GL_VERTEX_CONSISTENT_HINT_PGI 107051 -#define LOCAL_GL_MATERIAL_SIDE_HINT_PGI 107052 -#define LOCAL_GL_MAX_VERTEX_HINT_PGI 107053 -#define LOCAL_GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 -#define LOCAL_GL_MAT_DIFFUSE_BIT_PGI 0x00400000 -#define LOCAL_GL_MAT_EMISSION_BIT_PGI 0x00800000 -#define LOCAL_GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 -#define LOCAL_GL_MAT_SHININESS_BIT_PGI 0x02000000 -#define LOCAL_GL_MAT_SPECULAR_BIT_PGI 0x04000000 -#define LOCAL_GL_NORMAL_BIT_PGI 0x08000000 -#define LOCAL_GL_TEXCOORD1_BIT_PGI 0x10000000 -#define LOCAL_GL_TEXCOORD2_BIT_PGI 0x20000000 -#define LOCAL_GL_TEXCOORD3_BIT_PGI 0x40000000 -#define LOCAL_GL_TEXCOORD4_BIT_PGI 0x80000000 -#define LOCAL_GL_REND_screen_coordinates 1 -#define LOCAL_GL_SCREEN_COORDINATES_REND 0x8490 -#define LOCAL_GL_INVERTED_SCREEN_W_REND 0x8491 -#define LOCAL_GL_S3_s3tc 1 -#define LOCAL_GL_RGB_S3TC 0x83A0 -#define LOCAL_GL_RGB4_S3TC 0x83A1 -#define LOCAL_GL_RGBA_S3TC 0x83A2 -#define LOCAL_GL_RGBA4_S3TC 0x83A3 -#define LOCAL_GL_RGBA_DXT5_S3TC 0x83A4 -#define LOCAL_GL_RGBA4_DXT5_S3TC 0x83A5 -#define LOCAL_GL_SGIS_color_range 1 -#define LOCAL_GL_EXTENDED_RANGE_SGIS 0x85A5 -#define LOCAL_GL_MIN_RED_SGIS 0x85A6 -#define LOCAL_GL_MAX_RED_SGIS 0x85A7 -#define LOCAL_GL_MIN_GREEN_SGIS 0x85A8 -#define LOCAL_GL_MAX_GREEN_SGIS 0x85A9 -#define LOCAL_GL_MIN_BLUE_SGIS 0x85AA -#define LOCAL_GL_MAX_BLUE_SGIS 0x85AB -#define LOCAL_GL_MIN_ALPHA_SGIS 0x85AC -#define LOCAL_GL_MAX_ALPHA_SGIS 0x85AD -#define LOCAL_GL_SGIS_detail_texture 1 -#define LOCAL_GL_SGIS_fog_function 1 -#define LOCAL_GL_SGIS_generate_mipmap 1 -#define LOCAL_GL_GENERATE_MIPMAP_SGIS 0x8191 -#define LOCAL_GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 -#define LOCAL_GL_SGIS_multisample 1 -#define LOCAL_GL_MULTISAMPLE_SGIS 0x809D -#define LOCAL_GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E -#define LOCAL_GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F -#define LOCAL_GL_SAMPLE_MASK_SGIS 0x80A0 -#define LOCAL_GL_1PASS_SGIS 0x80A1 -#define LOCAL_GL_2PASS_0_SGIS 0x80A2 -#define LOCAL_GL_2PASS_1_SGIS 0x80A3 -#define LOCAL_GL_4PASS_0_SGIS 0x80A4 -#define LOCAL_GL_4PASS_1_SGIS 0x80A5 -#define LOCAL_GL_4PASS_2_SGIS 0x80A6 -#define LOCAL_GL_4PASS_3_SGIS 0x80A7 -#define LOCAL_GL_SAMPLE_BUFFERS_SGIS 0x80A8 -#define LOCAL_GL_SAMPLES_SGIS 0x80A9 -#define LOCAL_GL_SAMPLE_MASK_VALUE_SGIS 0x80AA -#define LOCAL_GL_SAMPLE_MASK_INVERT_SGIS 0x80AB -#define LOCAL_GL_SAMPLE_PATTERN_SGIS 0x80AC -#define LOCAL_GL_MULTISAMPLE_BIT_EXT 0x20000000 -#define LOCAL_GL_SGIS_pixel_texture 1 -#define LOCAL_GL_SGIS_sharpen_texture 1 -#define LOCAL_GL_SGIS_texture4D 1 -#define LOCAL_GL_SGIS_texture_border_clamp 1 -#define LOCAL_GL_CLAMP_TO_BORDER_SGIS 0x812D -#define LOCAL_GL_SGIS_texture_edge_clamp 1 -#define LOCAL_GL_CLAMP_TO_EDGE_SGIS 0x812F -#define LOCAL_GL_SGIS_texture_filter4 1 -#define LOCAL_GL_SGIS_texture_lod 1 -#define LOCAL_GL_TEXTURE_MIN_LOD_SGIS 0x813A -#define LOCAL_GL_TEXTURE_MAX_LOD_SGIS 0x813B -#define LOCAL_GL_TEXTURE_BASE_LEVEL_SGIS 0x813C -#define LOCAL_GL_TEXTURE_MAX_LEVEL_SGIS 0x813D -#define LOCAL_GL_SGIS_texture_select 1 -#define LOCAL_GL_SGIX_async 1 -#define LOCAL_GL_ASYNC_MARKER_SGIX 0x8329 -#define LOCAL_GL_SGIX_async_histogram 1 -#define LOCAL_GL_ASYNC_HISTOGRAM_SGIX 0x832C -#define LOCAL_GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D -#define LOCAL_GL_SGIX_async_pixel 1 -#define LOCAL_GL_ASYNC_TEX_IMAGE_SGIX 0x835C -#define LOCAL_GL_ASYNC_DRAW_PIXELS_SGIX 0x835D -#define LOCAL_GL_ASYNC_READ_PIXELS_SGIX 0x835E -#define LOCAL_GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F -#define LOCAL_GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 -#define LOCAL_GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 -#define LOCAL_GL_SGIX_blend_alpha_minmax 1 -#define LOCAL_GL_ALPHA_MIN_SGIX 0x8320 -#define LOCAL_GL_ALPHA_MAX_SGIX 0x8321 -#define LOCAL_GL_SGIX_clipmap 1 -#define LOCAL_GL_SGIX_depth_texture 1 -#define LOCAL_GL_DEPTH_COMPONENT16_SGIX 0x81A5 -#define LOCAL_GL_DEPTH_COMPONENT24_SGIX 0x81A6 -#define LOCAL_GL_DEPTH_COMPONENT32_SGIX 0x81A7 -#define LOCAL_GL_SGIX_flush_raster 1 -#define LOCAL_GL_SGIX_fog_offset 1 -#define LOCAL_GL_FOG_OFFSET_SGIX 0x8198 -#define LOCAL_GL_FOG_OFFSET_VALUE_SGIX 0x8199 -#define LOCAL_GL_SGIX_fog_texture 1 -#define LOCAL_GL_TEXTURE_FOG_SGIX 0 -#define LOCAL_GL_FOG_PATCHY_FACTOR_SGIX 0 -#define LOCAL_GL_FRAGMENT_FOG_SGIX 0 -#define LOCAL_GL_SGIX_fragment_specular_lighting 1 -#define LOCAL_GL_SGIX_framezoom 1 -#define LOCAL_GL_SGIX_interlace 1 -#define LOCAL_GL_INTERLACE_SGIX 0x8094 -#define LOCAL_GL_SGIX_ir_instrument1 1 -#define LOCAL_GL_SGIX_list_priority 1 -#define LOCAL_GL_SGIX_pixel_texture 1 -#define LOCAL_GL_SGIX_pixel_texture_bits 1 -#define LOCAL_GL_SGIX_reference_plane 1 -#define LOCAL_GL_SGIX_resample 1 -#define LOCAL_GL_PACK_RESAMPLE_SGIX 0x842E -#define LOCAL_GL_UNPACK_RESAMPLE_SGIX 0x842F -#define LOCAL_GL_RESAMPLE_DECIMATE_SGIX 0x8430 -#define LOCAL_GL_RESAMPLE_REPLICATE_SGIX 0x8433 -#define LOCAL_GL_RESAMPLE_ZERO_FILL_SGIX 0x8434 -#define LOCAL_GL_SGIX_shadow 1 -#define LOCAL_GL_TEXTURE_COMPARE_SGIX 0x819A -#define LOCAL_GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B -#define LOCAL_GL_TEXTURE_LEQUAL_R_SGIX 0x819C -#define LOCAL_GL_TEXTURE_GEQUAL_R_SGIX 0x819D -#define LOCAL_GL_SGIX_shadow_ambient 1 -#define LOCAL_GL_SHADOW_AMBIENT_SGIX 0x80BF -#define LOCAL_GL_SGIX_sprite 1 -#define LOCAL_GL_SGIX_tag_sample_buffer 1 -#define LOCAL_GL_SGIX_texture_add_env 1 -#define LOCAL_GL_SGIX_texture_coordinate_clamp 1 -#define LOCAL_GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 -#define LOCAL_GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A -#define LOCAL_GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B -#define LOCAL_GL_SGIX_texture_lod_bias 1 -#define LOCAL_GL_SGIX_texture_multi_buffer 1 -#define LOCAL_GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E -#define LOCAL_GL_SGIX_texture_range 1 -#define LOCAL_GL_RGB_SIGNED_SGIX 0x85E0 -#define LOCAL_GL_RGBA_SIGNED_SGIX 0x85E1 -#define LOCAL_GL_ALPHA_SIGNED_SGIX 0x85E2 -#define LOCAL_GL_LUMINANCE_SIGNED_SGIX 0x85E3 -#define LOCAL_GL_INTENSITY_SIGNED_SGIX 0x85E4 -#define LOCAL_GL_LUMINANCE_ALPHA_SIGNED_SGIX 0x85E5 -#define LOCAL_GL_RGB16_SIGNED_SGIX 0x85E6 -#define LOCAL_GL_RGBA16_SIGNED_SGIX 0x85E7 -#define LOCAL_GL_ALPHA16_SIGNED_SGIX 0x85E8 -#define LOCAL_GL_LUMINANCE16_SIGNED_SGIX 0x85E9 -#define LOCAL_GL_INTENSITY16_SIGNED_SGIX 0x85EA -#define LOCAL_GL_LUMINANCE16_ALPHA16_SIGNED_SGIX 0x85EB -#define LOCAL_GL_RGB_EXTENDED_RANGE_SGIX 0x85EC -#define LOCAL_GL_RGBA_EXTENDED_RANGE_SGIX 0x85ED -#define LOCAL_GL_ALPHA_EXTENDED_RANGE_SGIX 0x85EE -#define LOCAL_GL_LUMINANCE_EXTENDED_RANGE_SGIX 0x85EF -#define LOCAL_GL_INTENSITY_EXTENDED_RANGE_SGIX 0x85F0 -#define LOCAL_GL_LUMINANCE_ALPHA_EXTENDED_RANGE_SGIX 0x85F1 -#define LOCAL_GL_RGB16_EXTENDED_RANGE_SGIX 0x85F2 -#define LOCAL_GL_RGBA16_EXTENDED_RANGE_SGIX 0x85F3 -#define LOCAL_GL_ALPHA16_EXTENDED_RANGE_SGIX 0x85F4 -#define LOCAL_GL_LUMINANCE16_EXTENDED_RANGE_SGIX 0x85F5 -#define LOCAL_GL_INTENSITY16_EXTENDED_RANGE_SGIX 0x85F6 -#define LOCAL_GL_LUMINANCE16_ALPHA16_EXTENDED_RANGE_SGIX 0x85F7 -#define LOCAL_GL_MIN_LUMINANCE_SGIS 0x85F8 -#define LOCAL_GL_MAX_LUMINANCE_SGIS 0x85F9 -#define LOCAL_GL_MIN_INTENSITY_SGIS 0x85FA -#define LOCAL_GL_MAX_INTENSITY_SGIS 0x85FB -#define LOCAL_GL_SGIX_texture_scale_bias 1 -#define LOCAL_GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 -#define LOCAL_GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A -#define LOCAL_GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B -#define LOCAL_GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C -#define LOCAL_GL_SGIX_vertex_preclip 1 -#define LOCAL_GL_VERTEX_PRECLIP_SGIX 0x83EE -#define LOCAL_GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF -#define LOCAL_GL_SGIX_vertex_preclip_hint 1 -#define LOCAL_GL_VERTEX_PRECLIP_SGIX 0x83EE -#define LOCAL_GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF -#define LOCAL_GL_SGIX_ycrcb 1 -#define LOCAL_GL_SGI_color_matrix 1 -#define LOCAL_GL_COLOR_MATRIX_SGI 0x80B1 -#define LOCAL_GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 -#define LOCAL_GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 -#define LOCAL_GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 -#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 -#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 -#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 -#define LOCAL_GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 -#define LOCAL_GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 -#define LOCAL_GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA -#define LOCAL_GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB -#define LOCAL_GL_SGI_color_table 1 -#define LOCAL_GL_COLOR_TABLE_SGI 0x80D0 -#define LOCAL_GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 -#define LOCAL_GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 -#define LOCAL_GL_PROXY_COLOR_TABLE_SGI 0x80D3 -#define LOCAL_GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 -#define LOCAL_GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 -#define LOCAL_GL_COLOR_TABLE_SCALE_SGI 0x80D6 -#define LOCAL_GL_COLOR_TABLE_BIAS_SGI 0x80D7 -#define LOCAL_GL_COLOR_TABLE_FORMAT_SGI 0x80D8 -#define LOCAL_GL_COLOR_TABLE_WIDTH_SGI 0x80D9 -#define LOCAL_GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA -#define LOCAL_GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB -#define LOCAL_GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC -#define LOCAL_GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD -#define LOCAL_GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE -#define LOCAL_GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF -#define LOCAL_GL_SGI_texture_color_table 1 -#define LOCAL_GL_TEXTURE_COLOR_TABLE_SGI 0x80BC -#define LOCAL_GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD -#define LOCAL_GL_SUNX_constant_data 1 -#define LOCAL_GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 -#define LOCAL_GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 -#define LOCAL_GL_SUN_convolution_border_modes 1 -#define LOCAL_GL_WRAP_BORDER_SUN 0x81D4 -#define LOCAL_GL_SUN_global_alpha 1 -#define LOCAL_GL_GLOBAL_ALPHA_SUN 0x81D9 -#define LOCAL_GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA -#define LOCAL_GL_SUN_mesh_array 1 -#define LOCAL_GL_QUAD_MESH_SUN 0x8614 -#define LOCAL_GL_TRIANGLE_MESH_SUN 0x8615 -#define LOCAL_GL_SUN_read_video_pixels 1 -#define LOCAL_GL_SUN_slice_accum 1 -#define LOCAL_GL_SLICE_ACCUM_SUN 0x85CC -#define LOCAL_GL_SUN_triangle_list 1 -#define LOCAL_GL_RESTART_SUN 0x01 -#define LOCAL_GL_REPLACE_MIDDLE_SUN 0x02 -#define LOCAL_GL_REPLACE_OLDEST_SUN 0x03 -#define LOCAL_GL_TRIANGLE_LIST_SUN 0x81D7 -#define LOCAL_GL_REPLACEMENT_CODE_SUN 0x81D8 -#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 -#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 -#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 -#define LOCAL_GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 -#define LOCAL_GL_R1UI_V3F_SUN 0x85C4 -#define LOCAL_GL_R1UI_C4UB_V3F_SUN 0x85C5 -#define LOCAL_GL_R1UI_C3F_V3F_SUN 0x85C6 -#define LOCAL_GL_R1UI_N3F_V3F_SUN 0x85C7 -#define LOCAL_GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 -#define LOCAL_GL_R1UI_T2F_V3F_SUN 0x85C9 -#define LOCAL_GL_R1UI_T2F_N3F_V3F_SUN 0x85CA -#define LOCAL_GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB -#define LOCAL_GL_SUN_vertex 1 -#define LOCAL_GL_WIN_phong_shading 1 -#define LOCAL_GL_PHONG_WIN 0x80EA -#define LOCAL_GL_PHONG_HINT_WIN 0x80EB -#define LOCAL_GL_WIN_specular_fog 1 -#define LOCAL_GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC -#define LOCAL_GL_WIN_swap_hint 1 - -// ARB_sync -#define LOCAL_GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define LOCAL_GL_OBJECT_TYPE 0x9112 -#define LOCAL_GL_SYNC_CONDITION 0x9113 -#define LOCAL_GL_SYNC_STATUS 0x9114 -#define LOCAL_GL_SYNC_FLAGS 0x9115 -#define LOCAL_GL_SYNC_FENCE 0x9116 -#define LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define LOCAL_GL_UNSIGNALED 0x9118 -#define LOCAL_GL_SIGNALED 0x9119 -#define LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define LOCAL_GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#define LOCAL_GL_ALREADY_SIGNALED 0x911A -#define LOCAL_GL_TIMEOUT_EXPIRED 0x911B -#define LOCAL_GL_CONDITION_SATISFIED 0x911C -#define LOCAL_GL_WAIT_FAILED 0x911D - -// OES_EGL_image_external -#define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 - -#define LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define LOCAL_GL_MAX_VARYING_VECTORS 0x8DFC -#define LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 - -#define LOCAL_GL_MAX_SAMPLES 0x8D57 - -#define LOCAL_GL_LOW_FLOAT 0x8DF0 -#define LOCAL_GL_MEDIUM_FLOAT 0x8DF1 -#define LOCAL_GL_HIGH_FLOAT 0x8DF2 -#define LOCAL_GL_LOW_INT 0x8DF3 -#define LOCAL_GL_MEDIUM_INT 0x8DF4 -#define LOCAL_GL_HIGH_INT 0x8DF5 - -#define LOCAL_GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 - -#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 - -#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 - -#define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 - -#define LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define LOCAL_WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 - -#define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 -#define LOCAL_EGL_NO_RESET_NOTIFICATION_EXT 0x31BE -#define LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF - -#define LOCAL_GL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define LOCAL_GL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define LOCAL_GL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094 -#define LOCAL_GL_CONTEXT_PROFILE_MASK_ARB 0x9126 - -#define LOCAL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define LOCAL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define LOCAL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define LOCAL_WGL_CONTEXT_FLAGS_ARB 0x2094 -#define LOCAL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - -#define LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT 0x30BF - -#define LOCAL_GL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define LOCAL_GL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 - -#define LOCAL_WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define LOCAL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 - -#define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 - -#define LOCAL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define LOCAL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 - -// AMD_compressed_ATC_texture -#define LOCAL_GL_ATC_RGB 0x8C92 -#define LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA 0x8C93 -#define LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA 0x87EE - -// IMG_texture_compression_pvrtc -#define LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 0x8C00 -#define LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 0x8C01 -#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1 0x8C02 -#define LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 0x8C03 - -#define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define LOCAL_WGL_DRAW_TO_BITMAP_ARB 0x2002 -#define LOCAL_WGL_ACCELERATION_ARB 0x2003 -#define LOCAL_WGL_NEED_PALETTE_ARB 0x2004 -#define LOCAL_WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 -#define LOCAL_WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 -#define LOCAL_WGL_SWAP_METHOD_ARB 0x2007 -#define LOCAL_WGL_NUMBER_OVERLAYS_ARB 0x2008 -#define LOCAL_WGL_NUMBER_UNDERLAYS_ARB 0x2009 -#define LOCAL_WGL_TRANSPARENT_ARB 0x200A -#define LOCAL_WGL_SHARE_DEPTH_ARB 0x200C -#define LOCAL_WGL_SHARE_STENCIL_ARB 0x200D -#define LOCAL_WGL_SHARE_ACCUM_ARB 0x200E -#define LOCAL_WGL_SUPPORT_GDI_ARB 0x200F -#define LOCAL_WGL_SUPPORT_OPENGL_ARB 0x2010 -#define LOCAL_WGL_DOUBLE_BUFFER_ARB 0x2011 -#define LOCAL_WGL_STEREO_ARB 0x2012 -#define LOCAL_WGL_PIXEL_TYPE_ARB 0x2013 -#define LOCAL_WGL_COLOR_BITS_ARB 0x2014 -#define LOCAL_WGL_RED_BITS_ARB 0x2015 -#define LOCAL_WGL_RED_SHIFT_ARB 0x2016 -#define LOCAL_WGL_GREEN_BITS_ARB 0x2017 -#define LOCAL_WGL_GREEN_SHIFT_ARB 0x2018 -#define LOCAL_WGL_BLUE_BITS_ARB 0x2019 -#define LOCAL_WGL_BLUE_SHIFT_ARB 0x201A -#define LOCAL_WGL_ALPHA_BITS_ARB 0x201B -#define LOCAL_WGL_ALPHA_SHIFT_ARB 0x201C -#define LOCAL_WGL_ACCUM_BITS_ARB 0x201D -#define LOCAL_WGL_ACCUM_RED_BITS_ARB 0x201E -#define LOCAL_WGL_ACCUM_GREEN_BITS_ARB 0x201F -#define LOCAL_WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define LOCAL_WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define LOCAL_WGL_DEPTH_BITS_ARB 0x2022 -#define LOCAL_WGL_STENCIL_BITS_ARB 0x2023 -#define LOCAL_WGL_AUX_BUFFERS_ARB 0x2024 -#define LOCAL_WGL_NO_ACCELERATION_ARB 0x2025 -#define LOCAL_WGL_GENERIC_ACCELERATION_ARB 0x2026 -#define LOCAL_WGL_FULL_ACCELERATION_ARB 0x2027 -#define LOCAL_WGL_SWAP_EXCHANGE_ARB 0x2028 -#define LOCAL_WGL_SWAP_COPY_ARB 0x2029 -#define LOCAL_WGL_SWAP_UNDEFINED_ARB 0x202A -#define LOCAL_WGL_TYPE_RGBA_ARB 0x202B -#define LOCAL_WGL_TYPE_COLORINDEX_ARB 0x202C -#define LOCAL_WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 -#define LOCAL_WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 -#define LOCAL_WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 -#define LOCAL_WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A -#define LOCAL_WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B - -#define LOCAL_WGL_DRAW_TO_PBUFFER_ARB 0x202D -#define LOCAL_WGL_MAX_PBUFFER_PIXELS_ARB 0x202E -#define LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB 0x202F -#define LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 -#define LOCAL_WGL_PBUFFER_LARGEST_ARB 0x2033 -#define LOCAL_WGL_PBUFFER_WIDTH_ARB 0x2034 -#define LOCAL_WGL_PBUFFER_HEIGHT_ARB 0x2035 -#define LOCAL_WGL_PBUFFER_LOST_ARB 0x2036 - -#define LOCAL_WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define LOCAL_WGL_SAMPLES_ARB 0x2042 - -#define LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 -#define LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 -#define LOCAL_WGL_TEXTURE_FORMAT_ARB 0x2072 -#define LOCAL_WGL_TEXTURE_TARGET_ARB 0x2073 -#define LOCAL_WGL_MIPMAP_TEXTURE_ARB 0x2074 -#define LOCAL_WGL_TEXTURE_RGB_ARB 0x2075 -#define LOCAL_WGL_TEXTURE_RGBA_ARB 0x2076 -#define LOCAL_WGL_NO_TEXTURE_ARB 0x2077 -#define LOCAL_WGL_TEXTURE_2D_ARB 0x207A -#define LOCAL_WGL_MIPMAP_LEVEL_ARB 0x207B -#define LOCAL_WGL_FRONT_LEFT_ARB 0x2083 -#define LOCAL_WGL_FRONT_RIGHT_ARB 0x2084 -#define LOCAL_WGL_BACK_LEFT_ARB 0x2085 -#define LOCAL_WGL_BACK_RIGHT_ARB 0x2086 - -#define LOCAL_EGL_BUFFER_SIZE 0x3020 -#define LOCAL_EGL_ALPHA_SIZE 0x3021 -#define LOCAL_EGL_BLUE_SIZE 0x3022 -#define LOCAL_EGL_GREEN_SIZE 0x3023 -#define LOCAL_EGL_RED_SIZE 0x3024 -#define LOCAL_EGL_DEPTH_SIZE 0x3025 -#define LOCAL_EGL_STENCIL_SIZE 0x3026 -#define LOCAL_EGL_CONFIG_CAVEAT 0x3027 -#define LOCAL_EGL_CONFIG_ID 0x3028 -#define LOCAL_EGL_LEVEL 0x3029 -#define LOCAL_EGL_MAX_PBUFFER_HEIGHT 0x302A -#define LOCAL_EGL_MAX_PBUFFER_PIXELS 0x302B -#define LOCAL_EGL_MAX_PBUFFER_WIDTH 0x302C -#define LOCAL_EGL_NATIVE_RENDERABLE 0x302D -#define LOCAL_EGL_NATIVE_VISUAL_ID 0x302E -#define LOCAL_EGL_NATIVE_VISUAL_TYPE 0x302F -#define LOCAL_EGL_PRESERVED_RESOURCES 0x3030 -#define LOCAL_EGL_SAMPLES 0x3031 -#define LOCAL_EGL_SAMPLE_BUFFERS 0x3032 -#define LOCAL_EGL_SURFACE_TYPE 0x3033 -#define LOCAL_EGL_TRANSPARENT_TYPE 0x3034 -#define LOCAL_EGL_TRANSPARENT_BLUE_VALUE 0x3035 -#define LOCAL_EGL_TRANSPARENT_GREEN_VALUE 0x3036 -#define LOCAL_EGL_TRANSPARENT_RED_VALUE 0x3037 -#define LOCAL_EGL_NONE 0x3038 -#define LOCAL_EGL_BIND_TO_TEXTURE_RGB 0x3039 -#define LOCAL_EGL_BIND_TO_TEXTURE_RGBA 0x303A -#define LOCAL_EGL_MIN_SWAP_INTERVAL 0x303B -#define LOCAL_EGL_MAX_SWAP_INTERVAL 0x303C -#define LOCAL_EGL_LUMINANCE_SIZE 0x303D -#define LOCAL_EGL_ALPHA_MASK_SIZE 0x303E -#define LOCAL_EGL_COLOR_BUFFER_TYPE 0x303F -#define LOCAL_EGL_RENDERABLE_TYPE 0x3040 -#define LOCAL_EGL_MATCH_NATIVE_PIXMAP 0x3041 -#define LOCAL_EGL_CONFORMANT 0x3042 -#define LOCAL_EGL_OPENGL_ES_BIT 0x0001 -#define LOCAL_EGL_OPENVG_BIT 0x0002 -#define LOCAL_EGL_OPENGL_ES2_BIT 0x0004 -#define LOCAL_EGL_OPENGL_ES_API 0x30A0 -#define LOCAL_EGL_PBUFFER_BIT 0x0001 -#define LOCAL_EGL_PIXMAP_BIT 0x0002 -#define LOCAL_EGL_WINDOW_BIT 0x0004 -#define LOCAL_EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 -#define LOCAL_EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 -#define LOCAL_EGL_VENDOR 0x3053 -#define LOCAL_EGL_VERSION 0x3054 -#define LOCAL_EGL_EXTENSIONS 0x3055 -#define LOCAL_EGL_CLIENT_APIS 0x308D -#define LOCAL_EGL_HEIGHT 0x3056 -#define LOCAL_EGL_WIDTH 0x3057 -#define LOCAL_EGL_LARGEST_PBUFFER 0x3058 -#define LOCAL_EGL_TEXTURE_FORMAT 0x3080 -#define LOCAL_EGL_TEXTURE_TARGET 0x3081 -#define LOCAL_EGL_MIPMAP_TEXTURE 0x3082 -#define LOCAL_EGL_MIPMAP_LEVEL 0x3083 -#define LOCAL_EGL_RENDER_BUFFER 0x3086 -#define LOCAL_EGL_VG_COLORSPACE 0x3087 -#define LOCAL_EGL_VG_ALPHA_FORMAT 0x3088 -#define LOCAL_EGL_HORIZONTAL_RESOLUTION 0x3090 -#define LOCAL_EGL_VERTICAL_RESOLUTION 0x3091 -#define LOCAL_EGL_PIXEL_ASPECT_RATIO 0x3092 -#define LOCAL_EGL_SWAP_BEHAVIOR 0x3093 -#define LOCAL_EGL_MULTISAMPLE_RESOLVE 0x3099 -#define LOCAL_EGL_CONTEXT_CLIENT_TYPE 0x3097 -#define LOCAL_EGL_CONTEXT_CLIENT_VERSION 0x3098 -#define LOCAL_EGL_BACK_BUFFER 0x3084 -#define LOCAL_EGL_TEXTURE_RGB 0x305D -#define LOCAL_EGL_TEXTURE_RGBA 0x305E -#define LOCAL_EGL_TEXTURE_2D 0x305F -#define LOCAL_EGL_FALSE 0 -#define LOCAL_EGL_TRUE 1 -#define LOCAL_EGL_BITMAP_POINTER_KHR 0x30C6 -#define LOCAL_EGL_BITMAP_PITCH_KHR 0x30C7 -#define LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 -#define LOCAL_EGL_LOCK_USAGE_HINT_KHR 0x30C5 -#define LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 -#define LOCAL_EGL_READ_SURFACE_BIT_KHR 0x0001 -#define LOCAL_EGL_WRITE_SURFACE_BIT_KHR 0x0002 -#define LOCAL_EGL_LOCK_SURFACE_BIT_KHR 0x0080 -#define LOCAL_EGL_CORE_NATIVE_ENGINE 0x305B -#define LOCAL_EGL_READ 0x305A -#define LOCAL_EGL_DRAW 0x3059 -#define LOCAL_EGL_BAD_PARAMETER 0x300C -#define LOCAL_EGL_CONTEXT_LOST 0x300E - -// EGL_KHR_image_base (not supplied by EGL_KHR_image!) -#define LOCAL_EGL_IMAGE_PRESERVED 0x30D2 - -// EGL_KHR_image_pixmap -#define LOCAL_EGL_NATIVE_PIXMAP 0x30B0 - -// EGL_KHR_gl_texture_2D_image -#define LOCAL_EGL_GL_TEXTURE_2D 0x30B1 - -// EGL_KHR_gl_renderbuffer_image -#define LOCAL_EGL_GL_RENDERBUFFER 0x30B9 - -// OES_EGL_image_external -#define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 - -// EGL_KHR_fence_sync -#define LOCAL_EGL_SYNC_FENCE 0x30F9 -#define LOCAL_EGL_SYNC_TYPE 0x30F7 -#define LOCAL_EGL_SYNC_STATUS 0x30F1 -#define LOCAL_EGL_SYNC_CONDITION 0x30F8 -#define LOCAL_EGL_SIGNALED 0x30F2 -#define LOCAL_EGL_UNSIGNALED 0x30F3 -#define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 -#define LOCAL_EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 -#define LOCAL_EGL_FOREVER 0xFFFFFFFFFFFFFFFFull -#define LOCAL_EGL_TIMEOUT_EXPIRED 0x30F5 -#define LOCAL_EGL_CONDITION_SATISFIED 0x30F6 -#define LOCAL_EGL_SUCCESS 0x3000 - -// EGL_ANGLE_surface_d3d_texture_2d_share_handle -#define LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 - -// FAKE_EGL_image_android -#define LOCAL_EGL_NATIVE_BUFFER_ANDROID 0x3140 - -#endif diff --git a/libazure/include/mozilla/ipc/chromium/src/base/basictypes.h b/libazure/include/mozilla/ipc/chromium/src/base/basictypes.h deleted file mode 100644 index 801379b..0000000 --- a/libazure/include/mozilla/ipc/chromium/src/base/basictypes.h +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASICTYPES_H_ -#define BASE_BASICTYPES_H_ - -#include // So we can set the bounds of our types -#include // For size_t -#include // for memcpy - -#include "base/port.h" // Types that only need exist on certain systems - -#include "mozilla/Assertions.h" -#include "mozilla/StandardInteger.h" - -// A type to represent a Unicode code-point value. As of Unicode 4.0, -// such values require up to 21 bits. -// (For type-checking on pointers, make this explicitly signed, -// and it should always be the signed version of whatever int32_t is.) -typedef signed int char32; - -const uint8_t kuint8max = (( uint8_t) 0xFF); -const uint16_t kuint16max = ((uint16_t) 0xFFFF); -const uint32_t kuint32max = ((uint32_t) 0xFFFFFFFF); -const uint64_t kuint64max = ((uint64_t) GG_LONGLONG(0xFFFFFFFFFFFFFFFF)); -const int8_t kint8min = (( int8_t) 0x80); -const int8_t kint8max = (( int8_t) 0x7F); -const int16_t kint16min = (( int16_t) 0x8000); -const int16_t kint16max = (( int16_t) 0x7FFF); -const int32_t kint32min = (( int32_t) 0x80000000); -const int32_t kint32max = (( int32_t) 0x7FFFFFFF); -const int64_t kint64min = (( int64_t) GG_LONGLONG(0x8000000000000000)); -const int64_t kint64max = (( int64_t) GG_LONGLONG(0x7FFFFFFFFFFFFFFF)); - -// Platform- and hardware-dependent printf specifiers -# if defined(OS_POSIX) -# define __STDC_FORMAT_MACROS 1 -# include // for 64-bit integer format macros -# define PRId64L "I64d" -# define PRIu64L "I64u" -# define PRIx64L "I64x" -# elif defined(OS_WIN) -# define PRId64 "I64d" -# define PRIu64 "I64u" -# define PRIx64 "I64x" -# define PRId64L L"I64d" -# define PRIu64L L"I64u" -# define PRIx64L L"I64x" -# endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -// An older, deprecated, politically incorrect name for the above. -#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName) - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) - -// The arraysize(arr) macro returns the # of elements in an array arr. -// The expression is a compile-time constant, and therefore can be -// used in defining new arrays, for example. If you use arraysize on -// a pointer by mistake, you will get a compile-time error. -// -// One caveat is that arraysize() doesn't accept any array of an -// anonymous type or a type defined inside a function. In these rare -// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is -// due to a limitation in C++'s template system. The limitation might -// eventually be removed, but it hasn't happened yet. - -// This template function declaration is used in defining arraysize. -// Note that the function doesn't need an implementation, as we only -// use its type. -template -char (&ArraySizeHelper(T (&array)[N]))[N]; - -// That gcc wants both of these prototypes seems mysterious. VC, for -// its part, can't decide which to use (another mystery). Matching of -// template overloads: the final frontier. -#ifndef _MSC_VER -template -char (&ArraySizeHelper(const T (&array)[N]))[N]; -#endif - -#define arraysize(array) (sizeof(ArraySizeHelper(array))) - -// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize, -// but can be used on anonymous types or types defined inside -// functions. It's less safe than arraysize as it accepts some -// (although not all) pointers. Therefore, you should use arraysize -// whenever possible. -// -// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type -// size_t. -// -// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error -// -// "warning: division by zero in ..." -// -// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer. -// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays. -// -// The following comments are on the implementation details, and can -// be ignored by the users. -// -// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in -// the array) and sizeof(*(arr)) (the # of bytes in one array -// element). If the former is divisible by the latter, perhaps arr is -// indeed an array, in which case the division result is the # of -// elements in the array. Otherwise, arr cannot possibly be an array, -// and we generate a compiler error to prevent the code from -// compiling. -// -// Since the size of bool is implementation-defined, we need to cast -// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final -// result has type size_t. -// -// This macro is not perfect as it wrongfully accepts certain -// pointers, namely where the pointer size is divisible by the pointee -// size. Since all our code has to go through a 32-bit compiler, -// where a pointer is 4 bytes, this means all pointers to a type whose -// size is 3 or greater than 4 will be (righteously) rejected. - -#define ARRAYSIZE_UNSAFE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) - - -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertable to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: -// -// implicit_cast(expr) -// -// implicit_cast would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -template -inline To implicit_cast(From const &f) { - return f; -} - -// The COMPILE_ASSERT macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#undef COMPILE_ASSERT -#define COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] - -// Implementation details of COMPILE_ASSERT: -// -// - COMPILE_ASSERT works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// COMPILE_ASSERT(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - - -// MetatagId refers to metatag-id that we assign to -// each metatag pair.. -typedef uint32_t MetatagId; - -// Argument type used in interfaces that can optionally take ownership -// of a passed in argument. If TAKE_OWNERSHIP is passed, the called -// object takes ownership of the argument. Otherwise it does not. -enum Ownership { - DO_NOT_TAKE_OWNERSHIP, - TAKE_OWNERSHIP -}; - -// bit_cast is a template function that implements the -// equivalent of "*reinterpret_cast(&source)". We need this in -// very low-level functions like the protobuf library and fast math -// support. -// -// float f = 3.14159265358979; -// int i = bit_cast(f); -// // i = 0x40490fdb -// -// The classical address-casting method is: -// -// // WRONG -// float f = 3.14159265358979; // WRONG -// int i = * reinterpret_cast(&f); // WRONG -// -// The address-casting method actually produces undefined behavior -// according to ISO C++ specification section 3.10 -15 -. Roughly, this -// section says: if an object in memory has one type, and a program -// accesses it with a different type, then the result is undefined -// behavior for most values of "different type". -// -// This is true for any cast syntax, either *(int*)&f or -// *reinterpret_cast(&f). And it is particularly true for -// conversions betweeen integral lvalues and floating-point lvalues. -// -// The purpose of 3.10 -15- is to allow optimizing compilers to assume -// that expressions with different types refer to different memory. gcc -// 4.0.1 has an optimizer that takes advantage of this. So a -// non-conforming program quietly produces wildly incorrect output. -// -// The problem is not the use of reinterpret_cast. The problem is type -// punning: holding an object in memory of one type and reading its bits -// back using a different type. -// -// The C++ standard is more subtle and complex than this, but that -// is the basic idea. -// -// Anyways ... -// -// bit_cast<> calls memcpy() which is blessed by the standard, -// especially by the example in section 3.9 . Also, of course, -// bit_cast<> wraps up the nasty logic in one place. -// -// Fortunately memcpy() is very fast. In optimized mode, with a -// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline -// code with the minimal amount of data movement. On a 32-bit system, -// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8) -// compiles to two loads and two stores. -// -// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1. -// -// WARNING: if Dest or Source is a non-POD type, the result of the memcpy -// is likely to surprise you. - -template -inline Dest bit_cast(const Source& source) { - // Compile time assertion: sizeof(Dest) == sizeof(Source) - // A compile error here means your Dest and Source have different sizes. - MOZ_STATIC_ASSERT(sizeof(Dest) == sizeof(Source), - "Only bit-cast between identically-sized types!"); - - Dest dest; - memcpy(&dest, &source, sizeof(dest)); - return dest; -} - -// The following enum should be used only as a constructor argument to indicate -// that the variable has static storage class, and that the constructor should -// do nothing to its state. It indicates to the reader that it is legal to -// declare a static instance of the class, provided the constructor is given -// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a -// static variable that has a constructor or a destructor because invocation -// order is undefined. However, IF the type can be initialized by filling with -// zeroes (which the loader does for static variables), AND the destructor also -// does nothing to the storage, AND there are no virtual methods, then a -// constructor declared as -// explicit MyClass(base::LinkerInitialized x) {} -// and invoked as -// static MyClass my_variable_name(base::LINKER_INITIALIZED); -namespace base { -enum LinkerInitialized { LINKER_INITIALIZED }; -} // base - - -/* #include "nscore.h" // pick up mozalloc operator new() etc. */ - - -#endif // BASE_BASICTYPES_H_ diff --git a/libazure/include/mozilla/ipc/chromium/src/base/cpu.h b/libazure/include/mozilla/ipc/chromium/src/base/cpu.h deleted file mode 100644 index 15cc668..0000000 --- a/libazure/include/mozilla/ipc/chromium/src/base/cpu.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CPU_H_ -#define BASE_CPU_H_ - -#include - -namespace base { - -// Query information about the processor. -class CPU { - public: - // Constructor - CPU(); - - // Accessors for CPU information. - const std::string& vendor_name() const { return cpu_vendor_; } - int stepping() const { return stepping_; } - int model() const { return model_; } - int family() const { return family_; } - int type() const { return type_; } - int extended_model() const { return ext_model_; } - int extended_family() const { return ext_family_; } - - private: - // Query the processor for CPUID information. - void Initialize(); - - int type_; // process type - int family_; // family of the processor - int model_; // model of processor - int stepping_; // processor revision number - int ext_model_; - int ext_family_; - std::string cpu_vendor_; -}; - -} // namespace base - -#endif // BASE_CPU_H_ diff --git a/libazure/include/mozilla/ipc/chromium/src/base/port.h b/libazure/include/mozilla/ipc/chromium/src/base/port.h deleted file mode 100644 index 573f5f0..0000000 --- a/libazure/include/mozilla/ipc/chromium/src/base/port.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PORT_H_ -#define BASE_PORT_H_ - -#include -#include "build/build_config.h" - -#ifdef COMPILER_MSVC -#define GG_LONGLONG(x) x##I64 -#define GG_ULONGLONG(x) x##UI64 -#else -#define GG_LONGLONG(x) x##LL -#define GG_ULONGLONG(x) x##ULL -#endif - -// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including -// to get the INTn_C and UINTn_C macros for integer constants. It's difficult -// to guarantee any specific ordering of header includes, so it's difficult to -// guarantee that the INTn_C macros can be defined by including at -// any specific point. Provide GG_INTn_C macros instead. - -#define GG_INT8_C(x) (x) -#define GG_INT16_C(x) (x) -#define GG_INT32_C(x) (x) -#define GG_INT64_C(x) GG_LONGLONG(x) - -#define GG_UINT8_C(x) (x ## U) -#define GG_UINT16_C(x) (x ## U) -#define GG_UINT32_C(x) (x ## U) -#define GG_UINT64_C(x) GG_ULONGLONG(x) - -namespace base { - -// It's possible for functions that use a va_list, such as StringPrintf, to -// invalidate the data in it upon use. The fix is to make a copy of the -// structure before using it and use that copy instead. va_copy is provided -// for this purpose. MSVC does not provide va_copy, so define an -// implementation here. It is not guaranteed that assignment is a copy, so the -// StringUtil.VariableArgsFunc unit test tests this capability. - -// The C standard says that va_copy is a "macro", not a function. Trying to -// use va_list as ref args to a function, as above, breaks some machines. -# if defined(COMPILER_GCC) -# define base_va_copy(_a, _b) ::va_copy(_a, _b) -# elif defined(COMPILER_MSVC) -# define base_va_copy(_a, _b) (_a = _b) -# else -# error No va_copy for your compiler -# endif - -} // namespace base - -// Define an OS-neutral wrapper for shared library entry points -#if defined(OS_WIN) -#define API_CALL __stdcall -#elif defined(OS_LINUX) || defined(OS_MACOSX) -#define API_CALL -#endif - -#endif // BASE_PORT_H_ diff --git a/libazure/include/mozilla/ipc/chromium/src/base/stack_container.h b/libazure/include/mozilla/ipc/chromium/src/base/stack_container.h deleted file mode 100644 index 1b325b1..0000000 --- a/libazure/include/mozilla/ipc/chromium/src/base/stack_container.h +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STACK_CONTAINER_H_ -#define BASE_STACK_CONTAINER_H_ - -#include -#include - -#include "base/basictypes.h" - -// This allocator can be used with STL containers to provide a stack buffer -// from which to allocate memory and overflows onto the heap. This stack buffer -// would be allocated on the stack and allows us to avoid heap operations in -// some situations. -// -// STL likes to make copies of allocators, so the allocator itself can't hold -// the data. Instead, we make the creator responsible for creating a -// StackAllocator::Source which contains the data. Copying the allocator -// merely copies the pointer to this shared source, so all allocators created -// based on our allocator will share the same stack buffer. -// -// This stack buffer implementation is very simple. The first allocation that -// fits in the stack buffer will use the stack buffer. Any subsequent -// allocations will not use the stack buffer, even if there is unused room. -// This makes it appropriate for array-like containers, but the caller should -// be sure to reserve() in the container up to the stack buffer size. Otherwise -// the container will allocate a small array which will "use up" the stack -// buffer. -template -class StackAllocator : public std::allocator { - public: - typedef typename std::allocator::pointer pointer; - typedef typename std::allocator::size_type size_type; - - // Backing store for the allocator. The container owner is responsible for - // maintaining this for as long as any containers using this allocator are - // live. - struct Source { - Source() : used_stack_buffer_(false) { - } - - // Casts the buffer in its right type. - T* stack_buffer() { return reinterpret_cast(stack_buffer_); } - const T* stack_buffer() const { - return reinterpret_cast(stack_buffer_); - } - - // - // IMPORTANT: Take care to ensure that stack_buffer_ is aligned - // since it is used to mimic an array of T. - // Be careful while declaring any unaligned types (like bool) - // before stack_buffer_. - // - - // The buffer itself. It is not of type T because we don't want the - // constructors and destructors to be automatically called. Define a POD - // buffer of the right size instead. - char stack_buffer_[sizeof(T[stack_capacity])]; - - // Set when the stack buffer is used for an allocation. We do not track - // how much of the buffer is used, only that somebody is using it. - bool used_stack_buffer_; - }; - - // Used by containers when they want to refer to an allocator of type U. - template - struct rebind { - typedef StackAllocator other; - }; - - // For the straight up copy c-tor, we can share storage. - StackAllocator(const StackAllocator& rhs) - : source_(rhs.source_) { - } - - // ISO C++ requires the following constructor to be defined, - // and std::vector in VC++2008SP1 Release fails with an error - // in the class _Container_base_aux_alloc_real (from ) - // if the constructor does not exist. - // For this constructor, we cannot share storage; there's - // no guarantee that the Source buffer of Ts is large enough - // for Us. - // TODO: If we were fancy pants, perhaps we could share storage - // iff sizeof(T) == sizeof(U). - template - StackAllocator(const StackAllocator& other) - : source_(NULL) { - } - - explicit StackAllocator(Source* source) : source_(source) { - } - - // Actually do the allocation. Use the stack buffer if nobody has used it yet - // and the size requested fits. Otherwise, fall through to the standard - // allocator. - pointer allocate(size_type n, void* hint = 0) { - if (source_ != NULL && !source_->used_stack_buffer_ - && n <= stack_capacity) { - source_->used_stack_buffer_ = true; - return source_->stack_buffer(); - } else { - return std::allocator::allocate(n, hint); - } - } - - // Free: when trying to free the stack buffer, just mark it as free. For - // non-stack-buffer pointers, just fall though to the standard allocator. - void deallocate(pointer p, size_type n) { - if (source_ != NULL && p == source_->stack_buffer()) - source_->used_stack_buffer_ = false; - else - std::allocator::deallocate(p, n); - } - - private: - Source* source_; -}; - -// A wrapper around STL containers that maintains a stack-sized buffer that the -// initial capacity of the vector is based on. Growing the container beyond the -// stack capacity will transparently overflow onto the heap. The container must -// support reserve(). -// -// WATCH OUT: the ContainerType MUST use the proper StackAllocator for this -// type. This object is really intended to be used only internally. You'll want -// to use the wrappers below for different types. -template -class StackContainer { - public: - typedef TContainerType ContainerType; - typedef typename ContainerType::value_type ContainedType; - typedef StackAllocator Allocator; - - // Allocator must be constructed before the container! - StackContainer() : allocator_(&stack_data_), container_(allocator_) { - // Make the container use the stack allocation by reserving our buffer size - // before doing anything else. - container_.reserve(stack_capacity); - } - - // Getters for the actual container. - // - // Danger: any copies of this made using the copy constructor must have - // shorter lifetimes than the source. The copy will share the same allocator - // and therefore the same stack buffer as the original. Use std::copy to - // copy into a "real" container for longer-lived objects. - ContainerType& container() { return container_; } - const ContainerType& container() const { return container_; } - - // Support operator-> to get to the container. This allows nicer syntax like: - // StackContainer<...> foo; - // std::sort(foo->begin(), foo->end()); - ContainerType* operator->() { return &container_; } - const ContainerType* operator->() const { return &container_; } - -#ifdef UNIT_TEST - // Retrieves the stack source so that that unit tests can verify that the - // buffer is being used properly. - const typename Allocator::Source& stack_data() const { - return stack_data_; - } -#endif - - protected: - typename Allocator::Source stack_data_; - Allocator allocator_; - ContainerType container_; - - DISALLOW_EVIL_CONSTRUCTORS(StackContainer); -}; - -// StackString -template -class StackString : public StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity> { - public: - StackString() : StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity>() { - } - - private: - DISALLOW_EVIL_CONSTRUCTORS(StackString); -}; - -// StackWString -template -class StackWString : public StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity> { - public: - StackWString() : StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity>() { - } - - private: - DISALLOW_EVIL_CONSTRUCTORS(StackWString); -}; - -// StackVector -// -// Example: -// StackVector foo; -// foo->push_back(22); // we have overloaded operator-> -// foo[0] = 10; // as well as operator[] -template -class StackVector : public StackContainer< - std::vector >, - stack_capacity> { - public: - StackVector() : StackContainer< - std::vector >, - stack_capacity>() { - } - - // We need to put this in STL containers sometimes, which requires a copy - // constructor. We can't call the regular copy constructor because that will - // take the stack buffer from the original. Here, we create an empty object - // and make a stack buffer of its own. - StackVector(const StackVector& other) - : StackContainer< - std::vector >, - stack_capacity>() { - this->container().assign(other->begin(), other->end()); - } - - StackVector& operator=( - const StackVector& other) { - this->container().assign(other->begin(), other->end()); - return *this; - } - - // Vectors are commonly indexed, which isn't very convenient even with - // operator-> (using "->at()" does exception stuff we don't want). - T& operator[](size_t i) { return this->container().operator[](i); } - const T& operator[](size_t i) const { - return this->container().operator[](i); - } -}; - -#endif // BASE_STACK_CONTAINER_H_ diff --git a/libazure/include/mozilla/ipc/chromium/src/build/build_config.h b/libazure/include/mozilla/ipc/chromium/src/build/build_config.h deleted file mode 100644 index 782ab78..0000000 --- a/libazure/include/mozilla/ipc/chromium/src/build/build_config.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file adds defines about the platform we're currently building on. -// Operating System: -// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) -// Compiler: -// COMPILER_MSVC / COMPILER_GCC -// Processor: -// ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64) -// ARCH_CPU_32_BITS / ARCH_CPU_64_BITS - -#ifndef BUILD_BUILD_CONFIG_H_ -#define BUILD_BUILD_CONFIG_H_ - -// A set of macros to use for platform detection. -#if defined(__APPLE__) -#define OS_MACOSX 1 -#elif defined(__linux__) || defined(ANDROID) -#define OS_LINUX 1 -#elif defined(__DragonFly__) -#define OS_DRAGONFLY 1 -#elif defined(__FreeBSD__) -#define OS_FREEBSD 1 -#elif defined(__NetBSD__) -#define OS_NETBSD 1 -#elif defined(__OpenBSD__) -#define OS_OPENBSD 1 -#elif defined(_WIN32) -#define OS_WIN 1 -#else -#error Please add support for your platform in build/build_config.h -#endif - -// For access to standard BSD features, use OS_BSD instead of a -// more specific macro. -#if defined(OS_DRAGONFLY) || defined(OS_FREEBSD) \ - || defined(OS_NETBSD) || defined(OS_OPENBSD) -#define OS_BSD 1 -#endif - -// For access to standard POSIX features, use OS_POSIX instead of a more -// specific macro. -#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_BSD) -#define OS_POSIX 1 -#endif - -// Compiler detection. -#if defined(__GNUC__) -#define COMPILER_GCC 1 -#elif defined(_MSC_VER) -#define COMPILER_MSVC 1 -#else -#error Please add support for your compiler in build/build_config.h -#endif - -// Processor architecture detection. For more info on what's defined, see: -// http://msdn.microsoft.com/en-us/library/b0084kay.aspx -// http://www.agner.org/optimize/calling_conventions.pdf -// or with gcc, run: "echo | gcc -E -dM -" -#if defined(_M_X64) || defined(__x86_64__) -#define ARCH_CPU_X86_FAMILY 1 -#define ARCH_CPU_X86_64 1 -#define ARCH_CPU_64_BITS 1 -#elif defined(_M_IX86) || defined(__i386__) -#define ARCH_CPU_X86_FAMILY 1 -#define ARCH_CPU_X86 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__ARMEL__) -#define ARCH_CPU_ARM_FAMILY 1 -#define ARCH_CPU_ARMEL 1 -#define ARCH_CPU_32_BITS 1 -#define WCHAR_T_IS_UNSIGNED 1 -#elif defined(__powerpc64__) -#define ARCH_CPU_PPC64 1 -#define ARCH_CPU_64_BITS 1 -#elif defined(__ppc__) || defined(__powerpc__) -#define ARCH_CPU_PPC 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__sparc64__) -#define ARCH_CPU_SPARC 1 -#define ARCH_CPU_64_BITS 1 -#elif defined(__sparc__) -#define ARCH_CPU_SPARC 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__mips__) -#define ARCH_CPU_MIPS 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__hppa__) -#define ARCH_CPU_HPPA 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__ia64__) -#define ARCH_CPU_IA64 1 -#define ARCH_CPU_64_BITS 1 -#elif defined(__s390x__) -#define ARCH_CPU_S390X 1 -#define ARCH_CPU_64_BITS 1 -#elif defined(__s390__) -#define ARCH_CPU_S390 1 -#define ARCH_CPU_32_BITS 1 -#elif defined(__alpha__) -#define ARCH_CPU_ALPHA 1 -#define ARCH_CPU_64_BITS 1 -#else -#error Please add support for your architecture in build/build_config.h -#endif - -// Type detection for wchar_t. -#if defined(OS_WIN) -#define WCHAR_T_IS_UTF16 -#else -#define WCHAR_T_IS_UTF32 -#endif - -#endif // BUILD_BUILD_CONFIG_H_ diff --git a/libazure/include/mozilla/mozalloc.h b/libazure/include/mozilla/mozalloc.h deleted file mode 100644 index 3d1e12a..0000000 --- a/libazure/include/mozilla/mozalloc.h +++ /dev/null @@ -1,293 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_mozalloc_h -#define mozilla_mozalloc_h - -/* - * https://bugzilla.mozilla.org/show_bug.cgi?id=427099 - */ - -#include -#include -#if defined(__cplusplus) -# include -#endif -#include "xpcom-config.h" - -#if defined(__cplusplus) -#include "mozilla/fallible.h" -#endif -#include "mozilla/Attributes.h" - -#define MOZALLOC_HAVE_XMALLOC - -#if defined(MOZALLOC_EXPORT) -/* do nothing: it's been defined to __declspec(dllexport) by - * mozalloc*.cpp on platforms where that's required. */ -#elif defined(XP_WIN) || (defined(XP_OS2) && defined(__declspec)) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif - - -#if defined(MOZ_ALWAYS_INLINE) -# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE -#elif defined(HAVE_FORCEINLINE) -# define MOZALLOC_INLINE __forceinline -#else -# define MOZALLOC_INLINE inline -#endif - -/* Workaround build problem with Sun Studio 12 */ -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef NS_WARN_UNUSED_RESULT -# define NS_WARN_UNUSED_RESULT -# undef NS_ATTR_MALLOC -# define NS_ATTR_MALLOC -#endif - -#if defined(__cplusplus) -extern "C" { -#endif /* ifdef __cplusplus */ - - -/* - * Each pair of declarations below is analogous to a "standard" - * allocation function, except that the out-of-memory handling is made - * explicit. The |moz_x| versions will never return a NULL pointer; - * if memory is exhausted, they abort. The |moz_| versions may return - * NULL pointers if memory is exhausted: their return value must be - * checked. - * - * All these allocation functions are *guaranteed* to return a pointer - * to memory allocated in such a way that that memory can be freed by - * passing that pointer to |moz_free()|. - */ - -MOZALLOC_EXPORT -void moz_free(void* ptr); - -MOZALLOC_EXPORT void* moz_xmalloc(size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT -void* moz_malloc(size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - - -MOZALLOC_EXPORT void* moz_xcalloc(size_t nmemb, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT void* moz_calloc(size_t nmemb, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - - -MOZALLOC_EXPORT void* moz_xrealloc(void* ptr, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT void* moz_realloc(void* ptr, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - - -MOZALLOC_EXPORT char* moz_xstrdup(const char* str) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT char* moz_strdup(const char* str) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT size_t moz_malloc_usable_size(void *ptr); - -MOZALLOC_EXPORT size_t moz_malloc_size_of(const void *ptr); - -#if defined(HAVE_STRNDUP) -MOZALLOC_EXPORT char* moz_xstrndup(const char* str, size_t strsize) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT char* moz_strndup(const char* str, size_t strsize) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -#endif /* if defined(HAVE_STRNDUP) */ - - -#if defined(HAVE_POSIX_MEMALIGN) -MOZALLOC_EXPORT int moz_xposix_memalign(void **ptr, size_t alignment, size_t size) - NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT int moz_posix_memalign(void **ptr, size_t alignment, size_t size) - NS_WARN_UNUSED_RESULT; -#endif /* if defined(HAVE_POSIX_MEMALIGN) */ - - -#if defined(HAVE_MEMALIGN) -MOZALLOC_EXPORT void* moz_xmemalign(size_t boundary, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT void* moz_memalign(size_t boundary, size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -#endif /* if defined(HAVE_MEMALIGN) */ - - -#if defined(HAVE_VALLOC) -MOZALLOC_EXPORT void* moz_xvalloc(size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; - -MOZALLOC_EXPORT void* moz_valloc(size_t size) - NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -#endif /* if defined(HAVE_VALLOC) */ - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* ifdef __cplusplus */ - - -#ifdef __cplusplus - -/* - * We implement the default operators new/delete as part of - * libmozalloc, replacing their definitions in libstdc++. The - * operator new* definitions in libmozalloc will never return a NULL - * pointer. - * - * Each operator new immediately below returns a pointer to memory - * that can be delete'd by any of - * - * (1) the matching infallible operator delete immediately below - * (2) the matching "fallible" operator delete further below - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| - * - * NB: these are declared |throw(std::bad_alloc)|, though they will never - * throw that exception. This declaration is consistent with the rule - * that |::operator new() throw(std::bad_alloc)| will never return NULL. - */ - -/* NB: This is defined just to silence vacuous warnings about symbol - * visibility on OS X/gcc. These symbols are force-inline and not - * exported. */ -#if defined(XP_MACOSX) -# define MOZALLOC_EXPORT_NEW MOZALLOC_EXPORT -#else -# define MOZALLOC_EXPORT_NEW -#endif - -#if defined(ANDROID) || defined(_MSC_VER) -/* - * Android doesn't fully support exceptions, so its header - * has operators that don't specify throw() at all. Also include MSVC - * to suppress build warning spam (bug 578546). - */ -#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS /**/ -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS -#else -#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc) -#endif - -#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_malloc(size); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_malloc(size); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_free(ptr); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_free(ptr); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_free(ptr); -} - -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_free(ptr); -} - - -/* - * We also add a new allocator variant: "fallible operator new." - * Unlike libmozalloc's implementations of the standard nofail - * allocators, this allocator is allowed to return NULL. It can be used - * as follows - * - * Foo* f = new (mozilla::fallible) Foo(...); - * - * operator delete(fallible) is defined for completeness only. - * - * Each operator new below returns a pointer to memory that can be - * delete'd by any of - * - * (1) the matching "fallible" operator delete below - * (2) the matching infallible operator delete above - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| - */ - -MOZALLOC_INLINE -void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_malloc(size); -} - -MOZALLOC_INLINE -void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return moz_malloc(size); -} - -MOZALLOC_INLINE -void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - moz_free(ptr); -} - -MOZALLOC_INLINE -void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - moz_free(ptr); -} - -#endif /* ifdef __cplusplus */ - - -#endif /* ifndef mozilla_mozalloc_h */ diff --git a/libazure/include/mozilla/mozalloc_abort.h b/libazure/include/mozilla/mozalloc_abort.h deleted file mode 100644 index 08ee399..0000000 --- a/libazure/include/mozilla/mozalloc_abort.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_mozalloc_abort_h -#define mozilla_mozalloc_abort_h - -#include "mozilla/Attributes.h" - -#if defined(MOZALLOC_EXPORT) -// do nothing: it's been defined to __declspec(dllexport) by -// mozalloc*.cpp on platforms where that's required -#elif defined(XP_WIN) || (defined(XP_OS2) && defined(__declspec)) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif - -/** - * Terminate this process in such a way that breakpad is triggered, if - * at all possible. - * - * Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't - * use that annotation there. - */ -MOZALLOC_EXPORT -#if !defined(__arm__) - MOZ_NORETURN -#endif - void mozalloc_abort(const char* const msg); - - -#endif /* ifndef mozilla_mozalloc_abort_h */ diff --git a/libazure/include/mozilla/mozalloc_macro_wrappers.h b/libazure/include/mozilla/mozalloc_macro_wrappers.h deleted file mode 100644 index b9aadd8..0000000 --- a/libazure/include/mozilla/mozalloc_macro_wrappers.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_mozalloc_macro_wrappers_h -#define mozilla_mozalloc_macro_wrappers_h - - -/* - * Make libc "allocating functions" never fail (return NULL). - * - * FIXME: use infallible allocators by default after - * http://bugzilla.mozilla.org/show_bug.cgi?id=507249 - * lands. - */ -#define free(_) moz_free(_) - -#define malloc(_) moz_malloc(_) - -#define calloc(_, __) moz_calloc(_, __) - -#define realloc(_, __) moz_realloc(_, __) - -#define strdup(_) moz_strdup(_) - -#if defined(HAVE_STRNDUP) -#define strndup(_, __) moz_strndup(_, __) -#endif - -#if defined(HAVE_POSIX_MEMALIGN) -#define posix_memalign(_, __, ___) moz_posix_memalign(_, __, ___) -#endif - -#if defined(HAVE_MEMALIGN) -#define memalign(_, __) moz_memalign(_, __) -#endif - -#if defined(HAVE_VALLOC) -#define valloc(_) moz_valloc(_) -#endif - - -#endif /* ifndef mozilla_mozalloc_macro_wrappers_h */ diff --git a/libazure/include/mozilla/mozalloc_oom.h b/libazure/include/mozilla/mozalloc_oom.h deleted file mode 100644 index 75b356a..0000000 --- a/libazure/include/mozilla/mozalloc_oom.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_mozalloc_oom_h -#define mozilla_mozalloc_oom_h - -#include "mozalloc.h" - -#if defined(MOZALLOC_EXPORT) -// do nothing: it's been defined to __declspec(dllexport) by -// mozalloc*.cpp on platforms where that's required -#elif defined(XP_WIN) || (defined(XP_OS2) && defined(__declspec)) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif - - -/** - * Called when memory is critically low. Returns iff it was able to - * remedy the critical memory situation; if not, it will abort(). - * - * We have to re-#define MOZALLOC_EXPORT because this header can be - * used indepedently of mozalloc.h. - */ -MOZALLOC_EXPORT void mozalloc_handle_oom(size_t requestedSize); - -/** - * Called by embedders (specifically Mozilla breakpad) which wants to be - * notified of an intentional abort, to annotate any crash report with - * the size of the allocation on which we aborted. - */ -typedef void (*mozalloc_oom_abort_handler)(size_t size); -MOZALLOC_EXPORT void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler); - -/* TODO: functions to query system memory usage and register - * critical-memory handlers. */ - - -#endif /* ifndef mozilla_mozalloc_oom_h */ diff --git a/libazure/include/obsolete/protypes.h b/libazure/include/obsolete/protypes.h deleted file mode 100644 index d8e947a..0000000 --- a/libazure/include/obsolete/protypes.h +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape Portable Runtime (NSPR). - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * This header typedefs the old 'native' types to the new PRs. - * These definitions are scheduled to be eliminated at the earliest - * possible time. The NSPR API is implemented and documented using - * the new definitions. - */ - -#if !defined(PROTYPES_H) -#define PROTYPES_H - -typedef PRUintn uintn; -#ifndef _XP_Core_ -typedef PRIntn intn; -#endif - -/* - * It is trickier to define uint, int8, uint8, int16, uint16, - * int32, uint32, int64, and uint64 because some of these int - * types are defined by standard header files on some platforms. - * Our strategy here is to include all such standard headers - * first, and then define these int types only if they are not - * defined by those standard headers. - */ - -/* - * BeOS defines all the int types below in its standard header - * file SupportDefs.h. - */ -#ifdef XP_BEOS -#include -#endif - -/* - * SVR4 typedef of uint is commonly found on UNIX machines. - * - * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h) - * defines the types int8, int16, int32, and int64. - * - * On OS/2, sys/types.h defines uint. - */ -#if defined(XP_UNIX) || defined(XP_OS2) -#include -#endif - -/* model.h on HP-UX defines int8, int16, and int32. */ -#ifdef HPUX -#include -#endif - -/* - * uint - */ - -#if !defined(XP_BEOS) && !defined(XP_OS2) && !defined(XP_UNIX) || defined(NTO) -typedef PRUintn uint; -#endif - -/* - * uint64 - */ - -#if !defined(XP_BEOS) -typedef PRUint64 uint64; -#endif - -/* - * uint32 - */ - -#if !defined(XP_BEOS) -#if !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) -typedef PRUint32 uint32; -#else -typedef unsigned long uint32; -#endif -#endif - -/* - * uint16 - */ - -#if !defined(XP_BEOS) -typedef PRUint16 uint16; -#endif - -/* - * uint8 - */ - -#if !defined(XP_BEOS) -typedef PRUint8 uint8; -#endif - -/* - * int64 - */ - -#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) -typedef PRInt64 int64; -#endif - -/* - * int32 - */ - -#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ - && !defined(HPUX) -#if !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) -typedef PRInt32 int32; -#else -typedef long int32; -#endif -#endif - -/* - * int16 - */ - -#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ - && !defined(HPUX) -typedef PRInt16 int16; -#endif - -/* - * int8 - */ - -#if !defined(XP_BEOS) && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ - && !defined(HPUX) -typedef PRInt8 int8; -#endif - -typedef PRFloat64 float64; -typedef PRUptrdiff uptrdiff_t; -typedef PRUword uprword_t; -typedef PRWord prword_t; - - -/* Re: prbit.h */ -#define TEST_BIT PR_TEST_BIT -#define SET_BIT PR_SET_BIT -#define CLEAR_BIT PR_CLEAR_BIT - -/* Re: prarena.h->plarena.h */ -#define PRArena PLArena -#define PRArenaPool PLArenaPool -#define PRArenaStats PLArenaStats -#define PR_ARENA_ALIGN PL_ARENA_ALIGN -#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL -#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE -#define PR_ARENA_GROW PL_ARENA_GROW -#define PR_ARENA_MARK PL_ARENA_MARK -#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED -#define PR_CLEAR_ARENA PL_CLEAR_ARENA -#define PR_ARENA_RELEASE PL_ARENA_RELEASE -#define PR_COUNT_ARENA PL_COUNT_ARENA -#define PR_ARENA_DESTROY PL_ARENA_DESTROY -#define PR_InitArenaPool PL_InitArenaPool -#define PR_FreeArenaPool PL_FreeArenaPool -#define PR_FinishArenaPool PL_FinishArenaPool -#define PR_CompactArenaPool PL_CompactArenaPool -#define PR_ArenaFinish PL_ArenaFinish -#define PR_ArenaAllocate PL_ArenaAllocate -#define PR_ArenaGrow PL_ArenaGrow -#define PR_ArenaRelease PL_ArenaRelease -#define PR_ArenaCountAllocation PL_ArenaCountAllocation -#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth -#define PR_ArenaCountGrowth PL_ArenaCountGrowth -#define PR_ArenaCountRelease PL_ArenaCountRelease -#define PR_ArenaCountRetract PL_ArenaCountRetract - -/* Re: prhash.h->plhash.h */ -#define PRHashEntry PLHashEntry -#define PRHashTable PLHashTable -#define PRHashNumber PLHashNumber -#define PRHashFunction PLHashFunction -#define PRHashComparator PLHashComparator -#define PRHashEnumerator PLHashEnumerator -#define PRHashAllocOps PLHashAllocOps -#define PR_NewHashTable PL_NewHashTable -#define PR_HashTableDestroy PL_HashTableDestroy -#define PR_HashTableRawLookup PL_HashTableRawLookup -#define PR_HashTableRawAdd PL_HashTableRawAdd -#define PR_HashTableRawRemove PL_HashTableRawRemove -#define PR_HashTableAdd PL_HashTableAdd -#define PR_HashTableRemove PL_HashTableRemove -#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries -#define PR_HashTableLookup PL_HashTableLookup -#define PR_HashTableDump PL_HashTableDump -#define PR_HashString PL_HashString -#define PR_CompareStrings PL_CompareStrings -#define PR_CompareValues PL_CompareValues - -#endif /* !defined(PROTYPES_H) */ diff --git a/libazure/include/prcpucfg.h b/libazure/include/prcpucfg.h deleted file mode 100644 index 450a170..0000000 --- a/libazure/include/prcpucfg.h +++ /dev/null @@ -1,906 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape Portable Runtime (NSPR). - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * This file is used by not only Linux but also other glibc systems - * such as GNU/Hurd and GNU/k*BSD. - */ - -#ifndef nspr_cpucfg___ -#define nspr_cpucfg___ - -#ifndef XP_UNIX -#define XP_UNIX -#endif - -#if !defined(LINUX) && defined(__linux__) -#define LINUX -#endif - -#ifdef __FreeBSD_kernel__ -#define PR_AF_INET6 28 /* same as AF_INET6 */ -#else -#define PR_AF_INET6 10 /* same as AF_INET6 */ -#endif - -#ifdef __powerpc64__ - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__powerpc__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__alpha) - -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__ia64__) - -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__x86_64__) - -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__mc68000__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 2 -#define PR_ALIGN_OF_LONG 2 -#define PR_ALIGN_OF_INT64 2 -#define PR_ALIGN_OF_FLOAT 2 -#define PR_ALIGN_OF_DOUBLE 2 -#define PR_ALIGN_OF_POINTER 2 -#define PR_ALIGN_OF_WORD 2 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__sparc__) && defined (__arch64__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__sparc__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__i386__) - -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__mips__) - -#ifdef __MIPSEB__ -#define IS_BIG_ENDIAN 1 -#undef IS_LITTLE_ENDIAN -#elif defined(__MIPSEL__) -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN -#else -#error "Unknown MIPS endianness." -#endif - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__arm__) - -#ifdef __ARMEB__ -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 -#elif defined(__ARMEL__) -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN -#else -#error "Unknown ARM endianness." -#endif - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__hppa__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__s390x__) - -#define IS_BIG_ENDIAN 1 -#undef IS_LITTLE_ENDIAN -#define IS_64 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 8 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 8 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 64 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 64 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 6 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 6 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 8 -#define PR_ALIGN_OF_INT64 8 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 8 -#define PR_ALIGN_OF_POINTER 8 -#define PR_ALIGN_OF_WORD 8 - -#define PR_BYTES_PER_WORD_LOG2 3 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__s390__) - -#define IS_BIG_ENDIAN 1 -#undef IS_LITTLE_ENDIAN - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__sh__) - -#define IS_LITTLE_ENDIAN 1 -#undef IS_BIG_ENDIAN - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__avr32__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#elif defined(__m32r__) - -#undef IS_LITTLE_ENDIAN -#define IS_BIG_ENDIAN 1 - -#define PR_BYTES_PER_BYTE 1 -#define PR_BYTES_PER_SHORT 2 -#define PR_BYTES_PER_INT 4 -#define PR_BYTES_PER_INT64 8 -#define PR_BYTES_PER_LONG 4 -#define PR_BYTES_PER_FLOAT 4 -#define PR_BYTES_PER_DOUBLE 8 -#define PR_BYTES_PER_WORD 4 -#define PR_BYTES_PER_DWORD 8 - -#define PR_BITS_PER_BYTE 8 -#define PR_BITS_PER_SHORT 16 -#define PR_BITS_PER_INT 32 -#define PR_BITS_PER_INT64 64 -#define PR_BITS_PER_LONG 32 -#define PR_BITS_PER_FLOAT 32 -#define PR_BITS_PER_DOUBLE 64 -#define PR_BITS_PER_WORD 32 - -#define PR_BITS_PER_BYTE_LOG2 3 -#define PR_BITS_PER_SHORT_LOG2 4 -#define PR_BITS_PER_INT_LOG2 5 -#define PR_BITS_PER_INT64_LOG2 6 -#define PR_BITS_PER_LONG_LOG2 5 -#define PR_BITS_PER_FLOAT_LOG2 5 -#define PR_BITS_PER_DOUBLE_LOG2 6 -#define PR_BITS_PER_WORD_LOG2 5 - -#define PR_ALIGN_OF_SHORT 2 -#define PR_ALIGN_OF_INT 4 -#define PR_ALIGN_OF_LONG 4 -#define PR_ALIGN_OF_INT64 4 -#define PR_ALIGN_OF_FLOAT 4 -#define PR_ALIGN_OF_DOUBLE 4 -#define PR_ALIGN_OF_POINTER 4 -#define PR_ALIGN_OF_WORD 4 - -#define PR_BYTES_PER_WORD_LOG2 2 -#define PR_BYTES_PER_DWORD_LOG2 3 - -#else - -#error "Unknown CPU architecture" - -#endif - -#ifndef HAVE_LONG_LONG -#define HAVE_LONG_LONG -#endif -#if PR_ALIGN_OF_DOUBLE == 8 -#define HAVE_ALIGNED_DOUBLES -#endif -#if PR_ALIGN_OF_INT64 == 8 -#define HAVE_ALIGNED_LONGLONGS -#endif - -#ifndef NO_NSPR_10_SUPPORT - -#define BYTES_PER_BYTE PR_BYTES_PER_BYTE -#define BYTES_PER_SHORT PR_BYTES_PER_SHORT -#define BYTES_PER_INT PR_BYTES_PER_INT -#define BYTES_PER_INT64 PR_BYTES_PER_INT64 -#define BYTES_PER_LONG PR_BYTES_PER_LONG -#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT -#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE -#define BYTES_PER_WORD PR_BYTES_PER_WORD -#define BYTES_PER_DWORD PR_BYTES_PER_DWORD - -#define BITS_PER_BYTE PR_BITS_PER_BYTE -#define BITS_PER_SHORT PR_BITS_PER_SHORT -#define BITS_PER_INT PR_BITS_PER_INT -#define BITS_PER_INT64 PR_BITS_PER_INT64 -#define BITS_PER_LONG PR_BITS_PER_LONG -#define BITS_PER_FLOAT PR_BITS_PER_FLOAT -#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE -#define BITS_PER_WORD PR_BITS_PER_WORD - -#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 -#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 -#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 -#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 -#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 -#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 -#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 -#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 - -#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT -#define ALIGN_OF_INT PR_ALIGN_OF_INT -#define ALIGN_OF_LONG PR_ALIGN_OF_LONG -#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 -#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT -#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE -#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER -#define ALIGN_OF_WORD PR_ALIGN_OF_WORD - -#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 -#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 -#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 - -#endif /* NO_NSPR_10_SUPPORT */ - -#endif /* nspr_cpucfg___ */ diff --git a/libazure/include/prtypes.h b/libazure/include/prtypes.h deleted file mode 100644 index a5069bb..0000000 --- a/libazure/include/prtypes.h +++ /dev/null @@ -1,565 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* -** File: prtypes.h -** Description: Definitions of NSPR's basic types -** -** Prototypes and macros used to make up for deficiencies that we have found -** in ANSI environments. -** -** Since we do not wrap and all the other standard headers, authors -** of portable code will not know in general that they need these definitions. -** Instead of requiring these authors to find the dependent uses in their code -** and take the following steps only in those C files, we take steps once here -** for all C files. -**/ - -#ifndef prtypes_h___ -#define prtypes_h___ - -#ifdef MDCPUCFG -#include MDCPUCFG -#else -#include "prcpucfg.h" -#endif - -#include - -/*********************************************************************** -** MACROS: PR_EXTERN -** PR_IMPLEMENT -** DESCRIPTION: -** These are only for externally visible routines and globals. For -** internal routines, just use "extern" for type checking and that -** will not export internal cross-file or forward-declared symbols. -** Define a macro for declaring procedures return types. We use this to -** deal with windoze specific type hackery for DLL definitions. Use -** PR_EXTERN when the prototype for the method is declared. Use -** PR_IMPLEMENT for the implementation of the method. -** -** Example: -** in dowhim.h -** PR_EXTERN( void ) DoWhatIMean( void ); -** in dowhim.c -** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } -** -** -***********************************************************************/ -#if defined(WIN32) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) __declspec(dllimport) __type -#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(XP_BEOS) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) extern __declspec(dllexport) __type -#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(XP_OS2) && defined(__declspec) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPORT(__type) extern __declspec(dllimport) __type -#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type - -#define PR_EXTERN(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT(__type) __declspec(dllexport) __type -#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type -#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#elif defined(SYMBIAN) - -#define PR_EXPORT(__type) extern __declspec(dllexport) __type -#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type -#ifdef __WINS__ -#define PR_IMPORT(__type) extern __declspec(dllexport) __type -#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type -#else -#define PR_IMPORT(__type) extern __declspec(dllimport) __type -#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type -#endif - -#define PR_EXTERN(__type) extern __type -#define PR_IMPLEMENT(__type) __type -#define PR_EXTERN_DATA(__type) extern __type -#define PR_IMPLEMENT_DATA(__type) __type - -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#else /* Unix */ - -/* GCC 3.3 and later support the visibility attribute. */ -#if (__GNUC__ >= 4) || \ - (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) -#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default"))) -#else -#define PR_VISIBILITY_DEFAULT -#endif - -#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type -#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type -#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type -#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type - -#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type -#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type -#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type -#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type -#define PR_CALLBACK -#define PR_CALLBACK_DECL -#define PR_STATIC_CALLBACK(__x) static __x - -#endif - -#if defined(_NSPR_BUILD_) -#define NSPR_API(__type) PR_EXPORT(__type) -#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) -#else -#define NSPR_API(__type) PR_IMPORT(__type) -#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) -#endif - -/*********************************************************************** -** MACROS: PR_BEGIN_MACRO -** PR_END_MACRO -** DESCRIPTION: -** Macro body brackets so that macros with compound statement definitions -** behave syntactically more like functions when called. -***********************************************************************/ -#define PR_BEGIN_MACRO do { -#define PR_END_MACRO } while (0) - -/*********************************************************************** -** MACROS: PR_BEGIN_EXTERN_C -** PR_END_EXTERN_C -** DESCRIPTION: -** Macro shorthands for conditional C++ extern block delimiters. -***********************************************************************/ -#ifdef __cplusplus -#define PR_BEGIN_EXTERN_C extern "C" { -#define PR_END_EXTERN_C } -#else -#define PR_BEGIN_EXTERN_C -#define PR_END_EXTERN_C -#endif - -/*********************************************************************** -** MACROS: PR_BIT -** PR_BITMASK -** DESCRIPTION: -** Bit masking macros. XXX n must be <= 31 to be portable -***********************************************************************/ -#define PR_BIT(n) ((PRUint32)1 << (n)) -#define PR_BITMASK(n) (PR_BIT(n) - 1) - -/*********************************************************************** -** MACROS: PR_ROUNDUP -** PR_MIN -** PR_MAX -** PR_ABS -** DESCRIPTION: -** Commonly used macros for operations on compatible types. -***********************************************************************/ -#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) -#define PR_MIN(x,y) ((x)<(y)?(x):(y)) -#define PR_MAX(x,y) ((x)>(y)?(x):(y)) -#define PR_ABS(x) ((x)<0?-(x):(x)) - -/*********************************************************************** -** MACROS: PR_ARRAY_SIZE -** DESCRIPTION: -** The number of elements in an array. -***********************************************************************/ -#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) - -PR_BEGIN_EXTERN_C - -/* -** Starting in NSPR 4.9.5, NSPR's exact-width integer types should match -** the exact-width integer types defined in . This allows sloppy -** code to use PRInt{N} and int{N}_t interchangeably. -** -** The 8-bit and 16-bit integer types can only be defined using char and -** short. All platforms define the 32-bit integer types using int. So only -** the 64-bit integer types could be defined differently. -** -** NSPR's original strategy was to use the "shortest" 64-bit integer type: -** if long is 64-bit, then prefer it over long long. This strategy is also -** used by Linux/glibc, FreeBSD, and NetBSD. -** -** Other platforms use a different strategy: simply define the 64-bit -** integer types using long long. We define the PR_ALTERNATE_INT64_TYPEDEF -** macro on these platforms. Note that PR_ALTERNATE_INT64_TYPEDEF is for -** internal use by NSPR headers only. Do not define or test this macro in -** your code. -** -** NOTE: NSPR can't use because C99 requires C++ code to define -** __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS to make all the macros -** defined in available. This strange requirement is gone in -** C11. When most platforms ignore this C99 requirement, NSPR will be able -** to use . A patch to do that is in NSPR bug 634793. -*/ - -#if defined(__APPLE__) || defined(__ANDROID__) || defined(__OpenBSD__) -#define PR_ALTERNATE_INT64_TYPEDEF -#endif - -/************************************************************************ -** TYPES: PRUint8 -** PRInt8 -** DESCRIPTION: -** The int8 types are known to be 8 bits each. There is no type that -** is equivalent to a plain "char". -************************************************************************/ -#if PR_BYTES_PER_BYTE == 1 -typedef unsigned char PRUint8; -/* -** Some cfront-based C++ compilers do not like 'signed char' and -** issue the warning message: -** warning: "signed" not implemented (ignored) -** For these compilers, we have to define PRInt8 as plain 'char'. -** Make sure that plain 'char' is indeed signed under these compilers. -*/ -#if (defined(HPUX) && defined(__cplusplus) \ - && !defined(__GNUC__) && __cplusplus < 199707L) \ - || (defined(SCO) && defined(__cplusplus) \ - && !defined(__GNUC__) && __cplusplus == 1L) -typedef char PRInt8; -#else -typedef signed char PRInt8; -#endif -#else -#error No suitable type for PRInt8/PRUint8 -#endif - -/************************************************************************ - * MACROS: PR_INT8_MAX - * PR_INT8_MIN - * PR_UINT8_MAX - * DESCRIPTION: - * The maximum and minimum values of a PRInt8 or PRUint8. -************************************************************************/ - -#define PR_INT8_MAX 127 -#define PR_INT8_MIN (-128) -#define PR_UINT8_MAX 255U - -/************************************************************************ -** TYPES: PRUint16 -** PRInt16 -** DESCRIPTION: -** The int16 types are known to be 16 bits each. -************************************************************************/ -#if PR_BYTES_PER_SHORT == 2 -typedef unsigned short PRUint16; -typedef short PRInt16; -#else -#error No suitable type for PRInt16/PRUint16 -#endif - -/************************************************************************ - * MACROS: PR_INT16_MAX - * PR_INT16_MIN - * PR_UINT16_MAX - * DESCRIPTION: - * The maximum and minimum values of a PRInt16 or PRUint16. -************************************************************************/ - -#define PR_INT16_MAX 32767 -#define PR_INT16_MIN (-32768) -#define PR_UINT16_MAX 65535U - -/************************************************************************ -** TYPES: PRUint32 -** PRInt32 -** DESCRIPTION: -** The int32 types are known to be 32 bits each. -************************************************************************/ -#if PR_BYTES_PER_INT == 4 -typedef unsigned int PRUint32; -typedef int PRInt32; -#define PR_INT32(x) x -#define PR_UINT32(x) x ## U -#elif PR_BYTES_PER_LONG == 4 -typedef unsigned long PRUint32; -typedef long PRInt32; -#define PR_INT32(x) x ## L -#define PR_UINT32(x) x ## UL -#else -#error No suitable type for PRInt32/PRUint32 -#endif - -/************************************************************************ - * MACROS: PR_INT32_MAX - * PR_INT32_MIN - * PR_UINT32_MAX - * DESCRIPTION: - * The maximum and minimum values of a PRInt32 or PRUint32. -************************************************************************/ - -#define PR_INT32_MAX PR_INT32(2147483647) -#define PR_INT32_MIN (-PR_INT32_MAX - 1) -#define PR_UINT32_MAX PR_UINT32(4294967295) - -/************************************************************************ -** TYPES: PRUint64 -** PRInt64 -** DESCRIPTION: -** The int64 types are known to be 64 bits each. Care must be used when -** declaring variables of type PRUint64 or PRInt64. Different hardware -** architectures and even different compilers have varying support for -** 64 bit values. The only guaranteed portability requires the use of -** the LL_ macros (see prlong.h). -** -** MACROS: PR_INT64 -** PR_UINT64 -** DESCRIPTION: -** The PR_INT64 and PR_UINT64 macros provide a portable way for -** specifying 64-bit integer constants. They can only be used if -** PRInt64 and PRUint64 are defined as compiler-supported 64-bit -** integer types (i.e., if HAVE_LONG_LONG is defined, which is true -** for all the supported compilers topday). If PRInt64 and PRUint64 -** are defined as structs, the LL_INIT macro defined in prlong.h has -** to be used. -** -** MACROS: PR_INT64_MAX -** PR_INT64_MIN -** PR_UINT64_MAX -** DESCRIPTION: -** The maximum and minimum values of a PRInt64 or PRUint64. -************************************************************************/ -#ifdef HAVE_LONG_LONG -/* Keep this in sync with prlong.h. */ -#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) -typedef long PRInt64; -typedef unsigned long PRUint64; -#define PR_INT64(x) x ## L -#define PR_UINT64(x) x ## UL -#elif defined(WIN32) && !defined(__GNUC__) -typedef __int64 PRInt64; -typedef unsigned __int64 PRUint64; -#define PR_INT64(x) x ## i64 -#define PR_UINT64(x) x ## ui64 -#else -typedef long long PRInt64; -typedef unsigned long long PRUint64; -#define PR_INT64(x) x ## LL -#define PR_UINT64(x) x ## ULL -#endif /* PR_BYTES_PER_LONG == 8 */ - -#define PR_INT64_MAX PR_INT64(0x7fffffffffffffff) -#define PR_INT64_MIN (-PR_INT64_MAX - 1) -#define PR_UINT64_MAX PR_UINT64(-1) -#else /* !HAVE_LONG_LONG */ -typedef struct { -#ifdef IS_LITTLE_ENDIAN - PRUint32 lo, hi; -#else - PRUint32 hi, lo; -#endif -} PRInt64; -typedef PRInt64 PRUint64; - -#define PR_INT64_MAX (PRInt64){0x7fffffff, 0xffffffff} -#define PR_INT64_MIN (PRInt64){0xffffffff, 0xffffffff} -#define PR_UINT64_MAX (PRUint64){0xffffffff, 0xffffffff} - -#endif /* !HAVE_LONG_LONG */ - -/************************************************************************ -** TYPES: PRUintn -** PRIntn -** DESCRIPTION: -** The PRIntn types are most appropriate for automatic variables. They are -** guaranteed to be at least 16 bits, though various architectures may -** define them to be wider (e.g., 32 or even 64 bits). These types are -** never valid for fields of a structure. -************************************************************************/ -#if PR_BYTES_PER_INT >= 2 -typedef int PRIntn; -typedef unsigned int PRUintn; -#else -#error 'sizeof(int)' not sufficient for platform use -#endif - -/************************************************************************ -** TYPES: PRFloat64 -** DESCRIPTION: -** NSPR's floating point type is always 64 bits. -************************************************************************/ -typedef double PRFloat64; - -/************************************************************************ -** TYPES: PRSize -** DESCRIPTION: -** A type for representing the size of objects. -************************************************************************/ -typedef size_t PRSize; - - -/************************************************************************ -** TYPES: PROffset32, PROffset64 -** DESCRIPTION: -** A type for representing byte offsets from some location. -************************************************************************/ -typedef PRInt32 PROffset32; -typedef PRInt64 PROffset64; - -/************************************************************************ -** TYPES: PRPtrDiff -** DESCRIPTION: -** A type for pointer difference. Variables of this type are suitable -** for storing a pointer or pointer subtraction. -************************************************************************/ -typedef ptrdiff_t PRPtrdiff; - -/************************************************************************ -** TYPES: PRUptrdiff -** DESCRIPTION: -** A type for pointer difference. Variables of this type are suitable -** for storing a pointer or pointer sutraction. -************************************************************************/ -#ifdef _WIN64 -typedef PRUint64 PRUptrdiff; -#else -typedef unsigned long PRUptrdiff; -#endif - -/************************************************************************ -** TYPES: PRBool -** DESCRIPTION: -** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE -** for clarity of target type in assignments and actual arguments. Use -** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans -** just as you would C int-valued conditions. -************************************************************************/ -typedef PRIntn PRBool; -#define PR_TRUE 1 -#define PR_FALSE 0 - -/************************************************************************ -** TYPES: PRPackedBool -** DESCRIPTION: -** Use PRPackedBool within structs where bitfields are not desirable -** but minimum and consistant overhead matters. -************************************************************************/ -typedef PRUint8 PRPackedBool; - -/* -** Status code used by some routines that have a single point of failure or -** special status return. -*/ -typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; - -#ifndef __PRUNICHAR__ -#define __PRUNICHAR__ -#ifdef WIN32 -typedef wchar_t PRUnichar; -#else -typedef PRUint16 PRUnichar; -#endif -#endif - -/* -** WARNING: The undocumented data types PRWord and PRUword are -** only used in the garbage collection and arena code. Do not -** use PRWord and PRUword in new code. -** -** A PRWord is an integer that is the same size as a void*. -** It implements the notion of a "word" in the Java Virtual -** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine -** Specification, Addison-Wesley, September 1996. -** http://java.sun.com/docs/books/vmspec/index.html.) -*/ -#ifdef _WIN64 -typedef PRInt64 PRWord; -typedef PRUint64 PRUword; -#else -typedef long PRWord; -typedef unsigned long PRUword; -#endif - -#if defined(NO_NSPR_10_SUPPORT) -#else -/********* ???????????????? FIX ME ??????????????????????????? *****/ -/********************** Some old definitions until pr=>ds transition is done ***/ -/********************** Also, we are still using NSPR 1.0. GC ******************/ -/* -** Fundamental NSPR macros, used nearly everywhere. -*/ - -#define PR_PUBLIC_API PR_IMPLEMENT - -/* -** Macro body brackets so that macros with compound statement definitions -** behave syntactically more like functions when called. -*/ -#define NSPR_BEGIN_MACRO do { -#define NSPR_END_MACRO } while (0) - -/* -** Macro shorthands for conditional C++ extern block delimiters. -*/ -#ifdef NSPR_BEGIN_EXTERN_C -#undef NSPR_BEGIN_EXTERN_C -#endif -#ifdef NSPR_END_EXTERN_C -#undef NSPR_END_EXTERN_C -#endif - -#ifdef __cplusplus -#define NSPR_BEGIN_EXTERN_C extern "C" { -#define NSPR_END_EXTERN_C } -#else -#define NSPR_BEGIN_EXTERN_C -#define NSPR_END_EXTERN_C -#endif - -#include "obsolete/protypes.h" - -/********* ????????????? End Fix me ?????????????????????????????? *****/ -#endif /* NO_NSPR_10_SUPPORT */ - -/* -** Compile-time assert. "condition" must be a constant expression. -** The macro can be used only in places where an "extern" declaration is -** allowed. -*/ -#define PR_STATIC_ASSERT(condition) \ - extern void pr_static_assert(int arg[(condition) ? 1 : -1]) - -PR_END_EXTERN_C - -#endif /* prtypes_h___ */ - diff --git a/libazure/include/xpcom-config.h b/libazure/include/xpcom-config.h deleted file mode 100644 index e69de29..0000000 diff --git a/libazure/src/gfx/2d/moz-d2d1-1.h b/libazure/moz-d2d1-1.h similarity index 100% rename from libazure/src/gfx/2d/moz-d2d1-1.h rename to libazure/moz-d2d1-1.h diff --git a/libazure/src/mfbt/tests/moz.build b/libazure/moz.build similarity index 74% rename from libazure/src/mfbt/tests/moz.build rename to libazure/moz.build index 895d119..58ce5e2 100644 --- a/libazure/src/mfbt/tests/moz.build +++ b/libazure/moz.build @@ -1,4 +1,3 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/libazure/mozilla/Alignment.h b/libazure/mozilla/Alignment.h new file mode 100644 index 0000000..0ac8a48 --- /dev/null +++ b/libazure/mozilla/Alignment.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Functionality related to memory alignment. */ + +#ifndef mozilla_Alignment_h +#define mozilla_Alignment_h + +#include +#include + +namespace mozilla { + +/* + * This class, and the corresponding macro MOZ_ALIGNOF, figures out how many + * bytes of alignment a given type needs. + */ +template +class AlignmentFinder +{ + struct Aligner + { + char mChar; + T mT; + }; + +public: + static const size_t alignment = sizeof(Aligner) - sizeof(T); +}; + +#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder::alignment + +/* + * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types. + * + * For instance, + * + * MOZ_ALIGNED_DECL(char arr[2], 8); + * + * will declare a two-character array |arr| aligned to 8 bytes. + */ + +#if defined(__GNUC__) +# define MOZ_ALIGNED_DECL(_type, _align) \ + _type __attribute__((aligned(_align))) +#elif defined(_MSC_VER) +# define MOZ_ALIGNED_DECL(_type, _align) \ + __declspec(align(_align)) _type +#else +# warning "We don't know how to align variables on this compiler." +# define MOZ_ALIGNED_DECL(_type, _align) _type +#endif + +/* + * AlignedElem is a structure whose alignment is guaranteed to be at least N + * bytes. + * + * We support 1, 2, 4, 8, and 16-bit alignment. + */ +template +struct AlignedElem; + +/* + * We have to specialize this template because GCC doesn't like + * __attribute__((aligned(foo))) where foo is a template parameter. + */ + +template<> +struct AlignedElem<1> +{ + MOZ_ALIGNED_DECL(uint8_t elem, 1); +}; + +template<> +struct AlignedElem<2> +{ + MOZ_ALIGNED_DECL(uint8_t elem, 2); +}; + +template<> +struct AlignedElem<4> +{ + MOZ_ALIGNED_DECL(uint8_t elem, 4); +}; + +template<> +struct AlignedElem<8> +{ + MOZ_ALIGNED_DECL(uint8_t elem, 8); +}; + +template<> +struct AlignedElem<16> +{ + MOZ_ALIGNED_DECL(uint8_t elem, 16); +}; + +/* + * This utility pales in comparison to Boost's aligned_storage. The utility + * simply assumes that uint64_t is enough alignment for anyone. This may need + * to be extended one day... + * + * As an important side effect, pulling the storage into this template is + * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving + * false negatives when we cast from the char buffer to whatever type we've + * constructed using the bytes. + */ +template +struct AlignedStorage +{ + union U + { + char mBytes[Nbytes]; + uint64_t mDummy; + } u; + + const void* addr() const { return u.mBytes; } + void* addr() { return u.mBytes; } +}; + +template +struct AlignedStorage2 +{ + union U + { + char mBytes[sizeof(T)]; + uint64_t mDummy; + } u; + + const T* addr() const { return reinterpret_cast(u.mBytes); } + T* addr() { return static_cast(static_cast(u.mBytes)); } +}; + +} /* namespace mozilla */ + +#endif /* mozilla_Alignment_h */ diff --git a/libazure/mozilla/AllocPolicy.h b/libazure/mozilla/AllocPolicy.h new file mode 100644 index 0000000..a3ca984 --- /dev/null +++ b/libazure/mozilla/AllocPolicy.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * An allocation policy concept, usable for structures and algorithms to + * control how memory is allocated and how failures are handled. + */ + +#ifndef mozilla_AllocPolicy_h +#define mozilla_AllocPolicy_h + +#include "mozilla/NullPtr.h" +#include "mozilla/TemplateLib.h" + +#include +#include + +namespace mozilla { + +/* + * Allocation policies are used to implement the standard allocation behaviors + * in a customizable way. Additionally, custom behaviors may be added to these + * behaviors, such as additionally reporting an error through an out-of-band + * mechanism when OOM occurs. The concept modeled here is as follows: + * + * - public copy constructor, assignment, destructor + * - template T* pod_malloc(size_t) + * Responsible for OOM reporting when null is returned. + * - template T* pod_calloc(size_t) + * Responsible for OOM reporting when null is returned. + * - template T* pod_realloc(T*, size_t, size_t) + * Responsible for OOM reporting when null is returned. The old allocation + * size is passed in, in addition to the new allocation size requested. + * - void free_(void*) + * - void reportAllocOverflow() const + * Called on allocation overflow (that is, an allocation implicitly tried + * to allocate more than the available memory space -- think allocating an + * array of large-size objects, where N * size overflows) before null is + * returned. + * + * mfbt provides (and typically uses by default) only MallocAllocPolicy, which + * does nothing more than delegate to the malloc/alloc/free functions. + */ + +/* + * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no + * extra behaviors. + */ +class MallocAllocPolicy +{ +public: + template + T* pod_malloc(size_t aNumElems) + { + if (aNumElems & mozilla::tl::MulOverflowMask::value) + return nullptr; + return static_cast(malloc(aNumElems * sizeof(T))); + } + + template + T* pod_calloc(size_t aNumElems) + { + return static_cast(calloc(aNumElems, sizeof(T))); + } + + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) + { + if (aNewSize & mozilla::tl::MulOverflowMask::value) + return nullptr; + return static_cast(realloc(aPtr, aNewSize * sizeof(T))); + } + + void free_(void* aPtr) + { + free(aPtr); + } + + void reportAllocOverflow() const + { + } +}; + +} // namespace mozilla + +#endif /* mozilla_AllocPolicy_h */ diff --git a/libazure/mozilla/Array.h b/libazure/mozilla/Array.h new file mode 100644 index 0000000..b2ab578 --- /dev/null +++ b/libazure/mozilla/Array.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A compile-time constant-length array with bounds-checking assertions. */ + +#ifndef mozilla_Array_h +#define mozilla_Array_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#include + +namespace mozilla { + +template +class Array +{ + T mArr[Length]; + +public: + T& operator[](size_t aIndex) + { + MOZ_ASSERT(aIndex < Length); + return mArr[aIndex]; + } + + const T& operator[](size_t aIndex) const + { + MOZ_ASSERT(aIndex < Length); + return mArr[aIndex]; + } +}; + +template +class Array +{ +public: + T& operator[](size_t aIndex) + { + MOZ_CRASH("indexing into zero-length array"); + } + + const T& operator[](size_t aIndex) const + { + MOZ_CRASH("indexing into zero-length array"); + } +}; + +} /* namespace mozilla */ + +#endif /* mozilla_Array_h */ diff --git a/libazure/mozilla/ArrayUtils.h b/libazure/mozilla/ArrayUtils.h new file mode 100644 index 0000000..44f5980 --- /dev/null +++ b/libazure/mozilla/ArrayUtils.h @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements various helper functions related to arrays. + */ + +#ifndef mozilla_ArrayUtils_h +#define mozilla_ArrayUtils_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#include + +#ifdef __cplusplus + +#include "mozilla/Alignment.h" +#include "mozilla/Array.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +/* + * Safely subtract two pointers when it is known that aEnd >= aBegin. This + * avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has + * the MSB set, the unsigned subtraction followed by right shift will produce + * -1, or size_t(-1), instead of the real difference. + */ +template +MOZ_ALWAYS_INLINE size_t +PointerRangeSize(T* aBegin, T* aEnd) +{ + MOZ_ASSERT(aEnd >= aBegin); + return (size_t(aEnd) - size_t(aBegin)) / sizeof(T); +} + +/* + * Compute the length of an array with constant length. (Use of this method + * with a non-array pointer will not compile.) + * + * Beware of the implicit trailing '\0' when using this with string constants. + */ +template +MOZ_CONSTEXPR size_t +ArrayLength(T (&aArr)[N]) +{ + return N; +} + +template +MOZ_CONSTEXPR size_t +ArrayLength(const Array& aArr) +{ + return N; +} + +/* + * Compute the address one past the last element of a constant-length array. + * + * Beware of the implicit trailing '\0' when using this with string constants. + */ +template +MOZ_CONSTEXPR T* +ArrayEnd(T (&aArr)[N]) +{ + return aArr + ArrayLength(aArr); +} + +template +MOZ_CONSTEXPR T* +ArrayEnd(Array& aArr) +{ + return &aArr[0] + ArrayLength(aArr); +} + +template +MOZ_CONSTEXPR const T* +ArrayEnd(const Array& aArr) +{ + return &aArr[0] + ArrayLength(aArr); +} + +namespace detail { + +template +struct AlignedChecker +{ + static void + test(Pointee* aPtr) + { + MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0, + "performing a range-check with a misaligned pointer"); + } +}; + +template +struct AlignedChecker +{ + static void + test(Pointee* aPtr) + { + } +}; + +} // namespace detail + +/** + * Determines whether |aPtr| points at an object in the range [aBegin, aEnd). + * + * |aPtr| must have the same alignment as |aBegin| and |aEnd|. This usually + * should be achieved by ensuring |aPtr| points at a |U|, not just that it + * points at a |T|. + * + * It is a usage error for any argument to be misaligned. + * + * It's okay for T* to be void*, and if so U* may also be void*. In the latter + * case no argument is required to be aligned (obviously, as void* implies no + * particular alignment). + */ +template +inline typename EnableIf::value || + IsBaseOf::value || + IsVoid::value, + bool>::Type +IsInRange(T* aPtr, U* aBegin, U* aEnd) +{ + MOZ_ASSERT(aBegin <= aEnd); + detail::AlignedChecker::test(aPtr); + detail::AlignedChecker::test(aBegin); + detail::AlignedChecker::test(aEnd); + return aBegin <= static_cast(aPtr) && static_cast(aPtr) < aEnd; +} + +/** + * Convenience version of the above method when the valid range is specified as + * uintptr_t values. As above, |aPtr| must be aligned, and |aBegin| and |aEnd| + * must be aligned with respect to |T|. + */ +template +inline bool +IsInRange(T* aPtr, uintptr_t aBegin, uintptr_t aEnd) +{ + return IsInRange(aPtr, + reinterpret_cast(aBegin), reinterpret_cast(aEnd)); +} + +namespace detail { + +/* + * Helper for the MOZ_ARRAY_LENGTH() macro to make the length a typesafe + * compile-time constant even on compilers lacking constexpr support. + */ +template +char (&ArrayLengthHelper(T (&array)[N]))[N]; + +} /* namespace detail */ + +} /* namespace mozilla */ + +#endif /* __cplusplus */ + +/* + * MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files + * that can't use C++ template functions and for static_assert() calls that + * can't call ArrayLength() when it is not a C++11 constexpr function. + */ +#ifdef __cplusplus +# define MOZ_ARRAY_LENGTH(array) sizeof(mozilla::detail::ArrayLengthHelper(array)) +#else +# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) +#endif + +#endif /* mozilla_ArrayUtils_h */ diff --git a/libazure/mozilla/Assertions.h b/libazure/mozilla/Assertions.h new file mode 100644 index 0000000..771f254 --- /dev/null +++ b/libazure/mozilla/Assertions.h @@ -0,0 +1,518 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Implementations of runtime and static assertion macros for C and C++. */ + +#ifndef mozilla_Assertions_h +#define mozilla_Assertions_h + +#if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus) +#define MOZ_DUMP_ASSERTION_STACK +#endif + +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/Likely.h" +#include "mozilla/MacroArgs.h" +#ifdef MOZ_DUMP_ASSERTION_STACK +#include "nsTraceRefcnt.h" +#endif + +#include +#include +#include +#ifdef WIN32 + /* + * TerminateProcess and GetCurrentProcess are defined in , which + * further depends on . We hardcode these few definitions manually + * because those headers clutter the global namespace with a significant + * number of undesired macros and symbols. + */ +# ifdef __cplusplus +extern "C" { +# endif +__declspec(dllimport) int __stdcall +TerminateProcess(void* hProcess, unsigned int uExitCode); +__declspec(dllimport) void* __stdcall GetCurrentProcess(void); +# ifdef __cplusplus +} +# endif +#else +# include +#endif +#ifdef ANDROID +# include +#endif + +/* + * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C. + * In C++11, static_assert is provided by the compiler to the same effect. + * This can be useful when you make certain assumptions about what must hold for + * optimal, or even correct, behavior. For example, you might assert that the + * size of a struct is a multiple of the target architecture's word size: + * + * struct S { ... }; + * // C + * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0, + * "S should be a multiple of word size for efficiency"); + * // C++11 + * static_assert(sizeof(S) % sizeof(size_t) == 0, + * "S should be a multiple of word size for efficiency"); + * + * This macro can be used in any location where both an extern declaration and a + * typedef could be used. + */ +#ifndef __cplusplus + /* + * Some of the definitions below create an otherwise-unused typedef. This + * triggers compiler warnings with some versions of gcc, so mark the typedefs + * as permissibly-unused to disable the warnings. + */ +# if defined(__GNUC__) +# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +# else +# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ +# endif +# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y +# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) +# if defined(__SUNPRO_CC) + /* + * The Sun Studio C++ compiler is buggy when declaring, inside a function, + * another extern'd function with an array argument whose length contains a + * sizeof, triggering the error message "sizeof expression not accepted as + * size of array parameter". This bug (6688515, not public yet) would hit + * defining moz_static_assert as a function, so we always define an extern + * array for Sun Studio. + * + * We include the line number in the symbol name in a best-effort attempt + * to avoid conflicts (see below). + */ +# define MOZ_STATIC_ASSERT(cond, reason) \ + extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] +# elif defined(__COUNTER__) + /* + * If there was no preferred alternative, use a compiler-agnostic version. + * + * Note that the non-__COUNTER__ version has a bug in C++: it can't be used + * in both |extern "C"| and normal C++ in the same translation unit. (Alas + * |extern "C"| isn't allowed in a function.) The only affected compiler + * we really care about is gcc 4.2. For that compiler and others like it, + * we include the line number in the function name to do the best we can to + * avoid conflicts. These should be rare: a conflict would require use of + * MOZ_STATIC_ASSERT on the same line in separate files in the same + * translation unit, *and* the uses would have to be in code with + * different linkage, *and* the first observed use must be in C++-linkage + * code. + */ +# define MOZ_STATIC_ASSERT(cond, reason) \ + typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +# else +# define MOZ_STATIC_ASSERT(cond, reason) \ + extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +# endif + +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) +#else +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Prints |aStr| as an assertion failure (using aFilename and aLine as the + * location of the assertion) to the standard debug-output channel. + * + * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This + * method is primarily for internal use in this header, and only secondarily + * for use in implementing release-build assertions. + */ +static MOZ_ALWAYS_INLINE void +MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine) + MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", + "Assertion failure: %s, at %s:%d\n", + aStr, aFilename, aLine); +#else + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); +#ifdef MOZ_DUMP_ASSERTION_STACK + nsTraceRefcnt::WalkTheStack(stderr); +#endif + fflush(stderr); +#endif +} + +static MOZ_ALWAYS_INLINE void +MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) + MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", + "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); +#else + fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); +#ifdef MOZ_DUMP_ASSERTION_STACK + nsTraceRefcnt::WalkTheStack(stderr); +#endif + fflush(stderr); +#endif +} + +/** + * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should + * call MOZ_CRASH instead. + */ +#if defined(_MSC_VER) + /* + * On MSVC use the __debugbreak compiler intrinsic, which produces an inline + * (not nested in a system function) breakpoint. This distinctively invokes + * Breakpad without requiring system library symbols on all stack-processing + * machines, as a nested breakpoint would require. + * + * We use TerminateProcess with the exit code aborting would generate + * because we don't want to invoke atexit handlers, destructors, library + * unload handlers, and so on when our process might be in a compromised + * state. + * + * We don't use abort() because it'd cause Windows to annoyingly pop up the + * process error dialog multiple times. See bug 345118 and bug 426163. + * + * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the + * compiler doesn't hassle us to provide a return statement after a + * MOZ_REALLY_CRASH() call. + * + * (Technically these are Windows requirements, not MSVC requirements. But + * practically you need MSVC for debugging, and we only ship builds created + * by MSVC, so doing it this way reduces complexity.) + */ + +__declspec(noreturn) __inline void MOZ_NoReturn() {} + +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + ::__debugbreak(); \ + *((volatile int*) NULL) = 123; \ + ::TerminateProcess(::GetCurrentProcess(), 3); \ + ::MOZ_NoReturn(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + __debugbreak(); \ + *((volatile int*) NULL) = 123; \ + TerminateProcess(GetCurrentProcess(), 3); \ + MOZ_NoReturn(); \ + } while (0) +# endif +#else +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = 123; \ + ::abort(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = 123; \ + abort(); \ + } while (0) +# endif +#endif + +/* + * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a + * Breakpad-compatible way, in both debug and release builds. + * + * MOZ_CRASH is a good solution for "handling" failure cases when you're + * unwilling or unable to handle them more cleanly -- for OOM, for likely memory + * corruption, and so on. It's also a good solution if you need safe behavior + * in release builds as well as debug builds. But if the failure is one that + * should be debugged and fixed, MOZ_ASSERT is generally preferable. + * + * The optional explanation-string, if provided, must be a string literal + * explaining why we're crashing. This argument is intended for use with + * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's + * obvious why we're crashing. + * + * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an + * explanation-string, we print the string to stderr. Otherwise, we don't + * print anything; this is because we want MOZ_CRASH to be 100% safe in release + * builds, and it's hard to print to stderr safely when memory might have been + * corrupted. + */ +#ifndef DEBUG +# define MOZ_CRASH(...) MOZ_REALLY_CRASH() +#else +# define MOZ_CRASH(...) \ + do { \ + MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } while (0) +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* + * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in + * debug builds. If it is, execution continues. Otherwise, an error message + * including the expression and the explanation-string (if provided) is printed, + * an attempt is made to invoke any existing debugger, and execution halts. + * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition + * which can correctly be falsy. + * + * The optional explanation-string, if provided, must be a string literal + * explaining the assertion. It is intended for use with assertions whose + * correctness or rationale is non-obvious, and for assertions where the "real" + * condition being tested is best described prosaically. Don't provide an + * explanation if it's not actually helpful. + * + * // No explanation needed: pointer arguments often must not be NULL. + * MOZ_ASSERT(arg); + * + * // An explanation can be helpful to explain exactly how we know an + * // assertion is valid. + * MOZ_ASSERT(state == WAITING_FOR_RESPONSE, + * "given that and , we must have..."); + * + * // Or it might disambiguate multiple identical (save for their location) + * // assertions of the same expression. + * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), + * "we already set [[PrimitiveThis]] for this Boolean object"); + * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), + * "we already set [[PrimitiveThis]] for this String object"); + * + * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs + * *only* during debugging, not "in the field". If you want the latter, use + * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well. + */ + +/* + * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against + * accidentally passing something unintended in lieu of an assertion condition. + */ + +#ifdef __cplusplus +# if defined(__clang__) +# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# elif defined(__GNUC__) +// B2G GCC 4.4 has insufficient decltype support. +# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) +# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# endif +# elif defined(_MSC_VER) +// Disabled for now because of insufficient decltype support. Bug 1004028. +# endif +#endif + +#ifdef MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# include "mozilla/TypeTraits.h" +namespace mozilla { +namespace detail { + +template +struct IsFunction +{ + static const bool value = false; +}; + +template +struct IsFunction +{ + static const bool value = true; +}; + +template +struct AssertionConditionType +{ + typedef typename RemoveReference::Type ValueT; + static_assert(!IsArray::value, + "Expected boolean assertion condition, got an array or a " + "string!"); + static_assert(!IsFunction::value, + "Expected boolean assertion condition, got a function! Did " + "you intend to call that function?"); + static_assert(!IsFloatingPoint::value, + "It's often a bad idea to assert that a floating-point number " + "is nonzero, because such assertions tend to intermittently " + "fail. Shouldn't your code gracefully handle this case instead " + "of asserting? Anyway, if you really want to do that, write an " + "explicit boolean condition, like !!x or x!=0."); + + static const bool isValid = true; +}; + +} // namespace detail +} // namespace mozilla +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ + static_assert(mozilla::detail::AssertionConditionType::isValid, \ + "invalid assertion condition") +#else +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +#endif + +/* First the single-argument form. */ +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!(expr))) { \ + MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } \ + } while (0) +/* Now the two-argument form. */ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!(expr))) { \ + MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } \ + } while (0) + +#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) + +#ifdef DEBUG +# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) +#else +# define MOZ_ASSERT(...) do { } while (0) +#endif /* DEBUG */ + +/* + * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is + * true. + * + * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num)); + * + * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is + * designed to catch bugs during debugging, not "in the field". + */ +#ifdef DEBUG +# define MOZ_ASSERT_IF(cond, expr) \ + do { \ + if (cond) { \ + MOZ_ASSERT(expr); \ + } \ + } while (0) +#else +# define MOZ_ASSERT_IF(cond, expr) do { } while (0) +#endif + +/* + * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that + * it is undefined behavior for execution to reach this point. No guarantees + * are made about what will happen if this is reached at runtime. Most code + * should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra + * asserts. + */ +#if defined(__clang__) +# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() +#elif defined(__GNUC__) + /* + * __builtin_unreachable() was implemented in gcc 4.5. If we don't have + * that, call a noreturn function; abort() will do nicely. Qualify the call + * in C++ in case there's another abort() visible in local scope. + */ +# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) +# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() +# else +# ifdef __cplusplus +# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() +# else +# define MOZ_ASSUME_UNREACHABLE_MARKER() abort() +# endif +# endif +#elif defined(_MSC_VER) +# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) +#else +# ifdef __cplusplus +# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() +# else +# define MOZ_ASSUME_UNREACHABLE_MARKER() abort() +# endif +#endif + +/* + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it + * can assume that the macro call cannot be reached during execution. This lets + * the compiler generate better-optimized code under some circumstances, at the + * expense of the program's behavior being undefined if control reaches the + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE. + * + * In Gecko, you probably should not use this macro outside of performance- or + * size-critical code, because it's unsafe. If you don't care about code size + * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH. + * + * SpiderMonkey is a different beast, and there it's acceptable to use + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely. + * + * Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid + * not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE + * call. + * + * Example usage: + * + * enum ValueType { + * VALUE_STRING, + * VALUE_INT, + * VALUE_FLOAT + * }; + * + * int ptrToInt(ValueType type, void* value) { + * { + * // We know for sure that type is either INT or FLOAT, and we want this + * // code to run as quickly as possible. + * switch (type) { + * case VALUE_INT: + * return *(int*) value; + * case VALUE_FLOAT: + * return (int) *(float*) value; + * default: + * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType"); + * } + * } + */ + +/* + * Unconditional assert in debug builds for (assumed) unreachable code paths + * that have a safe return without crashing in release builds. + */ +#define MOZ_ASSERT_UNREACHABLE(reason) \ + MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) + +#define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \ + do { \ + MOZ_ASSERT_UNREACHABLE(reason); \ + MOZ_ASSUME_UNREACHABLE_MARKER(); \ + } while (0) + +/* + * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided + * expression, in debug builds and in release builds both. Then, in debug + * builds only, the value of the expression is asserted either true or false + * using MOZ_ASSERT. + */ +#ifdef DEBUG +# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) +# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) +#else +# define MOZ_ALWAYS_TRUE(expr) ((void)(expr)) +# define MOZ_ALWAYS_FALSE(expr) ((void)(expr)) +#endif + +#undef MOZ_DUMP_ASSERTION_STACK + +#endif /* mozilla_Assertions_h */ diff --git a/libazure/mozilla/Atomics.h b/libazure/mozilla/Atomics.h new file mode 100644 index 0000000..495a9d3 --- /dev/null +++ b/libazure/mozilla/Atomics.h @@ -0,0 +1,1178 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements (almost always) lock-free atomic operations. The operations here + * are a subset of that which can be found in C++11's header, with a + * different API to enforce consistent memory ordering constraints. + * + * Anyone caught using |volatile| for inter-thread memory safety needs to be + * sent a copy of this header and the C++11 standard. + */ + +#ifndef mozilla_Atomics_h +#define mozilla_Atomics_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/TypeTraits.h" + +#include + +/* + * Our minimum deployment target on clang/OS X is OS X 10.6, whose SDK + * does not have . So be sure to check for support + * along with C++0x support. + */ +#if defined(__clang__) || defined(__GNUC__) + /* + * Clang doesn't like from libstdc++ before 4.7 due to the + * loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline + * definitions for unspecialized std::atomic and causes linking errors. + * Therefore, we require at least 4.7.0 for using libstdc++. + */ +# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0) +# define MOZ_HAVE_CXX11_ATOMICS +# elif MOZ_USING_LIBCXX +# define MOZ_HAVE_CXX11_ATOMICS +# endif +/* + * Although Visual Studio 2012's CRT supports , its atomic load + * implementation unnecessarily uses an atomic intrinsic for the less + * restrictive memory orderings, which can be prohibitively expensive. + * Therefore, we require at least Visual Studio 2013 for using the CRT + * (bug 1061764). + */ +#elif defined(_MSC_VER) && _MSC_VER >= 1800 +# if defined(DEBUG) + /* + * Provide our own failure code since we're having trouble linking to + * std::_Debug_message (bug 982310). + */ +# define _INVALID_MEMORY_ORDER MOZ_CRASH("Invalid memory order") +# endif +# define MOZ_HAVE_CXX11_ATOMICS +#endif + +namespace mozilla { + +/** + * An enum of memory ordering possibilities for atomics. + * + * Memory ordering is the observable state of distinct values in memory. + * (It's a separate concept from atomicity, which concerns whether an + * operation can ever be observed in an intermediate state. Don't + * conflate the two!) Given a sequence of operations in source code on + * memory, it is *not* always the case that, at all times and on all + * cores, those operations will appear to have occurred in that exact + * sequence. First, the compiler might reorder that sequence, if it + * thinks another ordering will be more efficient. Second, the CPU may + * not expose so consistent a view of memory. CPUs will often perform + * their own instruction reordering, above and beyond that performed by + * the compiler. And each core has its own memory caches, and accesses + * (reads and writes both) to "memory" may only resolve to out-of-date + * cache entries -- not to the "most recently" performed operation in + * some global sense. Any access to a value that may be used by + * multiple threads, potentially across multiple cores, must therefore + * have a memory ordering imposed on it, for all code on all + * threads/cores to have a sufficiently coherent worldview. + * + * http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and + * http://en.cppreference.com/w/cpp/atomic/memory_order go into more + * detail on all this, including examples of how each mode works. + * + * Note that for simplicity and practicality, not all of the modes in + * C++11 are supported. The missing C++11 modes are either subsumed by + * the modes we provide below, or not relevant for the CPUs we support + * in Gecko. These three modes are confusing enough as it is! + */ +enum MemoryOrdering { + /* + * Relaxed ordering is the simplest memory ordering: none at all. + * When the result of a write is observed, nothing may be inferred + * about other memory. Writes ostensibly performed "before" on the + * writing thread may not yet be visible. Writes performed "after" on + * the writing thread may already be visible, if the compiler or CPU + * reordered them. (The latter can happen if reads and/or writes get + * held up in per-processor caches.) Relaxed ordering means + * operations can always use cached values (as long as the actual + * updates to atomic values actually occur, correctly, eventually), so + * it's usually the fastest sort of atomic access. For this reason, + * *it's also the most dangerous kind of access*. + * + * Relaxed ordering is good for things like process-wide statistics + * counters that don't need to be consistent with anything else, so + * long as updates themselves are atomic. (And so long as any + * observations of that value can tolerate being out-of-date -- if you + * need some sort of up-to-date value, you need some sort of other + * synchronizing operation.) It's *not* good for locks, mutexes, + * reference counts, etc. that mediate access to other memory, or must + * be observably consistent with other memory. + * + * x86 architectures don't take advantage of the optimization + * opportunities that relaxed ordering permits. Thus it's possible + * that using relaxed ordering will "work" on x86 but fail elsewhere + * (ARM, say, which *does* implement non-sequentially-consistent + * relaxed ordering semantics). Be extra-careful using relaxed + * ordering if you can't easily test non-x86 architectures! + */ + Relaxed, + + /* + * When an atomic value is updated with ReleaseAcquire ordering, and + * that new value is observed with ReleaseAcquire ordering, prior + * writes (atomic or not) are also observable. What ReleaseAcquire + * *doesn't* give you is any observable ordering guarantees for + * ReleaseAcquire-ordered operations on different objects. For + * example, if there are two cores that each perform ReleaseAcquire + * operations on separate objects, each core may or may not observe + * the operations made by the other core. The only way the cores can + * be synchronized with ReleaseAcquire is if they both + * ReleaseAcquire-access the same object. This implies that you can't + * necessarily describe some global total ordering of ReleaseAcquire + * operations. + * + * ReleaseAcquire ordering is good for (as the name implies) atomic + * operations on values controlling ownership of things: reference + * counts, mutexes, and the like. However, if you are thinking about + * using these to implement your own locks or mutexes, you should take + * a good, hard look at actual lock or mutex primitives first. + */ + ReleaseAcquire, + + /* + * When an atomic value is updated with SequentiallyConsistent + * ordering, all writes observable when the update is observed, just + * as with ReleaseAcquire ordering. But, furthermore, a global total + * ordering of SequentiallyConsistent operations *can* be described. + * For example, if two cores perform SequentiallyConsistent operations + * on separate objects, one core will observably perform its update + * (and all previous operations will have completed), then the other + * core will observably perform its update (and all previous + * operations will have completed). (Although those previous + * operations aren't themselves ordered -- they could be intermixed, + * or ordered if they occur on atomic values with ordering + * requirements.) SequentiallyConsistent is the *simplest and safest* + * ordering of atomic operations -- it's always as if one operation + * happens, then another, then another, in some order -- and every + * core observes updates to happen in that single order. Because it + * has the most synchronization requirements, operations ordered this + * way also tend to be slowest. + * + * SequentiallyConsistent ordering can be desirable when multiple + * threads observe objects, and they all have to agree on the + * observable order of changes to them. People expect + * SequentiallyConsistent ordering, even if they shouldn't, when + * writing code, atomic or otherwise. SequentiallyConsistent is also + * the ordering of choice when designing lockless data structures. If + * you don't know what order to use, use this one. + */ + SequentiallyConsistent, +}; + +} // namespace mozilla + +// Build up the underlying intrinsics. +#ifdef MOZ_HAVE_CXX11_ATOMICS + +# include + +namespace mozilla { +namespace detail { + +/* + * We provide CompareExchangeFailureOrder to work around a bug in some + * versions of GCC's header. See bug 898491. + */ +template struct AtomicOrderConstraints; + +template<> +struct AtomicOrderConstraints +{ + static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed; + static const std::memory_order LoadOrder = std::memory_order_relaxed; + static const std::memory_order StoreOrder = std::memory_order_relaxed; + static const std::memory_order CompareExchangeFailureOrder = + std::memory_order_relaxed; +}; + +template<> +struct AtomicOrderConstraints +{ + static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel; + static const std::memory_order LoadOrder = std::memory_order_acquire; + static const std::memory_order StoreOrder = std::memory_order_release; + static const std::memory_order CompareExchangeFailureOrder = + std::memory_order_acquire; +}; + +template<> +struct AtomicOrderConstraints +{ + static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst; + static const std::memory_order LoadOrder = std::memory_order_seq_cst; + static const std::memory_order StoreOrder = std::memory_order_seq_cst; + static const std::memory_order CompareExchangeFailureOrder = + std::memory_order_seq_cst; +}; + +template +struct IntrinsicBase +{ + typedef std::atomic ValueType; + typedef AtomicOrderConstraints OrderedOp; +}; + +template +struct IntrinsicMemoryOps : public IntrinsicBase +{ + typedef IntrinsicBase Base; + + static T load(const typename Base::ValueType& aPtr) + { + return aPtr.load(Base::OrderedOp::LoadOrder); + } + + static void store(typename Base::ValueType& aPtr, T aVal) + { + aPtr.store(aVal, Base::OrderedOp::StoreOrder); + } + + static T exchange(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder); + } + + static bool compareExchange(typename Base::ValueType& aPtr, + T aOldVal, T aNewVal) + { + return aPtr.compare_exchange_strong(aOldVal, aNewVal, + Base::OrderedOp::AtomicRMWOrder, + Base::OrderedOp::CompareExchangeFailureOrder); + } +}; + +template +struct IntrinsicAddSub : public IntrinsicBase +{ + typedef IntrinsicBase Base; + + static T add(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder); + } + + static T sub(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder); + } +}; + +template +struct IntrinsicAddSub : public IntrinsicBase +{ + typedef IntrinsicBase Base; + + static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal) + { + return aPtr.fetch_add(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder); + } + + static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal) + { + return aPtr.fetch_sub(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder); + } +private: + /* + * GCC 4.6's header has a bug where adding X to an + * atomic is not the same as adding X to a T*. Hence the need + * for this function to provide the correct addend. + */ + static ptrdiff_t fixupAddend(ptrdiff_t aVal) + { +#if defined(__clang__) || defined(_MSC_VER) + return aVal; +#elif defined(__GNUC__) && MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) && \ + !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) + return aVal * sizeof(T); +#else + return aVal; +#endif + } +}; + +template +struct IntrinsicIncDec : public IntrinsicAddSub +{ + typedef IntrinsicBase Base; + + static T inc(typename Base::ValueType& aPtr) + { + return IntrinsicAddSub::add(aPtr, 1); + } + + static T dec(typename Base::ValueType& aPtr) + { + return IntrinsicAddSub::sub(aPtr, 1); + } +}; + +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec +{ + typedef IntrinsicBase Base; + + static T or_(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder); + } + + static T xor_(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder); + } + + static T and_(typename Base::ValueType& aPtr, T aVal) + { + return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder); + } +}; + +template +struct AtomicIntrinsics + : public IntrinsicMemoryOps, public IntrinsicIncDec +{ +}; + +} // namespace detail +} // namespace mozilla + +#elif defined(__GNUC__) + +namespace mozilla { +namespace detail { + +/* + * The __sync_* family of intrinsics is documented here: + * + * http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html + * + * While these intrinsics are deprecated in favor of the newer __atomic_* + * family of intrincs: + * + * http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html + * + * any GCC version that supports the __atomic_* intrinsics will also support + * the header and so will be handled above. We provide a version of + * atomics using the __sync_* intrinsics to support older versions of GCC. + * + * All __sync_* intrinsics that we use below act as full memory barriers, for + * both compiler and hardware reordering, except for __sync_lock_test_and_set, + * which is a only an acquire barrier. When we call __sync_lock_test_and_set, + * we add a barrier above it as appropriate. + */ + +template struct Barrier; + +/* + * Some processors (in particular, x86) don't require quite so many calls to + * __sync_sychronize as our specializations of Barrier produce. If + * performance turns out to be an issue, defining these specializations + * on a per-processor basis would be a good first tuning step. + */ + +template<> +struct Barrier +{ + static void beforeLoad() {} + static void afterLoad() {} + static void beforeStore() {} + static void afterStore() {} +}; + +template<> +struct Barrier +{ + static void beforeLoad() {} + static void afterLoad() { __sync_synchronize(); } + static void beforeStore() { __sync_synchronize(); } + static void afterStore() {} +}; + +template<> +struct Barrier +{ + static void beforeLoad() { __sync_synchronize(); } + static void afterLoad() { __sync_synchronize(); } + static void beforeStore() { __sync_synchronize(); } + static void afterStore() { __sync_synchronize(); } +}; + +template +struct IntrinsicMemoryOps +{ + static T load(const T& aPtr) + { + Barrier::beforeLoad(); + T val = aPtr; + Barrier::afterLoad(); + return val; + } + + static void store(T& aPtr, T aVal) + { + Barrier::beforeStore(); + aPtr = aVal; + Barrier::afterStore(); + } + + static T exchange(T& aPtr, T aVal) + { + // __sync_lock_test_and_set is only an acquire barrier; loads and stores + // can't be moved up from after to before it, but they can be moved down + // from before to after it. We may want a stricter ordering, so we need + // an explicit barrier. + Barrier::beforeStore(); + return __sync_lock_test_and_set(&aPtr, aVal); + } + + static bool compareExchange(T& aPtr, T aOldVal, T aNewVal) + { + return __sync_bool_compare_and_swap(&aPtr, aOldVal, aNewVal); + } +}; + +template +struct IntrinsicAddSub +{ + typedef T ValueType; + + static T add(T& aPtr, T aVal) + { + return __sync_fetch_and_add(&aPtr, aVal); + } + + static T sub(T& aPtr, T aVal) + { + return __sync_fetch_and_sub(&aPtr, aVal); + } +}; + +template +struct IntrinsicAddSub +{ + typedef T* ValueType; + + /* + * The reinterpret_casts are needed so that + * __sync_fetch_and_{add,sub} will properly type-check. + * + * Also, these functions do not provide standard semantics for + * pointer types, so we need to adjust the addend. + */ + static ValueType add(ValueType& aPtr, ptrdiff_t aVal) + { + ValueType amount = reinterpret_cast(aVal * sizeof(T)); + return __sync_fetch_and_add(&aPtr, amount); + } + + static ValueType sub(ValueType& aPtr, ptrdiff_t aVal) + { + ValueType amount = reinterpret_cast(aVal * sizeof(T)); + return __sync_fetch_and_sub(&aPtr, amount); + } +}; + +template +struct IntrinsicIncDec : public IntrinsicAddSub +{ + static T inc(T& aPtr) { return IntrinsicAddSub::add(aPtr, 1); } + static T dec(T& aPtr) { return IntrinsicAddSub::sub(aPtr, 1); } +}; + +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec +{ + static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); } + static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); } + static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); } +}; + +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec +{ +}; + +} // namespace detail +} // namespace mozilla + +#elif defined(_MSC_VER) + +/* + * Windows comes with a full complement of atomic operations. + * Unfortunately, most of those aren't available for Windows XP (even if + * the compiler supports intrinsics for them), which is the oldest + * version of Windows we support. Therefore, we only provide operations + * on 32-bit datatypes for 32-bit Windows versions; for 64-bit Windows + * versions, we support 64-bit datatypes as well. + */ + +# include + +# pragma intrinsic(_InterlockedExchangeAdd) +# pragma intrinsic(_InterlockedOr) +# pragma intrinsic(_InterlockedXor) +# pragma intrinsic(_InterlockedAnd) +# pragma intrinsic(_InterlockedExchange) +# pragma intrinsic(_InterlockedCompareExchange) + +namespace mozilla { +namespace detail { + +# if !defined(_M_IX86) && !defined(_M_X64) + /* + * The implementations below are optimized for x86ish systems. You + * will have to modify them if you are porting to Windows on a + * different architecture. + */ +# error "Unknown CPU type" +# endif + +/* + * The PrimitiveIntrinsics template should define |Type|, the datatype of size + * DataSize upon which we operate, and the following eight functions. + * + * static Type add(Type* aPtr, Type aVal); + * static Type sub(Type* aPtr, Type aVal); + * static Type or_(Type* aPtr, Type aVal); + * static Type xor_(Type* aPtr, Type aVal); + * static Type and_(Type* aPtr, Type aVal); + * + * These functions perform the obvious operation on the value contained in + * |*aPtr| combined with |aVal| and return the value previously stored in + * |*aPtr|. + * + * static void store(Type* aPtr, Type aVal); + * + * This function atomically stores |aVal| into |*aPtr| and must provide a full + * memory fence after the store to prevent compiler and hardware instruction + * reordering. It should also act as a compiler barrier to prevent reads and + * writes from moving to after the store. + * + * static Type exchange(Type* aPtr, Type aVal); + * + * This function atomically stores |aVal| into |*aPtr| and returns the + * previous contents of |*aPtr|; + * + * static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal); + * + * This function atomically performs the following operation: + * + * if (*aPtr == aOldVal) { + * *aPtr = aNewVal; + * return true; + * } else { + * return false; + * } + * + */ +template struct PrimitiveIntrinsics; + +template<> +struct PrimitiveIntrinsics<4> +{ + typedef long Type; + + static Type add(Type* aPtr, Type aVal) + { + return _InterlockedExchangeAdd(aPtr, aVal); + } + + static Type sub(Type* aPtr, Type aVal) + { + /* + * _InterlockedExchangeSubtract isn't available before Windows 7, + * and we must support Windows XP. + */ + return _InterlockedExchangeAdd(aPtr, -aVal); + } + + static Type or_(Type* aPtr, Type aVal) + { + return _InterlockedOr(aPtr, aVal); + } + + static Type xor_(Type* aPtr, Type aVal) + { + return _InterlockedXor(aPtr, aVal); + } + + static Type and_(Type* aPtr, Type aVal) + { + return _InterlockedAnd(aPtr, aVal); + } + + static void store(Type* aPtr, Type aVal) + { + _InterlockedExchange(aPtr, aVal); + } + + static Type exchange(Type* aPtr, Type aVal) + { + return _InterlockedExchange(aPtr, aVal); + } + + static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal) + { + return _InterlockedCompareExchange(aPtr, aNewVal, aOldVal) == aOldVal; + } +}; + +# if defined(_M_X64) + +# pragma intrinsic(_InterlockedExchangeAdd64) +# pragma intrinsic(_InterlockedOr64) +# pragma intrinsic(_InterlockedXor64) +# pragma intrinsic(_InterlockedAnd64) +# pragma intrinsic(_InterlockedExchange64) +# pragma intrinsic(_InterlockedCompareExchange64) + +template <> +struct PrimitiveIntrinsics<8> +{ + typedef __int64 Type; + + static Type add(Type* aPtr, Type aVal) + { + return _InterlockedExchangeAdd64(aPtr, aVal); + } + + static Type sub(Type* aPtr, Type aVal) + { + /* + * There is no _InterlockedExchangeSubtract64. + */ + return _InterlockedExchangeAdd64(aPtr, -aVal); + } + + static Type or_(Type* aPtr, Type aVal) + { + return _InterlockedOr64(aPtr, aVal); + } + + static Type xor_(Type* aPtr, Type aVal) + { + return _InterlockedXor64(aPtr, aVal); + } + + static Type and_(Type* aPtr, Type aVal) + { + return _InterlockedAnd64(aPtr, aVal); + } + + static void store(Type* aPtr, Type aVal) + { + _InterlockedExchange64(aPtr, aVal); + } + + static Type exchange(Type* aPtr, Type aVal) + { + return _InterlockedExchange64(aPtr, aVal); + } + + static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal) + { + return _InterlockedCompareExchange64(aPtr, aNewVal, aOldVal) == aOldVal; + } +}; + +# endif + +# pragma intrinsic(_ReadWriteBarrier) + +template struct Barrier; + +/* + * We do not provide an afterStore method in Barrier, as Relaxed and + * ReleaseAcquire orderings do not require one, and the required barrier + * for SequentiallyConsistent is handled by PrimitiveIntrinsics. + */ + +template<> +struct Barrier +{ + static void beforeLoad() {} + static void afterLoad() {} + static void beforeStore() {} +}; + +template<> +struct Barrier +{ + static void beforeLoad() {} + static void afterLoad() { _ReadWriteBarrier(); } + static void beforeStore() { _ReadWriteBarrier(); } +}; + +template<> +struct Barrier +{ + static void beforeLoad() { _ReadWriteBarrier(); } + static void afterLoad() { _ReadWriteBarrier(); } + static void beforeStore() { _ReadWriteBarrier(); } +}; + +template +struct CastHelper +{ + static PrimType toPrimType(T aVal) { return static_cast(aVal); } + static T fromPrimType(PrimType aVal) { return static_cast(aVal); } +}; + +template +struct CastHelper +{ + static PrimType toPrimType(T* aVal) { return reinterpret_cast(aVal); } + static T* fromPrimType(PrimType aVal) { return reinterpret_cast(aVal); } +}; + +template +struct IntrinsicBase +{ + typedef T ValueType; + typedef PrimitiveIntrinsics Primitives; + typedef typename Primitives::Type PrimType; + static_assert(sizeof(PrimType) == sizeof(T), + "Selection of PrimitiveIntrinsics was wrong"); + typedef CastHelper Cast; +}; + +template +struct IntrinsicMemoryOps : public IntrinsicBase +{ + typedef typename IntrinsicBase::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; + typedef typename IntrinsicBase::PrimType PrimType; + typedef typename IntrinsicBase::Cast Cast; + + static ValueType load(const ValueType& aPtr) + { + Barrier::beforeLoad(); + ValueType val = aPtr; + Barrier::afterLoad(); + return val; + } + + static void store(ValueType& aPtr, ValueType aVal) + { + // For SequentiallyConsistent, Primitives::store() will generate the + // proper memory fence. Everything else just needs a barrier before + // the store. + if (Order == SequentiallyConsistent) { + Primitives::store(reinterpret_cast(&aPtr), + Cast::toPrimType(aVal)); + } else { + Barrier::beforeStore(); + aPtr = aVal; + } + } + + static ValueType exchange(ValueType& aPtr, ValueType aVal) + { + PrimType oldval = + Primitives::exchange(reinterpret_cast(&aPtr), + Cast::toPrimType(aVal)); + return Cast::fromPrimType(oldval); + } + + static bool compareExchange(ValueType& aPtr, ValueType aOldVal, + ValueType aNewVal) + { + return Primitives::compareExchange(reinterpret_cast(&aPtr), + Cast::toPrimType(aOldVal), + Cast::toPrimType(aNewVal)); + } +}; + +template +struct IntrinsicApplyHelper : public IntrinsicBase +{ + typedef typename IntrinsicBase::ValueType ValueType; + typedef typename IntrinsicBase::PrimType PrimType; + typedef typename IntrinsicBase::Cast Cast; + typedef PrimType (*BinaryOp)(PrimType*, PrimType); + typedef PrimType (*UnaryOp)(PrimType*); + + static ValueType applyBinaryFunction(BinaryOp aOp, ValueType& aPtr, + ValueType aVal) + { + PrimType* primTypePtr = reinterpret_cast(&aPtr); + PrimType primTypeVal = Cast::toPrimType(aVal); + return Cast::fromPrimType(aOp(primTypePtr, primTypeVal)); + } + + static ValueType applyUnaryFunction(UnaryOp aOp, ValueType& aPtr) + { + PrimType* primTypePtr = reinterpret_cast(&aPtr); + return Cast::fromPrimType(aOp(primTypePtr)); + } +}; + +template +struct IntrinsicAddSub : public IntrinsicApplyHelper +{ + typedef typename IntrinsicApplyHelper::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; + + static ValueType add(ValueType& aPtr, ValueType aVal) + { + return applyBinaryFunction(&Primitives::add, aPtr, aVal); + } + + static ValueType sub(ValueType& aPtr, ValueType aVal) + { + return applyBinaryFunction(&Primitives::sub, aPtr, aVal); + } +}; + +template +struct IntrinsicAddSub : public IntrinsicApplyHelper +{ + typedef typename IntrinsicApplyHelper::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; + + static ValueType add(ValueType& aPtr, ptrdiff_t aAmount) + { + return applyBinaryFunction(&Primitives::add, aPtr, + (ValueType)(aAmount * sizeof(T))); + } + + static ValueType sub(ValueType& aPtr, ptrdiff_t aAmount) + { + return applyBinaryFunction(&Primitives::sub, aPtr, + (ValueType)(aAmount * sizeof(T))); + } +}; + +template +struct IntrinsicIncDec : public IntrinsicAddSub +{ + typedef typename IntrinsicAddSub::ValueType ValueType; + static ValueType inc(ValueType& aPtr) { return add(aPtr, 1); } + static ValueType dec(ValueType& aPtr) { return sub(aPtr, 1); } +}; + +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec +{ + typedef typename IntrinsicIncDec::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; + + static ValueType or_(ValueType& aPtr, T aVal) + { + return applyBinaryFunction(&Primitives::or_, aPtr, aVal); + } + + static ValueType xor_(ValueType& aPtr, T aVal) + { + return applyBinaryFunction(&Primitives::xor_, aPtr, aVal); + } + + static ValueType and_(ValueType& aPtr, T aVal) + { + return applyBinaryFunction(&Primitives::and_, aPtr, aVal); + } +}; + +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec +{ + typedef typename IntrinsicMemoryOps::ValueType ValueType; + // This is required to make us be able to build with MSVC10, for unknown + // reasons. + typedef typename IntrinsicBase::Primitives Primitives; +}; + +} // namespace detail +} // namespace mozilla + +#else +# error "Atomic compiler intrinsics are not supported on your platform" +#endif + +namespace mozilla { + +namespace detail { + +template +class AtomicBase +{ + // We only support 32-bit types on 32-bit Windows, which constrains our + // implementation elsewhere. But we support pointer-sized types everywhere. + static_assert(sizeof(T) == 4 || (sizeof(uintptr_t) == 8 && sizeof(T) == 8), + "mozilla/Atomics.h only supports 32-bit and pointer-sized types"); + +protected: + typedef typename detail::AtomicIntrinsics Intrinsics; + typename Intrinsics::ValueType mValue; + +public: + MOZ_CONSTEXPR AtomicBase() : mValue() {} + explicit MOZ_CONSTEXPR AtomicBase(T aInit) : mValue(aInit) {} + + // Note: we can't provide operator T() here because Atomic inherits + // from AtomcBase with T=uint32_t and not T=bool. If we implemented + // operator T() here, it would cause errors when comparing Atomic with + // a regular bool. + + T operator=(T aVal) + { + Intrinsics::store(mValue, aVal); + return aVal; + } + + /** + * Performs an atomic swap operation. aVal is stored and the previous + * value of this variable is returned. + */ + T exchange(T aVal) + { + return Intrinsics::exchange(mValue, aVal); + } + + /** + * Performs an atomic compare-and-swap operation and returns true if it + * succeeded. This is equivalent to atomically doing + * + * if (mValue == aOldValue) { + * mValue = aNewValue; + * return true; + * } else { + * return false; + * } + */ + bool compareExchange(T aOldValue, T aNewValue) + { + return Intrinsics::compareExchange(mValue, aOldValue, aNewValue); + } + +private: + template + AtomicBase(const AtomicBase& aCopy) MOZ_DELETE; +}; + +template +class AtomicBaseIncDec : public AtomicBase +{ + typedef typename detail::AtomicBase Base; + +public: + MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {} + explicit MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {} + + using Base::operator=; + + operator T() const { return Base::Intrinsics::load(Base::mValue); } + T operator++(int) { return Base::Intrinsics::inc(Base::mValue); } + T operator--(int) { return Base::Intrinsics::dec(Base::mValue); } + T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; } + T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; } + +private: + template + AtomicBaseIncDec(const AtomicBaseIncDec& aCopy) MOZ_DELETE; +}; + +} // namespace detail + +/** + * A wrapper for a type that enforces that all memory accesses are atomic. + * + * In general, where a variable |T foo| exists, |Atomic foo| can be used in + * its place. Implementations for integral and pointer types are provided + * below. + * + * Atomic accesses are sequentially consistent by default. You should + * use the default unless you are tall enough to ride the + * memory-ordering roller coaster (if you're not sure, you aren't) and + * you have a compelling reason to do otherwise. + * + * There is one exception to the case of atomic memory accesses: providing an + * initial value of the atomic value is not guaranteed to be atomic. This is a + * deliberate design choice that enables static atomic variables to be declared + * without introducing extra static constructors. + */ +template +class Atomic; + +/** + * Atomic implementation for integral types. + * + * In addition to atomic store and load operations, compound assignment and + * increment/decrement operators are implemented which perform the + * corresponding read-modify-write operation atomically. Finally, an atomic + * swap method is provided. + */ +template +class Atomic::value && + !IsSame::value>::Type> + : public detail::AtomicBaseIncDec +{ + typedef typename detail::AtomicBaseIncDec Base; + +public: + MOZ_CONSTEXPR Atomic() : Base() {} + explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + + using Base::operator=; + + T operator+=(T aDelta) + { + return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; + } + + T operator-=(T aDelta) + { + return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; + } + + T operator|=(T aVal) + { + return Base::Intrinsics::or_(Base::mValue, aVal) | aVal; + } + + T operator^=(T aVal) + { + return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal; + } + + T operator&=(T aVal) + { + return Base::Intrinsics::and_(Base::mValue, aVal) & aVal; + } + +private: + Atomic(Atomic& aOther) MOZ_DELETE; +}; + +/** + * Atomic implementation for pointer types. + * + * An atomic compare-and-swap primitive for pointer variables is provided, as + * are atomic increment and decement operators. Also provided are the compound + * assignment operators for addition and subtraction. Atomic swap (via + * exchange()) is included as well. + */ +template +class Atomic : public detail::AtomicBaseIncDec +{ + typedef typename detail::AtomicBaseIncDec Base; + +public: + MOZ_CONSTEXPR Atomic() : Base() {} + explicit MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {} + + using Base::operator=; + + T* operator+=(ptrdiff_t aDelta) + { + return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; + } + + T* operator-=(ptrdiff_t aDelta) + { + return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; + } + +private: + Atomic(Atomic& aOther) MOZ_DELETE; +}; + +/** + * Atomic implementation for enum types. + * + * The atomic store and load operations and the atomic swap method is provided. + */ +template +class Atomic::value>::Type> + : public detail::AtomicBase +{ + typedef typename detail::AtomicBase Base; + +public: + MOZ_CONSTEXPR Atomic() : Base() {} + explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + + operator T() const { return Base::Intrinsics::load(Base::mValue); } + + using Base::operator=; + +private: + Atomic(Atomic& aOther) MOZ_DELETE; +}; + +/** + * Atomic implementation for boolean types. + * + * The atomic store and load operations and the atomic swap method is provided. + * + * Note: + * + * - sizeof(Atomic) != sizeof(bool) for some implementations of + * bool and/or some implementations of std::atomic. This is allowed in + * [atomic.types.generic]p9. + * + * - It's not obvious whether the 8-bit atomic functions on Windows are always + * inlined or not. If they are not inlined, the corresponding functions in the + * runtime library are not available on Windows XP. This is why we implement + * Atomic with an underlying type of uint32_t. + */ +template +class Atomic + : protected detail::AtomicBase +{ + typedef typename detail::AtomicBase Base; + +public: + MOZ_CONSTEXPR Atomic() : Base() {} + explicit MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} + + // We provide boolean wrappers for the underlying AtomicBase methods. + operator bool() const + { + return Base::Intrinsics::load(Base::mValue); + } + + bool operator=(bool aVal) + { + return Base::operator=(aVal); + } + + bool exchange(bool aVal) + { + return Base::exchange(aVal); + } + + bool compareExchange(bool aOldValue, bool aNewValue) + { + return Base::compareExchange(aOldValue, aNewValue); + } + +private: + Atomic(Atomic& aOther) MOZ_DELETE; +}; + +} // namespace mozilla + +#endif /* mozilla_Atomics_h */ diff --git a/libazure/include/mozilla/Attributes.h b/libazure/mozilla/Attributes.h similarity index 59% rename from libazure/include/mozilla/Attributes.h rename to libazure/mozilla/Attributes.h index 2f2d12e..cdce8c7 100644 --- a/libazure/include/mozilla/Attributes.h +++ b/libazure/mozilla/Attributes.h @@ -1,46 +1,43 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Implementations of various class and method modifier attributes. */ -#ifndef mozilla_Attributes_h_ -#define mozilla_Attributes_h_ +#ifndef mozilla_Attributes_h +#define mozilla_Attributes_h #include "mozilla/Compiler.h" -/* - * MOZ_INLINE is a macro which expands to tell the compiler that the method - * decorated with it should be inlined. This macro is usable from C and C++ - * code, even though C89 does not support the |inline| keyword. The compiler - * may ignore this directive if it chooses. - */ -#if defined(__cplusplus) -# define MOZ_INLINE inline -#elif defined(_MSC_VER) -# define MOZ_INLINE __inline -#elif defined(__GNUC__) -# define MOZ_INLINE __inline__ -#else -# define MOZ_INLINE inline -#endif - /* * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the * method decorated with it must be inlined, even if the compiler thinks - * otherwise. This is only a (much) stronger version of the MOZ_INLINE hint: + * otherwise. This is only a (much) stronger version of the inline hint: * compilers are not guaranteed to respect it (although they're much more likely * to do so). + * + * The MOZ_ALWAYS_INLINE_EVEN_DEBUG macro is yet stronger. It tells the + * compiler to inline even in DEBUG builds. It should be used very rarely. */ #if defined(_MSC_VER) -# define MOZ_ALWAYS_INLINE __forceinline +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline #elif defined(__GNUC__) -# define MOZ_ALWAYS_INLINE __attribute__((always_inline)) MOZ_INLINE +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline +#else +# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline +#endif + +#if !defined(DEBUG) +# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG +#elif defined(_MSC_VER) && !defined(__cplusplus) +# define MOZ_ALWAYS_INLINE __inline #else -# define MOZ_ALWAYS_INLINE MOZ_INLINE +# define MOZ_ALWAYS_INLINE inline #endif +#if defined(_MSC_VER) /* * g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality * without warnings (functionality used by the macros below). These modes are @@ -48,8 +45,27 @@ * standardly, by checking whether __cplusplus has a C++11 or greater value. * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. + * + * Even though some versions of MSVC support explicit conversion operators, we + * don't indicate support for them here, due to + * http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug */ -#if defined(__clang__) +# if _MSC_VER >= 1800 +# define MOZ_HAVE_CXX11_DELETE +# endif +# if _MSC_VER >= 1700 +# define MOZ_HAVE_CXX11_FINAL final +# else +# if defined(__clang__) +# error Please do not try to use clang-cl with MSVC10 or below emulation! +# endif + /* MSVC <= 10 used to spell "final" as "sealed". */ +# define MOZ_HAVE_CXX11_FINAL sealed +# endif +# define MOZ_HAVE_CXX11_OVERRIDE +# define MOZ_HAVE_NEVER_INLINE __declspec(noinline) +# define MOZ_HAVE_NORETURN __declspec(noreturn) +#elif defined(__clang__) /* * Per Clang documentation, "Note that marketing version numbers should not * be used to check for language features, as different vendors use different @@ -61,6 +77,9 @@ # if __has_extension(cxx_constexpr) # define MOZ_HAVE_CXX11_CONSTEXPR # endif +# if __has_extension(cxx_explicit_conversions) +# define MOZ_HAVE_EXPLICIT_CONVERSION +# endif # if __has_extension(cxx_deleted_functions) # define MOZ_HAVE_CXX11_DELETE # endif @@ -83,6 +102,9 @@ # if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) # define MOZ_HAVE_CXX11_CONSTEXPR # endif +# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) +# define MOZ_HAVE_EXPLICIT_CONVERSION +# endif # define MOZ_HAVE_CXX11_DELETE # else /* __final is a non-C++11 GCC synonym for 'final', per GCC r176655. */ @@ -92,27 +114,59 @@ # endif # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # define MOZ_HAVE_NORETURN __attribute__((noreturn)) -#elif defined(_MSC_VER) -# if _MSC_VER >= 1700 -# define MOZ_HAVE_CXX11_FINAL final -# else - /* MSVC <= 10 used to spell "final" as "sealed". */ -# define MOZ_HAVE_CXX11_FINAL sealed +#endif + +/* + * When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN + * to mark some false positives + */ +#ifdef __clang_analyzer__ +# if __has_extension(attribute_analyzer_noreturn) +# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) # endif -# define MOZ_HAVE_CXX11_OVERRIDE -# define MOZ_HAVE_NEVER_INLINE __declspec(noinline) -# define MOZ_HAVE_NORETURN __declspec(noreturn) #endif /* * The MOZ_CONSTEXPR specifier declares that a C++11 compiler can evaluate a * function at compile time. A constexpr function cannot examine any values * except its arguments and can have no side effects except its return value. + * The MOZ_CONSTEXPR_VAR specifier tells a C++11 compiler that a variable's + * value may be computed at compile time. It should be prefered to just + * marking variables as MOZ_CONSTEXPR because if the compiler does not support + * constexpr it will fall back to making the variable const, and some compilers + * do not accept variables being marked both const and constexpr. */ #ifdef MOZ_HAVE_CXX11_CONSTEXPR # define MOZ_CONSTEXPR constexpr +# define MOZ_CONSTEXPR_VAR constexpr #else # define MOZ_CONSTEXPR /* no support */ +# define MOZ_CONSTEXPR_VAR const +#endif + +/* + * MOZ_EXPLICIT_CONVERSION is a specifier on a type conversion + * overloaded operator that declares that a C++11 compiler should restrict + * this operator to allow only explicit type conversions, disallowing + * implicit conversions. + * + * Example: + * + * template + * class Ptr + * { + * T* mPtr; + * MOZ_EXPLICIT_CONVERSION operator bool() const + * { + * return mPtr != nullptr; + * } + * }; + * + */ +#ifdef MOZ_HAVE_EXPLICIT_CONVERSION +# define MOZ_EXPLICIT_CONVERSION explicit +#else +# define MOZ_EXPLICIT_CONVERSION /* no support */ #endif /* @@ -147,19 +201,67 @@ # define MOZ_NORETURN /* no support */ #endif +/* + * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function + * declaration, indicates that for the purposes of static analysis, this + * function does not return. (The function definition does not need to be + * annotated.) + * + * MOZ_ReportCrash(const char* s, const char* file, int ln) + * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS + * + * Some static analyzers, like scan-build from clang, can use this information + * to eliminate false positives. From the upstream documentation of scan-build: + * "This attribute is useful for annotating assertion handlers that actually + * can return, but for the purpose of using the analyzer we want to pretend + * that such functions do not return." + * + */ +#if defined(MOZ_HAVE_ANALYZER_NORETURN) +# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN +#else +# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ +#endif + /* * MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time + * instrumentation shipped with Clang and GCC) to not instrument the annotated + * function. Furthermore, it will prevent the compiler from inlining the + * function because inlining currently breaks the blacklisting mechanism of + * AddressSanitizer. + */ +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +# define MOZ_HAVE_ASAN_BLACKLIST +# endif +#elif defined(__GNUC__) +# if defined(__SANITIZE_ADDRESS__) +# define MOZ_HAVE_ASAN_BLACKLIST +# endif +#endif + +#if defined(MOZ_HAVE_ASAN_BLACKLIST) +# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) +#else +# define MOZ_ASAN_BLACKLIST /* nothing */ +#endif + +/* + * MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time * instrumentation shipped with Clang) to not instrument the annotated function. * Furthermore, it will prevent the compiler from inlining the function because - * inlining currently breaks the blacklisting mechanism of AddressSanitizer. + * inlining currently breaks the blacklisting mechanism of ThreadSanitizer. */ -#if defined(MOZ_ASAN) -# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_address_safety_analysis)) -# else -# define MOZ_ASAN_BLACKLIST +#if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) +# else +# define MOZ_TSAN_BLACKLIST /* nothing */ +# endif +#else +# define MOZ_TSAN_BLACKLIST /* nothing */ #endif - #ifdef __cplusplus /* @@ -172,9 +274,9 @@ * * struct NonCopyable * { - * private: - * NonCopyable(const NonCopyable& other) MOZ_DELETE; - * void operator=(const NonCopyable& other) MOZ_DELETE; + * private: + * NonCopyable(const NonCopyable& aOther) MOZ_DELETE; + * void operator=(const NonCopyable& aOther) MOZ_DELETE; * }; * * If MOZ_DELETE can't be implemented for the current compiler, use of the @@ -200,23 +302,23 @@ * * class Base * { - * public: - * virtual void f() = 0; + * public: + * virtual void f() = 0; * }; * class Derived1 : public Base * { - * public: - * virtual void f() MOZ_OVERRIDE; + * public: + * virtual void f() MOZ_OVERRIDE; * }; * class Derived2 : public Base * { - * public: - * virtual void f() MOZ_OVERRIDE = 0; + * public: + * virtual void f() MOZ_OVERRIDE = 0; * }; * class Derived3 : public Base * { - * public: - * virtual void f() MOZ_OVERRIDE { } + * public: + * virtual void f() MOZ_OVERRIDE { } * }; * * In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that @@ -244,16 +346,16 @@ * * class Base MOZ_FINAL * { - * public: - * Base(); - * ~Base(); - * virtual void f() { } + * public: + * Base(); + * ~Base(); + * virtual void f() { } * }; * // This will be an error in some compilers: * class Derived : public Base * { - * public: - * ~Derived() { } + * public: + * ~Derived() { } * }; * * One particularly common reason to specify MOZ_FINAL upon a class is to tell @@ -280,14 +382,14 @@ * * class Base * { - * public: - * virtual void f() MOZ_FINAL; + * public: + * virtual void f() MOZ_FINAL; * }; * class Derived * { - * public: - * // This will be an error in some compilers: - * virtual void f(); + * public: + * // This will be an error in some compilers: + * virtual void f(); * }; * * In compilers implementing final controls, it is an error for a derived class @@ -347,13 +449,13 @@ * * typedef int MOZ_TYPE_ATTRIBUTE MagicInt; * int MOZ_TYPE_ATTRIBUTE someVariable; - * int * MOZ_TYPE_ATTRIBUTE magicPtrInt; - * int MOZ_TYPE_ATTRIBUTE * ptrToMagicInt; + * int* MOZ_TYPE_ATTRIBUTE magicPtrInt; + * int MOZ_TYPE_ATTRIBUTE* ptrToMagicInt; * * Attributes that apply to statements precede the statement: * * MOZ_IF_ATTRIBUTE if (x == 0) - * MOZ_DO_ATTRIBUTE do { } while(0); + * MOZ_DO_ATTRIBUTE do { } while (0); * * Attributes that apply to labels precede the label: * @@ -370,13 +472,65 @@ * attribute is not limited to virtual methods, so if it is applied to a * nonvirtual method and the subclass does not provide an equivalent * definition, the compiler will emit an error. + * MOZ_STACK_CLASS: Applies to all classes. Any class with this annotation is + * expected to live on the stack, so it is a compile-time error to use it, or + * an array of such objects, as a global or static variable, or as the type of + * a new expression (unless placement new is being used). If a member of + * another class uses this class, or if another class inherits from this + * class, then it is considered to be a stack class as well, although this + * attribute need not be provided in such cases. + * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is + * expected to live on the stack or in static storage, so it is a compile-time + * error to use it, or an array of such objects, as the type of a new + * expression (unless placement new is being used). If a member of another + * class uses this class, or if another class inherits from this class, then + * it is considered to be a non-heap class as well, although this attribute + * need not be provided in such cases. + * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return + * value is allocated on the heap, and will as a result check such allocations + * during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking. + * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors + * are disallowed by default unless they are marked as MOZ_IMPLICIT. This + * attribute must be used for constructors which intend to provide implicit + * conversions. */ #ifdef MOZ_CLANG_PLUGIN -# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) +/* + * It turns out that clang doesn't like void func() __attribute__ {} without a + * warning, so use pragmas to disable the warning. This code won't work on GCC + * anyways, so the warning is safe to ignore. + */ +# define MOZ_HEAP_ALLOCATOR \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("clang diagnostic pop") #else -# define MOZ_MUST_OVERRIDE /* nothing */ +# define MOZ_MUST_OVERRIDE /* nothing */ +# define MOZ_STACK_CLASS /* nothing */ +# define MOZ_NONHEAP_CLASS /* nothing */ +# define MOZ_IMPLICIT /* nothing */ +# define MOZ_HEAP_ALLOCATOR /* nothing */ #endif /* MOZ_CLANG_PLUGIN */ +/* + * MOZ_THIS_IN_INITIALIZER_LIST is used to avoid a warning when we know that + * it's safe to use 'this' in an initializer list. + */ +#ifdef _MSC_VER +# define MOZ_THIS_IN_INITIALIZER_LIST() \ + __pragma(warning(push)) \ + __pragma(warning(disable:4355)) \ + this \ + __pragma(warning(pop)) +#else +# define MOZ_THIS_IN_INITIALIZER_LIST() this +#endif + #endif /* __cplusplus */ -#endif /* mozilla_Attributes_h_ */ +#endif /* mozilla_Attributes_h */ diff --git a/libazure/mozilla/BinarySearch.h b/libazure/mozilla/BinarySearch.h new file mode 100644 index 0000000..e4cebdf --- /dev/null +++ b/libazure/mozilla/BinarySearch.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_BinarySearch_h +#define mozilla_BinarySearch_h + +#include "mozilla/Assertions.h" + +#include + +namespace mozilla { + +/* + * The BinarySearch() algorithm searches the given container |aContainer| over + * the sorted index range [aBegin, aEnd) for an index |i| where + * |aContainer[i] == aTarget|. + * If such an index |i| is found, BinarySearch returns |true| and the index is + * returned via the outparam |aMatchOrInsertionPoint|. If no index is found, + * BinarySearch returns |false| and the outparam returns the first index in + * [aBegin, aEnd] where |aTarget| can be inserted to maintain sorted order. + * + * Example: + * + * Vector sortedInts = ... + * + * size_t match; + * if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match)) { + * printf("found 13 at %lu\n", match); + * } + * + * The BinarySearchIf() version behaves similar, but takes |aComparator|, a + * functor to compare the values with, instead of a value to find. + * That functor should take one argument - the value to compare - and return an + * |int| with the comparison result: + * + * * 0, if the argument is equal to, + * * less than 0, if the argument is greater than, + * * greater than 0, if the argument is less than + * + * the value. + * + * Example: + * + * struct Comparator { + * int operator()(int val) const { + * if (mTarget < val) return -1; + * if (mValue > val) return 1; + * return 0; + * } + * Comparator(int target) : mTarget(target) {} + const int mTarget; + * }; + * + * Vector sortedInts = ... + * + * size_t match; + * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) { + * printf("found 13 at %lu\n", match); + * } + * + */ + +template +bool +BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd, + const Comparator& aCompare, size_t* aMatchOrInsertionPoint) +{ + MOZ_ASSERT(aBegin <= aEnd); + + size_t low = aBegin; + size_t high = aEnd; + while (high != low) { + size_t middle = low + (high - low) / 2; + + // Allow any intermediate type so long as it provides a suitable ordering + // relation. + const int result = aCompare(aContainer[middle]); + + if (result == 0) { + *aMatchOrInsertionPoint = middle; + return true; + } + + if (result < 0) { + high = middle; + } else { + low = middle + 1; + } + } + + *aMatchOrInsertionPoint = low; + return false; +} + +namespace detail { + +template +class BinarySearchDefaultComparator +{ +public: + explicit BinarySearchDefaultComparator(const T& aTarget) + : mTarget(aTarget) + {} + + template + int operator()(const U& val) const { + if (mTarget == val) { + return 0; + } + + if (mTarget < val) { + return -1; + } + + return 1; + } + +private: + const T& mTarget; +}; + +} // namespace detail + +template +bool +BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd, + T aTarget, size_t* aMatchOrInsertionPoint) +{ + return BinarySearchIf(aContainer, aBegin, aEnd, + detail::BinarySearchDefaultComparator(aTarget), + aMatchOrInsertionPoint); +} + +} // namespace mozilla + +#endif // mozilla_BinarySearch_h diff --git a/libazure/mozilla/BloomFilter.h b/libazure/mozilla/BloomFilter.h new file mode 100644 index 0000000..6757e41 --- /dev/null +++ b/libazure/mozilla/BloomFilter.h @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * A counting Bloom filter implementation. This allows consumers to + * do fast probabilistic "is item X in set Y?" testing which will + * never answer "no" when the correct answer is "yes" (but might + * incorrectly answer "yes" when the correct answer is "no"). + */ + +#ifndef mozilla_BloomFilter_h +#define mozilla_BloomFilter_h + +#include "mozilla/Assertions.h" +#include "mozilla/Likely.h" + +#include +#include + +namespace mozilla { + +/* + * This class implements a counting Bloom filter as described at + * , with + * 8-bit counters. This allows quick probabilistic answers to the + * question "is object X in set Y?" where the contents of Y might not + * be time-invariant. The probabilistic nature of the test means that + * sometimes the answer will be "yes" when it should be "no". If the + * answer is "no", then X is guaranteed not to be in Y. + * + * The filter is parametrized on KeySize, which is the size of the key + * generated by each of hash functions used by the filter, in bits, + * and the type of object T being added and removed. T must implement + * a |uint32_t hash() const| method which returns a uint32_t hash key + * that will be used to generate the two separate hash functions for + * the Bloom filter. This hash key MUST be well-distributed for good + * results! KeySize is not allowed to be larger than 16. + * + * The filter uses exactly 2**KeySize bytes of memory. From now on we + * will refer to the memory used by the filter as M. + * + * The expected rate of incorrect "yes" answers depends on M and on + * the number N of objects in set Y. As long as N is small compared + * to M, the rate of such answers is expected to be approximately + * 4*(N/M)**2 for this filter. In practice, if Y has a few hundred + * elements then using a KeySize of 12 gives a reasonably low + * incorrect answer rate. A KeySize of 12 has the additional benefit + * of using exactly one page for the filter in typical hardware + * configurations. + */ + +template +class BloomFilter +{ + /* + * A counting Bloom filter with 8-bit counters. For now we assume + * that having two hash functions is enough, but we may revisit that + * decision later. + * + * The filter uses an array with 2**KeySize entries. + * + * Assuming a well-distributed hash function, a Bloom filter with + * array size M containing N elements and + * using k hash function has expected false positive rate exactly + * + * $ (1 - (1 - 1/M)^{kN})^k $ + * + * because each array slot has a + * + * $ (1 - 1/M)^{kN} $ + * + * chance of being 0, and the expected false positive rate is the + * probability that all of the k hash functions will hit a nonzero + * slot. + * + * For reasonable assumptions (M large, kN large, which should both + * hold if we're worried about false positives) about M and kN this + * becomes approximately + * + * $$ (1 - \exp(-kN/M))^k $$ + * + * For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$, + * or in other words + * + * $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$ + * + * where r is the false positive rate. This can be used to compute + * the desired KeySize for a given load N and false positive rate r. + * + * If N/M is assumed small, then the false positive rate can + * further be approximated as 4*N^2/M^2. So increasing KeySize by + * 1, which doubles M, reduces the false positive rate by about a + * factor of 4, and a false positive rate of 1% corresponds to + * about M/N == 20. + * + * What this means in practice is that for a few hundred keys using a + * KeySize of 12 gives false positive rates on the order of 0.25-4%. + * + * Similarly, using a KeySize of 10 would lead to a 4% false + * positive rate for N == 100 and to quite bad false positive + * rates for larger N. + */ +public: + BloomFilter() + { + static_assert(KeySize <= kKeyShift, "KeySize too big"); + + // Should we have a custom operator new using calloc instead and + // require that we're allocated via the operator? + clear(); + } + + /* + * Clear the filter. This should be done before reusing it, because + * just removing all items doesn't clear counters that hit the upper + * bound. + */ + void clear(); + + /* + * Add an item to the filter. + */ + void add(const T* aValue); + + /* + * Remove an item from the filter. + */ + void remove(const T* aValue); + + /* + * Check whether the filter might contain an item. This can + * sometimes return true even if the item is not in the filter, + * but will never return false for items that are actually in the + * filter. + */ + bool mightContain(const T* aValue) const; + + /* + * Methods for add/remove/contain when we already have a hash computed + */ + void add(uint32_t aHash); + void remove(uint32_t aHash); + bool mightContain(uint32_t aHash) const; + +private: + static const size_t kArraySize = (1 << KeySize); + static const uint32_t kKeyMask = (1 << KeySize) - 1; + static const uint32_t kKeyShift = 16; + + static uint32_t hash1(uint32_t aHash) + { + return aHash & kKeyMask; + } + static uint32_t hash2(uint32_t aHash) + { + return (aHash >> kKeyShift) & kKeyMask; + } + + uint8_t& firstSlot(uint32_t aHash) + { + return mCounters[hash1(aHash)]; + } + uint8_t& secondSlot(uint32_t aHash) + { + return mCounters[hash2(aHash)]; + } + + const uint8_t& firstSlot(uint32_t aHash) const + { + return mCounters[hash1(aHash)]; + } + const uint8_t& secondSlot(uint32_t aHash) const + { + return mCounters[hash2(aHash)]; + } + + static bool full(const uint8_t& aSlot) { return aSlot == UINT8_MAX; } + + uint8_t mCounters[kArraySize]; +}; + +template +inline void +BloomFilter::clear() +{ + memset(mCounters, 0, kArraySize); +} + +template +inline void +BloomFilter::add(uint32_t aHash) +{ + uint8_t& slot1 = firstSlot(aHash); + if (MOZ_LIKELY(!full(slot1))) { + ++slot1; + } + uint8_t& slot2 = secondSlot(aHash); + if (MOZ_LIKELY(!full(slot2))) { + ++slot2; + } +} + +template +MOZ_ALWAYS_INLINE void +BloomFilter::add(const T* aValue) +{ + uint32_t hash = aValue->hash(); + return add(hash); +} + +template +inline void +BloomFilter::remove(uint32_t aHash) +{ + // If the slots are full, we don't know whether we bumped them to be + // there when we added or not, so just leave them full. + uint8_t& slot1 = firstSlot(aHash); + if (MOZ_LIKELY(!full(slot1))) { + --slot1; + } + uint8_t& slot2 = secondSlot(aHash); + if (MOZ_LIKELY(!full(slot2))) { + --slot2; + } +} + +template +MOZ_ALWAYS_INLINE void +BloomFilter::remove(const T* aValue) +{ + uint32_t hash = aValue->hash(); + remove(hash); +} + +template +MOZ_ALWAYS_INLINE bool +BloomFilter::mightContain(uint32_t aHash) const +{ + // Check that all the slots for this hash contain something + return firstSlot(aHash) && secondSlot(aHash); +} + +template +MOZ_ALWAYS_INLINE bool +BloomFilter::mightContain(const T* aValue) const +{ + uint32_t hash = aValue->hash(); + return mightContain(hash); +} + +} // namespace mozilla + +#endif /* mozilla_BloomFilter_h */ diff --git a/libazure/mozilla/Casting.h b/libazure/mozilla/Casting.h new file mode 100644 index 0000000..176e54d --- /dev/null +++ b/libazure/mozilla/Casting.h @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Cast operations to supplement the built-in casting operations. */ + +#ifndef mozilla_Casting_h +#define mozilla_Casting_h + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +/** + * Return a value of type |To|, containing the underlying bit pattern of + * |aFrom|. + * + * |To| and |From| must be types of the same size; be careful of cross-platform + * size differences, or this might fail to compile on some but not all + * platforms. + */ +template +inline To +BitwiseCast(const From aFrom) +{ + static_assert(sizeof(From) == sizeof(To), + "To and From must have the same size"); + union + { + From mFrom; + To mTo; + } u; + u.mFrom = aFrom; + return u.mTo; +} + +namespace detail { + +enum ToSignedness { ToIsSigned, ToIsUnsigned }; +enum FromSignedness { FromIsSigned, FromIsUnsigned }; + +template::value ? FromIsSigned : FromIsUnsigned, + ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> +struct BoundsCheckImpl; + +// Implicit conversions on operands to binary operations make this all a bit +// hard to verify. Attempt to ease the pain below by *only* comparing values +// that are obviously the same type (and will undergo no further conversions), +// even when it's not strictly necessary, for explicitness. + +enum UUComparison { FromIsBigger, FromIsNotBigger }; + +// Unsigned-to-unsigned range check + +template sizeof(To)) + ? FromIsBigger + : FromIsNotBigger> +struct UnsignedUnsignedCheck; + +template +struct UnsignedUnsignedCheck +{ +public: + static bool checkBounds(const From aFrom) + { + return aFrom <= From(To(-1)); + } +}; + +template +struct UnsignedUnsignedCheck +{ +public: + static bool checkBounds(const From aFrom) + { + return true; + } +}; + +template +struct BoundsCheckImpl +{ +public: + static bool checkBounds(const From aFrom) + { + return UnsignedUnsignedCheck::checkBounds(aFrom); + } +}; + +// Signed-to-unsigned range check + +template +struct BoundsCheckImpl +{ +public: + static bool checkBounds(const From aFrom) + { + if (aFrom < 0) { + return false; + } + if (sizeof(To) >= sizeof(From)) { + return true; + } + return aFrom <= From(To(-1)); + } +}; + +// Unsigned-to-signed range check + +enum USComparison { FromIsSmaller, FromIsNotSmaller }; + +template +struct UnsignedSignedCheck; + +template +struct UnsignedSignedCheck +{ +public: + static bool checkBounds(const From aFrom) + { + return true; + } +}; + +template +struct UnsignedSignedCheck +{ +public: + static bool checkBounds(const From aFrom) + { + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); + return aFrom <= From(MaxValue); + } +}; + +template +struct BoundsCheckImpl +{ +public: + static bool checkBounds(const From aFrom) + { + return UnsignedSignedCheck::checkBounds(aFrom); + } +}; + +// Signed-to-signed range check + +template +struct BoundsCheckImpl +{ +public: + static bool checkBounds(const From aFrom) + { + if (sizeof(From) <= sizeof(To)) { + return true; + } + const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); + const To MinValue = -MaxValue - To(1); + return From(MinValue) <= aFrom && + From(aFrom) <= From(MaxValue); + } +}; + +template::value && + IsIntegral::value> +class BoundsChecker; + +template +class BoundsChecker +{ +public: + static bool checkBounds(const From aFrom) { return true; } +}; + +template +class BoundsChecker +{ +public: + static bool checkBounds(const From aFrom) + { + return BoundsCheckImpl::checkBounds(aFrom); + } +}; + +template +inline bool +IsInBounds(const From aFrom) +{ + return BoundsChecker::checkBounds(aFrom); +} + +} // namespace detail + +/** + * Cast a value of integral type |From| to a value of integral type |To|, + * asserting that the cast will be a safe cast per C++ (that is, that |to| is in + * the range of values permitted for the type |From|). + */ +template +inline To +AssertedCast(const From aFrom) +{ + MOZ_ASSERT((detail::IsInBounds(aFrom))); + return static_cast(aFrom); +} + +} // namespace mozilla + +#endif /* mozilla_Casting_h */ diff --git a/libazure/mozilla/ChaosMode.h b/libazure/mozilla/ChaosMode.h new file mode 100644 index 0000000..ff59f2c --- /dev/null +++ b/libazure/mozilla/ChaosMode.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ChaosMode_h +#define mozilla_ChaosMode_h + +#include +#include + +namespace mozilla { + +/** + * When "chaos mode" is activated, code that makes implicitly nondeterministic + * choices is encouraged to make random and extreme choices, to test more + * code paths and uncover bugs. + */ +class ChaosMode +{ +public: + static bool isActive() + { + // Flip this to true to activate chaos mode + return false; + } + + /** + * Returns a somewhat (but not uniformly) random uint32_t < aBound. + * Not to be used for anything except ChaosMode, since it's not very random. + */ + static uint32_t randomUint32LessThan(uint32_t aBound) + { + return uint32_t(rand()) % aBound; + } +}; + +} /* namespace mozilla */ + +#endif /* mozilla_ChaosMode_h */ diff --git a/libazure/mozilla/Char16.h b/libazure/mozilla/Char16.h new file mode 100644 index 0000000..e54eb0d --- /dev/null +++ b/libazure/mozilla/Char16.h @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Implements a UTF-16 character type. */ + +#ifndef mozilla_Char16_h +#define mozilla_Char16_h + +#ifdef __cplusplus + +/* + * C++11 introduces a char16_t type and support for UTF-16 string and character + * literals. C++11's char16_t is a distinct builtin type. Technically, char16_t + * is a 16-bit code unit of a Unicode code point, not a "character". + */ + +#ifdef _MSC_VER + /* + * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h + * typedefs char16_t as an unsigned short. We would like to alias char16_t + * to Windows's 16-bit wchar_t so we can declare UTF-16 literals as constant + * expressions (and pass char16_t pointers to Windows APIs). We #define + * _CHAR16T here in order to prevent yvals.h from overriding our char16_t + * typedefs, which we set to wchar_t for C++ code. + * + * In addition, #defining _CHAR16T will prevent yvals.h from defining a + * char32_t type, so we have to undo that damage here and provide our own, + * which is identical to the yvals.h type. + */ +# define MOZ_UTF16_HELPER(s) L##s +# define _CHAR16T +typedef wchar_t char16_t; +typedef unsigned int char32_t; +#else + /* C++11 has a builtin char16_t type. */ +# define MOZ_UTF16_HELPER(s) u##s + /** + * This macro is used to distinguish when char16_t would be a distinct + * typedef from wchar_t. + */ +# define MOZ_CHAR16_IS_NOT_WCHAR +# ifdef WIN32 +# define MOZ_USE_CHAR16_WRAPPER +# endif +#endif + +#ifdef MOZ_USE_CHAR16_WRAPPER +# include + /** + * Win32 API extensively uses wchar_t, which is represented by a separated + * builtin type than char16_t per spec. It's not the case for MSVC, but GCC + * follows the spec. We want to mix wchar_t and char16_t on Windows builds. + * This class is supposed to make it easier. It stores char16_t const pointer, + * but provides implicit casts for wchar_t as well. On other platforms, we + * simply use |typedef const char16_t* char16ptr_t|. Here, we want to make + * the class as similar to this typedef, including providing some casts that + * are allowed by the typedef. + */ +class char16ptr_t +{ +private: + const char16_t* mPtr; + static_assert(sizeof(char16_t) == sizeof(wchar_t), + "char16_t and wchar_t sizes differ"); + +public: + char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} + char16ptr_t(const wchar_t* aPtr) : + mPtr(reinterpret_cast(aPtr)) + {} + + /* Without this, nullptr assignment would be ambiguous. */ + constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} + + operator const char16_t*() const + { + return mPtr; + } + operator const wchar_t*() const + { + return reinterpret_cast(mPtr); + } + operator const void*() const + { + return mPtr; + } + operator bool() const + { + return mPtr != nullptr; + } + operator std::wstring() const + { + return std::wstring(static_cast(*this)); + } + + /* Explicit cast operators to allow things like (char16_t*)str. */ + explicit operator char16_t*() const + { + return const_cast(mPtr); + } + explicit operator wchar_t*() const + { + return const_cast(static_cast(*this)); + } + + /** + * Some Windows API calls accept BYTE* but require that data actually be + * WCHAR*. Supporting this requires explicit operators to support the + * requisite explicit casts. + */ + explicit operator const char*() const + { + return reinterpret_cast(mPtr); + } + explicit operator const unsigned char*() const + { + return reinterpret_cast(mPtr); + } + explicit operator unsigned char*() const + { + return + const_cast(reinterpret_cast(mPtr)); + } + explicit operator void*() const + { + return const_cast(mPtr); + } + + /* Some operators used on pointers. */ + char16_t operator[](size_t aIndex) const + { + return mPtr[aIndex]; + } + bool operator==(const char16ptr_t& aOther) const + { + return mPtr == aOther.mPtr; + } + bool operator==(decltype(nullptr)) const + { + return mPtr == nullptr; + } + bool operator!=(const char16ptr_t& aOther) const + { + return mPtr != aOther.mPtr; + } + bool operator!=(decltype(nullptr)) const + { + return mPtr != nullptr; + } + char16ptr_t operator+(size_t aValue) const + { + return char16ptr_t(mPtr + aValue); + } + ptrdiff_t operator-(const char16ptr_t& aOther) const + { + return mPtr - aOther.mPtr; + } +}; + +inline decltype((char*)0-(char*)0) +operator-(const char16_t* aX, const char16ptr_t aY) +{ + return aX - static_cast(aY); +} + +#else + +typedef const char16_t* char16ptr_t; + +#endif + +/* + * Macro arguments used in concatenation or stringification won't be expanded. + * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to + * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper + * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro + * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the + * CPP manual for a more accurate and precise explanation. + */ +#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) + +static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); +static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?"); +static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); +static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); + +#endif + +#endif /* mozilla_Char16_h */ diff --git a/libazure/mozilla/CheckedInt.h b/libazure/mozilla/CheckedInt.h new file mode 100644 index 0000000..714e8a5 --- /dev/null +++ b/libazure/mozilla/CheckedInt.h @@ -0,0 +1,779 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Provides checked integers, detecting integer overflow and divide-by-0. */ + +#ifndef mozilla_CheckedInt_h +#define mozilla_CheckedInt_h + +#include +#include "mozilla/Assertions.h" +#include "mozilla/IntegerTypeTraits.h" + +namespace mozilla { + +template class CheckedInt; + +namespace detail { + +/* + * Step 1: manually record supported types + * + * What's nontrivial here is that there are different families of integer + * types: basic integer types and stdint types. It is merrily undefined which + * types from one family may be just typedefs for a type from another family. + * + * For example, on GCC 4.6, aside from the basic integer types, the only other + * type that isn't just a typedef for some of them, is int8_t. + */ + +struct UnsupportedType {}; + +template +struct IsSupportedPass2 +{ + static const bool value = false; +}; + +template +struct IsSupported +{ + static const bool value = IsSupportedPass2::value; +}; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + +template<> +struct IsSupported +{ static const bool value = true; }; + + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +template<> +struct IsSupportedPass2 +{ static const bool value = true; }; + +/* + * Step 2: Implement the actual validity checks. + * + * Ideas taken from IntegerLib, code different. + */ + +template +struct TwiceBiggerType +{ + typedef typename detail::StdintTypeForSizeAndSignedness< + sizeof(IntegerType) * 2, + IsSigned::value + >::Type Type; +}; + +template +struct TwiceBiggerType +{ + typedef UnsupportedType Type; +}; + +template +inline bool +HasSignBit(T aX) +{ + // In C++, right bit shifts on negative values is undefined by the standard. + // Notice that signed-to-unsigned conversions are always well-defined in the + // standard, as the value congruent modulo 2**n as expected. By contrast, + // unsigned-to-signed is only well-defined if the value is representable. + return bool(typename MakeUnsigned::Type(aX) >> + PositionOfSignBit::value); +} + +// Bitwise ops may return a larger type, so it's good to use this inline +// helper guaranteeing that the result is really of type T. +template +inline T +BinaryComplement(T aX) +{ + return ~aX; +} + +template::value, + bool IsUSigned = IsSigned::value> +struct DoesRangeContainRange +{ +}; + +template +struct DoesRangeContainRange +{ + static const bool value = sizeof(T) >= sizeof(U); +}; + +template +struct DoesRangeContainRange +{ + static const bool value = sizeof(T) > sizeof(U); +}; + +template +struct DoesRangeContainRange +{ + static const bool value = false; +}; + +template::value, + bool IsUSigned = IsSigned::value, + bool DoesTRangeContainURange = DoesRangeContainRange::value> +struct IsInRangeImpl {}; + +template +struct IsInRangeImpl +{ + static bool run(U) + { + return true; + } +}; + +template +struct IsInRangeImpl +{ + static bool run(U aX) + { + return aX <= MaxValue::value && aX >= MinValue::value; + } +}; + +template +struct IsInRangeImpl +{ + static bool run(U aX) + { + return aX <= MaxValue::value; + } +}; + +template +struct IsInRangeImpl +{ + static bool run(U aX) + { + return sizeof(T) > sizeof(U) || aX <= U(MaxValue::value); + } +}; + +template +struct IsInRangeImpl +{ + static bool run(U aX) + { + return sizeof(T) >= sizeof(U) + ? aX >= 0 + : aX >= 0 && aX <= U(MaxValue::value); + } +}; + +template +inline bool +IsInRange(U aX) +{ + return IsInRangeImpl::run(aX); +} + +template +inline bool +IsAddValid(T aX, T aY) +{ + // Addition is valid if the sign of aX+aY is equal to either that of aX or + // that of aY. Since the value of aX+aY is undefined if we have a signed + // type, we compute it using the unsigned type of the same size. Beware! + // These bitwise operations can return a larger integer type, if T was a + // small type like int8_t, so we explicitly cast to T. + + typename MakeUnsigned::Type ux = aX; + typename MakeUnsigned::Type uy = aY; + typename MakeUnsigned::Type result = ux + uy; + return IsSigned::value + ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY)))) + : BinaryComplement(aX) >= aY; +} + +template +inline bool +IsSubValid(T aX, T aY) +{ + // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX + // have same sign. Since the value of aX-aY is undefined if we have a signed + // type, we compute it using the unsigned type of the same size. + typename MakeUnsigned::Type ux = aX; + typename MakeUnsigned::Type uy = aY; + typename MakeUnsigned::Type result = ux - uy; + + return IsSigned::value + ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY)))) + : aX >= aY; +} + +template::value, + bool TwiceBiggerTypeIsSupported = + IsSupported::Type>::value> +struct IsMulValidImpl {}; + +template +struct IsMulValidImpl +{ + static bool run(T aX, T aY) + { + typedef typename TwiceBiggerType::Type TwiceBiggerType; + TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY); + return IsInRange(product); + } +}; + +template +struct IsMulValidImpl +{ + static bool run(T aX, T aY) + { + const T max = MaxValue::value; + const T min = MinValue::value; + + if (aX == 0 || aY == 0) { + return true; + } + if (aX > 0) { + return aY > 0 + ? aX <= max / aY + : aY >= min / aX; + } + + // If we reach this point, we know that aX < 0. + return aY > 0 + ? aX >= min / aY + : aY >= max / aX; + } +}; + +template +struct IsMulValidImpl +{ + static bool run(T aX, T aY) + { + return aY == 0 || aX <= MaxValue::value / aY; + } +}; + +template +inline bool +IsMulValid(T aX, T aY) +{ + return IsMulValidImpl::run(aX, aY); +} + +template +inline bool +IsDivValid(T aX, T aY) +{ + // Keep in mind that in the signed case, min/-1 is invalid because + // abs(min)>max. + return aY != 0 && + !(IsSigned::value && aX == MinValue::value && aY == T(-1)); +} + +template::value> +struct IsModValidImpl; + +template +inline bool +IsModValid(T aX, T aY) +{ + return IsModValidImpl::run(aX, aY); +} + +/* + * Mod is pretty simple. + * For now, let's just use the ANSI C definition: + * If aX or aY are negative, the results are implementation defined. + * Consider these invalid. + * Undefined for aY=0. + * The result will never exceed either aX or aY. + * + * Checking that aX>=0 is a warning when T is unsigned. + */ + +template +struct IsModValidImpl +{ + static inline bool run(T aX, T aY) + { + return aY >= 1; + } +}; + +template +struct IsModValidImpl +{ + static inline bool run(T aX, T aY) + { + if (aX < 0) { + return false; + } + return aY >= 1; + } +}; + +template::value> +struct NegateImpl; + +template +struct NegateImpl +{ + static CheckedInt negate(const CheckedInt& aVal) + { + // Handle negation separately for signed/unsigned, for simpler code and to + // avoid an MSVC warning negating an unsigned value. + return CheckedInt(0, aVal.isValid() && aVal.mValue == 0); + } +}; + +template +struct NegateImpl +{ + static CheckedInt negate(const CheckedInt& aVal) + { + // Watch out for the min-value, which (with twos-complement) can't be + // negated as -min-value is then (max-value + 1). + if (!aVal.isValid() || aVal.mValue == MinValue::value) { + return CheckedInt(aVal.mValue, false); + } + return CheckedInt(-aVal.mValue, true); + } +}; + +} // namespace detail + + +/* + * Step 3: Now define the CheckedInt class. + */ + +/** + * @class CheckedInt + * @brief Integer wrapper class checking for integer overflow and other errors + * @param T the integer type to wrap. Can be any type among the following: + * - any basic integer type such as |int| + * - any stdint type such as |int8_t| + * + * This class implements guarded integer arithmetic. Do a computation, check + * that isValid() returns true, you then have a guarantee that no problem, such + * as integer overflow, happened during this computation, and you can call + * value() to get the plain integer value. + * + * The arithmetic operators in this class are guaranteed not to raise a signal + * (e.g. in case of a division by zero). + * + * For example, suppose that you want to implement a function that computes + * (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by + * zero or integer overflow). You could code it as follows: + @code + bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult) + { + CheckedInt checkedResult = (CheckedInt(aX) + aY) / aZ; + if (checkedResult.isValid()) { + *aResult = checkedResult.value(); + return true; + } else { + return false; + } + } + @endcode + * + * Implicit conversion from plain integers to checked integers is allowed. The + * plain integer is checked to be in range before being casted to the + * destination type. This means that the following lines all compile, and the + * resulting CheckedInts are correctly detected as valid or invalid: + * @code + // 1 is of type int, is found to be in range for uint8_t, x is valid + CheckedInt x(1); + // -1 is of type int, is found not to be in range for uint8_t, x is invalid + CheckedInt x(-1); + // -1 is of type int, is found to be in range for int8_t, x is valid + CheckedInt x(-1); + // 1000 is of type int16_t, is found not to be in range for int8_t, + // x is invalid + CheckedInt x(int16_t(1000)); + // 3123456789 is of type uint32_t, is found not to be in range for int32_t, + // x is invalid + CheckedInt x(uint32_t(3123456789)); + * @endcode + * Implicit conversion from + * checked integers to plain integers is not allowed. As shown in the + * above example, to get the value of a checked integer as a normal integer, + * call value(). + * + * Arithmetic operations between checked and plain integers is allowed; the + * result type is the type of the checked integer. + * + * Checked integers of different types cannot be used in the same arithmetic + * expression. + * + * There are convenience typedefs for all stdint types, of the following form + * (these are just 2 examples): + @code + typedef CheckedInt CheckedInt32; + typedef CheckedInt CheckedUint16; + @endcode + */ +template +class CheckedInt +{ +protected: + T mValue; + bool mIsValid; + + template + CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid) + { + static_assert(detail::IsSupported::value && + detail::IsSupported::value, + "This type is not supported by CheckedInt"); + } + + friend struct detail::NegateImpl; + +public: + /** + * Constructs a checked integer with given @a value. The checked integer is + * initialized as valid or invalid depending on whether the @a value + * is in range. + * + * This constructor is not explicit. Instead, the type of its argument is a + * separate template parameter, ensuring that no conversion is performed + * before this constructor is actually called. As explained in the above + * documentation for class CheckedInt, this constructor checks that its + * argument is valid. + */ + template + CheckedInt(U aValue) + : mValue(T(aValue)), + mIsValid(detail::IsInRange(aValue)) + { + static_assert(detail::IsSupported::value && + detail::IsSupported::value, + "This type is not supported by CheckedInt"); + } + + template + friend class CheckedInt; + + template + CheckedInt toChecked() const + { + CheckedInt ret(mValue); + ret.mIsValid = ret.mIsValid && mIsValid; + return ret; + } + + /** Constructs a valid checked integer with initial value 0 */ + CheckedInt() : mValue(0), mIsValid(true) + { + static_assert(detail::IsSupported::value, + "This type is not supported by CheckedInt"); + } + + /** @returns the actual value */ + T value() const + { + MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)"); + return mValue; + } + + /** + * @returns true if the checked integer is valid, i.e. is not the result + * of an invalid operation or of an operation involving an invalid checked + * integer + */ + bool isValid() const + { + return mIsValid; + } + + template + friend CheckedInt operator +(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator +=(U aRhs); + + template + friend CheckedInt operator -(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator -=(U aRhs); + + template + friend CheckedInt operator *(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator *=(U aRhs); + + template + friend CheckedInt operator /(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator /=(U aRhs); + + template + friend CheckedInt operator %(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator %=(U aRhs); + + CheckedInt operator -() const + { + return detail::NegateImpl::negate(*this); + } + + /** + * @returns true if the left and right hand sides are valid + * and have the same value. + * + * Note that these semantics are the reason why we don't offer + * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b) + * but that would mean that whenever a or b is invalid, a!=b + * is always true, which would be very confusing. + * + * For similar reasons, operators <, >, <=, >= would be very tricky to + * specify, so we just avoid offering them. + * + * Notice that these == semantics are made more reasonable by these facts: + * 1. a==b implies equality at the raw data level + * (the converse is false, as a==b is never true among invalids) + * 2. This is similar to the behavior of IEEE floats, where a==b + * means that a and b have the same value *and* neither is NaN. + */ + bool operator ==(const CheckedInt& aOther) const + { + return mIsValid && aOther.mIsValid && mValue == aOther.mValue; + } + + /** prefix ++ */ + CheckedInt& operator++() + { + *this += 1; + return *this; + } + + /** postfix ++ */ + CheckedInt operator++(int) + { + CheckedInt tmp = *this; + *this += 1; + return tmp; + } + + /** prefix -- */ + CheckedInt& operator--() + { + *this -= 1; + return *this; + } + + /** postfix -- */ + CheckedInt operator--(int) + { + CheckedInt tmp = *this; + *this -= 1; + return tmp; + } + +private: + /** + * The !=, <, <=, >, >= operators are disabled: + * see the comment on operator==. + */ + template bool operator !=(U aOther) const MOZ_DELETE; + template bool operator < (U aOther) const MOZ_DELETE; + template bool operator <=(U aOther) const MOZ_DELETE; + template bool operator > (U aOther) const MOZ_DELETE; + template bool operator >=(U aOther) const MOZ_DELETE; +}; + +#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ + template \ + inline CheckedInt \ + operator OP(const CheckedInt& aLhs, const CheckedInt& aRhs) \ + { \ + if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \ + return CheckedInt(0, false); \ + } \ + return CheckedInt(aLhs.mValue OP aRhs.mValue, \ + aLhs.mIsValid && aRhs.mIsValid); \ + } + +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %) + +#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR + +// Implement castToCheckedInt(x), making sure that +// - it allows x to be either a CheckedInt or any integer type +// that can be casted to T +// - if x is already a CheckedInt, we just return a reference to it, +// instead of copying it (optimization) + +namespace detail { + +template +struct CastToCheckedIntImpl +{ + typedef CheckedInt ReturnType; + static CheckedInt run(U aU) { return aU; } +}; + +template +struct CastToCheckedIntImpl > +{ + typedef const CheckedInt& ReturnType; + static const CheckedInt& run(const CheckedInt& aU) { return aU; } +}; + +} // namespace detail + +template +inline typename detail::CastToCheckedIntImpl::ReturnType +castToCheckedInt(U aU) +{ + static_assert(detail::IsSupported::value && + detail::IsSupported::value, + "This type is not supported by CheckedInt"); + return detail::CastToCheckedIntImpl::run(aU); +} + +#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ + template \ + template \ + CheckedInt& CheckedInt::operator COMPOUND_OP(U aRhs) \ + { \ + *this = *this OP castToCheckedInt(aRhs); \ + return *this; \ + } \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, U aRhs) \ + { \ + return aLhs OP castToCheckedInt(aRhs); \ + } \ + template \ + inline CheckedInt operator OP(U aLhs, const CheckedInt& aRhs) \ + { \ + return castToCheckedInt(aLhs) OP aRhs; \ + } + +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) +MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=) + +#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS + +template +inline bool +operator ==(const CheckedInt& aLhs, U aRhs) +{ + return aLhs == castToCheckedInt(aRhs); +} + +template +inline bool +operator ==(U aLhs, const CheckedInt& aRhs) +{ + return castToCheckedInt(aLhs) == aRhs; +} + +// Convenience typedefs. +typedef CheckedInt CheckedInt8; +typedef CheckedInt CheckedUint8; +typedef CheckedInt CheckedInt16; +typedef CheckedInt CheckedUint16; +typedef CheckedInt CheckedInt32; +typedef CheckedInt CheckedUint32; +typedef CheckedInt CheckedInt64; +typedef CheckedInt CheckedUint64; + +} // namespace mozilla + +#endif /* mozilla_CheckedInt_h */ diff --git a/libazure/mozilla/Compiler.h b/libazure/mozilla/Compiler.h new file mode 100644 index 0000000..50f127d --- /dev/null +++ b/libazure/mozilla/Compiler.h @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Various compiler checks. */ + +#ifndef mozilla_Compiler_h +#define mozilla_Compiler_h + +#define MOZ_IS_GCC 0 +#define MOS_IS_MSVC 0 + +#if !defined(__clang__) && defined(__GNUC__) + +# undef MOZ_IS_GCC +# define MOZ_IS_GCC 1 + /* + * This macro should simplify gcc version checking. For example, to check + * for gcc 4.5.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 5, 1)`. + */ +# define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ + >= ((major) * 10000 + (minor) * 100 + (patchlevel))) +# if !MOZ_GCC_VERSION_AT_LEAST(4, 4, 0) +# error "mfbt (and Gecko) require at least gcc 4.4 to build." +# endif + +#elif defined(_MSC_VER) + +# undef MOZ_IS_MSVC +# define MOZ_IS_MSVC 1 + /* + * This macro should simplify MSVC version checking. For example, to check + * for VC10 or later, check `#ifdef MOZ_MSVC_VERSION_AT_LEAST(10)`. + */ +# define MOZ_MSVC_VERSION_AT_LEAST(version) \ + (version == 10 ? _MSC_VER >= 1600 : \ + (version == 11 ? _MSC_VER >= 1700 : \ + (version == 12 ? _MSC_VER >= 1800 : \ + (version == 13 ? _MSC_VER >= 1900 : \ + 0)))) +# if !MOZ_MSVC_VERSION_AT_LEAST(10) +# error "mfbt (and Gecko) require at least MSVC 2010 RTM to build." +# endif + +#endif + +/* + * The situation with standard libraries is a lot worse than with compilers, + * particularly as clang and gcc could end up using one of three or so standard + * libraries, and they may not be up-to-snuff with newer C++11 versions. To + * detect the library, we're going to include cstddef (which is a small header + * which will be transitively included by everybody else at some point) to grab + * the version macros and deduce macros from there. + */ +#ifdef __cplusplus +# include +# ifdef _STLPORT_MAJOR +# define MOZ_USING_STLPORT 1 +# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ + (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) +# elif defined(_LIBCPP_VERSION) + /* + * libc++, unfortunately, doesn't appear to have useful versioning macros. + * Hopefully, the recommendations of N3694 with respect to standard libraries + * will get applied instead and we won't need to worry about version numbers + * here. + */ +# define MOZ_USING_LIBCXX 1 +# elif defined(__GLIBCXX__) +# define MOZ_USING_LIBSTDCXX 1 + /* + * libstdc++ is also annoying and doesn't give us useful versioning macros + * for the library. If we're using gcc, then assume that libstdc++ matches + * the compiler version. If we're using clang, we're going to have to fake + * major/minor combinations by looking for newly-defined config macros. + */ +# if MOZ_IS_GCC +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) +# elif defined(_GLIBCXX_THROW_OR_ABORT) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 8)) +# elif defined(_GLIBCXX_NOEXCEPT) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 7)) +# elif defined(_GLIBCXX_USE_DEPRECATED) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 6)) +# elif defined(_GLIBCXX_PSEUDO_VISIBILITY) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 5)) +# elif defined(_GLIBCXX_BEGIN_EXTERN_C) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 4)) +# elif defined(_GLIBCXX_VISIBILITY_ATTR) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 3)) +# elif defined(_GLIBCXX_VISIBILITY) +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 2)) +# else +# error "Your version of libstdc++ is unknown to us and is likely too old." +# endif +# endif + + // Flesh out the defines for everyone else +# ifndef MOZ_USING_STLPORT +# define MOZ_USING_STLPORT 0 +# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 +# endif +# ifndef MOZ_USING_LIBCXX +# define MOZ_USING_LIBCXX 0 +# endif +# ifndef MOZ_USING_LIBSTDCXX +# define MOZ_USING_LIBSTDCXX 0 +# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 +# endif +#endif /* __cplusplus */ + +#endif /* mozilla_Compiler_h */ diff --git a/libazure/mozilla/Compression.h b/libazure/mozilla/Compression.h new file mode 100644 index 0000000..a764a1b --- /dev/null +++ b/libazure/mozilla/Compression.h @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Various simple compression/decompression functions. */ + +#ifndef mozilla_Compression_h_ +#define mozilla_Compression_h_ + +#include "mozilla/Types.h" +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace Compression { + +/** + * LZ4 is a very fast byte-wise compression algorithm. + * + * Compared to Google's Snappy it is faster to compress and decompress and + * generally produces output of about the same size. + * + * Compared to zlib it compresses at about 10x the speed, decompresses at about + * 4x the speed and produces output of about 1.5x the size. + */ + +class LZ4 +{ +public: + /** + * Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination + * buffer must be already allocated, and must be sized to handle worst cases + * situations (input data not compressible). Worst case size evaluation is + * provided by function maxCompressedSize() + * + * @param aInputSize is the input size. Max supported value is ~1.9GB + * @return the number of bytes written in buffer |aDest| + */ + static MFBT_API size_t + compress(const char* aSource, size_t aInputSize, char* aDest); + + /** + * Compress |aInputSize| bytes from |aSource| into an output buffer + * |aDest| of maximum size |aMaxOutputSize|. If it cannot achieve it, + * compression will stop, and result of the function will be zero, + * |aDest| will still be written to, but since the number of input + * bytes consumed is not returned the result is not usable. + * + * This function never writes outside of provided output buffer. + * + * @param aInputSize is the input size. Max supported value is ~1.9GB + * @param aMaxOutputSize is the size of the destination buffer (which must + * be already allocated) + * @return the number of bytes written in buffer |aDest| or 0 if the + * compression fails + */ + static MFBT_API size_t + compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest, + size_t aMaxOutputSize); + + /** + * If the source stream is malformed, the function will stop decoding + * and return a negative result, indicating the byte position of the + * faulty instruction + * + * This function never writes outside of provided buffers, and never + * modifies input buffer. + * + * Note: destination buffer must be already allocated, and its size must be a + * minimum of |aOutputSize| bytes. + * + * @param aOutputSize is the output size, therefore the original size + * @return the number of bytes read in the source buffer + */ + static MFBT_API bool + decompress(const char* aSource, char* aDest, size_t aOutputSize); + + /** + * If the source stream is malformed, the function will stop decoding + * and return false. + * + * This function never writes beyond aDest + aMaxOutputSize, and is + * therefore protected against malicious data packets. + * + * Note: Destination buffer must be already allocated. This version is + * slightly slower than the decompress without the aMaxOutputSize. + * + * @param aInputSize is the length of the input compressed data + * @param aMaxOutputSize is the size of the destination buffer (which must be + * already allocated) + * @param aOutputSize the actual number of bytes decoded in the destination + * buffer (necessarily <= aMaxOutputSize) + */ + static MFBT_API bool + decompress(const char* aSource, size_t aInputSize, char* aDest, + size_t aMaxOutputSize, size_t* aOutputSize); + + /* + * Provides the maximum size that LZ4 may output in a "worst case" + * scenario (input data not compressible) primarily useful for memory + * allocation of output buffer. + * note : this function is limited by "int" range (2^31-1) + * + * @param aInputSize is the input size. Max supported value is ~1.9GB + * @return maximum output size in a "worst case" scenario + */ + static inline size_t maxCompressedSize(size_t aInputSize) + { + size_t max = (aInputSize + (aInputSize / 255) + 16); + MOZ_ASSERT(max > aInputSize); + return max; + } +}; + +} /* namespace Compression */ +} /* namespace mozilla */ + +#endif /* mozilla_Compression_h_ */ diff --git a/libazure/include/mozilla/Constants.h b/libazure/mozilla/Constants.h similarity index 61% rename from libazure/include/mozilla/Constants.h rename to libazure/mozilla/Constants.h index 904b301..86bbb6b 100644 --- a/libazure/include/mozilla/Constants.h +++ b/libazure/mozilla/Constants.h @@ -1,15 +1,16 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* mfbt math constants. */ -#ifndef mozilla_Constants_h_ -#define mozilla_Constants_h_ +#ifndef mozilla_Constants_h +#define mozilla_Constants_h #ifndef M_PI # define M_PI 3.14159265358979323846 #endif -#endif /* mozilla_Constants_h_ */ +#endif /* mozilla_Constants_h */ diff --git a/libazure/mozilla/DebugOnly.h b/libazure/mozilla/DebugOnly.h new file mode 100644 index 0000000..5d0197b --- /dev/null +++ b/libazure/mozilla/DebugOnly.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Provides DebugOnly, a type for variables used only in debug builds (i.e. by + * assertions). + */ + +#ifndef mozilla_DebugOnly_h +#define mozilla_DebugOnly_h + +#include "mozilla/Attributes.h" + +namespace mozilla { + +/** + * DebugOnly contains a value of type T, but only in debug builds. In release + * builds, it does not contain a value. This helper is intended to be used with + * MOZ_ASSERT()-style macros, allowing one to write: + * + * DebugOnly check = func(); + * MOZ_ASSERT(check); + * + * more concisely than declaring |check| conditional on #ifdef DEBUG, but also + * without allocating storage space for |check| in release builds. + * + * DebugOnly instances can only be coerced to T in debug builds. In release + * builds they don't have a value, so type coercion is not well defined. + * + * Note that DebugOnly instances still take up one byte of space, plus padding, + * when used as members of structs. + */ +template +class DebugOnly +{ +public: +#ifdef DEBUG + T value; + + DebugOnly() { } + MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) { } + DebugOnly(const DebugOnly& aOther) : value(aOther.value) { } + DebugOnly& operator=(const T& aRhs) { + value = aRhs; + return *this; + } + + void operator++(int) { value++; } + void operator--(int) { value--; } + + T* operator&() { return &value; } + + operator T&() { return value; } + operator const T&() const { return value; } + + T& operator->() { return value; } + const T& operator->() const { return value; } + +#else + DebugOnly() { } + MOZ_IMPLICIT DebugOnly(const T&) { } + DebugOnly(const DebugOnly&) { } + DebugOnly& operator=(const T&) { return *this; } + void operator++(int) { } + void operator--(int) { } +#endif + + /* + * DebugOnly must always have a destructor or else it will + * generate "unused variable" warnings, exactly what it's intended + * to avoid! + */ + ~DebugOnly() {} +}; + +} + +#endif /* mozilla_DebugOnly_h */ diff --git a/libazure/mozilla/Endian.h b/libazure/mozilla/Endian.h new file mode 100644 index 0000000..e4e1ff8 --- /dev/null +++ b/libazure/mozilla/Endian.h @@ -0,0 +1,695 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Functions for reading and writing integers in various endiannesses. */ + +/* + * The classes LittleEndian and BigEndian expose static methods for + * reading and writing 16-, 32-, and 64-bit signed and unsigned integers + * in their respective endianness. The naming scheme is: + * + * {Little,Big}Endian::{read,write}{Uint,Int} + * + * For instance, LittleEndian::readInt32 will read a 32-bit signed + * integer from memory in little endian format. Similarly, + * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory + * in big-endian format. + * + * The class NativeEndian exposes methods for conversion of existing + * data to and from the native endianness. These methods are intended + * for cases where data needs to be transferred, serialized, etc. + * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. + * Bulk conversion functions are also provided which optimize the + * no-conversion-needed case: + * + * - copyAndSwap{To,From}{Little,Big}Endian; + * - swap{To,From}{Little,Big}EndianInPlace. + * + * The *From* variants are intended to be used for reading data and the + * *To* variants for writing data. + * + * Methods on NativeEndian work with integer data of any type. + * Floating-point data is not supported. + * + * For clarity in networking code, "Network" may be used as a synonym + * for "Big" in any of the above methods or class names. + * + * As an example, reading a file format header whose fields are stored + * in big-endian format might look like: + * + * class ExampleHeader + * { + * private: + * uint32_t mMagic; + * uint32_t mLength; + * uint32_t mTotalRecords; + * uint64_t mChecksum; + * + * public: + * ExampleHeader(const void* data) + * { + * const uint8_t* ptr = static_cast(data); + * mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mChecksum = BigEndian::readUint64(ptr); + * } + * ... + * }; + */ + +#ifndef mozilla_Endian_h +#define mozilla_Endian_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/TypeTraits.h" + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1300 +# include +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) +#endif + +#if defined(_WIN64) +# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(_WIN32) +# if defined(_M_IX86) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) +# if __LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# endif +#elif defined(__GNUC__) && \ + defined(__BYTE_ORDER__) && \ + defined(__ORDER_LITTLE_ENDIAN__) && \ + defined(__ORDER_BIG_ENDIAN__) + /* + * Some versions of GCC provide architecture-independent macros for + * this. Yes, there are more than two values for __BYTE_ORDER__. + */ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# else +# error "Can't handle mixed-endian architectures" +# endif +/* + * We can't include useful headers like or + * here because they're not present on all platforms. Instead we have + * this big conditional that ideally will catch all the interesting + * cases. + */ +#elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__hppa) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || defined(__AARCH64EB__) || \ + (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) +# define MOZ_BIG_ENDIAN 1 +#elif defined(__i386) || defined(__i386__) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_MIPSEL) || defined(__ARMEL__) || \ + defined(__alpha__) || defined(__AARCH64EL__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && !defined(__BIG_ENDIAN__)) +# define MOZ_LITTLE_ENDIAN 1 +#endif + +#if MOZ_BIG_ENDIAN +# define MOZ_LITTLE_ENDIAN 0 +#elif MOZ_LITTLE_ENDIAN +# define MOZ_BIG_ENDIAN 0 +#else +# error "Cannot determine endianness" +#endif + +#if defined(__clang__) +# if __has_builtin(__builtin_bswap16) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +# endif +#elif defined(__GNUC__) +# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +# endif +#elif defined(_MSC_VER) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort +#endif + +namespace mozilla { + +namespace detail { + +/* + * We need wrappers here because free functions with default template + * arguments and/or partial specialization of function templates are not + * supported by all the compilers we use. + */ +template +struct Swapper; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) + return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); +#else + return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8)); +#endif + } +}; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap32(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_ulong(aValue)); +#else + return T(((aValue & 0x000000ffU) << 24) | + ((aValue & 0x0000ff00U) << 8) | + ((aValue & 0x00ff0000U) >> 8) | + ((aValue & 0xff000000U) >> 24)); +#endif + } +}; + +template +struct Swapper +{ + static inline T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap64(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_uint64(aValue)); +#else + return T(((aValue & 0x00000000000000ffULL) << 56) | + ((aValue & 0x000000000000ff00ULL) << 40) | + ((aValue & 0x0000000000ff0000ULL) << 24) | + ((aValue & 0x00000000ff000000ULL) << 8) | + ((aValue & 0x000000ff00000000ULL) >> 8) | + ((aValue & 0x0000ff0000000000ULL) >> 24) | + ((aValue & 0x00ff000000000000ULL) >> 40) | + ((aValue & 0xff00000000000000ULL) >> 56)); +#endif + } +}; + +enum Endianness { Little, Big }; + +#if MOZ_BIG_ENDIAN +# define MOZ_NATIVE_ENDIANNESS detail::Big +#else +# define MOZ_NATIVE_ENDIANNESS detail::Little +#endif + +class EndianUtils +{ + /** + * Assert that the memory regions [aDest, aDest+aCount) and + * [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes. + */ + static void assertNoOverlap(const void* aDest, const void* aSrc, + size_t aCount) + { + DebugOnly byteDestPtr = static_cast(aDest); + DebugOnly byteSrcPtr = static_cast(aSrc); + MOZ_ASSERT((byteDestPtr <= byteSrcPtr && + byteDestPtr + aCount <= byteSrcPtr) || + (byteSrcPtr <= byteDestPtr && + byteSrcPtr + aCount <= byteDestPtr)); + } + + template + static void assertAligned(T* aPtr) + { + MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); + } + +protected: + /** + * Return |aValue| converted from SourceEndian encoding to DestEndian + * encoding. + */ + template + static inline T maybeSwap(T aValue) + { + if (SourceEndian == DestEndian) { + return aValue; + } + return Swapper::swap(aValue); + } + + /** + * Convert |aCount| elements at |aPtr| from SourceEndian encoding to + * DestEndian encoding. + */ + template + static inline void maybeSwapInPlace(T* aPtr, size_t aCount) + { + assertAligned(aPtr); + + if (SourceEndian == DestEndian) { + return; + } + for (size_t i = 0; i < aCount; i++) { + aPtr[i] = Swapper::swap(aPtr[i]); + } + } + + /** + * Write |aCount| elements to the unaligned address |aDest| in DestEndian + * format, using elements found at |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aSrc); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + uint8_t* byteDestPtr = static_cast(aDest); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + u.mVal = maybeSwap(aSrc[i]); + memcpy(byteDestPtr, u.mBuffer, sizeof(T)); + byteDestPtr += sizeof(T); + } + } + + /** + * Write |aCount| elements to |aDest| in DestEndian format, using elements + * found at the unaligned address |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aDest); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + const uint8_t* byteSrcPtr = static_cast(aSrc); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, byteSrcPtr, sizeof(T)); + aDest[i] = maybeSwap(u.mVal); + byteSrcPtr += sizeof(T); + } + } +}; + +template +class Endian : private EndianUtils +{ +protected: + /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* aPtr) + { + return read(aPtr); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint16(void* aPtr, uint16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint32(void* aPtr, uint32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint64(void* aPtr, uint64_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt16(void* aPtr, int16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt32(void* aPtr, int32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt64(void* aPtr, int64_t aValue) + { + write(aPtr, aValue); + } + + /* + * Converts a value of type T to little-endian format. + * + * This function is intended for cases where you have data in your + * native-endian format and you need it to appear in little-endian + * format for transmission. + */ + template + MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T to big-endian format. + */ + template + MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + + template + MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T aValue) + { + return swapToBigEndian(aValue); + } + + template + static void + copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) + { + copyAndSwapToBigEndian(aDest, aSrc, aCount); + } + + template + static void + swapToNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapToBigEndianInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from little-endian format. + */ + template + MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from big-endian format. + */ + template + MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + template + MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T aValue) + { + return swapFromBigEndian(aValue); + } + + template + static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFromBigEndian(aDest, aSrc, aCount); + } + + template + static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapFromBigEndianInPlace(aPtr, aCount); + } + +private: + /** + * Read a value of type T, encoded in endianness ThisEndian from |aPtr|. + * Return that value encoded in native endianness. + */ + template + static T read(const void* aPtr) + { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, aPtr, sizeof(T)); + return maybeSwap(u.mVal); + } + + /** + * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian + * endianness. + */ + template + static void write(void* aPtr, T aValue) + { + T tmp = maybeSwap(aValue); + memcpy(aPtr, &tmp, sizeof(T)); + } + + Endian() MOZ_DELETE; + Endian(const Endian& aTther) MOZ_DELETE; + void operator=(const Endian& aOther) MOZ_DELETE; +}; + +template +class EndianReadWrite : public Endian +{ +private: + typedef Endian super; + +public: + using super::readUint16; + using super::readUint32; + using super::readUint64; + using super::readInt16; + using super::readInt32; + using super::readInt64; + using super::writeUint16; + using super::writeUint32; + using super::writeUint64; + using super::writeInt16; + using super::writeInt32; + using super::writeInt64; +}; + +} /* namespace detail */ + +class LittleEndian MOZ_FINAL : public detail::EndianReadWrite +{}; + +class BigEndian MOZ_FINAL : public detail::EndianReadWrite +{}; + +typedef BigEndian NetworkEndian; + +class NativeEndian MOZ_FINAL : public detail::Endian +{ +private: + typedef detail::Endian super; + +public: + /* + * These functions are intended for cases where you have data in your + * native-endian format and you need the data to appear in the appropriate + * endianness for transmission, serialization, etc. + */ + using super::swapToLittleEndian; + using super::copyAndSwapToLittleEndian; + using super::swapToLittleEndianInPlace; + using super::swapToBigEndian; + using super::copyAndSwapToBigEndian; + using super::swapToBigEndianInPlace; + using super::swapToNetworkOrder; + using super::copyAndSwapToNetworkOrder; + using super::swapToNetworkOrderInPlace; + + /* + * These functions are intended for cases where you have data in the + * given endianness (e.g. reading from disk or a file-format) and you + * need the data to appear in native-endian format for processing. + */ + using super::swapFromLittleEndian; + using super::copyAndSwapFromLittleEndian; + using super::swapFromLittleEndianInPlace; + using super::swapFromBigEndian; + using super::copyAndSwapFromBigEndian; + using super::swapFromBigEndianInPlace; + using super::swapFromNetworkOrder; + using super::copyAndSwapFromNetworkOrder; + using super::swapFromNetworkOrderInPlace; +}; + +#undef MOZ_NATIVE_ENDIANNESS + +} /* namespace mozilla */ + +#endif /* mozilla_Endian_h */ diff --git a/libazure/mozilla/EnumSet.h b/libazure/mozilla/EnumSet.h new file mode 100644 index 0000000..8c78b2b --- /dev/null +++ b/libazure/mozilla/EnumSet.h @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A set abstraction for enumeration values. */ + +#ifndef mozilla_EnumSet_h +#define mozilla_EnumSet_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#include + +namespace mozilla { + +/** + * EnumSet is a set of values defined by an enumeration. It is implemented + * using a 32 bit mask for each value so it will only work for enums with an int + * representation less than 32. It works both for enum and enum class types. + */ +template +class EnumSet +{ +public: + EnumSet() + : mBitField(0) + { } + + MOZ_IMPLICIT EnumSet(T aEnum) + : mBitField(bitFor(aEnum)) + { } + + EnumSet(T aEnum1, T aEnum2) + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2)) + { } + + EnumSet(T aEnum1, T aEnum2, T aEnum3) + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2) | + bitFor(aEnum3)) + { } + + EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2) | + bitFor(aEnum3) | + bitFor(aEnum4)) + { } + + EnumSet(const EnumSet& aEnumSet) + : mBitField(aEnumSet.mBitField) + { } + + /** + * Add an element + */ + void operator+=(T aEnum) + { + mBitField |= bitFor(aEnum); + } + + /** + * Add an element + */ + EnumSet operator+(T aEnum) const + { + EnumSet result(*this); + result += aEnum; + return result; + } + + /** + * Union + */ + void operator+=(const EnumSet aEnumSet) + { + mBitField |= aEnumSet.mBitField; + } + + /** + * Union + */ + EnumSet operator+(const EnumSet aEnumSet) const + { + EnumSet result(*this); + result += aEnumSet; + return result; + } + + /** + * Remove an element + */ + void operator-=(T aEnum) + { + mBitField &= ~(bitFor(aEnum)); + } + + /** + * Remove an element + */ + EnumSet operator-(T aEnum) const + { + EnumSet result(*this); + result -= aEnum; + return result; + } + + /** + * Remove a set of elements + */ + void operator-=(const EnumSet aEnumSet) + { + mBitField &= ~(aEnumSet.mBitField); + } + + /** + * Remove a set of elements + */ + EnumSet operator-(const EnumSet aEnumSet) const + { + EnumSet result(*this); + result -= aEnumSet; + return result; + } + + /** + * Intersection + */ + void operator&=(const EnumSet aEnumSet) + { + mBitField &= aEnumSet.mBitField; + } + + /** + * Intersection + */ + EnumSet operator&(const EnumSet aEnumSet) const + { + EnumSet result(*this); + result &= aEnumSet; + return result; + } + + /** + * Equality + */ + bool operator==(const EnumSet aEnumSet) const + { + return mBitField == aEnumSet.mBitField; + } + + /** + * Test is an element is contained in the set. + */ + bool contains(T aEnum) const + { + return mBitField & bitFor(aEnum); + } + + /** + * Return the number of elements in the set. + */ + uint8_t size() + { + uint8_t count = 0; + for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { + if (bitField & 1) { + count++; + } + } + return count; + } + + bool isEmpty() const + { + return mBitField == 0; + } + + uint32_t serialize() const + { + return mBitField; + } + + void deserialize(uint32_t aValue) + { + mBitField = aValue; + } + +private: + static uint32_t bitFor(T aEnum) + { + uint32_t bitNumber = (uint32_t)aEnum; + MOZ_ASSERT(bitNumber < 32); + return 1U << bitNumber; + } + + uint32_t mBitField; +}; + +} // namespace mozilla + +#endif /* mozilla_EnumSet_h_*/ diff --git a/libazure/mozilla/EnumeratedArray.h b/libazure/mozilla/EnumeratedArray.h new file mode 100644 index 0000000..7e8e892 --- /dev/null +++ b/libazure/mozilla/EnumeratedArray.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* EnumeratedArray is like Array, but indexed by a typed enum. */ + +#ifndef mozilla_EnumeratedArray_h +#define mozilla_EnumeratedArray_h + +#include "mozilla/Array.h" +#include "mozilla/TypedEnum.h" + +namespace mozilla { + +/** + * EnumeratedArray is a fixed-size array container for use when an + * array is indexed by a specific enum class, as currently implemented + * by MOZ_BEGIN_ENUM_CLASS. + * + * This provides type safety by guarding at compile time against accidentally + * indexing such arrays with unrelated values. This also removes the need + * for manual casting when using a typed enum value to index arrays. + * + * Aside from the typing of indices, EnumeratedArray is similar to Array. + * + * Example: + * + * MOZ_BEGIN_ENUM_CLASS(AnimalSpecies) + * Cow, + * Sheep, + * Count + * MOZ_END_ENUM_CLASS(AnimalSpecies) + * + * EnumeratedArray headCount; + * + * headCount[AnimalSpecies::Cow] = 17; + * headCount[AnimalSpecies::Sheep] = 30; + * + */ +template +class EnumeratedArray +{ +public: + static const size_t kSize = size_t(SizeAsEnumValue); + +private: + Array mArray; + +public: + EnumeratedArray() {} + + explicit EnumeratedArray(const EnumeratedArray& aOther) + { + for (size_t i = 0; i < kSize; i++) { + mArray[i] = aOther.mArray[i]; + } + } + + ValueType& operator[](IndexType aIndex) + { + return mArray[size_t(aIndex)]; + } + + const ValueType& operator[](IndexType aIndex) const + { + return mArray[size_t(aIndex)]; + } +}; + +} // namespace mozilla + +#endif // mozilla_EnumeratedArray_h diff --git a/libazure/mozilla/FloatingPoint.h b/libazure/mozilla/FloatingPoint.h new file mode 100644 index 0000000..75b75df --- /dev/null +++ b/libazure/mozilla/FloatingPoint.h @@ -0,0 +1,424 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Various predicates and operations on IEEE-754 floating point types. */ + +#ifndef mozilla_FloatingPoint_h +#define mozilla_FloatingPoint_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Casting.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/Types.h" + +#include + +namespace mozilla { + +/* + * It's reasonable to ask why we have this header at all. Don't isnan, + * copysign, the built-in comparison operators, and the like solve these + * problems? Unfortunately, they don't. We've found that various compilers + * (MSVC, MSVC when compiling with PGO, and GCC on OS X, at least) miscompile + * the standard methods in various situations, so we can't use them. Some of + * these compilers even have problems compiling seemingly reasonable bitwise + * algorithms! But with some care we've found algorithms that seem to not + * trigger those compiler bugs. + * + * For the aforementioned reasons, be very wary of making changes to any of + * these algorithms. If you must make changes, keep a careful eye out for + * compiler bustage, particularly PGO-specific bustage. + */ + +struct FloatTypeTraits +{ + typedef uint32_t Bits; + + static const unsigned kExponentBias = 127; + static const unsigned kExponentShift = 23; + + static const Bits kSignBit = 0x80000000UL; + static const Bits kExponentBits = 0x7F800000UL; + static const Bits kSignificandBits = 0x007FFFFFUL; +}; + +struct DoubleTypeTraits +{ + typedef uint64_t Bits; + + static const unsigned kExponentBias = 1023; + static const unsigned kExponentShift = 52; + + static const Bits kSignBit = 0x8000000000000000ULL; + static const Bits kExponentBits = 0x7ff0000000000000ULL; + static const Bits kSignificandBits = 0x000fffffffffffffULL; +}; + +template struct SelectTrait; +template<> struct SelectTrait : public FloatTypeTraits {}; +template<> struct SelectTrait : public DoubleTypeTraits {}; + +/* + * This struct contains details regarding the encoding of floating-point + * numbers that can be useful for direct bit manipulation. As of now, the + * template parameter has to be float or double. + * + * The nested typedef |Bits| is the unsigned integral type with the same size + * as T: uint32_t for float and uint64_t for double (static assertions + * double-check these assumptions). + * + * kExponentBias is the offset that is subtracted from the exponent when + * computing the value, i.e. one plus the opposite of the mininum possible + * exponent. + * kExponentShift is the shift that one needs to apply to retrieve the + * exponent component of the value. + * + * kSignBit contains a bits mask. Bit-and-ing with this mask will result in + * obtaining the sign bit. + * kExponentBits contains the mask needed for obtaining the exponent bits and + * kSignificandBits contains the mask needed for obtaining the significand + * bits. + * + * Full details of how floating point number formats are encoded are beyond + * the scope of this comment. For more information, see + * http://en.wikipedia.org/wiki/IEEE_floating_point + * http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers + */ +template +struct FloatingPoint : public SelectTrait +{ + typedef SelectTrait Base; + typedef typename Base::Bits Bits; + + static_assert((Base::kSignBit & Base::kExponentBits) == 0, + "sign bit shouldn't overlap exponent bits"); + static_assert((Base::kSignBit & Base::kSignificandBits) == 0, + "sign bit shouldn't overlap significand bits"); + static_assert((Base::kExponentBits & Base::kSignificandBits) == 0, + "exponent bits shouldn't overlap significand bits"); + + static_assert((Base::kSignBit | Base::kExponentBits | Base::kSignificandBits) == + ~Bits(0), + "all bits accounted for"); + + /* + * These implementations assume float/double are 32/64-bit single/double + * format number types compatible with the IEEE-754 standard. C++ don't + * require this to be the case. But we required this in implementations of + * these algorithms that preceded this header, so we shouldn't break anything + * if we keep doing so. + */ + static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T"); +}; + +/** Determines whether a double is NaN. */ +template +static MOZ_ALWAYS_INLINE bool +IsNaN(T aValue) +{ + /* + * A float/double is NaN if all exponent bits are 1 and the significand + * contains at least one non-zero bit. + */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return (bits & Traits::kExponentBits) == Traits::kExponentBits && + (bits & Traits::kSignificandBits) != 0; +} + +/** Determines whether a float/double is +Infinity or -Infinity. */ +template +static MOZ_ALWAYS_INLINE bool +IsInfinite(T aValue) +{ + /* Infinities have all exponent bits set to 1 and an all-0 significand. */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return (bits & ~Traits::kSignBit) == Traits::kExponentBits; +} + +/** Determines whether a float/double is not NaN or infinite. */ +template +static MOZ_ALWAYS_INLINE bool +IsFinite(T aValue) +{ + /* + * NaN and Infinities are the only non-finite floats/doubles, and both have + * all exponent bits set to 1. + */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return (bits & Traits::kExponentBits) != Traits::kExponentBits; +} + +/** + * Determines whether a float/double is negative. It is an error to call this + * method on a float/double which is NaN. + */ +template +static MOZ_ALWAYS_INLINE bool +IsNegative(T aValue) +{ + MOZ_ASSERT(!IsNaN(aValue), "NaN does not have a sign"); + + /* The sign bit is set if the double is negative. */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return (bits & Traits::kSignBit) != 0; +} + +/** Determines whether a float/double represents -0. */ +template +static MOZ_ALWAYS_INLINE bool +IsNegativeZero(T aValue) +{ + /* Only the sign bit is set if the value is -0. */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return bits == Traits::kSignBit; +} + +/** + * Returns 0 if a float/double is NaN or infinite; + * otherwise, the float/double is returned. + */ +template +static MOZ_ALWAYS_INLINE T +ToZeroIfNonfinite(T aValue) +{ + return IsFinite(aValue) ? aValue : 0; +} + +/** + * Returns the exponent portion of the float/double. + * + * Zero is not special-cased, so ExponentComponent(0.0) is + * -int_fast16_t(Traits::kExponentBias). + */ +template +static MOZ_ALWAYS_INLINE int_fast16_t +ExponentComponent(T aValue) +{ + /* + * The exponent component of a float/double is an unsigned number, biased + * from its actual value. Subtract the bias to retrieve the actual exponent. + */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return int_fast16_t((bits & Traits::kExponentBits) >> Traits::kExponentShift) - + int_fast16_t(Traits::kExponentBias); +} + +/** Returns +Infinity. */ +template +static MOZ_ALWAYS_INLINE T +PositiveInfinity() +{ + /* + * Positive infinity has all exponent bits set, sign bit set to 0, and no + * significand. + */ + typedef FloatingPoint Traits; + return BitwiseCast(Traits::kExponentBits); +} + +/** Returns -Infinity. */ +template +static MOZ_ALWAYS_INLINE T +NegativeInfinity() +{ + /* + * Negative infinity has all exponent bits set, sign bit set to 1, and no + * significand. + */ + typedef FloatingPoint Traits; + return BitwiseCast(Traits::kSignBit | Traits::kExponentBits); +} + + +/** Constructs a NaN value with the specified sign bit and significand bits. */ +template +static MOZ_ALWAYS_INLINE T +SpecificNaN(int signbit, typename FloatingPoint::Bits significand) +{ + typedef FloatingPoint Traits; + MOZ_ASSERT(signbit == 0 || signbit == 1); + MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0); + MOZ_ASSERT(significand & Traits::kSignificandBits); + + T t = BitwiseCast((signbit ? Traits::kSignBit : 0) | + Traits::kExponentBits | + significand); + MOZ_ASSERT(IsNaN(t)); + return t; +} + +/** Computes the smallest non-zero positive float/double value. */ +template +static MOZ_ALWAYS_INLINE T +MinNumberValue() +{ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + return BitwiseCast(Bits(1)); +} + +/** + * If aValue is equal to some int32_t value, set *aInt32 to that value and + * return true; otherwise return false. + * + * Note that negative zero is "equal" to zero here. To test whether a value can + * be losslessly converted to int32_t and back, use NumberIsInt32 instead. + */ +template +static MOZ_ALWAYS_INLINE bool +NumberEqualsInt32(T aValue, int32_t* aInt32) +{ + /* + * XXX Casting a floating-point value that doesn't truncate to int32_t, to + * int32_t, induces undefined behavior. We should definitely fix this + * (bug 744965), but as apparently it "works" in practice, it's not a + * pressing concern now. + */ + return aValue == (*aInt32 = int32_t(aValue)); +} + +/** + * If d can be converted to int32_t and back to an identical double value, + * set *aInt32 to that value and return true; otherwise return false. + * + * The difference between this and NumberEqualsInt32 is that this method returns + * false for negative zero. + */ +template +static MOZ_ALWAYS_INLINE bool +NumberIsInt32(T aValue, int32_t* aInt32) +{ + return !IsNegativeZero(aValue) && NumberEqualsInt32(aValue, aInt32); +} + +/** + * Computes a NaN value. Do not use this method if you depend upon a particular + * NaN value being returned. + */ +template +static MOZ_ALWAYS_INLINE T +UnspecifiedNaN() +{ + /* + * If we can use any quiet NaN, we might as well use the all-ones NaN, + * since it's cheap to materialize on common platforms (such as x64, where + * this value can be represented in a 32-bit signed immediate field, allowing + * it to be stored to memory in a single instruction). + */ + typedef FloatingPoint Traits; + return SpecificNaN(1, Traits::kSignificandBits); +} + +/** + * Compare two doubles for equality, *without* equating -0 to +0, and equating + * any NaN value to any other NaN value. (The normal equality operators equate + * -0 with +0, and they equate NaN to no other value.) + */ +template +static inline bool +NumbersAreIdentical(T aValue1, T aValue2) +{ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + if (IsNaN(aValue1)) { + return IsNaN(aValue2); + } + return BitwiseCast(aValue1) == BitwiseCast(aValue2); +} + +namespace detail { + +template +struct FuzzyEqualsEpsilon; + +template<> +struct FuzzyEqualsEpsilon +{ + // A number near 1e-5 that is exactly representable in a float. + static float value() { return 1.0f / (1 << 17); } +}; + +template<> +struct FuzzyEqualsEpsilon +{ + // A number near 1e-12 that is exactly representable in a double. + static double value() { return 1.0 / (1LL << 40); } +}; + +} // namespace detail + +/** + * Compare two floating point values for equality, modulo rounding error. That + * is, the two values are considered equal if they are both not NaN and if they + * are less than or equal to aEpsilon apart. The default value of aEpsilon is + * near 1e-5. + * + * For most scenarios you will want to use FuzzyEqualsMultiplicative instead, + * as it is more reasonable over the entire range of floating point numbers. + * This additive version should only be used if you know the range of the + * numbers you are dealing with is bounded and stays around the same order of + * magnitude. + */ +template +static MOZ_ALWAYS_INLINE bool +FuzzyEqualsAdditive(T aValue1, T aValue2, + T aEpsilon = detail::FuzzyEqualsEpsilon::value()) +{ + static_assert(IsFloatingPoint::value, "floating point type required"); + return Abs(aValue1 - aValue2) <= aEpsilon; +} + +/** + * Compare two floating point values for equality, allowing for rounding error + * relative to the magnitude of the values. That is, the two values are + * considered equal if they are both not NaN and they are less than or equal to + * some aEpsilon apart, where the aEpsilon is scaled by the smaller of the two + * argument values. + * + * In most cases you will want to use this rather than FuzzyEqualsAdditive, as + * this function effectively masks out differences in the bottom few bits of + * the floating point numbers being compared, regardless of what order of + * magnitude those numbers are at. + */ +template +static MOZ_ALWAYS_INLINE bool +FuzzyEqualsMultiplicative(T aValue1, T aValue2, + T aEpsilon = detail::FuzzyEqualsEpsilon::value()) +{ + static_assert(IsFloatingPoint::value, "floating point type required"); + // can't use std::min because of bug 965340 + T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2); + return Abs(aValue1 - aValue2) <= aEpsilon * smaller; +} + +/** + * Returns true if the given value can be losslessly represented as an IEEE-754 + * single format number, false otherwise. All NaN values are considered + * representable (notwithstanding that the exact bit pattern of a double format + * NaN value can't be exactly represented in single format). + * + * This function isn't inlined to avoid buggy optimizations by MSVC. + */ +MOZ_WARN_UNUSED_RESULT +extern MFBT_API bool +IsFloat32Representable(double aFloat32); + +} /* namespace mozilla */ + +#endif /* mozilla_FloatingPoint_h */ diff --git a/libazure/src/mfbt/GuardObjects.h b/libazure/mozilla/GuardObjects.h similarity index 78% rename from libazure/src/mfbt/GuardObjects.h rename to libazure/mozilla/GuardObjects.h index 6c20589..2cd950f 100644 --- a/libazure/src/mfbt/GuardObjects.h +++ b/libazure/mozilla/GuardObjects.h @@ -1,4 +1,5 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -9,6 +10,7 @@ #define mozilla_GuardObjects_h #include "mozilla/Assertions.h" +#include "mozilla/NullPtr.h" #include "mozilla/Types.h" #ifdef __cplusplus @@ -66,48 +68,49 @@ namespace detail { * For more details, and examples of using these macros, see * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla */ -class MOZ_EXPORT GuardObjectNotifier +class GuardObjectNotifier { - private: - bool* statementDone; +private: + bool* mStatementDone; - public: - GuardObjectNotifier() : statementDone(NULL) { } +public: + GuardObjectNotifier() : mStatementDone(nullptr) { } - ~GuardObjectNotifier() { - *statementDone = true; - } + ~GuardObjectNotifier() { *mStatementDone = true; } - void setStatementDone(bool* statementIsDone) { - statementDone = statementIsDone; - } + void setStatementDone(bool* aStatementIsDone) + { + mStatementDone = aStatementIsDone; + } }; -class MOZ_EXPORT GuardObjectNotificationReceiver +class GuardObjectNotificationReceiver { - private: - bool statementDone; - - public: - GuardObjectNotificationReceiver() : statementDone(false) { } - - ~GuardObjectNotificationReceiver() { - /* - * Assert that the guard object was not used as a temporary. (Note that - * this assert might also fire if init is not called because the guard - * object's implementation is not using the above macros correctly.) - */ - MOZ_ASSERT(statementDone); - } - - void init(const GuardObjectNotifier& constNotifier) { - /* - * constNotifier is passed as a const reference so that we can pass a - * temporary, but we really intend it as non-const. - */ - GuardObjectNotifier& notifier = const_cast(constNotifier); - notifier.setStatementDone(&statementDone); - } +private: + bool mStatementDone; + +public: + GuardObjectNotificationReceiver() : mStatementDone(false) { } + + ~GuardObjectNotificationReceiver() { + /* + * Assert that the guard object was not used as a temporary. (Note that + * this assert might also fire if init is not called because the guard + * object's implementation is not using the above macros correctly.) + */ + MOZ_ASSERT(mStatementDone); + } + + void init(const GuardObjectNotifier& aConstNotifier) + { + /* + * aConstNotifier is passed as a const reference so that we can pass a + * temporary, but we really intend it as non-const. + */ + GuardObjectNotifier& notifier = + const_cast(aConstNotifier); + notifier.setStatementDone(&mStatementDone); + } }; } /* namespace detail */ diff --git a/libazure/src/mfbt/HashFunctions.h b/libazure/mozilla/HashFunctions.h similarity index 53% rename from libazure/src/mfbt/HashFunctions.h rename to libazure/mozilla/HashFunctions.h index 96242b6..86052a7 100644 --- a/libazure/src/mfbt/HashFunctions.h +++ b/libazure/mozilla/HashFunctions.h @@ -1,7 +1,8 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Utilities for hashing. */ @@ -26,49 +27,52 @@ * * class ComplexObject * { - * char* str; - * uint32_t uint1, uint2; - * void (*callbackFn)(); + * char* mStr; + * uint32_t mUint1, mUint2; + * void (*mCallbackFn)(); * - * public: - * uint32_t hash() { - * uint32_t hash = HashString(str); - * hash = AddToHash(hash, uint1, uint2); - * return AddToHash(hash, callbackFn); - * } + * public: + * uint32_t hash() + * { + * uint32_t hash = HashString(mStr); + * hash = AddToHash(hash, mUint1, mUint2); + * return AddToHash(hash, mCallbackFn); + * } * }; * * If you want to hash an nsAString or nsACString, use the HashString functions - * in nsHashKey.h. + * in nsHashKeys.h. */ -#ifndef mozilla_HashFunctions_h_ -#define mozilla_HashFunctions_h_ +#ifndef mozilla_HashFunctions_h +#define mozilla_HashFunctions_h #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" -#include "mozilla/StandardInteger.h" +#include "mozilla/Char16.h" #include "mozilla/Types.h" +#include + #ifdef __cplusplus namespace mozilla { /** * The golden ratio as a 32-bit fixed-point value. */ -static const uint32_t GoldenRatioU32 = 0x9E3779B9U; +static const uint32_t kGoldenRatioU32 = 0x9E3779B9U; inline uint32_t -RotateBitsLeft32(uint32_t value, uint8_t bits) +RotateBitsLeft32(uint32_t aValue, uint8_t aBits) { - MOZ_ASSERT(bits < 32); - return (value << bits) | (value >> (32 - bits)); + MOZ_ASSERT(aBits < 32); + return (aValue << aBits) | (aValue >> (32 - aBits)); } namespace detail { inline uint32_t -AddU32ToHash(uint32_t hash, uint32_t value) +AddU32ToHash(uint32_t aHash, uint32_t aValue) { /* * This is the meat of all our hash routines. This hash function is not @@ -88,12 +92,12 @@ AddU32ToHash(uint32_t hash, uint32_t value) * preferable so our hash explores the whole universe of possible rotations. * * Finally, we multiply by the golden ratio *after* xor'ing, not before. - * Otherwise, if |hash| is 0 (as it often is for the beginning of a message), - * the expression + * Otherwise, if |aHash| is 0 (as it often is for the beginning of a + * message), the expression * - * (GoldenRatioU32 * RotateBitsLeft(hash, 5)) |xor| value + * (kGoldenRatioU32 * RotateBitsLeft(aHash, 5)) |xor| aValue * - * evaluates to |value|. + * evaluates to |aValue|. * * (Number-theoretic aside: Because any odd number |m| is relatively prime to * our modulus (2^32), the list @@ -109,7 +113,7 @@ AddU32ToHash(uint32_t hash, uint32_t value) * multiplicative effect. Our golden ratio constant has order 2^29, which is * more than enough for our purposes.) */ - return GoldenRatioU32 * (RotateBitsLeft32(hash, 5) ^ value); + return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue); } /** @@ -117,29 +121,29 @@ AddU32ToHash(uint32_t hash, uint32_t value) */ template inline uint32_t -AddUintptrToHash(uint32_t hash, uintptr_t value); +AddUintptrToHash(uint32_t aHash, uintptr_t aValue); template<> inline uint32_t -AddUintptrToHash<4>(uint32_t hash, uintptr_t value) +AddUintptrToHash<4>(uint32_t aHash, uintptr_t aValue) { - return AddU32ToHash(hash, static_cast(value)); + return AddU32ToHash(aHash, static_cast(aValue)); } template<> inline uint32_t -AddUintptrToHash<8>(uint32_t hash, uintptr_t value) +AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) { /* * The static cast to uint64_t below is necessary because this function * sometimes gets compiled on 32-bit platforms (yes, even though it's a * template and we never call this particular override in a 32-bit build). If - * we do value >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t + * we do aValue >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t * right 32 bits, and the compiler throws an error. */ - uint32_t v1 = static_cast(value); - uint32_t v2 = static_cast(static_cast(value) >> 32); - return AddU32ToHash(AddU32ToHash(hash, v1), v2); + uint32_t v1 = static_cast(aValue); + uint32_t v2 = static_cast(static_cast(aValue) >> 32); + return AddU32ToHash(AddU32ToHash(aHash, v1), v2); } } /* namespace detail */ @@ -152,71 +156,63 @@ AddUintptrToHash<8>(uint32_t hash, uintptr_t value) * convert to uint32_t, data pointers, and function pointers. */ template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -AddToHash(uint32_t hash, A a) +MOZ_WARN_UNUSED_RESULT inline uint32_t +AddToHash(uint32_t aHash, A aA) { /* * Try to convert |A| to uint32_t implicitly. If this works, great. If not, * we'll error out. */ - return detail::AddU32ToHash(hash, a); + return detail::AddU32ToHash(aHash, aA); } template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -AddToHash(uint32_t hash, A* a) +MOZ_WARN_UNUSED_RESULT inline uint32_t +AddToHash(uint32_t aHash, A* aA) { /* * You might think this function should just take a void*. But then we'd only * catch data pointers and couldn't handle function pointers. */ - MOZ_STATIC_ASSERT(sizeof(a) == sizeof(uintptr_t), - "Strange pointer!"); + static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!"); - return detail::AddUintptrToHash(hash, uintptr_t(a)); + return detail::AddUintptrToHash(aHash, uintptr_t(aA)); } template<> -MOZ_WARN_UNUSED_RESULT -inline uint32_t -AddToHash(uint32_t hash, uintptr_t a) +MOZ_WARN_UNUSED_RESULT inline uint32_t +AddToHash(uint32_t aHash, uintptr_t aA) { - return detail::AddUintptrToHash(hash, a); + return detail::AddUintptrToHash(aHash, aA); } template -MOZ_WARN_UNUSED_RESULT -uint32_t -AddToHash(uint32_t hash, A a, B b) +MOZ_WARN_UNUSED_RESULT uint32_t +AddToHash(uint32_t aHash, A aA, B aB) { - return AddToHash(AddToHash(hash, a), b); + return AddToHash(AddToHash(aHash, aA), aB); } template -MOZ_WARN_UNUSED_RESULT -uint32_t -AddToHash(uint32_t hash, A a, B b, C c) +MOZ_WARN_UNUSED_RESULT uint32_t +AddToHash(uint32_t aHash, A aA, B aB, C aC) { - return AddToHash(AddToHash(hash, a, b), c); + return AddToHash(AddToHash(aHash, aA, aB), aC); } template -MOZ_WARN_UNUSED_RESULT -uint32_t -AddToHash(uint32_t hash, A a, B b, C c, D d) +MOZ_WARN_UNUSED_RESULT uint32_t +AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD) { - return AddToHash(AddToHash(hash, a, b, c), d); + return AddToHash(AddToHash(aHash, aA, aB, aC), aD); } template -MOZ_WARN_UNUSED_RESULT -uint32_t -AddToHash(uint32_t hash, A a, B b, C c, D d, E e) +MOZ_WARN_UNUSED_RESULT uint32_t +AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD, E aE) { - return AddToHash(AddToHash(hash, a, b, c, d), e); + return AddToHash(AddToHash(aHash, aA, aB, aC, aD), aE); } /** @@ -227,64 +223,61 @@ AddToHash(uint32_t hash, A a, B b, C c, D d, E e) * that x has already been hashed. */ template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashGeneric(A a) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashGeneric(A aA) { - return AddToHash(0, a); + return AddToHash(0, aA); } template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashGeneric(A a, B b) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashGeneric(A aA, B aB) { - return AddToHash(0, a, b); + return AddToHash(0, aA, aB); } template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashGeneric(A a, B b, C c) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashGeneric(A aA, B aB, C aC) { - return AddToHash(0, a, b, c); + return AddToHash(0, aA, aB, aC); } template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashGeneric(A a, B b, C c, D d) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashGeneric(A aA, B aB, C aC, D aD) { - return AddToHash(0, a, b, c, d); + return AddToHash(0, aA, aB, aC, aD); } template -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashGeneric(A a, B b, C c, D d, E e) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashGeneric(A aA, B aB, C aC, D aD, E aE) { - return AddToHash(0, a, b, c, d, e); + return AddToHash(0, aA, aB, aC, aD, aE); } namespace detail { template uint32_t -HashUntilZero(const T* str) +HashUntilZero(const T* aStr) { uint32_t hash = 0; - for (T c; (c = *str); str++) + for (T c; (c = *aStr); aStr++) { hash = AddToHash(hash, c); + } return hash; } template uint32_t -HashKnownLength(const T* str, size_t length) +HashKnownLength(const T* aStr, size_t aLength) { uint32_t hash = 0; - for (size_t i = 0; i < length; i++) - hash = AddToHash(hash, str[i]); + for (size_t i = 0; i < aLength; i++) { + hash = AddToHash(hash, aStr[i]); + } return hash; } @@ -296,51 +289,66 @@ HashKnownLength(const T* str, size_t length) * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashString(const char* str) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const char* aStr) { - return detail::HashUntilZero(str); + return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashString(const char* str, size_t length) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const char* aStr, size_t aLength) { - return detail::HashKnownLength(str, length); + return detail::HashKnownLength(reinterpret_cast(aStr), aLength); } MOZ_WARN_UNUSED_RESULT inline uint32_t -HashString(const uint16_t* str) +HashString(const unsigned char* aStr, size_t aLength) { - return detail::HashUntilZero(str); + return detail::HashKnownLength(aStr, aLength); } -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashString(const uint16_t* str, size_t length) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const uint16_t* aStr) +{ + return detail::HashUntilZero(aStr); +} + +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const uint16_t* aStr, size_t aLength) { - return detail::HashKnownLength(str, length); + return detail::HashKnownLength(aStr, aLength); } +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const char16_t* aStr) +{ + return detail::HashUntilZero(aStr); +} + +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const char16_t* aStr, size_t aLength) +{ + return detail::HashKnownLength(aStr, aLength); +} +#endif + /* - * On Windows, wchar_t (PRUnichar) is not the same as uint16_t, even though it's + * On Windows, wchar_t (char16_t) is not the same as uint16_t, even though it's * the same width! */ #ifdef WIN32 -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashString(const wchar_t* str) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const wchar_t* aStr) { - return detail::HashUntilZero(str); + return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT -inline uint32_t -HashString(const wchar_t* str, size_t length) +MOZ_WARN_UNUSED_RESULT inline uint32_t +HashString(const wchar_t* aStr, size_t aLength) { - return detail::HashKnownLength(str, length); + return detail::HashKnownLength(aStr, aLength); } #endif @@ -350,10 +358,10 @@ HashString(const wchar_t* str, size_t length) * This hash walks word-by-word, rather than byte-by-byte, so you won't get the * same result out of HashBytes as you would out of HashString. */ -MOZ_WARN_UNUSED_RESULT -extern MFBT_API uint32_t -HashBytes(const void* bytes, size_t length); +MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t +HashBytes(const void* bytes, size_t aLength); } /* namespace mozilla */ #endif /* __cplusplus */ -#endif /* mozilla_HashFunctions_h_ */ + +#endif /* mozilla_HashFunctions_h */ diff --git a/libazure/mozilla/IntegerPrintfMacros.h b/libazure/mozilla/IntegerPrintfMacros.h new file mode 100644 index 0000000..28bfc14 --- /dev/null +++ b/libazure/mozilla/IntegerPrintfMacros.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Implements the C99 interface, minus the SCN* format macros. */ + +#ifndef mozilla_IntegerPrintfMacros_h_ +#define mozilla_IntegerPrintfMacros_h_ + +/* + * MSVC++ doesn't include , even in versions shipping , so + * we have to reimplement it there. Note: #includes . + * + * Note that this header DOES NOT implement 's scanf macros. MSVC's + * scanf doesn't have sufficient format specifier support to implement them + * (specifically, to implement scanning into an 8-bit location). + * + * http://stackoverflow.com/questions/3036396/scanfd-char-char-as-int-format-string + * + * Moreover, scanf is a footgun: if the input number exceeds the bounds of the + * target type, behavior is undefined (in the compiler sense: that is, this code + * could overwrite your hard drive with zeroes): + * + * uint8_t u; + * sscanf("256", "%" SCNu8, &u); // BAD + * + * This header will sometimes provide SCN* macros, by dint of being implemented + * using . But for these reasons, *never* use them! + */ + +#if defined(MOZ_CUSTOM_INTTYPES_H) +# include MOZ_CUSTOM_INTTYPES_H +#elif defined(_MSC_VER) +# include "mozilla/MSIntTypes.h" +#else +# include +#endif + +/* + * Fix up Android's broken [u]intptr_t inttype macros. Android's PRI*PTR + * macros are defined as "ld", but sizeof(long) is 8 and sizeof(intptr_t) + * is 4 on 32-bit Android. TestTypeTraits.cpp asserts that these new macro + * definitions match the actual type sizes seen at compile time. + */ +#if defined(ANDROID) && !defined(__LP64__) +# undef PRIdPTR /* intptr_t */ +# define PRIdPTR "d" /* intptr_t */ +# undef PRIiPTR /* intptr_t */ +# define PRIiPTR "i" /* intptr_t */ +# undef PRIoPTR /* uintptr_t */ +# define PRIoPTR "o" /* uintptr_t */ +# undef PRIuPTR /* uintptr_t */ +# define PRIuPTR "u" /* uintptr_t */ +# undef PRIxPTR /* uintptr_t */ +# define PRIxPTR "x" /* uintptr_t */ +# undef PRIXPTR /* uintptr_t */ +# define PRIXPTR "X" /* uintptr_t */ +#endif + +/** + * For printing size_t. + */ +#define PRIuSIZE PRIuPTR + +#endif /* mozilla_IntegerPrintfMacros_h_ */ diff --git a/libazure/mozilla/IntegerTypeTraits.h b/libazure/mozilla/IntegerTypeTraits.h new file mode 100644 index 0000000..9414451 --- /dev/null +++ b/libazure/mozilla/IntegerTypeTraits.h @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Helpers to manipulate integer types that don't fit in TypeTraits.h */ + +#ifndef mozilla_IntegerTypeTraits_h +#define mozilla_IntegerTypeTraits_h + +#include "mozilla/TypeTraits.h" +#include + +namespace mozilla { + +namespace detail { + +/** + * StdintTypeForSizeAndSignedness returns the stdint integer type + * of given size (can be 1, 2, 4 or 8) and given signedness + * (false means unsigned, true means signed). + */ +template +struct StdintTypeForSizeAndSignedness; + +template<> +struct StdintTypeForSizeAndSignedness<1, true> +{ + typedef int8_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<1, false> +{ + typedef uint8_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<2, true> +{ + typedef int16_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<2, false> +{ + typedef uint16_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<4, true> +{ + typedef int32_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<4, false> +{ + typedef uint32_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<8, true> +{ + typedef int64_t Type; +}; + +template<> +struct StdintTypeForSizeAndSignedness<8, false> +{ + typedef uint64_t Type; +}; + +} // namespace detail + +template +struct UnsignedStdintTypeForSize + : detail::StdintTypeForSizeAndSignedness +{}; + +template +struct PositionOfSignBit +{ + static_assert(IsIntegral::value, + "PositionOfSignBit is only for integral types"); + // 8 here should be CHAR_BIT from limits.h, but the world has moved on. + static const size_t value = 8 * sizeof(IntegerType) - 1; +}; + +/** + * MinValue returns the minimum value of the given integer type as a + * compile-time constant, which std::numeric_limits::min() + * cannot do in c++98. + */ +template +struct MinValue +{ +private: + static_assert(IsIntegral::value, + "MinValue is only for integral types"); + + typedef typename MakeUnsigned::Type UnsignedIntegerType; + static const size_t PosOfSignBit = PositionOfSignBit::value; + +public: + // Bitwise ops may return a larger type, that's why we cast explicitly. + // In C++, left bit shifts on signed values is undefined by the standard + // unless the shifted value is representable. + // Notice that signed-to-unsigned conversions are always well-defined in + // the standard as the value congruent to 2**n, as expected. By contrast, + // unsigned-to-signed is only well-defined if the value is representable. + static const IntegerType value = + IsSigned::value + ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) + : IntegerType(0); +}; + +/** + * MaxValue returns the maximum value of the given integer type as a + * compile-time constant, which std::numeric_limits::max() + * cannot do in c++98. + */ +template +struct MaxValue +{ + static_assert(IsIntegral::value, + "MaxValue is only for integral types"); + + // Tricksy, but covered by the CheckedInt unit test. + // Relies on the type of MinValue::value + // being IntegerType. + static const IntegerType value = ~MinValue::value; +}; + +} // namespace mozilla + +#endif // mozilla_IntegerTypeTraits_h diff --git a/libazure/mozilla/JSONWriter.h b/libazure/mozilla/JSONWriter.h new file mode 100644 index 0000000..98747b1 --- /dev/null +++ b/libazure/mozilla/JSONWriter.h @@ -0,0 +1,420 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A JSON pretty-printer class. */ + +// A typical JSON-writing library requires you to first build up a data +// structure that represents a JSON object and then serialize it (to file, or +// somewhere else). This approach makes for a clean API, but building the data +// structure takes up memory. Sometimes that isn't desirable, such as when the +// JSON data is produced for memory reporting. +// +// The JSONWriter class instead allows JSON data to be written out +// incrementally without building up large data structures. +// +// The API is slightly uglier than you would see in a typical JSON-writing +// library, but still fairly easy to use. It's possible to generate invalid +// JSON with JSONWriter, but typically the most basic testing will identify any +// such problems. +// +// Similarly, there are no RAII facilities for automatically closing objects +// and arrays. These would be nice if you are generating all your code within +// nested functions, but in other cases you'd have to maintain an explicit +// stack of RAII objects and manually unwind it, which is no better than just +// calling "end" functions. Furthermore, the consequences of forgetting to +// close an object or array are obvious and, again, will be identified via +// basic testing, unlike other cases where RAII is typically used (e.g. smart +// pointers) and the consequences of defects are more subtle. +// +// Importantly, the class does solve the two hard problems of JSON +// pretty-printing, which are (a) correctly escaping strings, and (b) adding +// appropriate indentation and commas between items. +// +// Strings used (for property names and string property values) are |const +// char*| throughout, and can be ASCII or UTF-8. +// +// EXAMPLE +// ------- +// Assume that |MyWriteFunc| is a class that implements |JSONWriteFunc|. The +// following code: +// +// JSONWriter w(MakeUnique()); +// w.Start(); +// { +// w.NullProperty("null"); +// w.BoolProperty("bool", true); +// w.IntProperty("int", 1); +// w.StringProperty("string", "hello"); +// w.StartArrayProperty("array"); +// { +// w.DoubleElement(3.4); +// w.StartObjectElement(); +// { +// w.PointerProperty("ptr", (void*)0x12345678); +// } +// w.EndObjectElement(); +// } +// w.EndArrayProperty(); +// } +// w.End(); +// +// will produce pretty-printed output for the following JSON object: +// +// { +// "null": null, +// "bool": true, +// "int": 1, +// "string": "hello", +// "array": [ +// 3.4, +// { +// "ptr": "0x12345678" +// } +// ] +// } +// +// The nesting in the example code is obviously optional, but can aid +// readability. + +#ifndef mozilla_JSONWriter_h +#define mozilla_JSONWriter_h + +#include "mozilla/double-conversion.h" +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/PodOperations.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include + +namespace mozilla { + +// A quasi-functor for JSONWriter. We don't use a true functor because that +// requires templatizing JSONWriter, and the templatization seeps to lots of +// places we don't want it to. +class JSONWriteFunc +{ +public: + virtual void Write(const char* aStr) = 0; + virtual ~JSONWriteFunc() {} +}; + +// Ideally this would be within |EscapedString| but when compiling with GCC +// on Linux that caused link errors, whereas this formulation didn't. +namespace detail { +extern MFBT_DATA const char gTwoCharEscapes[256]; +} + +class JSONWriter +{ + // From http://www.ietf.org/rfc/rfc4627.txt: + // + // "All Unicode characters may be placed within the quotation marks except + // for the characters that must be escaped: quotation mark, reverse + // solidus, and the control characters (U+0000 through U+001F)." + // + // This implementation uses two-char escape sequences where possible, namely: + // + // \", \\, \b, \f, \n, \r, \t + // + // All control characters not in the above list are represented with a + // six-char escape sequence, e.g. '\u000b' (a.k.a. '\v'). + // + class EscapedString + { + // Only one of |mUnownedStr| and |mOwnedStr| are ever non-null. |mIsOwned| + // indicates which one is in use. They're not within a union because that + // wouldn't work with UniquePtr. + bool mIsOwned; + const char* mUnownedStr; + UniquePtr mOwnedStr; + + void SanityCheck() const + { + MOZ_ASSERT_IF( mIsOwned, mOwnedStr.get() && !mUnownedStr); + MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr); + } + + static char hexDigitToAsciiChar(uint8_t u) + { + u = u & 0xf; + return u < 10 ? '0' + u : 'a' + (u - 10); + } + + public: + EscapedString(const char* aStr) + : mUnownedStr(nullptr) + , mOwnedStr(nullptr) + { + const char* p; + + // First, see if we need to modify the string. + size_t nExtra = 0; + p = aStr; + while (true) { + uint8_t u = *p; // ensure it can't be interpreted as negative + if (u == 0) { + break; + } + if (detail::gTwoCharEscapes[u]) { + nExtra += 1; + } else if (u <= 0x1f) { + nExtra += 5; + } + p++; + } + + if (nExtra == 0) { + // No escapes needed. Easy. + mIsOwned = false; + mUnownedStr = aStr; + return; + } + + // Escapes are needed. We'll create a new string. + mIsOwned = true; + size_t len = (p - aStr) + nExtra; + mOwnedStr = MakeUnique(len + 1); + + p = aStr; + size_t i = 0; + + while (true) { + uint8_t u = *p; // ensure it can't be interpreted as negative + if (u == 0) { + mOwnedStr[i] = 0; + break; + } + if (detail::gTwoCharEscapes[u]) { + mOwnedStr[i++] = '\\'; + mOwnedStr[i++] = detail::gTwoCharEscapes[u]; + } else if (u <= 0x1f) { + mOwnedStr[i++] = '\\'; + mOwnedStr[i++] = 'u'; + mOwnedStr[i++] = '0'; + mOwnedStr[i++] = '0'; + mOwnedStr[i++] = hexDigitToAsciiChar((u & 0x00f0) >> 4); + mOwnedStr[i++] = hexDigitToAsciiChar(u & 0x000f); + } else { + mOwnedStr[i++] = u; + } + p++; + } + } + + ~EscapedString() + { + SanityCheck(); + } + + const char* get() const + { + SanityCheck(); + return mIsOwned ? mOwnedStr.get() : mUnownedStr; + } + }; + + const UniquePtr mWriter; + Vector mNeedComma; // do we need a comma at depth N? + size_t mDepth; // the current nesting depth + + void Indent() + { + for (size_t i = 0; i < mDepth; i++) { + mWriter->Write(" "); + } + } + + // Adds whatever is necessary (maybe a comma, and then a newline and + // whitespace) to separate an item (property or element) from what's come + // before. + void Separator() + { + if (mNeedComma[mDepth]) { + mWriter->Write(","); + } + if (mDepth > 0) { + mWriter->Write("\n"); + } + Indent(); + } + + void PropertyNameAndColon(const char* aName) + { + EscapedString escapedName(aName); + mWriter->Write("\""); + mWriter->Write(escapedName.get()); + mWriter->Write("\": "); + } + + void Scalar(const char* aMaybePropertyName, const char* aStringValue) + { + Separator(); + if (aMaybePropertyName) { + PropertyNameAndColon(aMaybePropertyName); + } + mWriter->Write(aStringValue); + mNeedComma[mDepth] = true; + } + + void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue) + { + Separator(); + if (aMaybePropertyName) { + PropertyNameAndColon(aMaybePropertyName); + } + mWriter->Write("\""); + mWriter->Write(aStringValue); + mWriter->Write("\""); + mNeedComma[mDepth] = true; + } + + void NewCommaEntry() + { + // If this tiny allocation OOMs we might as well just crash because we must + // be in serious memory trouble. + MOZ_RELEASE_ASSERT(mNeedComma.growByUninitialized(1)); + mNeedComma[mDepth] = false; + } + + void StartCollection(const char* aMaybePropertyName, const char* aStartChar) + { + Separator(); + if (aMaybePropertyName) { + mWriter->Write("\""); + mWriter->Write(aMaybePropertyName); + mWriter->Write("\": "); + } + mWriter->Write(aStartChar); + mNeedComma[mDepth] = true; + mDepth++; + NewCommaEntry(); + } + + // Adds the whitespace and closing char necessary to end a collection. + void EndCollection(const char* aEndChar) + { + mDepth--; + mWriter->Write("\n"); + Indent(); + mWriter->Write(aEndChar); + } + +public: + explicit JSONWriter(UniquePtr aWriter) + : mWriter(Move(aWriter)) + , mNeedComma() + , mDepth(0) + { + NewCommaEntry(); + } + + // Returns the JSONWriteFunc passed in at creation, for temporary use. The + // JSONWriter object still owns the JSONWriteFunc. + JSONWriteFunc* WriteFunc() const { return mWriter.get(); } + + // For all the following functions, the "Prints:" comment indicates what the + // basic output looks like. However, it doesn't indicate the indentation and + // trailing commas, which are automatically added as required. + // + // All property names and string properties are escaped as necessary. + + // Prints: { + void Start() { StartCollection(nullptr, "{"); } + + // Prints: }\n + void End() { EndCollection("}\n"); } + + // Prints: "": null + void NullProperty(const char* aName) + { + Scalar(aName, "null"); + } + + // Prints: null + void NullElement() { NullProperty(nullptr); } + + // Prints: "": + void BoolProperty(const char* aName, bool aBool) + { + Scalar(aName, aBool ? "true" : "false"); + } + + // Prints: + void BoolElement(bool aBool) { BoolProperty(nullptr, aBool); } + + // Prints: "": + void IntProperty(const char* aName, int64_t aInt) + { + char buf[64]; + sprintf(buf, "%" PRId64, aInt); + Scalar(aName, buf); + } + + // Prints: + void IntElement(int64_t aInt) { IntProperty(nullptr, aInt); } + + // Prints: "": + void DoubleProperty(const char* aName, double aDouble) + { + static const size_t buflen = 64; + char buf[buflen]; + const double_conversion::DoubleToStringConverter &converter = + double_conversion::DoubleToStringConverter::EcmaScriptConverter(); + double_conversion::StringBuilder builder(buf, buflen); + converter.ToShortest(aDouble, &builder); + Scalar(aName, builder.Finalize()); + } + + // Prints: + void DoubleElement(double aDouble) { DoubleProperty(nullptr, aDouble); } + + // Prints: "": "" + void StringProperty(const char* aName, const char* aStr) + { + EscapedString escapedStr(aStr); + QuotedScalar(aName, escapedStr.get()); + } + + // Prints: "" + void StringElement(const char* aStr) { StringProperty(nullptr, aStr); } + + // Prints: "": "" + // The pointer is printed as a hexadecimal integer with a leading '0x'. + void PointerProperty(const char* aName, const void* aPtr) + { + char buf[32]; + sprintf(buf, "0x%" PRIxPTR, uintptr_t(aPtr)); + QuotedScalar(aName, buf); + } + + // Prints: "" + // The pointer is printed as a hexadecimal integer with a leading '0x'. + void PointerElement(const void* aPtr) { PointerProperty(nullptr, aPtr); } + + // Prints: "": [ + void StartArrayProperty(const char* aName) { StartCollection(aName, "["); } + + // Prints: [ + void StartArrayElement() { StartArrayProperty(nullptr); } + + // Prints: ] + void EndArray() { EndCollection("]"); } + + // Prints: "": { + void StartObjectProperty(const char* aName) { StartCollection(aName, "{"); } + + // Prints: { + void StartObjectElement() { StartObjectProperty(nullptr); } + + // Prints: } + void EndObject() { EndCollection("}"); } +}; + +} // namespace mozilla + +#endif /* mozilla_JSONWriter_h */ + diff --git a/libazure/include/mozilla/Likely.h b/libazure/mozilla/Likely.h similarity index 66% rename from libazure/include/mozilla/Likely.h rename to libazure/mozilla/Likely.h index 6412b49..4f21609 100644 --- a/libazure/include/mozilla/Likely.h +++ b/libazure/mozilla/Likely.h @@ -1,15 +1,16 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * MOZ_LIKELY and MOZ_UNLIKELY macros to hint to the compiler how a * boolean predicate should be branch-predicted. */ -#ifndef mozilla_Likely_h_ -#define mozilla_Likely_h_ +#ifndef mozilla_Likely_h +#define mozilla_Likely_h #if defined(__clang__) || defined(__GNUC__) # define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) @@ -19,4 +20,4 @@ # define MOZ_UNLIKELY(x) (!!(x)) #endif -#endif /* mozilla_Likely_h_ */ +#endif /* mozilla_Likely_h */ diff --git a/libazure/mozilla/LinkedList.h b/libazure/mozilla/LinkedList.h new file mode 100644 index 0000000..693c019 --- /dev/null +++ b/libazure/mozilla/LinkedList.h @@ -0,0 +1,486 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A type-safe doubly-linked list class. */ + +/* + * The classes LinkedList and LinkedListElement together form a + * convenient, type-safe doubly-linked list implementation. + * + * The class T which will be inserted into the linked list must inherit from + * LinkedListElement. A given object may be in only one linked list at a + * time. + * + * A LinkedListElement automatically removes itself from the list upon + * destruction, and a LinkedList will fatally assert in debug builds if it's + * non-empty when it's destructed. + * + * For example, you might use LinkedList in a simple observer list class as + * follows. + * + * class Observer : public LinkedListElement + * { + * public: + * void observe(char* aTopic) { ... } + * }; + * + * class ObserverContainer + * { + * private: + * LinkedList list; + * + * public: + * void addObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is part of another list. + * list.insertBack(aObserver); + * } + * + * void removeObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is not part of some list. + * aObserver.remove(); + * // Or, will assert if |aObserver| is not part of |list| specifically. + * // aObserver.removeFrom(list); + * } + * + * void notifyObservers(char* aTopic) + * { + * for (Observer* o = list.getFirst(); o != nullptr; o = o->getNext()) { + * o->observe(aTopic); + * } + * } + * }; + * + */ + +#ifndef mozilla_LinkedList_h +#define mozilla_LinkedList_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/Move.h" +#include "mozilla/NullPtr.h" + +#ifdef __cplusplus + +namespace mozilla { + +template +class LinkedList; + +template +class LinkedListElement +{ + /* + * It's convenient that we return nullptr when getNext() or getPrevious() + * hits the end of the list, but doing so costs an extra word of storage in + * each linked list node (to keep track of whether |this| is the sentinel + * node) and a branch on this value in getNext/getPrevious. + * + * We could get rid of the extra word of storage by shoving the "is + * sentinel" bit into one of the pointers, although this would, of course, + * have performance implications of its own. + * + * But the goal here isn't to win an award for the fastest or slimmest + * linked list; rather, we want a *convenient* linked list. So we won't + * waste time guessing which micro-optimization strategy is best. + * + * + * Speaking of unnecessary work, it's worth addressing here why we wrote + * mozilla::LinkedList in the first place, instead of using stl::list. + * + * The key difference between mozilla::LinkedList and stl::list is that + * mozilla::LinkedList stores the mPrev/mNext pointers in the object itself, + * while stl::list stores the mPrev/mNext pointers in a list element which + * itself points to the object being stored. + * + * mozilla::LinkedList's approach makes it harder to store an object in more + * than one list. But the upside is that you can call next() / prev() / + * remove() directly on the object. With stl::list, you'd need to store a + * pointer to its iterator in the object in order to accomplish this. Not + * only would this waste space, but you'd have to remember to update that + * pointer every time you added or removed the object from a list. + * + * In-place, constant-time removal is a killer feature of doubly-linked + * lists, and supporting this painlessly was a key design criterion. + */ + +private: + LinkedListElement* mNext; + LinkedListElement* mPrev; + const bool mIsSentinel; + +public: + LinkedListElement() + : mNext(MOZ_THIS_IN_INITIALIZER_LIST()), + mPrev(MOZ_THIS_IN_INITIALIZER_LIST()), + mIsSentinel(false) + { } + + LinkedListElement(LinkedListElement&& other) + : mIsSentinel(other.mIsSentinel) + { + if (!other.isInList()) { + mNext = this; + mPrev = this; + return; + } + + MOZ_ASSERT(other.mNext->mPrev == &other); + MOZ_ASSERT(other.mPrev->mNext == &other); + + /* + * Initialize |this| with |other|'s mPrev/mNext pointers, and adjust those + * element to point to this one. + */ + mNext = other.mNext; + mPrev = other.mPrev; + + mNext->mPrev = this; + mPrev->mNext = this; + + /* + * Adjust |other| so it doesn't think it's in a list. This makes it + * safely destructable. + */ + other.mNext = &other; + other.mPrev = &other; + } + + ~LinkedListElement() + { + if (!mIsSentinel && isInList()) { + remove(); + } + } + + /* + * Get the next element in the list, or nullptr if this is the last element + * in the list. + */ + T* getNext() { return mNext->asT(); } + const T* getNext() const { return mNext->asT(); } + + /* + * Get the previous element in the list, or nullptr if this is the first + * element in the list. + */ + T* getPrevious() { return mPrev->asT(); } + const T* getPrevious() const { return mPrev->asT(); } + + /* + * Insert aElem after this element in the list. |this| must be part of a + * linked list when you call setNext(); otherwise, this method will assert. + */ + void setNext(T* aElem) + { + MOZ_ASSERT(isInList()); + setNextUnsafe(aElem); + } + + /* + * Insert aElem before this element in the list. |this| must be part of a + * linked list when you call setPrevious(); otherwise, this method will + * assert. + */ + void setPrevious(T* aElem) + { + MOZ_ASSERT(isInList()); + setPreviousUnsafe(aElem); + } + + /* + * Remove this element from the list which contains it. If this element is + * not currently part of a linked list, this method asserts. + */ + void remove() + { + MOZ_ASSERT(isInList()); + + mPrev->mNext = mNext; + mNext->mPrev = mPrev; + mNext = this; + mPrev = this; + } + + /* + * Identical to remove(), but also asserts in debug builds that this element + * is in aList. + */ + void removeFrom(const LinkedList& aList) + { + aList.assertContains(asT()); + remove(); + } + + /* + * Return true if |this| part is of a linked list, and false otherwise. + */ + bool isInList() const + { + MOZ_ASSERT((mNext == this) == (mPrev == this)); + return mNext != this; + } + +private: + friend class LinkedList; + + enum NodeKind { + NODE_KIND_NORMAL, + NODE_KIND_SENTINEL + }; + + explicit LinkedListElement(NodeKind nodeKind) + : mNext(MOZ_THIS_IN_INITIALIZER_LIST()), + mPrev(MOZ_THIS_IN_INITIALIZER_LIST()), + mIsSentinel(nodeKind == NODE_KIND_SENTINEL) + { } + + /* + * Return |this| cast to T* if we're a normal node, or return nullptr if + * we're a sentinel node. + */ + T* asT() + { + return mIsSentinel ? nullptr : static_cast(this); + } + const T* asT() const + { + return mIsSentinel ? nullptr : static_cast(this); + } + + /* + * Insert aElem after this element, but don't check that this element is in + * the list. This is called by LinkedList::insertFront(). + */ + void setNextUnsafe(T* aElem) + { + LinkedListElement *listElem = static_cast(aElem); + MOZ_ASSERT(!listElem->isInList()); + + listElem->mNext = this->mNext; + listElem->mPrev = this; + this->mNext->mPrev = listElem; + this->mNext = listElem; + } + + /* + * Insert aElem before this element, but don't check that this element is in + * the list. This is called by LinkedList::insertBack(). + */ + void setPreviousUnsafe(T* aElem) + { + LinkedListElement* listElem = static_cast*>(aElem); + MOZ_ASSERT(!listElem->isInList()); + + listElem->mNext = this; + listElem->mPrev = this->mPrev; + this->mPrev->mNext = listElem; + this->mPrev = listElem; + } + +private: + LinkedListElement& operator=(const LinkedListElement& aOther) MOZ_DELETE; + LinkedListElement(const LinkedListElement& aOther) MOZ_DELETE; +}; + +template +class LinkedList +{ +private: + LinkedListElement sentinel; + +public: + LinkedList() : sentinel(LinkedListElement::NODE_KIND_SENTINEL) { } + + LinkedList(LinkedList&& aOther) + : sentinel(mozilla::Move(aOther.sentinel)) + { } + + ~LinkedList() { MOZ_ASSERT(isEmpty()); } + + /* + * Add aElem to the front of the list. + */ + void insertFront(T* aElem) + { + /* Bypass setNext()'s this->isInList() assertion. */ + sentinel.setNextUnsafe(aElem); + } + + /* + * Add aElem to the back of the list. + */ + void insertBack(T* aElem) + { + sentinel.setPreviousUnsafe(aElem); + } + + /* + * Get the first element of the list, or nullptr if the list is empty. + */ + T* getFirst() { return sentinel.getNext(); } + const T* getFirst() const { return sentinel.getNext(); } + + /* + * Get the last element of the list, or nullptr if the list is empty. + */ + T* getLast() { return sentinel.getPrevious(); } + const T* getLast() const { return sentinel.getPrevious(); } + + /* + * Get and remove the first element of the list. If the list is empty, + * return nullptr. + */ + T* popFirst() + { + T* ret = sentinel.getNext(); + if (ret) { + static_cast*>(ret)->remove(); + } + return ret; + } + + /* + * Get and remove the last element of the list. If the list is empty, + * return nullptr. + */ + T* popLast() + { + T* ret = sentinel.getPrevious(); + if (ret) { + static_cast*>(ret)->remove(); + } + return ret; + } + + /* + * Return true if the list is empty, or false otherwise. + */ + bool isEmpty() const + { + return !sentinel.isInList(); + } + + /* + * Remove all the elements from the list. + * + * This runs in time linear to the list's length, because we have to mark + * each element as not in the list. + */ + void clear() + { + while (popFirst()) { + continue; + } + } + + /* + * Measures the memory consumption of the list excluding |this|. Note that + * it only measures the list elements themselves. If the list elements + * contain pointers to other memory blocks, those blocks must be measured + * separately during a subsequent iteration over the list. + */ + size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const + { + size_t n = 0; + for (const T* t = getFirst(); t; t = t->getNext()) { + n += aMallocSizeOf(t); + } + return n; + } + + /* + * Like sizeOfExcludingThis(), but measures |this| as well. + */ + size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const + { + return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); + } + + /* + * In a debug build, make sure that the list is sane (no cycles, consistent + * mNext/mPrev pointers, only one sentinel). Has no effect in release builds. + */ + void debugAssertIsSane() const + { +#ifdef DEBUG + const LinkedListElement* slow; + const LinkedListElement* fast1; + const LinkedListElement* fast2; + + /* + * Check for cycles in the forward singly-linked list using the + * tortoise/hare algorithm. + */ + for (slow = sentinel.mNext, + fast1 = sentinel.mNext->mNext, + fast2 = sentinel.mNext->mNext->mNext; + slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; + slow = slow->mNext, fast1 = fast2->mNext, fast2 = fast1->mNext) { + MOZ_ASSERT(slow != fast1); + MOZ_ASSERT(slow != fast2); + } + + /* Check for cycles in the backward singly-linked list. */ + for (slow = sentinel.mPrev, + fast1 = sentinel.mPrev->mPrev, + fast2 = sentinel.mPrev->mPrev->mPrev; + slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; + slow = slow->mPrev, fast1 = fast2->mPrev, fast2 = fast1->mPrev) { + MOZ_ASSERT(slow != fast1); + MOZ_ASSERT(slow != fast2); + } + + /* + * Check that |sentinel| is the only node in the list with + * mIsSentinel == true. + */ + for (const LinkedListElement* elem = sentinel.mNext; + elem != &sentinel; + elem = elem->mNext) { + MOZ_ASSERT(!elem->mIsSentinel); + } + + /* Check that the mNext/mPrev pointers match up. */ + const LinkedListElement* prev = &sentinel; + const LinkedListElement* cur = sentinel.mNext; + do { + MOZ_ASSERT(cur->mPrev == prev); + MOZ_ASSERT(prev->mNext == cur); + + prev = cur; + cur = cur->mNext; + } while (cur != &sentinel); +#endif /* ifdef DEBUG */ + } + +private: + friend class LinkedListElement; + + void assertContains(const T* aValue) const + { +#ifdef DEBUG + for (const T* elem = getFirst(); elem; elem = elem->getNext()) { + if (elem == aValue) { + return; + } + } + MOZ_CRASH("element wasn't found in this list!"); +#endif + } + + LinkedList& operator=(const LinkedList& aOther) MOZ_DELETE; + LinkedList(const LinkedList& aOther) MOZ_DELETE; +}; + +} /* namespace mozilla */ + +#endif /* __cplusplus */ + +#endif /* mozilla_LinkedList_h */ diff --git a/libazure/mozilla/LinuxSignal.h b/libazure/mozilla/LinuxSignal.h new file mode 100644 index 0000000..9b8e1bb --- /dev/null +++ b/libazure/mozilla/LinuxSignal.h @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_LinuxSignal_h +#define mozilla_LinuxSignal_h + +namespace mozilla { + +#if defined(__arm__) + +// Some (old) Linux kernels on ARM have a bug where a signal handler +// can be called without clearing the IT bits in CPSR first. The result +// is that the first few instructions of the handler could be skipped, +// ultimately resulting in crashes. To workaround this bug, the handler +// on ARM is a trampoline that starts with enough NOP instructions, so +// that even if the IT bits are not cleared, only the NOP instructions +// will be skipped over. + +template +__attribute__((naked)) void +SignalTrampoline(int aSignal, siginfo_t* aInfo, void* aContext) +{ + asm volatile ( + "nop; nop; nop; nop" + : : : "memory"); + + // Because the assembler may generate additional insturctions below, we + // need to ensure NOPs are inserted first by separating them out above. + + asm volatile ( + "bx %0" + : + : "r"(H), "l"(aSignal), "l"(aInfo), "l"(aContext) + : "memory"); +} + +# define MOZ_SIGNAL_TRAMPOLINE(h) (mozilla::SignalTrampoline) + +#else // __arm__ + +# define MOZ_SIGNAL_TRAMPOLINE(h) (h) + +#endif // __arm__ + +} // namespace mozilla + +#endif // mozilla_LinuxSignal_h diff --git a/libazure/mozilla/MSIntTypes.h b/libazure/mozilla/MSIntTypes.h new file mode 100644 index 0000000..4ce922f --- /dev/null +++ b/libazure/mozilla/MSIntTypes.h @@ -0,0 +1,198 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// DO NOT SUPPORT THE scanf MACROS! See the comment at the top of +// IntegerPrintfMacros.h. + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff --git a/libazure/src/mfbt/MSStdInt.h b/libazure/mozilla/MSStdInt.h similarity index 100% rename from libazure/src/mfbt/MSStdInt.h rename to libazure/mozilla/MSStdInt.h diff --git a/libazure/mozilla/MacroArgs.h b/libazure/mozilla/MacroArgs.h new file mode 100644 index 0000000..c8b7338 --- /dev/null +++ b/libazure/mozilla/MacroArgs.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements various macros meant to ease the use of variadic macros. + */ + +#ifndef mozilla_MacroArgs_h +#define mozilla_MacroArgs_h + +/* + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic + * arguments and prefixes it with |aPrefix|. For example: + * + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3 + * + * You must pass in between 1 and 50 (inclusive) variadic arguments, past + * |aPrefix|. It is not legal to do + * + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix) + * + * (that is, pass in 0 variadic arguments). To ensure that a compile-time + * error occurs when these constraints are violated, use the + * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments + * wherever this macro is used. + * + * Passing (__VA_ARGS__, ) rather than simply calling + * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, ) very + * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__ + * as a single token in argument lists. For details, see: + * + * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement + * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 + */ +#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \ + MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \ + aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \ + aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \ + aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \ + aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \ + aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \ + aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \ + aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \ + aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \ + aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \ + aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0)) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \ + MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs + +#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \ + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \ + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \ + a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \ + a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \ + a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \ + a51, ...) a51 + +/* + * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs + * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are + * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used + * and pass it the same variadic arguments. + * + * This macro employs a few dirty tricks to function. To detect the zero + * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to + * what it should be in the absence of arguments. + * + * Detecting too many arguments is a little trickier. With a valid argument + * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14. + * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many + * arguments, it expands to the first argument over the limit. If this + * exceeding argument is a number, the assertion will fail as there is no + * number than can simultaneously be both > 10 and == 0. If the exceeding + * argument is not a number, a compile-time error should still occur due to + * the operations performed on it. + */ +#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x +#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \ + static_assert( \ + sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \ + (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \ + (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \ + "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */ + +/* + * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N| + * arguments. For example: + * + * MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d + */ +#define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__ +#define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__ + +/* + * MOZ_ARG_N expands to its |N|th argument. + */ +#define MOZ_ARG_1(a1, ...) a1 +#define MOZ_ARG_2(a1, a2, ...) a2 + +#endif /* mozilla_MacroArgs_h */ diff --git a/libazure/mozilla/MacroForEach.h b/libazure/mozilla/MacroForEach.h new file mode 100644 index 0000000..ae1f4d0 --- /dev/null +++ b/libazure/mozilla/MacroForEach.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements a higher-order macro for iteratively calling another macro with + * fixed leading arguments, plus a trailing element picked from a second list + * of arguments. + */ + +#ifndef mozilla_MacroForEach_h +#define mozilla_MacroForEach_h + +#include "mozilla/MacroArgs.h" + +/* + * MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) expands to N calls to the macro + * |aMacro| where N is equal the number of items in the list |aArgs|. The + * arguments for each |aMacro| call are composed of *all* arguments in the list + * |aFixedArgs| as well as a single argument in the list |aArgs|. For example: + * + * #define MACRO_A(x) x + + * int a = MOZ_FOR_EACH(MACRO_A, (), (1, 2, 3)) 0; + * // Expands to: MACRO_A(1) MACRO_A(2) MACRO_A(3) 0; + * // And further to: 1 + 2 + 3 + 0; + * + * #define MACRO_B(k, x) (k + x) + + * int b = MOZ_FOR_EACH(MACRO_B, (5,), (1, 2)) 0; + * // Expands to: MACRO_B(5, 1) MACRO_B(5, 2) 0; + * + * #define MACRO_C(k1, k2, x) (k1 + k2 + x) + + * int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0; + * // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0; + * + * If the |aFixedArgs| list is not empty, a trailing comma must be included. + * + * The |aArgs| list must be not be empty and may be up to 50 items long. Use + * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint + * results in a compile-time error. + */ +#define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__ +#define MOZ_FOR_EACH_GLUE(a, b) a b +#define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \ + MOZ_FOR_EACH_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \ + MOZ_FOR_EACH_EXPAND_HELPER aArgs), \ + (aMacro, aFixedArgs, aArgs)) + +#define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b +#define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \ + MOZ_FOR_EACH_HELPER_GLUE( \ + aMacro, \ + (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs)) + +#define MOZ_FOR_EACH_1(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) +#define MOZ_FOR_EACH_2(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_3(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_4(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_5(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_6(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_7(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_8(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_9(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_10(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_11(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_12(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_13(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_14(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_15(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_16(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_17(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_18(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_19(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_20(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_21(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_22(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_23(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_24(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_25(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_26(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_27(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_28(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_29(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_30(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_31(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_32(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_33(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_34(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_35(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_36(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_37(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_38(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_39(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_40(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_41(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_42(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_43(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_44(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_45(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_46(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_47(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_48(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_49(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_50(m, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a)) + +#endif /* mozilla_MacroForEach_h */ diff --git a/libazure/mozilla/MathAlgorithms.h b/libazure/mozilla/MathAlgorithms.h new file mode 100644 index 0000000..cd71d19 --- /dev/null +++ b/libazure/mozilla/MathAlgorithms.h @@ -0,0 +1,501 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* mfbt maths algorithms. */ + +#ifndef mozilla_MathAlgorithms_h +#define mozilla_MathAlgorithms_h + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" + +#include +#include +#include + +namespace mozilla { + +// Greatest Common Divisor +template +MOZ_ALWAYS_INLINE IntegerType +EuclidGCD(IntegerType aA, IntegerType aB) +{ + // Euclid's algorithm; O(N) in the worst case. (There are better + // ways, but we don't need them for the current use of this algo.) + MOZ_ASSERT(aA > IntegerType(0)); + MOZ_ASSERT(aB > IntegerType(0)); + + while (aA != aB) { + if (aA > aB) { + aA = aA - aB; + } else { + aB = aB - aA; + } + } + + return aA; +} + +// Least Common Multiple +template +MOZ_ALWAYS_INLINE IntegerType +EuclidLCM(IntegerType aA, IntegerType aB) +{ + // Divide first to reduce overflow risk. + return (aA / EuclidGCD(aA, aB)) * aB; +} + +namespace detail { + +template +struct AllowDeprecatedAbsFixed : FalseType {}; + +template<> struct AllowDeprecatedAbsFixed : TrueType {}; +template<> struct AllowDeprecatedAbsFixed : TrueType {}; + +template +struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed {}; + +template<> struct AllowDeprecatedAbs : TrueType {}; +template<> struct AllowDeprecatedAbs : TrueType {}; + +} // namespace detail + +// DO NOT USE DeprecatedAbs. It exists only until its callers can be converted +// to Abs below, and it will be removed when all callers have been changed. +template +inline typename mozilla::EnableIf::value, T>::Type +DeprecatedAbs(const T aValue) +{ + // The absolute value of the smallest possible value of a signed-integer type + // won't fit in that type (on twos-complement systems -- and we're blithely + // assuming we're on such systems, for the non- types listed above), + // so assert that the input isn't that value. + // + // This is the case if: the value is non-negative; or if adding one (giving a + // value in the range [-maxvalue, 0]), then negating (giving a value in the + // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, + // (minvalue + 1) == -maxvalue). + MOZ_ASSERT(aValue >= 0 || + -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), + "You can't negate the smallest possible negative integer!"); + return aValue >= 0 ? aValue : -aValue; +} + +namespace detail { + +// For now mozilla::Abs only takes intN_T, the signed natural types, and +// float/double/long double. Feel free to add overloads for other standard, +// signed types if you need them. + +template +struct AbsReturnTypeFixed; + +template<> struct AbsReturnTypeFixed { typedef uint8_t Type; }; +template<> struct AbsReturnTypeFixed { typedef uint16_t Type; }; +template<> struct AbsReturnTypeFixed { typedef uint32_t Type; }; +template<> struct AbsReturnTypeFixed { typedef uint64_t Type; }; + +template +struct AbsReturnType : AbsReturnTypeFixed {}; + +template<> struct AbsReturnType : + EnableIf {}; +template<> struct AbsReturnType { typedef unsigned char Type; }; +template<> struct AbsReturnType { typedef unsigned short Type; }; +template<> struct AbsReturnType { typedef unsigned int Type; }; +template<> struct AbsReturnType { typedef unsigned long Type; }; +template<> struct AbsReturnType { typedef unsigned long long Type; }; +template<> struct AbsReturnType { typedef float Type; }; +template<> struct AbsReturnType { typedef double Type; }; +template<> struct AbsReturnType { typedef long double Type; }; + +} // namespace detail + +template +inline typename detail::AbsReturnType::Type +Abs(const T aValue) +{ + typedef typename detail::AbsReturnType::Type ReturnType; + return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1; +} + +template<> +inline float +Abs(const float aFloat) +{ + return std::fabs(aFloat); +} + +template<> +inline double +Abs(const double aDouble) +{ + return std::fabs(aDouble); +} + +template<> +inline long double +Abs(const long double aLongDouble) +{ + return std::fabs(aLongDouble); +} + +} // namespace mozilla + +#if defined(_WIN32) && (_MSC_VER >= 1300) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) +# define MOZ_BITSCAN_WINDOWS + +# include +# pragma intrinsic(_BitScanForward, _BitScanReverse) + +# if defined(_M_AMD64) || defined(_M_X64) +# define MOZ_BITSCAN_WINDOWS64 +# pragma intrinsic(_BitScanForward64, _BitScanReverse64) +# endif + +#endif + +namespace mozilla { + +namespace detail { + +#if defined(MOZ_BITSCAN_WINDOWS) + +inline uint_fast8_t +CountLeadingZeroes32(uint32_t aValue) +{ + unsigned long index; + _BitScanReverse(&index, static_cast(aValue)); + return uint_fast8_t(31 - index); +} + + +inline uint_fast8_t +CountTrailingZeroes32(uint32_t aValue) +{ + unsigned long index; + _BitScanForward(&index, static_cast(aValue)); + return uint_fast8_t(index); +} + +inline uint_fast8_t +CountPopulation32(uint32_t aValue) +{ + uint32_t x = aValue - ((aValue >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +} +inline uint_fast8_t +CountPopulation64(uint64_t aValue) +{ + return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) + + CountPopulation32(aValue >> 32)); +} + +inline uint_fast8_t +CountLeadingZeroes64(uint64_t aValue) +{ +#if defined(MOZ_BITSCAN_WINDOWS64) + unsigned long index; + _BitScanReverse64(&index, static_cast(aValue)); + return uint_fast8_t(63 - index); +#else + uint32_t hi = uint32_t(aValue >> 32); + if (hi != 0) { + return CountLeadingZeroes32(hi); + } + return 32u + CountLeadingZeroes32(uint32_t(aValue)); +#endif +} + +inline uint_fast8_t +CountTrailingZeroes64(uint64_t aValue) +{ +#if defined(MOZ_BITSCAN_WINDOWS64) + unsigned long index; + _BitScanForward64(&index, static_cast(aValue)); + return uint_fast8_t(index); +#else + uint32_t lo = uint32_t(aValue); + if (lo != 0) { + return CountTrailingZeroes32(lo); + } + return 32u + CountTrailingZeroes32(uint32_t(aValue >> 32)); +#endif +} + +# ifdef MOZ_HAVE_BITSCAN64 +# undef MOZ_HAVE_BITSCAN64 +# endif + +#elif defined(__clang__) || defined(__GNUC__) + +# if defined(__clang__) +# if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) +# error "A clang providing __builtin_c[lt]z is required to build" +# endif +# else + // gcc has had __builtin_clz and friends since 3.4: no need to check. +# endif + +inline uint_fast8_t +CountLeadingZeroes32(uint32_t aValue) +{ + return __builtin_clz(aValue); +} + +inline uint_fast8_t +CountTrailingZeroes32(uint32_t aValue) +{ + return __builtin_ctz(aValue); +} + +inline uint_fast8_t +CountPopulation32(uint32_t aValue) +{ + return __builtin_popcount(aValue); +} + +inline uint_fast8_t +CountPopulation64(uint64_t aValue) +{ + return __builtin_popcountll(aValue); +} + +inline uint_fast8_t +CountLeadingZeroes64(uint64_t aValue) +{ + return __builtin_clzll(aValue); +} + +inline uint_fast8_t +CountTrailingZeroes64(uint64_t aValue) +{ + return __builtin_ctzll(aValue); +} + +#else +# error "Implement these!" +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) MOZ_DELETE; +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) MOZ_DELETE; +inline uint_fast8_t CountPopulation32(uint32_t aValue) MOZ_DELETE; +inline uint_fast8_t CountPopulation64(uint64_t aValue) MOZ_DELETE; +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) MOZ_DELETE; +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) MOZ_DELETE; +#endif + +} // namespace detail + +/** + * Compute the number of high-order zero bits in the NON-ZERO number |aValue|. + * That is, looking at the bitwise representation of the number, with the + * highest- valued bits at the start, return the number of zeroes before the + * first one is observed. + * + * CountLeadingZeroes32(0xF0FF1000) is 0; + * CountLeadingZeroes32(0x7F8F0001) is 1; + * CountLeadingZeroes32(0x3FFF0100) is 2; + * CountLeadingZeroes32(0x1FF50010) is 3; and so on. + */ +inline uint_fast8_t +CountLeadingZeroes32(uint32_t aValue) +{ + MOZ_ASSERT(aValue != 0); + return detail::CountLeadingZeroes32(aValue); +} + +/** + * Compute the number of low-order zero bits in the NON-ZERO number |aValue|. + * That is, looking at the bitwise representation of the number, with the + * lowest- valued bits at the start, return the number of zeroes before the + * first one is observed. + * + * CountTrailingZeroes32(0x0100FFFF) is 0; + * CountTrailingZeroes32(0x7000FFFE) is 1; + * CountTrailingZeroes32(0x0080FFFC) is 2; + * CountTrailingZeroes32(0x0080FFF8) is 3; and so on. + */ +inline uint_fast8_t +CountTrailingZeroes32(uint32_t aValue) +{ + MOZ_ASSERT(aValue != 0); + return detail::CountTrailingZeroes32(aValue); +} + +/** + * Compute the number of one bits in the number |aValue|, + */ +inline uint_fast8_t +CountPopulation32(uint32_t aValue) +{ + return detail::CountPopulation32(aValue); +} + +/** Analogous to CoutPopulation32, but for 64-bit numbers */ +inline uint_fast8_t +CountPopulation64(uint64_t aValue) +{ + return detail::CountPopulation64(aValue); +} + +/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */ +inline uint_fast8_t +CountLeadingZeroes64(uint64_t aValue) +{ + MOZ_ASSERT(aValue != 0); + return detail::CountLeadingZeroes64(aValue); +} + +/** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */ +inline uint_fast8_t +CountTrailingZeroes64(uint64_t aValue) +{ + MOZ_ASSERT(aValue != 0); + return detail::CountTrailingZeroes64(aValue); +} + +namespace detail { + +template +class CeilingLog2; + +template +class CeilingLog2 +{ +public: + static uint_fast8_t compute(const T aValue) + { + // Check for <= 1 to avoid the == 0 undefined case. + return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1); + } +}; + +template +class CeilingLog2 +{ +public: + static uint_fast8_t compute(const T aValue) + { + // Check for <= 1 to avoid the == 0 undefined case. + return aValue <= 1 ? 0 : 64 - CountLeadingZeroes64(aValue - 1); + } +}; + +} // namespace detail + +/** + * Compute the log of the least power of 2 greater than or equal to |aValue|. + * + * CeilingLog2(0..1) is 0; + * CeilingLog2(2) is 1; + * CeilingLog2(3..4) is 2; + * CeilingLog2(5..8) is 3; + * CeilingLog2(9..16) is 4; and so on. + */ +template +inline uint_fast8_t +CeilingLog2(const T aValue) +{ + return detail::CeilingLog2::compute(aValue); +} + +/** A CeilingLog2 variant that accepts only size_t. */ +inline uint_fast8_t +CeilingLog2Size(size_t aValue) +{ + return CeilingLog2(aValue); +} + +namespace detail { + +template +class FloorLog2; + +template +class FloorLog2 +{ +public: + static uint_fast8_t compute(const T aValue) + { + return 31u - CountLeadingZeroes32(aValue | 1); + } +}; + +template +class FloorLog2 +{ +public: + static uint_fast8_t compute(const T aValue) + { + return 63u - CountLeadingZeroes64(aValue | 1); + } +}; + +} // namespace detail + +/** + * Compute the log of the greatest power of 2 less than or equal to |aValue|. + * + * FloorLog2(0..1) is 0; + * FloorLog2(2..3) is 1; + * FloorLog2(4..7) is 2; + * FloorLog2(8..15) is 3; and so on. + */ +template +inline uint_fast8_t +FloorLog2(const T aValue) +{ + return detail::FloorLog2::compute(aValue); +} + +/** A FloorLog2 variant that accepts only size_t. */ +inline uint_fast8_t +FloorLog2Size(size_t aValue) +{ + return FloorLog2(aValue); +} + +/* + * Compute the smallest power of 2 greater than or equal to |x|. |x| must not + * be so great that the computed value would overflow |size_t|. + */ +inline size_t +RoundUpPow2(size_t aValue) +{ + MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)), + "can't round up -- will overflow!"); + return size_t(1) << CeilingLog2(aValue); +} + +/** + * Rotates the bits of the given value left by the amount of the shift width. + */ +template +inline T +RotateLeft(const T aValue, uint_fast8_t aShift) +{ + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift)); +} + +/** + * Rotates the bits of the given value right by the amount of the shift width. + */ +template +inline T +RotateRight(const T aValue, uint_fast8_t aShift) +{ + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift)); +} + +} /* namespace mozilla */ + +#endif /* mozilla_MathAlgorithms_h */ diff --git a/libazure/mozilla/Maybe.h b/libazure/mozilla/Maybe.h new file mode 100644 index 0000000..316343b --- /dev/null +++ b/libazure/mozilla/Maybe.h @@ -0,0 +1,651 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A class for optional values and in-place lazy construction. */ + +#ifndef mozilla_Maybe_h +#define mozilla_Maybe_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +#include // for placement new + +namespace mozilla { + +struct Nothing { }; + +/* + * Maybe is a container class which contains either zero or one elements. It + * serves two roles. It can represent values which are *semantically* optional, + * augmenting a type with an explicit 'Nothing' value. In this role, it provides + * methods that make it easy to work with values that may be missing, along with + * equality and comparison operators so that Maybe values can be stored in + * containers. Maybe values can be constructed conveniently in expressions using + * type inference, as follows: + * + * void doSomething(Maybe aFoo) { + * if (aFoo) // Make sure that aFoo contains a value... + * aFoo->takeAction(); // and then use |aFoo->| to access it. + * } // |*aFoo| also works! + * + * doSomething(Nothing()); // Passes a Maybe containing no value. + * doSomething(Some(Foo(100))); // Passes a Maybe containing |Foo(100)|. + * + * You'll note that it's important to check whether a Maybe contains a value + * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You + * can avoid these checks, and sometimes write more readable code, using + * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value + * in the Maybe and provide a default for the 'Nothing' case. You can also use + * |apply()| to call a function only if the Maybe holds a value, and |map()| to + * transform the value in the Maybe, returning another Maybe with a possibly + * different type. + * + * Maybe's other role is to support lazily constructing objects without using + * dynamic storage. A Maybe directly contains storage for a value, but it's + * empty by default. |emplace()|, as mentioned above, can be used to construct a + * value in Maybe's storage. The value a Maybe contains can be destroyed by + * calling |reset()|; this will happen automatically if a Maybe is destroyed + * while holding a value. + * + * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null + * value meaning 'Nothing' and any other value meaning 'Some'. You can convert + * from such a pointer to a Maybe value using 'ToMaybe()'. + * + * Maybe is inspired by similar types in the standard library of many other + * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's + * very similar to std::optional, which was proposed for C++14 and originated in + * Boost. The most important differences between Maybe and std::optional are: + * + * - std::optional may be compared with T. We deliberately forbid that. + * - std::optional allows in-place construction without a separate call to + * |emplace()| by using a dummy |in_place_t| value to tag the appropriate + * constructor. + * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but + * lacks corresponding methods for |refOr()| and |ptrOr()|. + * - std::optional lacks |map()| and |apply()|, making it less suitable for + * functional-style code. + * - std::optional lacks many convenience functions that Maybe has. Most + * unfortunately, it lacks equivalents of the type-inferred constructor + * functions |Some()| and |Nothing()|. + * + * N.B. GCC has missed optimizations with Maybe in the past and may generate + * extra branches/loads/stores. Use with caution on hot paths; it's not known + * whether or not this is still a problem. + */ +template +class Maybe +{ + typedef void (Maybe::* ConvertibleToBool)(float*****, double*****); + void nonNull(float*****, double*****) {} + + bool mIsSome; + AlignedStorage2 mStorage; + +public: + typedef T ValueType; + + Maybe() : mIsSome(false) { } + ~Maybe() { reset(); } + + MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { } + + Maybe(const Maybe& aOther) + : mIsSome(false) + { + if (aOther.mIsSome) { + emplace(*aOther); + } + } + + Maybe(Maybe&& aOther) + : mIsSome(false) + { + if (aOther.mIsSome) { + emplace(Move(*aOther)); + aOther.reset(); + } + } + + Maybe& operator=(const Maybe& aOther) + { + if (&aOther != this) { + if (aOther.mIsSome) { + if (mIsSome) { + // XXX(seth): The correct code for this branch, below, can't be used + // due to a bug in Visual Studio 2010. See bug 1052940. + /* + ref() = aOther.ref(); + */ + reset(); + emplace(*aOther); + } else { + emplace(*aOther); + } + } else { + reset(); + } + } + return *this; + } + + Maybe& operator=(Maybe&& aOther) + { + MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); + + if (aOther.mIsSome) { + if (mIsSome) { + ref() = Move(aOther.ref()); + } else { + emplace(Move(*aOther)); + } + aOther.reset(); + } else { + reset(); + } + + return *this; + } + + /* Methods that check whether this Maybe contains a value */ + operator ConvertibleToBool() const { return mIsSome ? &Maybe::nonNull : 0; } + bool isSome() const { return mIsSome; } + bool isNothing() const { return !mIsSome; } + + /* Returns the contents of this Maybe by value. Unsafe unless |isSome()|. */ + T value() const + { + MOZ_ASSERT(mIsSome); + return ref(); + } + + /* + * Returns the contents of this Maybe by value. If |isNothing()|, returns + * the default value provided. + */ + template + T valueOr(V&& aDefault) const + { + if (isSome()) { + return ref(); + } + return Forward(aDefault); + } + + /* + * Returns the contents of this Maybe by value. If |isNothing()|, returns + * the value returned from the function or functor provided. + */ + template + T valueOrFrom(F&& aFunc) const + { + if (isSome()) { + return ref(); + } + return aFunc(); + } + + /* Returns the contents of this Maybe by pointer. Unsafe unless |isSome()|. */ + T* ptr() + { + MOZ_ASSERT(mIsSome); + return &ref(); + } + + const T* ptr() const + { + MOZ_ASSERT(mIsSome); + return &ref(); + } + + /* + * Returns the contents of this Maybe by pointer. If |isNothing()|, + * returns the default value provided. + */ + T* ptrOr(T* aDefault) + { + if (isSome()) { + return ptr(); + } + return aDefault; + } + + const T* ptrOr(const T* aDefault) const + { + if (isSome()) { + return ptr(); + } + return aDefault; + } + + /* + * Returns the contents of this Maybe by pointer. If |isNothing()|, + * returns the value returned from the function or functor provided. + */ + template + T* ptrOrFrom(F&& aFunc) + { + if (isSome()) { + return ptr(); + } + return aFunc(); + } + + template + const T* ptrOrFrom(F&& aFunc) const + { + if (isSome()) { + return ptr(); + } + return aFunc(); + } + + T* operator->() + { + MOZ_ASSERT(mIsSome); + return ptr(); + } + + const T* operator->() const + { + MOZ_ASSERT(mIsSome); + return ptr(); + } + + /* Returns the contents of this Maybe by ref. Unsafe unless |isSome()|. */ + T& ref() + { + MOZ_ASSERT(mIsSome); + return *mStorage.addr(); + } + + const T& ref() const + { + MOZ_ASSERT(mIsSome); + return *mStorage.addr(); + } + + /* + * Returns the contents of this Maybe by ref. If |isNothing()|, returns + * the default value provided. + */ + T& refOr(T& aDefault) + { + if (isSome()) { + return ref(); + } + return aDefault; + } + + const T& refOr(const T& aDefault) const + { + if (isSome()) { + return ref(); + } + return aDefault; + } + + /* + * Returns the contents of this Maybe by ref. If |isNothing()|, returns the + * value returned from the function or functor provided. + */ + template + T& refOrFrom(F&& aFunc) + { + if (isSome()) { + return ref(); + } + return aFunc(); + } + + template + const T& refOrFrom(F&& aFunc) const + { + if (isSome()) { + return ref(); + } + return aFunc(); + } + + T& operator*() + { + MOZ_ASSERT(mIsSome); + return ref(); + } + + const T& operator*() const + { + MOZ_ASSERT(mIsSome); + return ref(); + } + + /* If |isSome()|, runs the provided function or functor on the contents of + * this Maybe. */ + template + void apply(F&& aFunc) + { + if (isSome()) { + aFunc(ref()); + } + } + + template + void apply(F&& aFunc) const + { + if (isSome()) { + aFunc(ref()); + } + } + + /* Variant of |apply()| that takes an additional argument for the function. */ + template + void apply(F&& aFunc, A&& aArg) + { + if (isSome()) { + aFunc(ref(), Forward(aArg)); + } + } + + template + void apply(F&& aFunc, A&& aArg) const + { + if (isSome()) { + aFunc(ref(), Forward(aArg)); + } + } + + /* + * If |isSome()|, runs the provided function and returns the result wrapped + * in a Maybe. If |isNothing()|, returns an empty Maybe value. + */ + template + Maybe map(R(*aFunc)(T&)) + { + if (isSome()) { + Maybe val; + val.emplace(aFunc(ref())); + return val; + } + return Maybe(); + } + + template + Maybe map(R(*aFunc)(const T&)) const + { + if (isSome()) { + Maybe val; + val.emplace(aFunc(ref())); + return val; + } + return Maybe(); + } + + /* Variant of |map()| that takes an additional argument for the function. */ + template + Maybe map(R(*aFunc)(T&, FA), A&& aArg) + { + if (isSome()) { + Maybe val; + val.emplace(aFunc(ref(), Forward(aArg))); + return val; + } + return Maybe(); + } + + template + Maybe map(R(*aFunc)(const T&, FA), A&& aArg) const + { + if (isSome()) { + Maybe val; + val.emplace(aFunc(ref(), Forward(aArg))); + return val; + } + return Maybe(); + } + + /* If |isSome()|, empties this Maybe and destroys its contents. */ + void reset() + { + if (isSome()) { + ref().~T(); + mIsSome = false; + } + } + + /* + * Constructs a T value in-place in this empty Maybe's storage. The + * arguments to |emplace()| are the parameters to T's constructor. + * + * WARNING: You can't pass a literal nullptr to these methods without + * hitting GCC 4.4-only (and hence B2G-only) compile errors. + */ + void emplace() + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(); + mIsSome = true; + } + + template + void emplace(T1&& t1) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5), Forward(t6)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6, + T7&& t7) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5), Forward(t6), + Forward(t7)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6, + T7&& t7, T8&& t8) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5), Forward(t6), + Forward(t7), Forward(t8)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6, + T7&& t7, T8&& t8, T9&& t9) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5), Forward(t6), + Forward(t7), Forward(t8), Forward(t9)); + mIsSome = true; + } + + template + void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6, + T7&& t7, T8&& t8, T9&& t9, T10&& t10) + { + MOZ_ASSERT(!mIsSome); + ::new (mStorage.addr()) T(Forward(t1), Forward(t2), Forward(t3), + Forward(t4), Forward(t5), Forward(t6), + Forward(t7), Forward(t8), Forward(t9), + Forward(t10)); + mIsSome = true; + } +}; + +/* + * Some() creates a Maybe value containing the provided T value. If T has a + * move constructor, it's used to make this as efficient as possible. + * + * Some() selects the type of Maybe it returns by removing any const, volatile, + * or reference qualifiers from the type of the value you pass to it. This gives + * it more intuitive behavior when used in expressions, but it also means that + * if you need to construct a Maybe value that holds a const, volatile, or + * reference value, you need to use emplace() instead. + */ +template +Maybe::Type>::Type> +Some(T&& aValue) +{ + typedef typename RemoveCV::Type>::Type U; + Maybe value; + value.emplace(Forward(aValue)); + return value; +} + +template +Maybe::Type>::Type> +ToMaybe(T* aPtr) +{ + if (aPtr) { + return Some(*aPtr); + } + return Nothing(); +} + +/* + * Two Maybe values are equal if + * - both are Nothing, or + * - both are Some, and the values they contain are equal. + */ +template bool +operator==(const Maybe& aLHS, const Maybe& aRHS) +{ + if (aLHS.isNothing() != aRHS.isNothing()) { + return false; + } + return aLHS.isNothing() || *aLHS == *aRHS; +} + +template bool +operator!=(const Maybe& aLHS, const Maybe& aRHS) +{ + return !(aLHS == aRHS); +} + +/* + * We support comparison to Nothing to allow reasonable expressions like: + * if (maybeValue == Nothing()) { ... } + */ +template bool +operator==(const Maybe& aLHS, const Nothing& aRHS) +{ + return aLHS.isNothing(); +} + +template bool +operator!=(const Maybe& aLHS, const Nothing& aRHS) +{ + return !(aLHS == aRHS); +} + +template bool +operator==(const Nothing& aLHS, const Maybe& aRHS) +{ + return aRHS.isNothing(); +} + +template bool +operator!=(const Nothing& aLHS, const Maybe& aRHS) +{ + return !(aLHS == aRHS); +} + +/* + * Maybe values are ordered in the same way T values are ordered, except that + * Nothing comes before anything else. + */ +template bool +operator<(const Maybe& aLHS, const Maybe& aRHS) +{ + if (aLHS.isNothing()) { + return aRHS.isSome(); + } + if (aRHS.isNothing()) { + return false; + } + return *aLHS < *aRHS; +} + +template bool +operator>(const Maybe& aLHS, const Maybe& aRHS) +{ + return !(aLHS < aRHS || aLHS == aRHS); +} + +template bool +operator<=(const Maybe& aLHS, const Maybe& aRHS) +{ + return aLHS < aRHS || aLHS == aRHS; +} + +template bool +operator>=(const Maybe& aLHS, const Maybe& aRHS) +{ + return !(aLHS < aRHS); +} + +} // namespace mozilla + +#endif /* mozilla_Maybe_h */ diff --git a/libazure/mozilla/MaybeOneOf.h b/libazure/mozilla/MaybeOneOf.h new file mode 100644 index 0000000..1c58f88 --- /dev/null +++ b/libazure/mozilla/MaybeOneOf.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_MaybeOneOf_h +#define mozilla_MaybeOneOf_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Move.h" +#include "mozilla/TemplateLib.h" + +#include // For placement new + +namespace mozilla { + +/* + * MaybeOneOf is like Maybe, but it supports constructing either T1 + * or T2. When a MaybeOneOf is constructed, it is |empty()|, i.e., + * no value has been constructed and no destructor will be called when the + * MaybeOneOf is destroyed. Upon calling |construct()| or + * |construct()|, a T1 or T2 object will be constructed with the given + * arguments and that object will be destroyed when the owning MaybeOneOf is + * destroyed. + */ +template +class MaybeOneOf +{ + AlignedStorage::value> storage; + + enum State { None, SomeT1, SomeT2 } state; + template struct Type2State {}; + + template + T& as() + { + MOZ_ASSERT(state == Type2State::result); + return *(T*)storage.addr(); + } + + template + const T& as() const + { + MOZ_ASSERT(state == Type2State::result); + return *(T*)storage.addr(); + } + +public: + MaybeOneOf() : state(None) {} + ~MaybeOneOf() { destroyIfConstructed(); } + + bool empty() const { return state == None; } + + template + bool constructed() const { return state == Type2State::result; } + + template + void construct() + { + MOZ_ASSERT(state == None); + state = Type2State::result; + ::new (storage.addr()) T(); + } + + template + void construct(U&& aU) + { + MOZ_ASSERT(state == None); + state = Type2State::result; + ::new (storage.addr()) T(Move(aU)); + } + + template + void construct(const U1& aU1) + { + MOZ_ASSERT(state == None); + state = Type2State::result; + ::new (storage.addr()) T(aU1); + } + + template + void construct(const U1& aU1, const U2& aU2) + { + MOZ_ASSERT(state == None); + state = Type2State::result; + ::new (storage.addr()) T(aU1, aU2); + } + + template + T& ref() + { + return as(); + } + + template + const T& ref() const + { + return as(); + } + + void destroy() + { + MOZ_ASSERT(state == SomeT1 || state == SomeT2); + if (state == SomeT1) { + as().~T1(); + } else if (state == SomeT2) { + as().~T2(); + } + state = None; + } + + void destroyIfConstructed() + { + if (!empty()) { + destroy(); + } + } + +private: + MaybeOneOf(const MaybeOneOf& aOther) MOZ_DELETE; + const MaybeOneOf& operator=(const MaybeOneOf& aOther) MOZ_DELETE; +}; + +template +template +struct MaybeOneOf::Type2State +{ + typedef MaybeOneOf Enclosing; + static const typename Enclosing::State result = Enclosing::SomeT1; +}; + +template +template +struct MaybeOneOf::Type2State +{ + typedef MaybeOneOf Enclosing; + static const typename Enclosing::State result = Enclosing::SomeT2; +}; + +} // namespace mozilla + +#endif /* mozilla_MaybeOneOf_h */ diff --git a/libazure/src/mfbt/MemoryChecking.h b/libazure/mozilla/MemoryChecking.h similarity index 57% rename from libazure/src/mfbt/MemoryChecking.h rename to libazure/mozilla/MemoryChecking.h index 3287e57..91a292c 100644 --- a/libazure/src/mfbt/MemoryChecking.h +++ b/libazure/mozilla/MemoryChecking.h @@ -1,10 +1,11 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - * Provides a common interface to the ASan (AddressSanitizer) and Valgrind + * Provides a common interface to the ASan (AddressSanitizer) and Valgrind * functions used to mark memory in certain ways. In detail, the following * three macros are provided: * @@ -19,8 +20,8 @@ * With no memory checker available, all macros expand to the empty statement. */ -#ifndef mozilla_MemoryChecking_h_ -#define mozilla_MemoryChecking_h_ +#ifndef mozilla_MemoryChecking_h +#define mozilla_MemoryChecking_h #if defined(MOZ_VALGRIND) #include "valgrind/memcheck.h" @@ -33,14 +34,16 @@ #if defined(MOZ_ASAN) #include +#include "mozilla/Types.h" + extern "C" { - /* These definitions are usually provided through the - * sanitizer/asan_interface.h header installed by ASan. - */ - void __asan_poison_memory_region(void const volatile *addr, size_t size) - __attribute__((visibility("default"))); - void __asan_unpoison_memory_region(void const volatile *addr, size_t size) - __attribute__((visibility("default"))); +/* These definitions are usually provided through the + * sanitizer/asan_interface.h header installed by ASan. + */ +void MOZ_EXPORT +__asan_poison_memory_region(void const volatile *addr, size_t size); +void MOZ_EXPORT +__asan_unpoison_memory_region(void const volatile *addr, size_t size); #define MOZ_MAKE_MEM_NOACCESS(addr, size) \ __asan_poison_memory_region((addr), (size)) @@ -51,6 +54,29 @@ extern "C" { #define MOZ_MAKE_MEM_DEFINED(addr, size) \ __asan_unpoison_memory_region((addr), (size)) } +#elif defined(MOZ_MSAN) +#include + +#include "mozilla/Types.h" + +extern "C" { +/* These definitions are usually provided through the + * sanitizer/msan_interface.h header installed by MSan. + */ +void MOZ_EXPORT +__msan_poison(void const volatile *addr, size_t size); +void MOZ_EXPORT +__msan_unpoison(void const volatile *addr, size_t size); + +#define MOZ_MAKE_MEM_NOACCESS(addr, size) \ + __msan_poison((addr), (size)) + +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \ + __msan_poison((addr), (size)) + +#define MOZ_MAKE_MEM_DEFINED(addr, size) \ + __msan_unpoison((addr), (size)) +} #elif defined(MOZ_VALGRIND) #define MOZ_MAKE_MEM_NOACCESS(addr, size) \ VALGRIND_MAKE_MEM_NOACCESS((addr), (size)) @@ -62,10 +88,10 @@ extern "C" { VALGRIND_MAKE_MEM_DEFINED((addr), (size)) #else -#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while(0) -#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while(0) -#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while(0) +#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while (0) +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while (0) +#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while (0) #endif -#endif /* mozilla_MemoryChecking_h_ */ +#endif /* mozilla_MemoryChecking_h */ diff --git a/libazure/mozilla/MemoryReporting.h b/libazure/mozilla/MemoryReporting.h new file mode 100644 index 0000000..d2340ec --- /dev/null +++ b/libazure/mozilla/MemoryReporting.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Memory reporting infrastructure. */ + +#ifndef mozilla_MemoryReporting_h +#define mozilla_MemoryReporting_h + +#include + +#ifdef __cplusplus + +namespace mozilla { + +/* + * This is for functions that are like malloc_usable_size. Such functions are + * used for measuring the size of data structures. + */ +typedef size_t (*MallocSizeOf)(const void* p); + +} /* namespace mozilla */ + +#endif /* __cplusplus */ + +typedef size_t (*MozMallocSizeOf)(const void* p); + +#endif /* mozilla_MemoryReporting_h */ diff --git a/libazure/mozilla/Move.h b/libazure/mozilla/Move.h new file mode 100644 index 0000000..08ae86f --- /dev/null +++ b/libazure/mozilla/Move.h @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* C++11-style, but C++98-usable, "move references" implementation. */ + +#ifndef mozilla_Move_h +#define mozilla_Move_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +/* + * "Move" References + * + * Some types can be copied much more efficiently if we know the original's + * value need not be preserved --- that is, if we are doing a "move", not a + * "copy". For example, if we have: + * + * Vector u; + * Vector v(u); + * + * the constructor for v must apply a copy constructor to each element of u --- + * taking time linear in the length of u. However, if we know we will not need u + * any more once v has been initialized, then we could initialize v very + * efficiently simply by stealing u's dynamically allocated buffer and giving it + * to v --- a constant-time operation, regardless of the size of u. + * + * Moves often appear in container implementations. For example, when we append + * to a vector, we may need to resize its buffer. This entails moving each of + * its extant elements from the old, smaller buffer to the new, larger buffer. + * But once the elements have been migrated, we're just going to throw away the + * old buffer; we don't care if they still have their values. So if the vector's + * element type can implement "move" more efficiently than "copy", the vector + * resizing should by all means use a "move" operation. Hash tables should also + * use moves when resizing their internal array as entries are added and + * removed. + * + * The details of the optimization, and whether it's worth applying, vary + * from one type to the next: copying an 'int' is as cheap as moving it, so + * there's no benefit in distinguishing 'int' moves from copies. And while + * some constructor calls for complex types are moves, many really have to + * be copies, and can't be optimized this way. So we need: + * + * 1) a way for a type (like Vector) to announce that it can be moved more + * efficiently than it can be copied, and provide an implementation of that + * move operation; and + * + * 2) a way for a particular invocation of a copy constructor to say that it's + * really a move, not a copy, and that the value of the original isn't + * important afterwards (although it must still be safe to destroy). + * + * If a constructor has a single argument of type 'T&&' (an 'rvalue reference + * to T'), that indicates that it is a 'move constructor'. That's 1). It should + * move, not copy, its argument into the object being constructed. It may leave + * the original in any safely-destructible state. + * + * If a constructor's argument is an rvalue, as in 'C(f(x))' or 'C(x + y)', as + * opposed to an lvalue, as in 'C(x)', then overload resolution will prefer the + * move constructor, if there is one. The 'mozilla::Move' function, defined in + * this file, is an identity function you can use in a constructor invocation to + * make any argument into an rvalue, like this: C(Move(x)). That's 2). (You + * could use any function that works, but 'Move' indicates your intention + * clearly.) + * + * Where we might define a copy constructor for a class C like this: + * + * C(const C& rhs) { ... copy rhs to this ... } + * + * we would declare a move constructor like this: + * + * C(C&& rhs) { .. move rhs to this ... } + * + * And where we might perform a copy like this: + * + * C c2(c1); + * + * we would perform a move like this: + * + * C c2(Move(c1)); + * + * Note that 'T&&' implicitly converts to 'T&'. So you can pass a 'T&&' to an + * ordinary copy constructor for a type that doesn't support a special move + * constructor, and you'll just get a copy. This means that templates can use + * Move whenever they know they won't use the original value any more, even if + * they're not sure whether the type at hand has a specialized move constructor. + * If it doesn't, the 'T&&' will just convert to a 'T&', and the ordinary copy + * constructor will apply. + * + * A class with a move constructor can also provide a move assignment operator. + * A generic definition would run this's destructor, and then apply the move + * constructor to *this's memory. A typical definition: + * + * C& operator=(C&& rhs) { + * MOZ_ASSERT(&rhs != this, "self-moves are prohibited"); + * this->~C(); + * new(this) C(Move(rhs)); + * return *this; + * } + * + * With that in place, one can write move assignments like this: + * + * c2 = Move(c1); + * + * This destroys c2, moves c1's value to c2, and leaves c1 in an undefined but + * destructible state. + * + * As we say, a move must leave the original in a "destructible" state. The + * original's destructor will still be called, so if a move doesn't + * actually steal all its resources, that's fine. We require only that the + * move destination must take on the original's value; and that destructing + * the original must not break the move destination. + * + * (Opinions differ on whether move assignment operators should deal with move + * assignment of an object onto itself. It seems wise to either handle that + * case, or assert that it does not occur.) + * + * Forwarding: + * + * Sometimes we want copy construction or assignment if we're passed an ordinary + * value, but move construction if passed an rvalue reference. For example, if + * our constructor takes two arguments and either could usefully be a move, it + * seems silly to write out all four combinations: + * + * C::C(X& x, Y& y) : x(x), y(y) { } + * C::C(X& x, Y&& y) : x(x), y(Move(y)) { } + * C::C(X&& x, Y& y) : x(Move(x)), y(y) { } + * C::C(X&& x, Y&& y) : x(Move(x)), y(Move(y)) { } + * + * To avoid this, C++11 has tweaks to make it possible to write what you mean. + * The four constructor overloads above can be written as one constructor + * template like so[0]: + * + * template + * C::C(XArg&& x, YArg&& y) : x(Forward(x)), y(Forward(y)) { } + * + * ("'Don't Repeat Yourself'? What's that?") + * + * This takes advantage of two new rules in C++11: + * + * - First, when a function template takes an argument that is an rvalue + * reference to a template argument (like 'XArg&& x' and 'YArg&& y' above), + * then when the argument is applied to an lvalue, the template argument + * resolves to 'T&'; and when it is applied to an rvalue, the template + * argument resolves to 'T&&'. Thus, in a call to C::C like: + * + * X foo(int); + * Y yy; + * + * C(foo(5), yy) + * + * XArg would resolve to 'X&&', and YArg would resolve to 'Y&'. + * + * - Second, Whereas C++ used to forbid references to references, C++11 defines + * 'collapsing rules': 'T& &', 'T&& &', and 'T& &&' (that is, any combination + * involving an lvalue reference) now collapse to simply 'T&'; and 'T&& &&' + * collapses to 'T&&'. + * + * Thus, in the call above, 'XArg&&' is 'X&& &&', collapsing to 'X&&'; and + * 'YArg&&' is 'Y& &&', which collapses to 'Y &'. Because the arguments are + * declared as rvalue references to template arguments, the rvalue-ness + * "shines through" where present. + * + * Then, the 'Forward' function --- you must invoke 'Forward' with its type + * argument --- returns an lvalue reference or an rvalue reference to its + * argument, depending on what T is. In our unified constructor definition, that + * means that we'll invoke either the copy or move constructors for x and y, + * depending on what we gave C's constructor. In our call, we'll move 'foo()' + * into 'x', but copy 'yy' into 'y'. + * + * This header file defines Move and Forward in the mozilla namespace. It's up + * to individual containers to annotate moves as such, by calling Move; and it's + * up to individual types to define move constructors and assignment operators + * when valuable. + * + * (C++11 says that the header file should define 'std::move' and + * 'std::forward', which are just like our 'Move' and 'Forward'; but those + * definitions aren't available in that header on all our platforms, so we + * define them ourselves here.) + * + * 0. This pattern is known as "perfect forwarding". Interestingly, it is not + * actually perfect, and it can't forward all possible argument expressions! + * There are two issues: one that's a C++11 issue, and one that's a legacy + * compiler issue. + * + * The C++11 issue is that you can't form a reference to a bit-field. As a + * workaround, assign the bit-field to a local variable and use that: + * + * // C is as above + * struct S { int x : 1; } s; + * C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those + * int tmp = s.x; + * C(tmp, 0); // OK: tmp not a bit-field + * + * The legacy issue is that when we don't have true nullptr and must emulate + * it (gcc 4.4/4.5), forwarding |nullptr| results in an |int| or |long| + * forwarded reference. But such a reference, even if its value is a null + * pointer constant expression, is not itself a null pointer constant + * expression. This causes -Werror=conversion-null errors and pointer-to- + * integer comparison errors. Until we always have true nullptr, users of + * forwarding methods must not pass |nullptr| to them. + */ + +/** + * Identical to std::Move(); this is necessary until our stlport supports + * std::move(). + */ +template +inline typename RemoveReference::Type&& +Move(T&& aX) +{ + return static_cast::Type&&>(aX); +} + +/** + * These two overloads are identical to std::forward(); they are necessary until + * our stlport supports std::forward(). + */ +template +inline T&& +Forward(typename RemoveReference::Type& aX) +{ + return static_cast(aX); +} + +template +inline T&& +Forward(typename RemoveReference::Type&& aX) +{ + static_assert(!IsLvalueReference::value, + "misuse of Forward detected! try the other overload"); + return static_cast(aX); +} + +/** Swap |aX| and |aY| using move-construction if possible. */ +template +inline void +Swap(T& aX, T& aY) +{ + T tmp(Move(aX)); + aX = Move(aY); + aY = Move(tmp); +} + +} // namespace mozilla + +#endif /* mozilla_Move_h */ diff --git a/libazure/mozilla/NullPtr.h b/libazure/mozilla/NullPtr.h new file mode 100644 index 0000000..5963613 --- /dev/null +++ b/libazure/mozilla/NullPtr.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements a workaround for compilers which do not support the C++11 nullptr + * constant. + */ + +#ifndef mozilla_NullPtr_h +#define mozilla_NullPtr_h + +#if defined(__clang__) +# if !__has_extension(cxx_nullptr) +# error "clang version natively supporting nullptr is required." +# endif +# define MOZ_HAVE_CXX11_NULLPTR +#elif defined(__GNUC__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +# include "mozilla/Compiler.h" +# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) +# define MOZ_HAVE_CXX11_NULLPTR +# endif +# endif +#elif defined(_MSC_VER) + // The minimum supported MSVC (10, _MSC_VER 1600) supports nullptr. +# define MOZ_HAVE_CXX11_NULLPTR +#endif + +namespace mozilla { + +/** + * IsNullPointer::value is true iff T is the type of C++11's nullptr. If + * nullptr is emulated, IsNullPointer::value is false for all T. + * + * IsNullPointer is useful to give an argument the true decltype(nullptr) type. + * decltype(nullptr) doesn't work when nullptr is emulated. The simplest + * workaround is to use template overloading and SFINAE to expose an overload + * only if an argument's type is decltype(nullptr). Some examples (that assume + * namespace mozilla has been opened, for simplicity): + * + * // foo(T*), foo(stuff that converts to T*), and foo(decltype(nullptr)) + * // (only invoked if nullptr is true nullptr, otherwise foo(T*) is invoked) + * // but nothing else + * void foo(T*) { } + * template + * void foo(N, + * typename EnableIf::value, int>::Type dummy = 0) + * { } + * + * // foo(T*) *exactly* and foo(decltype(nullptr)), nothing else + * void foo(T*) { } + * template + * void foo(U, + * typename EnableIf::value, int>::Type dummy = 0) + * MOZ_DELETE; + * + * The exact details of how set up the SFINAE bits vary on a case-by-case basis. + * If you need help with this (and unless you've internalized way more sadmaking + * nullptr-emulation knowledge than you should have, you do), feel free to poke + * the person with blame on this comment with questions. :-) + * + * Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer + * (fixed in C++1y), so in the interests of easing a switch to , + * this trait lives elsewhere. + */ +template +struct IsNullPointer { static const bool value = false; }; + +} // namespace mozilla + +/** + * mozilla::NullptrT is a type that's sort of like decltype(nullptr). But it + * can't be identical, because emulated nullptr doesn't have a distinct type. + * Only with gcc 4.4/4.5, emulated nullptr is __null, and decltype(__null) is + * int or long. But passing __null to an int/long parameter triggers + * -Werror=conversion-null errors with gcc 4.5, or (depending on subsequent use + * inside the overloaded function) can trigger pointer-to-integer comparison + * compiler errors. So fairly often, actually, NullptrT is *not* what you want. + * + * Instead, often you should use template-based overloading in concert with + * SFINAE to add a nullptr overload -- see the comments by IsNullPointer. + * + * So when *should* you use NullptrT? Thus far, the only truly good use seems + * to be as an argument type for operator overloads (because C++ doesn't allow + * operator= to have more than one argument, operator== to have more than two, + * &c.). But even in such cases, it really only works if there are no other + * overloads of the operator that accept a pointer type. If you want both T* + * and nullptr_t overloads, you'll have to wait til we drop gcc 4.4/4.5 support. + * (Currently b2g is the only impediment to this.) + */ +#ifdef MOZ_HAVE_CXX11_NULLPTR +// decltype does the right thing for actual nullptr. +namespace mozilla { +typedef decltype(nullptr) NullptrT; +template<> +struct IsNullPointer { static const bool value = true; }; +} +# undef MOZ_HAVE_CXX11_NULLPTR +#elif MOZ_IS_GCC +# define nullptr __null +// void* sweeps up more than just nullptr, but compilers supporting true +// nullptr are the majority now, so they should detect mistakes. If you're +// feeling paranoid, check/assert that your NullptrT equals nullptr. +namespace mozilla { typedef void* NullptrT; } +#else +# error "No compiler support for nullptr or its emulation." +#endif + +#endif /* mozilla_NullPtr_h */ diff --git a/libazure/mozilla/NumericLimits.h b/libazure/mozilla/NumericLimits.h new file mode 100644 index 0000000..730fcb4 --- /dev/null +++ b/libazure/mozilla/NumericLimits.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Compatibility with std::numeric_limits. */ + +#ifndef mozilla_NumericLimits_h +#define mozilla_NumericLimits_h + +#include "mozilla/Char16.h" + +#include +#include + +namespace mozilla { + +/** + * The NumericLimits class provides a compatibility layer with + * std::numeric_limits for char16_t, otherwise it is exactly the same as + * std::numeric_limits. Code which does not need std::numeric_limits + * should avoid using NumericLimits. + */ +template +class NumericLimits : public std::numeric_limits +{ +}; + +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +template<> +class NumericLimits : public std::numeric_limits +{ + // char16_t and uint16_t numeric limits should be exactly the same. +}; +#endif + +} // namespace mozilla + +#endif /* mozilla_NumericLimits_h */ diff --git a/libazure/mozilla/Pair.h b/libazure/mozilla/Pair.h new file mode 100644 index 0000000..e9e8a76 --- /dev/null +++ b/libazure/mozilla/Pair.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A class holding a pair of objects that tries to conserve storage space. */ + +#ifndef mozilla_Pair_h +#define mozilla_Pair_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +enum StorageType { AsBase, AsMember }; + +// Optimize storage using the Empty Base Optimization -- that empty base classes +// don't take up space -- to optimize size when one or the other class is +// stateless and can be used as a base class. +// +// The extra conditions on storage for B are necessary so that PairHelper won't +// ambiguously inherit from either A or B, such that one or the other base class +// would be inaccessible. +template::value ? detail::AsBase : detail::AsMember, + detail::StorageType = + IsEmpty::value && !IsBaseOf::value && !IsBaseOf::value + ? detail::AsBase + : detail::AsMember> +struct PairHelper; + +template +struct PairHelper +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : mFirstA(Forward(aA)), + mSecondB(Forward(aB)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(mSecondB, aOther.mSecondB); + } + +private: + A mFirstA; + B mSecondB; +}; + +template +struct PairHelper : private B +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : B(Forward(aB)), + mFirstA(Forward(aA)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return *this; } + const B& second() const { return *this; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(static_cast(*this), static_cast(aOther)); + } + +private: + A mFirstA; +}; + +template +struct PairHelper : private A +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward(aA)), + mSecondB(Forward(aB)) + {} + + A& first() { return *this; } + const A& first() const { return *this; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(static_cast(*this), static_cast(aOther)); + Swap(mSecondB, aOther.mSecondB); + } + +private: + B mSecondB; +}; + +template +struct PairHelper : private A, private B +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward(aA)), + B(Forward(aB)) + {} + + A& first() { return static_cast(*this); } + const A& first() const { return static_cast(*this); } + B& second() { return static_cast(*this); } + const B& second() const { return static_cast(*this); } + + void swap(PairHelper& aOther) + { + Swap(static_cast(*this), static_cast(aOther)); + Swap(static_cast(*this), static_cast(aOther)); + } +}; + +} // namespace detail + +/** + * Pair is the logical concatenation of an instance of A with an instance B. + * Space is conserved when possible. Neither A nor B may be a final class. + * + * It's typically clearer to have individual A and B member fields. Except if + * you want the space-conserving qualities of Pair, you're probably better off + * not using this! + * + * No guarantees are provided about the memory layout of A and B, the order of + * initialization or destruction of A and B, and so on. (This is approximately + * required to optimize space usage.) The first/second names are merely + * conceptual! + */ +template +struct Pair + : private detail::PairHelper +{ + typedef typename detail::PairHelper Base; + +public: + template + Pair(AArg&& aA, BArg&& aB) + : Base(Forward(aA), Forward(aB)) + {} + + /** The A instance. */ + using Base::first; + /** The B instance. */ + using Base::second; + + /** Swap this pair with another pair. */ + void swap(Pair& aOther) { Base::swap(aOther); } + +private: + Pair(const Pair&) MOZ_DELETE; +}; + +template +void +Swap(Pair& aX, Pair& aY) +{ + aX.swap(aY); +} + +} // namespace mozilla + +#endif /* mozilla_Pair_h */ diff --git a/libazure/mozilla/PodOperations.h b/libazure/mozilla/PodOperations.h new file mode 100644 index 0000000..843e131 --- /dev/null +++ b/libazure/mozilla/PodOperations.h @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Operations for zeroing POD types, arrays, and so on. + * + * These operations are preferable to memset, memcmp, and the like because they + * don't require remembering to multiply by sizeof(T), array lengths, and so on + * everywhere. + */ + +#ifndef mozilla_PodOperations_h +#define mozilla_PodOperations_h + +#include "mozilla/Array.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Attributes.h" + +#include +#include + +namespace mozilla { + +/** Set the contents of |aT| to 0. */ +template +static MOZ_ALWAYS_INLINE void +PodZero(T* aT) +{ + memset(aT, 0, sizeof(T)); +} + +/** Set the contents of |aNElem| elements starting at |aT| to 0. */ +template +static MOZ_ALWAYS_INLINE void +PodZero(T* aT, size_t aNElem) +{ + /* + * This function is often called with 'aNElem' small; we use an inline loop + * instead of calling 'memset' with a non-constant length. The compiler + * should inline the memset call with constant size, though. + */ + for (T* end = aT + aNElem; aT < end; aT++) { + memset(aT, 0, sizeof(T)); + } +} + +/* + * Arrays implicitly convert to pointers to their first element, which is + * dangerous when combined with the above PodZero definitions. Adding an + * overload for arrays is ambiguous, so we need another identifier. The + * ambiguous overload is left to catch mistaken uses of PodZero; if you get a + * compile error involving PodZero and array types, use PodArrayZero instead. + */ +template +static void PodZero(T (&aT)[N]) MOZ_DELETE; +template +static void PodZero(T (&aT)[N], size_t aNElem) MOZ_DELETE; + +/** Set the contents of the array |aT| to zero. */ +template +static MOZ_ALWAYS_INLINE void +PodArrayZero(T (&aT)[N]) +{ + memset(aT, 0, N * sizeof(T)); +} + +template +static MOZ_ALWAYS_INLINE void +PodArrayZero(Array& aArr) +{ + memset(&aArr[0], 0, N * sizeof(T)); +} + +/** + * Assign |*aSrc| to |*aDst|. The locations must not be the same and must not + * overlap. + */ +template +static MOZ_ALWAYS_INLINE void +PodAssign(T* aDst, const T* aSrc) +{ + MOZ_ASSERT(aDst != aSrc); + MOZ_ASSERT_IF(aSrc < aDst, + PointerRangeSize(aSrc, static_cast(aDst)) >= 1); + MOZ_ASSERT_IF(aDst < aSrc, + PointerRangeSize(static_cast(aDst), aSrc) >= 1); + memcpy(reinterpret_cast(aDst), reinterpret_cast(aSrc), + sizeof(T)); +} + +/** + * Copy |aNElem| T elements from |aSrc| to |aDst|. The two memory ranges must + * not overlap! + */ +template +static MOZ_ALWAYS_INLINE void +PodCopy(T* aDst, const T* aSrc, size_t aNElem) +{ + MOZ_ASSERT(aDst != aSrc); + MOZ_ASSERT_IF(aSrc < aDst, + PointerRangeSize(aSrc, static_cast(aDst)) >= aNElem); + MOZ_ASSERT_IF(aDst < aSrc, + PointerRangeSize(static_cast(aDst), aSrc) >= aNElem); + + if (aNElem < 128) { + /* + * Avoid using operator= in this loop, as it may have been + * intentionally deleted by the POD type. + */ + for (const T* srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { + PodAssign(aDst, aSrc); + } + } else { + memcpy(aDst, aSrc, aNElem * sizeof(T)); + } +} + +template +static MOZ_ALWAYS_INLINE void +PodCopy(volatile T* aDst, const volatile T* aSrc, size_t aNElem) +{ + MOZ_ASSERT(aDst != aSrc); + MOZ_ASSERT_IF(aSrc < aDst, + PointerRangeSize(aSrc, static_cast(aDst)) >= aNElem); + MOZ_ASSERT_IF(aDst < aSrc, + PointerRangeSize(static_cast(aDst), aSrc) >= aNElem); + + /* + * Volatile |aDst| requires extra work, because it's undefined behavior to + * modify volatile objects using the mem* functions. Just write out the + * loops manually, using operator= rather than memcpy for the same reason, + * and let the compiler optimize to the extent it can. + */ + for (const volatile T* srcend = aSrc + aNElem; + aSrc < srcend; + aSrc++, aDst++) { + *aDst = *aSrc; + } +} + +/* + * Copy the contents of the array |aSrc| into the array |aDst|, both of size N. + * The arrays must not overlap! + */ +template +static MOZ_ALWAYS_INLINE void +PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N]) +{ + PodCopy(aDst, aSrc, N); +} + +/** + * Copy the memory for |aNElem| T elements from |aSrc| to |aDst|. If the two + * memory ranges overlap, then the effect is as if the |aNElem| elements are + * first copied from |aSrc| to a temporary array, and then from the temporary + * array to |aDst|. + */ +template +static MOZ_ALWAYS_INLINE void +PodMove(T* aDst, const T* aSrc, size_t aNElem) +{ + MOZ_ASSERT(aNElem <= SIZE_MAX / sizeof(T), + "trying to move an impossible number of elements"); + memmove(aDst, aSrc, aNElem * sizeof(T)); +} + +/** + * Determine whether the |len| elements at |one| are memory-identical to the + * |len| elements at |two|. + */ +template +static MOZ_ALWAYS_INLINE bool +PodEqual(const T* one, const T* two, size_t len) +{ + if (len < 128) { + const T* p1end = one + len; + const T* p1 = one; + const T* p2 = two; + for (; p1 < p1end; p1++, p2++) { + if (*p1 != *p2) { + return false; + } + } + return true; + } + + return !memcmp(one, two, len * sizeof(T)); +} + +} // namespace mozilla + +#endif /* mozilla_PodOperations_h */ diff --git a/libazure/mozilla/Poison.h b/libazure/mozilla/Poison.h new file mode 100644 index 0000000..75e0f08 --- /dev/null +++ b/libazure/mozilla/Poison.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * A poison value that can be used to fill a memory space with + * an address that leads to a safe crash when dereferenced. + */ + +#ifndef mozilla_Poison_h +#define mozilla_Poison_h + +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" + +#include + +MOZ_BEGIN_EXTERN_C + +extern MFBT_DATA uintptr_t gMozillaPoisonValue; + +/** + * @return the poison value. + */ +inline uintptr_t mozPoisonValue() +{ + return gMozillaPoisonValue; +} + +/** + * Overwrite the memory block of aSize bytes at aPtr with the poison value. + * aPtr MUST be aligned at a sizeof(uintptr_t) boundary. + * Only an even number of sizeof(uintptr_t) bytes are overwritten, the last + * few bytes (if any) is not overwritten. + */ +inline void mozWritePoison(void* aPtr, size_t aSize) +{ + const uintptr_t POISON = mozPoisonValue(); + char* p = (char*)aPtr; + char* limit = p + aSize; + MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment"); + MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect"); + for (; p < limit; p += sizeof(uintptr_t)) { + *((uintptr_t*)p) = POISON; + } +} + +/** + * Initialize the poison value. + * This should only be called once. + */ +extern MFBT_API void mozPoisonValueInit(); + +/* Values annotated by CrashReporter */ +extern MFBT_DATA uintptr_t gMozillaPoisonBase; +extern MFBT_DATA uintptr_t gMozillaPoisonSize; + +MOZ_END_EXTERN_C + +#endif /* mozilla_Poison_h */ diff --git a/libazure/mozilla/Range.h b/libazure/mozilla/Range.h new file mode 100644 index 0000000..814a282 --- /dev/null +++ b/libazure/mozilla/Range.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_Range_h +#define mozilla_Range_h + +#include "mozilla/NullPtr.h" +#include "mozilla/RangedPtr.h" + +#include + +namespace mozilla { + +// Range is a tuple containing a pointer and a length. +template +class Range +{ + const RangedPtr mStart; + const RangedPtr mEnd; + + typedef void (Range::* ConvertibleToBool)(); + void nonNull() {} + +public: + Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {} + Range(T* aPtr, size_t aLength) + : mStart(aPtr, aPtr, aPtr + aLength), + mEnd(aPtr + aLength, aPtr, aPtr + aLength) + {} + + RangedPtr start() const { return mStart; } + RangedPtr end() const { return mEnd; } + size_t length() const { return mEnd - mStart; } + + T& operator[](size_t aOffset) const { return mStart[aOffset]; } + + operator ConvertibleToBool() const { return mStart ? &Range::nonNull : 0; } +}; + +} // namespace mozilla + +#endif /* mozilla_Range_h */ diff --git a/libazure/mozilla/RangedPtr.h b/libazure/mozilla/RangedPtr.h new file mode 100644 index 0000000..4d94035 --- /dev/null +++ b/libazure/mozilla/RangedPtr.h @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Implements a smart pointer asserted to remain within a range specified at + * construction. + */ + +#ifndef mozilla_RangedPtr_h +#define mozilla_RangedPtr_h + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/NullPtr.h" + +#include + +namespace mozilla { + +/* + * RangedPtr is a smart pointer restricted to an address range specified at + * creation. The pointer (and any smart pointers derived from it) must remain + * within the range [start, end] (inclusive of end to facilitate use as + * sentinels). Dereferencing or indexing into the pointer (or pointers derived + * from it) must remain within the range [start, end). All the standard pointer + * operators are defined on it; in debug builds these operations assert that the + * range specified at construction is respected. + * + * In theory passing a smart pointer instance as an argument can be slightly + * slower than passing a T* (due to ABI requirements for passing structs versus + * passing pointers), if the method being called isn't inlined. If you are in + * extremely performance-critical code, you may want to be careful using this + * smart pointer as an argument type. + * + * RangedPtr intentionally does not implicitly convert to T*. Use get() to + * explicitly convert to T*. Keep in mind that the raw pointer of course won't + * implement bounds checking in debug builds. + */ +template +class RangedPtr +{ + T* mPtr; + +#ifdef DEBUG + T* const mRangeStart; + T* const mRangeEnd; +#endif + + typedef void (RangedPtr::* ConvertibleToBool)(); + void nonNull() {} + + void checkSanity() + { + MOZ_ASSERT(mRangeStart <= mPtr); + MOZ_ASSERT(mPtr <= mRangeEnd); + } + + /* Creates a new pointer for |aPtr|, restricted to this pointer's range. */ + RangedPtr create(T* aPtr) const + { +#ifdef DEBUG + return RangedPtr(aPtr, mRangeStart, mRangeEnd); +#else + return RangedPtr(aPtr, nullptr, size_t(0)); +#endif + } + + uintptr_t asUintptr() const { return reinterpret_cast(mPtr); } + +public: + RangedPtr(T* aPtr, T* aStart, T* aEnd) + : mPtr(aPtr) +#ifdef DEBUG + , mRangeStart(aStart), mRangeEnd(aEnd) +#endif + { + MOZ_ASSERT(mRangeStart <= mRangeEnd); + checkSanity(); + } + RangedPtr(T* aPtr, T* aStart, size_t aLength) + : mPtr(aPtr) +#ifdef DEBUG + , mRangeStart(aStart), mRangeEnd(aStart + aLength) +#endif + { + MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); + MOZ_ASSERT(reinterpret_cast(mRangeStart) + aLength * sizeof(T) >= + reinterpret_cast(mRangeStart)); + checkSanity(); + } + + /* Equivalent to RangedPtr(aPtr, aPtr, aLength). */ + RangedPtr(T* aPtr, size_t aLength) + : mPtr(aPtr) +#ifdef DEBUG + , mRangeStart(aPtr), mRangeEnd(aPtr + aLength) +#endif + { + MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); + MOZ_ASSERT(reinterpret_cast(mRangeStart) + aLength * sizeof(T) >= + reinterpret_cast(mRangeStart)); + checkSanity(); + } + + /* Equivalent to RangedPtr(aArr, aArr, N). */ + template + RangedPtr(T (&aArr)[N]) + : mPtr(aArr) +#ifdef DEBUG + , mRangeStart(aArr), mRangeEnd(aArr + N) +#endif + { + checkSanity(); + } + + T* get() const { return mPtr; } + + operator ConvertibleToBool() const { return mPtr ? &RangedPtr::nonNull : 0; } + + /* + * You can only assign one RangedPtr into another if the two pointers have + * the same valid range: + * + * char arr1[] = "hi"; + * char arr2[] = "bye"; + * RangedPtr p1(arr1, 2); + * p1 = RangedPtr(arr1 + 1, arr1, arr1 + 2); // works + * p1 = RangedPtr(arr2, 3); // asserts + */ + RangedPtr& operator=(const RangedPtr& aOther) + { + MOZ_ASSERT(mRangeStart == aOther.mRangeStart); + MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); + mPtr = aOther.mPtr; + checkSanity(); + return *this; + } + + RangedPtr operator+(size_t aInc) + { + MOZ_ASSERT(aInc <= size_t(-1) / sizeof(T)); + MOZ_ASSERT(asUintptr() + aInc * sizeof(T) >= asUintptr()); + return create(mPtr + aInc); + } + + RangedPtr operator-(size_t aDec) + { + MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T)); + MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr()); + return create(mPtr - aDec); + } + + /* + * You can assign a raw pointer into a RangedPtr if the raw pointer is + * within the range specified at creation. + */ + template + RangedPtr& operator=(U* aPtr) + { + *this = create(aPtr); + return *this; + } + + template + RangedPtr& operator=(const RangedPtr& aPtr) + { + MOZ_ASSERT(mRangeStart <= aPtr.mPtr); + MOZ_ASSERT(aPtr.mPtr <= mRangeEnd); + mPtr = aPtr.mPtr; + checkSanity(); + return *this; + } + + RangedPtr& operator++() + { + return (*this += 1); + } + + RangedPtr operator++(int) + { + RangedPtr rcp = *this; + ++*this; + return rcp; + } + + RangedPtr& operator--() + { + return (*this -= 1); + } + + RangedPtr operator--(int) + { + RangedPtr rcp = *this; + --*this; + return rcp; + } + + RangedPtr& operator+=(size_t aInc) + { + *this = *this + aInc; + return *this; + } + + RangedPtr& operator-=(size_t aDec) + { + *this = *this - aDec; + return *this; + } + + T& operator[](int aIndex) const + { + MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T)); + return *create(mPtr + aIndex); + } + + T& operator*() const + { + MOZ_ASSERT(mPtr >= mRangeStart); + MOZ_ASSERT(mPtr < mRangeEnd); + return *mPtr; + } + + template + bool operator==(const RangedPtr& aOther) const + { + return mPtr == aOther.mPtr; + } + template + bool operator!=(const RangedPtr& aOther) const + { + return !(*this == aOther); + } + + template + bool operator==(const U* u) const + { + return mPtr == u; + } + template + bool operator!=(const U* u) const + { + return !(*this == u); + } + + template + bool operator<(const RangedPtr& aOther) const + { + return mPtr < aOther.mPtr; + } + template + bool operator<=(const RangedPtr& aOther) const + { + return mPtr <= aOther.mPtr; + } + + template + bool operator>(const RangedPtr& aOther) const + { + return mPtr > aOther.mPtr; + } + template + bool operator>=(const RangedPtr& aOther) const + { + return mPtr >= aOther.mPtr; + } + + size_t operator-(const RangedPtr& aOther) const + { + MOZ_ASSERT(mPtr >= aOther.mPtr); + return PointerRangeSize(aOther.mPtr, mPtr); + } + +private: + RangedPtr() MOZ_DELETE; + T* operator&() MOZ_DELETE; +}; + +} /* namespace mozilla */ + +#endif /* mozilla_RangedPtr_h */ diff --git a/libazure/mozilla/ReentrancyGuard.h b/libazure/mozilla/ReentrancyGuard.h new file mode 100644 index 0000000..557c610 --- /dev/null +++ b/libazure/mozilla/ReentrancyGuard.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Small helper class for asserting uses of a class are non-reentrant. */ + +#ifndef mozilla_ReentrancyGuard_h +#define mozilla_ReentrancyGuard_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/GuardObjects.h" + +namespace mozilla { + +/* Useful for implementing containers that assert non-reentrancy */ +class ReentrancyGuard +{ + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +#ifdef DEBUG + bool& mEntered; +#endif + +public: + template +#ifdef DEBUG + ReentrancyGuard(T& aObj + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mEntered(aObj.mEntered) +#else + ReentrancyGuard(T& + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) +#endif + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; +#ifdef DEBUG + MOZ_ASSERT(!mEntered); + mEntered = true; +#endif + } + ~ReentrancyGuard() + { +#ifdef DEBUG + mEntered = false; +#endif + } + +private: + ReentrancyGuard(const ReentrancyGuard&) MOZ_DELETE; + void operator=(const ReentrancyGuard&) MOZ_DELETE; +}; + +} // namespace mozilla + +#endif /* mozilla_ReentrancyGuard_h */ diff --git a/libazure/mozilla/RefCountType.h b/libazure/mozilla/RefCountType.h new file mode 100644 index 0000000..e95a22a --- /dev/null +++ b/libazure/mozilla/RefCountType.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_RefCountType_h +#define mozilla_RefCountType_h + +#include + +/** + * MozRefCountType is Mozilla's reference count type. + * + * We use the same type to represent the refcount of RefCounted objects + * as well, in order to be able to use the leak detection facilities + * that are implemented by XPCOM. + * + * Note that this type is not in the mozilla namespace so that it is + * usable for both C and C++ code. + */ +typedef uintptr_t MozRefCountType; + +/* + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * + * The following ifdef exists to maintain binary compatibility with + * IUnknown, the base interface in Microsoft COM. + */ +#ifdef XP_WIN +typedef unsigned long MozExternalRefCountType; +#else +typedef uint32_t MozExternalRefCountType; +#endif + +#endif diff --git a/libazure/mozilla/RefPtr.h b/libazure/mozilla/RefPtr.h new file mode 100644 index 0000000..0cb6b1c --- /dev/null +++ b/libazure/mozilla/RefPtr.h @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Helpers for defining and using refcounted objects. */ + +#ifndef mozilla_RefPtr_h +#define mozilla_RefPtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" +#include "mozilla/Attributes.h" +#include "mozilla/NullPtr.h" +#include "mozilla/RefCountType.h" +#include "mozilla/TypeTraits.h" +#if defined(MOZILLA_INTERNAL_API) +#include "nsXPCOM.h" +#endif + +#if defined(MOZILLA_INTERNAL_API) && \ + (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) +#define MOZ_REFCOUNTED_LEAK_CHECKING +#endif + +namespace mozilla { + +template class RefCounted; +template class RefPtr; +template class TemporaryRef; +template class OutParamRef; +template OutParamRef byRef(RefPtr&); + +/** + * RefCounted is a sort of a "mixin" for a class T. RefCounted + * manages, well, refcounting for T, and because RefCounted is + * parameterized on T, RefCounted can call T's destructor directly. + * This means T doesn't need to have a virtual dtor and so doesn't + * need a vtable. + * + * RefCounted is created with refcount == 0. Newly-allocated + * RefCounted must immediately be assigned to a RefPtr to make the + * refcount > 0. It's an error to allocate and free a bare + * RefCounted, i.e. outside of the RefPtr machinery. Attempts to + * do so will abort DEBUG builds. + * + * Live RefCounted have refcount > 0. The lifetime (refcounts) of + * live RefCounted are controlled by RefPtr and + * RefPtr. Upon a transition from refcounted==1 + * to 0, the RefCounted "dies" and is destroyed. The "destroyed" + * state is represented in DEBUG builds by refcount==0xffffdead. This + * state distinguishes use-before-ref (refcount==0) from + * use-after-destroy (refcount==0xffffdead). + * + * Note that when deriving from RefCounted or AtomicRefCounted, you + * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public + * section of your class, where ClassName is the name of your class. + */ +namespace detail { +#ifdef DEBUG +const MozRefCountType DEAD = 0xffffdead; +#endif + +// When building code that gets compiled into Gecko, try to use the +// trace-refcount leak logging facilities. +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING +class RefCountLogger +{ +public: + static void logAddRef(const void* aPointer, MozRefCountType aRefCount, + const char* aTypeName, uint32_t aInstanceSize) + { + MOZ_ASSERT(aRefCount != DEAD); + NS_LogAddRef(const_cast(aPointer), aRefCount, aTypeName, + aInstanceSize); + } + + static void logRelease(const void* aPointer, MozRefCountType aRefCount, + const char* aTypeName) + { + MOZ_ASSERT(aRefCount != DEAD); + NS_LogRelease(const_cast(aPointer), aRefCount, aTypeName); + } +}; +#endif + +// This is used WeakPtr.h as well as this file. +enum RefCountAtomicity +{ + AtomicRefCount, + NonAtomicRefCount +}; + +template +class RefCounted +{ + friend class RefPtr; + +protected: + RefCounted() : mRefCnt(0) {} + ~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); } + +public: + // Compatibility with nsRefPtr. + void AddRef() const + { + // Note: this method must be thread safe for AtomicRefCounted. + MOZ_ASSERT(int32_t(mRefCnt) >= 0); +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING + ++mRefCnt; +#else + const char* type = static_cast(this)->typeName(); + uint32_t size = static_cast(this)->typeSize(); + const void* ptr = static_cast(this); + MozRefCountType cnt = ++mRefCnt; + detail::RefCountLogger::logAddRef(ptr, cnt, type, size); +#endif + } + + void Release() const + { + // Note: this method must be thread safe for AtomicRefCounted. + MOZ_ASSERT(int32_t(mRefCnt) > 0); +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING + MozRefCountType cnt = --mRefCnt; +#else + const char* type = static_cast(this)->typeName(); + const void* ptr = static_cast(this); + MozRefCountType cnt = --mRefCnt; + // Note: it's not safe to touch |this| after decrementing the refcount, + // except for below. + detail::RefCountLogger::logRelease(ptr, cnt, type); +#endif + if (0 == cnt) { + // Because we have atomically decremented the refcount above, only + // one thread can get a 0 count here, so as long as we can assume that + // everything else in the system is accessing this object through + // RefPtrs, it's safe to access |this| here. +#ifdef DEBUG + mRefCnt = detail::DEAD; +#endif + delete static_cast(this); + } + } + + // Compatibility with wtf::RefPtr. + void ref() { AddRef(); } + void deref() { Release(); } + MozRefCountType refCount() const { return mRefCnt; } + bool hasOneRef() const + { + MOZ_ASSERT(mRefCnt > 0); + return mRefCnt == 1; + } + +private: + mutable typename Conditional, + MozRefCountType>::Type mRefCnt; +}; + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \ + virtual const char* typeName() const { return #T; } \ + virtual size_t typeSize() const { return sizeof(*this); } +#else +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) +#endif + +// Note that this macro is expanded unconditionally because it declares only +// two small inline functions which will hopefully get eliminated by the linker +// in non-leak-checking builds. +#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ + const char* typeName() const { return #T; } \ + size_t typeSize() const { return sizeof(*this); } + +} // namespace detail + +template +class RefCounted : public detail::RefCounted +{ +public: + ~RefCounted() + { + static_assert(IsBaseOf::value, + "T must derive from RefCounted"); + } +}; + +namespace external { + +/** + * AtomicRefCounted is like RefCounted, with an atomically updated + * reference counter. + * + * NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING + * instead. + */ +template +class AtomicRefCounted : + public mozilla::detail::RefCounted +{ +public: + ~AtomicRefCounted() + { + static_assert(IsBaseOf::value, + "T must derive from AtomicRefCounted"); + } +}; + +} // namespace external + +/** + * RefPtr points to a refcounted thing that has AddRef and Release + * methods to increase/decrease the refcount, respectively. After a + * RefPtr is assigned a T*, the T* can be used through the RefPtr + * as if it were a T*. + * + * A RefPtr can forget its underlying T*, which results in the T* + * being wrapped in a temporary object until the T* is either + * re-adopted from or released by the temporary. + */ +template +class RefPtr +{ + // To allow them to use unref() + friend class TemporaryRef; + friend class OutParamRef; + + struct DontRef {}; + +public: + RefPtr() : mPtr(0) {} + RefPtr(const RefPtr& aOther) : mPtr(ref(aOther.mPtr)) {} + MOZ_IMPLICIT RefPtr(const TemporaryRef& aOther) : mPtr(aOther.drop()) {} + MOZ_IMPLICIT RefPtr(T* aVal) : mPtr(ref(aVal)) {} + + template + RefPtr(const RefPtr& aOther) : mPtr(ref(aOther.get())) {} + + ~RefPtr() { unref(mPtr); } + + RefPtr& operator=(const RefPtr& aOther) + { + assign(ref(aOther.mPtr)); + return *this; + } + RefPtr& operator=(const TemporaryRef& aOther) + { + assign(aOther.drop()); + return *this; + } + RefPtr& operator=(T* aVal) + { + assign(ref(aVal)); + return *this; + } + + template + RefPtr& operator=(const RefPtr& aOther) + { + assign(ref(aOther.get())); + return *this; + } + + TemporaryRef forget() + { + T* tmp = mPtr; + mPtr = nullptr; + return TemporaryRef(tmp, DontRef()); + } + + T* get() const { return mPtr; } + operator T*() const { return mPtr; } + T* operator->() const { return mPtr; } + T& operator*() const { return *mPtr; } + template + operator TemporaryRef() { return TemporaryRef(mPtr); } + +private: + void assign(T* aVal) + { + unref(mPtr); + mPtr = aVal; + } + + T* mPtr; + + static MOZ_ALWAYS_INLINE T* ref(T* aVal) + { + if (aVal) { + aVal->AddRef(); + } + return aVal; + } + + static MOZ_ALWAYS_INLINE void unref(T* aVal) + { + if (aVal) { + aVal->Release(); + } + } +}; + +/** + * TemporaryRef represents an object that holds a temporary + * reference to a T. TemporaryRef objects can't be manually ref'd or + * unref'd (being temporaries, not lvalues), so can only relinquish + * references to other objects, or unref on destruction. + */ +template +class TemporaryRef +{ + // To allow it to construct TemporaryRef from a bare T* + friend class RefPtr; + + typedef typename RefPtr::DontRef DontRef; + +public: + MOZ_IMPLICIT TemporaryRef(T* aVal) : mPtr(RefPtr::ref(aVal)) {} + TemporaryRef(const TemporaryRef& aOther) : mPtr(aOther.drop()) {} + + template + TemporaryRef(const TemporaryRef& aOther) : mPtr(aOther.drop()) {} + + ~TemporaryRef() { RefPtr::unref(mPtr); } + + T* drop() const + { + T* tmp = mPtr; + mPtr = nullptr; + return tmp; + } + +private: + TemporaryRef(T* aVal, const DontRef&) : mPtr(aVal) {} + + mutable T* mPtr; + + TemporaryRef() MOZ_DELETE; + void operator=(const TemporaryRef&) MOZ_DELETE; +}; + +/** + * OutParamRef is a wrapper that tracks a refcounted pointer passed as + * an outparam argument to a function. OutParamRef implements COM T** + * outparam semantics: this requires the callee to AddRef() the T* + * returned through the T** outparam on behalf of the caller. This + * means the caller (through OutParamRef) must Release() the old + * object contained in the tracked RefPtr. It's OK if the callee + * returns the same T* passed to it through the T** outparam, as long + * as the callee obeys the COM discipline. + * + * Prefer returning TemporaryRef from functions over creating T** + * outparams and passing OutParamRef to T**. Prefer RefPtr* + * outparams over T** outparams. + */ +template +class OutParamRef +{ + friend OutParamRef byRef(RefPtr&); + +public: + ~OutParamRef() + { + RefPtr::unref(mRefPtr.mPtr); + mRefPtr.mPtr = mTmp; + } + + operator T**() { return &mTmp; } + +private: + explicit OutParamRef(RefPtr& p) : mRefPtr(p), mTmp(p.get()) {} + + RefPtr& mRefPtr; + T* mTmp; + + OutParamRef() MOZ_DELETE; + OutParamRef& operator=(const OutParamRef&) MOZ_DELETE; +}; + +/** + * byRef cooperates with OutParamRef to implement COM outparam semantics. + */ +template +OutParamRef +byRef(RefPtr& aPtr) +{ + return OutParamRef(aPtr); +} + +} // namespace mozilla + +#endif /* mozilla_RefPtr_h */ diff --git a/libazure/mozilla/RollingMean.h b/libazure/mozilla/RollingMean.h new file mode 100644 index 0000000..5add14c --- /dev/null +++ b/libazure/mozilla/RollingMean.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A set abstraction for enumeration values. */ + +#ifndef mozilla_RollingMean_h_ +#define mozilla_RollingMean_h_ + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Vector.h" + +#include + +namespace mozilla { + +/** + * RollingMean calculates a rolling mean of the values it is given. It + * accumulates the total as values are added and removed. The second type + * argument S specifies the type of the total. This may need to be a bigger + * type in order to maintain that the sum of all values in the average doesn't + * exceed the maximum input value. + * + * WARNING: Float types are not supported due to rounding errors. + */ +template +class RollingMean +{ +private: + size_t mInsertIndex; + size_t mMaxValues; + Vector mValues; + S mTotal; + +public: + static_assert(!IsFloatingPoint::value, + "floating-point types are unsupported due to rounding " + "errors"); + + explicit RollingMean(size_t aMaxValues) + : mInsertIndex(0), + mMaxValues(aMaxValues), + mTotal(0) + { + MOZ_ASSERT(aMaxValues > 0); + } + + RollingMean& operator=(RollingMean&& aOther) + { + MOZ_ASSERT(this != &aOther, "self-assignment is forbidden"); + this->~RollingMean(); + new(this) RollingMean(aOther.mMaxValues); + mInsertIndex = aOther.mInsertIndex; + mTotal = aOther.mTotal; + mValues.swap(aOther.mValues); + return *this; + } + + /** + * Insert a value into the rolling mean. + */ + bool insert(T aValue) + { + MOZ_ASSERT(mValues.length() <= mMaxValues); + + if (mValues.length() == mMaxValues) { + mTotal = mTotal - mValues[mInsertIndex] + aValue; + mValues[mInsertIndex] = aValue; + } else { + if (!mValues.append(aValue)) { + return false; + } + mTotal = mTotal + aValue; + } + + mInsertIndex = (mInsertIndex + 1) % mMaxValues; + return true; + } + + /** + * Calculate the rolling mean. + */ + T mean() + { + MOZ_ASSERT(!empty()); + return T(mTotal / mValues.length()); + } + + bool empty() + { + return mValues.empty(); + } + + /** + * Remove all values from the rolling mean. + */ + void clear() + { + mValues.clear(); + mInsertIndex = 0; + mTotal = T(0); + } + + size_t maxValues() + { + return mMaxValues; + } +}; + +} // namespace mozilla + +#endif // mozilla_RollingMean_h_ diff --git a/libazure/src/mfbt/SHA1.h b/libazure/mozilla/SHA1.h similarity index 55% rename from libazure/src/mfbt/SHA1.h rename to libazure/mozilla/SHA1.h index a6604e6..ddccaa6 100644 --- a/libazure/src/mfbt/SHA1.h +++ b/libazure/mozilla/SHA1.h @@ -1,17 +1,18 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Simple class for computing SHA1. */ -#ifndef mozilla_SHA1_h_ -#define mozilla_SHA1_h_ +#ifndef mozilla_SHA1_h +#define mozilla_SHA1_h -#include "mozilla/StandardInteger.h" #include "mozilla/Types.h" #include +#include namespace mozilla { @@ -35,27 +36,28 @@ namespace mozilla { */ class SHA1Sum { - union { - uint32_t w[16]; /* input buffer */ - uint8_t b[64]; - } u; - uint64_t size; /* count of hashed bytes. */ - unsigned H[22]; /* 5 state variables, 16 tmp values, 1 extra */ - bool mDone; - - public: - MFBT_API SHA1Sum(); - - static const size_t HashSize = 20; - typedef uint8_t Hash[HashSize]; - - /* Add len bytes of dataIn to the data sequence being hashed. */ - MFBT_API void update(const void* dataIn, uint32_t len); - - /* Compute the final hash of all data into hashOut. */ - MFBT_API void finish(SHA1Sum::Hash& hashOut); + union + { + uint32_t mW[16]; /* input buffer */ + uint8_t mB[64]; + } mU; + uint64_t mSize; /* count of hashed bytes. */ + unsigned mH[22]; /* 5 state variables, 16 tmp values, 1 extra */ + bool mDone; + +public: + MFBT_API SHA1Sum(); + + static const size_t kHashSize = 20; + typedef uint8_t Hash[kHashSize]; + + /* Add len bytes of dataIn to the data sequence being hashed. */ + MFBT_API void update(const void* aData, uint32_t aLength); + + /* Compute the final hash of all data into hashOut. */ + MFBT_API void finish(SHA1Sum::Hash& aHashOut); }; } /* namespace mozilla */ -#endif /* mozilla_SHA1_h_ */ +#endif /* mozilla_SHA1_h */ diff --git a/libazure/mozilla/Scoped.h b/libazure/mozilla/Scoped.h new file mode 100644 index 0000000..a16f417 --- /dev/null +++ b/libazure/mozilla/Scoped.h @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* DEPRECATED: Use UniquePtr.h instead. */ + +#ifndef mozilla_Scoped_h +#define mozilla_Scoped_h + +/* + * DEPRECATED: Use UniquePtr.h instead. + * + * Resource Acquisition Is Initialization is a programming idiom used + * to write robust code that is able to deallocate resources properly, + * even in presence of execution errors or exceptions that need to be + * propagated. The Scoped* classes defined in this header perform the + * deallocation of the resource they hold once program execution + * reaches the end of the scope for which they have been defined. + * + * This header provides the following RAII classes: + * + * - |ScopedFreePtr| - a container for a pointer, that automatically calls + * |free()| at the end of the scope; + * - |ScopedDeletePtr| - a container for a pointer, that automatically calls + * |delete| at the end of the scope; + * + * |ScopedDeleteArray| is removed in favor of |UniquePtr|. + * + * The general scenario for each of the RAII classes is the following: + * + * ScopedClass foo(create_value()); + * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| + * to access the value. + * // ... In case of |return| or |throw|, |foo| is deallocated automatically. + * // ... If |foo| needs to be returned or stored, use |foo.forget()| + * + * Note that the RAII classes defined in this header do _not_ perform any form + * of reference-counting or garbage-collection. These classes have exactly two + * behaviors: + * + * - if |forget()| has not been called, the resource is always deallocated at + * the end of the scope; + * - if |forget()| has been called, any control on the resource is unbound + * and the resource is not deallocated by the class. + * + * Extension: + * + * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| + * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition + * of RAII classes for other scenarios. These macros have been used to + * automatically close file descriptors/file handles when reaching the end of + * the scope, graphics contexts, etc. + */ + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/GuardObjects.h" +#include "mozilla/Move.h" +#include "mozilla/NullPtr.h" + +namespace mozilla { + +/* + * Scoped is a helper to create RAII wrappers + * Type argument |Traits| is expected to have the following structure: + * + * struct Traits + * { + * // Define the type of the value stored in the wrapper + * typedef value_type type; + * // Returns the value corresponding to the uninitialized or freed state + * const static type empty(); + * // Release resources corresponding to the wrapped value + * // This function is responsible for not releasing an |empty| value + * const static void release(type); + * } + */ +template +class Scoped +{ +public: + typedef typename Traits::type Resource; + + explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : mValue(Traits::empty()) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + explicit Scoped(const Resource& aValue + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(aValue) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + /* Move constructor. */ + explicit Scoped(Scoped&& aOther + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(Move(aOther.mValue)) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + aOther.mValue = Traits::empty(); + } + + ~Scoped() { Traits::release(mValue); } + + // Constant getter + operator const Resource&() const { return mValue; } + const Resource& operator->() const { return mValue; } + const Resource& get() const { return mValue; } + // Non-constant getter. + Resource& rwget() { return mValue; } + + /* + * Forget the resource. + * + * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will + * have no effect at destruction (unless it is reset to another resource by + * |operator=|). + * + * @return The original resource. + */ + Resource forget() + { + Resource tmp = mValue; + mValue = Traits::empty(); + return tmp; + } + + /* + * Perform immediate clean-up of this |Scoped|. + * + * If this |Scoped| is currently empty, this method has no effect. + */ + void dispose() + { + Traits::release(mValue); + mValue = Traits::empty(); + } + + bool operator==(const Resource& aOther) const { return mValue == aOther; } + + /* + * Replace the resource with another resource. + * + * Calling |operator=| has the side-effect of triggering clean-up. If you do + * not want to trigger clean-up, you should first invoke |forget|. + * + * @return this + */ + Scoped& operator=(const Resource& aOther) { return reset(aOther); } + + Scoped& reset(const Resource& aOther) + { + Traits::release(mValue); + mValue = aOther; + return *this; + } + + /* Move assignment operator. */ + Scoped& operator=(Scoped&& aRhs) + { + MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed"); + this->~Scoped(); + new(this) Scoped(Move(aRhs)); + return *this; + } + +private: + explicit Scoped(const Scoped& aValue) MOZ_DELETE; + Scoped& operator=(const Scoped& aValue) MOZ_DELETE; + +private: + Resource mValue; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +/* + * SCOPED_TEMPLATE defines a templated class derived from Scoped + * This allows to implement templates such as ScopedFreePtr. + * + * @param name The name of the class to define. + * @param Traits A struct implementing clean-up. See the implementations + * for more details. + */ +#define SCOPED_TEMPLATE(name, Traits) \ +template \ +struct name : public mozilla::Scoped > \ +{ \ + typedef mozilla::Scoped > Super; \ + typedef typename Super::Resource Resource; \ + name& operator=(Resource aRhs) \ + { \ + Super::operator=(aRhs); \ + return *this; \ + } \ + name& operator=(name&& aRhs) \ + { \ + Super::operator=(Move(aRhs)); \ + return *this; \ + } \ + explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ + : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ + {} \ + explicit name(Resource aRhs \ + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(aRhs \ + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ + {} \ + explicit name(name&& aRhs \ + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(Move(aRhs) \ + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ + {} \ +private: \ + explicit name(name&) MOZ_DELETE; \ + name& operator=(name&) MOZ_DELETE; \ +}; + +/* + * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. + * + * struct S { ... }; + * ScopedFreePtr foo = malloc(sizeof(S)); + * ScopedFreePtr bar = strdup(str); + */ +template +struct ScopedFreePtrTraits +{ + typedef T* type; + static T* empty() { return nullptr; } + static void release(T* aPtr) { free(aPtr); } +}; +SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) + +/* + * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. + * + * struct S { ... }; + * ScopedDeletePtr foo = new S(); + */ +template +struct ScopedDeletePtrTraits : public ScopedFreePtrTraits +{ + static void release(T* aPtr) { delete aPtr; } +}; +SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) + +/* + * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped + * pointers for types with custom deleters; just overload + * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for + * type T. + * + * @param name The name of the class to define. + * @param Type A struct implementing clean-up. See the implementations + * for more details. + * *param Deleter The function that is used to delete/destroy/free a + * non-null value of Type*. + * + * Example: + * + * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \ + * PR_Close) + * ... + * { + * ScopedPRFileDesc file(PR_OpenFile(...)); + * ... + * } // file is closed with PR_Close here + */ +#define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ +template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \ +typedef ::mozilla::TypeSpecificScopedPointer name; + +template void TypeSpecificDelete(T* aValue); + +template +struct TypeSpecificScopedPointerTraits +{ + typedef T* type; + static type empty() { return nullptr; } + static void release(type aValue) + { + if (aValue) { + TypeSpecificDelete(aValue); + } + } +}; + +SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits) + +} /* namespace mozilla */ + +#endif /* mozilla_Scoped_h */ diff --git a/libazure/mozilla/SplayTree.h b/libazure/mozilla/SplayTree.h new file mode 100644 index 0000000..f620c4d --- /dev/null +++ b/libazure/mozilla/SplayTree.h @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * A sorted tree with optimal access times, where recently-accessed elements + * are faster to access again. + */ + +#ifndef mozilla_SplayTree_h +#define mozilla_SplayTree_h + +#include "mozilla/Assertions.h" +#include "mozilla/NullPtr.h" + +namespace mozilla { + +template +class SplayTree; + +template +class SplayTreeNode +{ +public: + template + friend class SplayTree; + + SplayTreeNode() + : mLeft(nullptr) + , mRight(nullptr) + , mParent(nullptr) + {} + +private: + T* mLeft; + T* mRight; + T* mParent; +}; + + +/** + * Class which represents a splay tree. + * Splay trees are balanced binary search trees for which search, insert and + * remove are all amortized O(log n), but where accessing a node makes it + * faster to access that node in the future. + * + * T indicates the type of tree elements, Comparator must have a static + * compare(const T&, const T&) method ordering the elements. The compare + * method must be free from side effects. + */ +template +class SplayTree +{ + T* mRoot; + +public: + SplayTree() + : mRoot(nullptr) + {} + + bool empty() const + { + return !mRoot; + } + + T* find(const T& aValue) + { + if (empty()) { + return nullptr; + } + + T* last = lookup(aValue); + splay(last); + return Comparator::compare(aValue, *last) == 0 ? last : nullptr; + } + + bool insert(T* aValue) + { + MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed."); + + if (!mRoot) { + mRoot = aValue; + return true; + } + T* last = lookup(*aValue); + int cmp = Comparator::compare(*aValue, *last); + + T** parentPointer = (cmp < 0) ? &last->mLeft : &last->mRight; + MOZ_ASSERT(!*parentPointer); + *parentPointer = aValue; + aValue->mParent = last; + + splay(aValue); + return true; + } + + T* remove(const T& aValue) + { + T* last = lookup(aValue); + MOZ_ASSERT(last, "This tree must contain the element being removed."); + MOZ_ASSERT(Comparator::compare(aValue, *last) == 0); + + // Splay the tree so that the item to remove is the root. + splay(last); + MOZ_ASSERT(last == mRoot); + + // Find another node which can be swapped in for the root: either the + // rightmost child of the root's left, or the leftmost child of the + // root's right. + T* swap; + T* swapChild; + if (mRoot->mLeft) { + swap = mRoot->mLeft; + while (swap->mRight) { + swap = swap->mRight; + } + swapChild = swap->mLeft; + } else if (mRoot->mRight) { + swap = mRoot->mRight; + while (swap->mLeft) { + swap = swap->mLeft; + } + swapChild = swap->mRight; + } else { + T* result = mRoot; + mRoot = nullptr; + return result; + } + + // The selected node has at most one child, in swapChild. Detach it + // from the subtree by replacing it with that child. + if (swap == swap->mParent->mLeft) { + swap->mParent->mLeft = swapChild; + } else { + swap->mParent->mRight = swapChild; + } + if (swapChild) { + swapChild->mParent = swap->mParent; + } + + // Make the selected node the new root. + mRoot = swap; + mRoot->mParent = nullptr; + mRoot->mLeft = last->mLeft; + mRoot->mRight = last->mRight; + if (mRoot->mLeft) { + mRoot->mLeft->mParent = mRoot; + } + if (mRoot->mRight) { + mRoot->mRight->mParent = mRoot; + } + + return last; + } + + T* removeMin() + { + MOZ_ASSERT(mRoot, "No min to remove!"); + + T* min = mRoot; + while (min->mLeft) { + min = min->mLeft; + } + return remove(*min); + } + + // For testing purposes only. + void checkCoherency() + { + checkCoherency(mRoot, nullptr); + } + +private: + /** + * Returns the node in this comparing equal to |aValue|, or a node just + * greater or just less than |aValue| if there is no such node. + */ + T* lookup(const T& aValue) + { + MOZ_ASSERT(!empty()); + + T* node = mRoot; + T* parent; + do { + parent = node; + int c = Comparator::compare(aValue, *node); + if (c == 0) { + return node; + } else if (c < 0) { + node = node->mLeft; + } else { + node = node->mRight; + } + } while (node); + return parent; + } + + /** + * Rotate the tree until |node| is at the root of the tree. Performing + * the rotations in this fashion preserves the amortized balancing of + * the tree. + */ + void splay(T* aNode) + { + MOZ_ASSERT(aNode); + + while (aNode != mRoot) { + T* parent = aNode->mParent; + if (parent == mRoot) { + // Zig rotation. + rotate(aNode); + MOZ_ASSERT(aNode == mRoot); + return; + } + T* grandparent = parent->mParent; + if ((parent->mLeft == aNode) == (grandparent->mLeft == parent)) { + // Zig-zig rotation. + rotate(parent); + rotate(aNode); + } else { + // Zig-zag rotation. + rotate(aNode); + rotate(aNode); + } + } + } + + void rotate(T* aNode) + { + // Rearrange nodes so that aNode becomes the parent of its current + // parent, while preserving the sortedness of the tree. + T* parent = aNode->mParent; + if (parent->mLeft == aNode) { + // x y + // y c ==> a x + // a b b c + parent->mLeft = aNode->mRight; + if (aNode->mRight) { + aNode->mRight->mParent = parent; + } + aNode->mRight = parent; + } else { + MOZ_ASSERT(parent->mRight == aNode); + // x y + // a y ==> x c + // b c a b + parent->mRight = aNode->mLeft; + if (aNode->mLeft) { + aNode->mLeft->mParent = parent; + } + aNode->mLeft = parent; + } + aNode->mParent = parent->mParent; + parent->mParent = aNode; + if (T* grandparent = aNode->mParent) { + if (grandparent->mLeft == parent) { + grandparent->mLeft = aNode; + } else { + grandparent->mRight = aNode; + } + } else { + mRoot = aNode; + } + } + + T* checkCoherency(T* aNode, T* aMinimum) + { + if (mRoot) { + MOZ_RELEASE_ASSERT(!mRoot->mParent); + } + if (!aNode) { + MOZ_RELEASE_ASSERT(!mRoot); + return nullptr; + } + if (!aNode->mParent) { + MOZ_RELEASE_ASSERT(aNode == mRoot); + } + if (aMinimum) { + MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum, *aNode) < 0); + } + if (aNode->mLeft) { + MOZ_RELEASE_ASSERT(aNode->mLeft->mParent == aNode); + T* leftMaximum = checkCoherency(aNode->mLeft, aMinimum); + MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum, *aNode) < 0); + } + if (aNode->mRight) { + MOZ_RELEASE_ASSERT(aNode->mRight->mParent == aNode); + return checkCoherency(aNode->mRight, aNode); + } + return aNode; + } + + SplayTree(const SplayTree&) MOZ_DELETE; + void operator=(const SplayTree&) MOZ_DELETE; +}; + +} /* namespace mozilla */ + +#endif /* mozilla_SplayTree_h */ diff --git a/libazure/include/mozilla/StandardInteger.h b/libazure/mozilla/StandardInteger.h similarity index 100% rename from libazure/include/mozilla/StandardInteger.h rename to libazure/mozilla/StandardInteger.h diff --git a/libazure/mozilla/TaggedAnonymousMemory.h b/libazure/mozilla/TaggedAnonymousMemory.h new file mode 100644 index 0000000..d26b06d --- /dev/null +++ b/libazure/mozilla/TaggedAnonymousMemory.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Some Linux kernels -- specifically, newer versions of Android and +// some B2G devices -- have a feature for assigning names to ranges of +// anonymous memory (i.e., memory that doesn't have a "name" in the +// form of an underlying mapped file). These names are reported in +// /proc//smaps alongside system-level memory usage information +// such as Proportional Set Size (memory usage adjusted for sharing +// between processes), which allows reporting this information at a +// finer granularity than would otherwise be possible (e.g., +// separating malloc() heap from JS heap). +// +// Existing memory can be tagged with MozTagAnonymousMemory(); it will +// tag the range of complete pages containing the given interval, so +// the results may be inexact if the range isn't page-aligned. +// MozTaggedAnonymousMmap() can be used like mmap() with an extra +// parameter, and will tag the returned memory if the mapping was +// successful (and if it was in fact anonymous). +// +// NOTE: The pointer given as the "tag" argument MUST remain valid as +// long as the mapping exists. The referenced string is read when +// /proc//smaps or /proc//maps is read, not when the tag is +// established, so freeing it or changing its contents will have +// unexpected results. Using a static string is probably best. +// +// Also note that this header can be used by both C and C++ code. + +#ifndef mozilla_TaggedAnonymousMemory_h +#define mozilla_TaggedAnonymousMemory_h + +#ifndef XP_WIN + +#include +#include + +#include "mozilla/Types.h" + +#ifdef ANDROID + +#ifdef __cplusplus +extern "C" { +#endif + +MFBT_API void +MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag); + +MFBT_API void* +MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, + int aFd, off_t aOffset, const char* aTag); + +MFBT_API int +MozTaggedMemoryIsSupported(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#else // ANDROID + +static inline void +MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag) +{ +} + +static inline void* +MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, + int aFd, off_t aOffset, const char* aTag) +{ + return mmap(aAddr, aLength, aProt, aFlags, aFd, aOffset); +} + +static inline int +MozTaggedMemoryIsSupported(void) +{ + return 0; +} + +#endif // ANDROID + +#endif // !XP_WIN + +#endif // mozilla_TaggedAnonymousMemory_h diff --git a/libazure/mozilla/TemplateLib.h b/libazure/mozilla/TemplateLib.h new file mode 100644 index 0000000..ea12c18 --- /dev/null +++ b/libazure/mozilla/TemplateLib.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Reusable template meta-functions on types and compile-time values. Meta- + * functions are placed inside the 'tl' namespace to avoid conflict with non- + * meta functions of the same name (e.g., mozilla::tl::FloorLog2 vs. + * mozilla::FloorLog2). + * + * When constexpr support becomes universal, we should probably use that instead + * of some of these templates, for simplicity. + */ + +#ifndef mozilla_TemplateLib_h +#define mozilla_TemplateLib_h + +#include +#include + +namespace mozilla { + +namespace tl { + +/** Compute min/max. */ +template +struct Min +{ + static const size_t value = I < J ? I : J; +}; +template +struct Max +{ + static const size_t value = I > J ? I : J; +}; + +/** Compute floor(log2(i)). */ +template +struct FloorLog2 +{ + static const size_t value = 1 + FloorLog2::value; +}; +template<> struct FloorLog2<0> { /* Error */ }; +template<> struct FloorLog2<1> { static const size_t value = 0; }; + +/** Compute ceiling(log2(i)). */ +template +struct CeilingLog2 +{ + static const size_t value = FloorLog2<2 * I - 1>::value; +}; + +/** Round up to the nearest power of 2. */ +template +struct RoundUpPow2 +{ + static const size_t value = size_t(1) << CeilingLog2::value; +}; +template<> +struct RoundUpPow2<0> +{ + static const size_t value = 1; +}; + +/** Compute the number of bits in the given unsigned type. */ +template +struct BitSize +{ + static const size_t value = sizeof(T) * CHAR_BIT; +}; + +/** + * Produce an N-bit mask, where N <= BitSize::value. Handle the + * language-undefined edge case when N = BitSize::value. + */ +template +struct NBitMask +{ + // Assert the precondition. On success this evaluates to 0. Otherwise it + // triggers divide-by-zero at compile time: a guaranteed compile error in + // C++11, and usually one in C++98. Add this value to |value| to assure + // its computation. + static const size_t checkPrecondition = + 0 / size_t(N < BitSize::value); + static const size_t value = (size_t(1) << N) - 1 + checkPrecondition; +}; +template<> +struct NBitMask::value> +{ + static const size_t value = size_t(-1); +}; + +/** + * For the unsigned integral type size_t, compute a mask M for N such that + * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) + */ +template +struct MulOverflowMask +{ + static const size_t value = + ~NBitMask::value - CeilingLog2::value>::value; +}; +template<> struct MulOverflowMask<0> { /* Error */ }; +template<> struct MulOverflowMask<1> { static const size_t value = 0; }; + +} // namespace tl + +} // namespace mozilla + +#endif /* mozilla_TemplateLib_h */ diff --git a/libazure/src/mfbt/ThreadLocal.h b/libazure/mozilla/ThreadLocal.h similarity index 64% rename from libazure/src/mfbt/ThreadLocal.h rename to libazure/mozilla/ThreadLocal.h index 2b4eb30..28015de 100644 --- a/libazure/src/mfbt/ThreadLocal.h +++ b/libazure/mozilla/ThreadLocal.h @@ -1,12 +1,13 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Cross-platform lightweight thread local data wrappers. */ -#ifndef mozilla_ThreadLocal_h_ -#define mozilla_ThreadLocal_h_ +#ifndef mozilla_ThreadLocal_h +#define mozilla_ThreadLocal_h #if defined(XP_WIN) // This file will get included in any file that wants to add a profiler mark. @@ -28,6 +29,7 @@ __declspec(dllimport) unsigned long __stdcall TlsAlloc(); #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/NullPtr.h" namespace mozilla { @@ -52,7 +54,10 @@ typedef sig_atomic_t sig_safe_t; * * API usage: * - * // Create a TLS item + * // Create a TLS item. + * // + * // Note that init() should be invoked exactly once, before any usage of set() + * // or get(). * mozilla::ThreadLocal tlsKey; * if (!tlsKey.init()) { * // deal with the error @@ -68,47 +73,46 @@ template class ThreadLocal { #if defined(XP_WIN) - typedef unsigned long key_t; + typedef unsigned long key_t; #else - typedef pthread_key_t key_t; + typedef pthread_key_t key_t; #endif - union Helper { - void* ptr; - T value; - }; + union Helper + { + void* mPtr; + T mValue; + }; - public: - MOZ_WARN_UNUSED_RESULT inline bool init(); +public: + MOZ_WARN_UNUSED_RESULT inline bool init(); - inline T get() const; + inline T get() const; - inline void set(const T value); + inline void set(const T aValue); - bool initialized() const { - return inited; - } + bool initialized() const { return mInited; } - private: - key_t key; - bool inited; +private: + key_t mKey; + bool mInited; }; template inline bool ThreadLocal::init() { - MOZ_STATIC_ASSERT(sizeof(T) <= sizeof(void*), - "mozilla::ThreadLocal can't be used for types larger than " - "a pointer"); + static_assert(sizeof(T) <= sizeof(void*), + "mozilla::ThreadLocal can't be used for types larger than " + "a pointer"); MOZ_ASSERT(!initialized()); #ifdef XP_WIN - key = TlsAlloc(); - inited = key != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES + mKey = TlsAlloc(); + mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES #else - inited = !pthread_key_create(&key, NULL); + mInited = !pthread_key_create(&mKey, nullptr); #endif - return inited; + return mInited; } template @@ -118,30 +122,30 @@ ThreadLocal::get() const MOZ_ASSERT(initialized()); Helper h; #ifdef XP_WIN - h.ptr = TlsGetValue(key); + h.mPtr = TlsGetValue(mKey); #else - h.ptr = pthread_getspecific(key); + h.mPtr = pthread_getspecific(mKey); #endif - return h.value; + return h.mValue; } template inline void -ThreadLocal::set(const T value) +ThreadLocal::set(const T aValue) { MOZ_ASSERT(initialized()); Helper h; - h.value = value; - bool succeeded; + h.mValue = aValue; #ifdef XP_WIN - succeeded = TlsSetValue(key, h.ptr); + bool succeeded = TlsSetValue(mKey, h.mPtr); #else - succeeded = !pthread_setspecific(key, h.ptr); + bool succeeded = !pthread_setspecific(mKey, h.mPtr); #endif - if (!succeeded) + if (!succeeded) { MOZ_CRASH(); + } } } // namespace mozilla -#endif // mozilla_ThreadLocal_h_ +#endif /* mozilla_ThreadLocal_h */ diff --git a/libazure/mozilla/ToString.h b/libazure/mozilla/ToString.h new file mode 100644 index 0000000..f11cad5 --- /dev/null +++ b/libazure/mozilla/ToString.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Utilities for converting an object to a string representation. */ + +#ifndef mozilla_ToString_h +#define mozilla_ToString_h + +#include +#include + +namespace mozilla { + +/** + * A convenience function for converting an object to a string representation. + * Supports any object which can be streamed to an std::ostream. + */ +template +std::string +ToString(const T& aValue) +{ + std::ostringstream stream; + stream << aValue; + return stream.str(); +} + +} // namespace mozilla + +#endif /* mozilla_ToString_h */ diff --git a/libazure/mozilla/TypeTraits.h b/libazure/mozilla/TypeTraits.h new file mode 100644 index 0000000..515c68d --- /dev/null +++ b/libazure/mozilla/TypeTraits.h @@ -0,0 +1,998 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Template-based metaprogramming and type-testing facilities. */ + +#ifndef mozilla_TypeTraits_h +#define mozilla_TypeTraits_h + +#include "mozilla/Types.h" + +/* + * These traits are approximate copies of the traits and semantics from C++11's + * header. Don't add traits not in that header! When all + * platforms provide that header, we can convert all users and remove this one. + */ + +#include + +namespace mozilla { + +/* Forward declarations. */ + +template struct RemoveCV; + +/* 20.9.3 Helper classes [meta.help] */ + +/** + * Helper class used as a base for various type traits, exposed publicly + * because exposes it as well. + */ +template +struct IntegralConstant +{ + static const T value = Value; + typedef T ValueType; + typedef IntegralConstant Type; +}; + +/** Convenient aliases. */ +typedef IntegralConstant TrueType; +typedef IntegralConstant FalseType; + +/* 20.9.4 Unary type traits [meta.unary] */ + +/* 20.9.4.1 Primary type categories [meta.unary.cat] */ + +namespace detail { + +template +struct IsVoidHelper : FalseType {}; + +template<> +struct IsVoidHelper : TrueType {}; + +} // namespace detail + +/** + * IsVoid determines whether a type is void. + * + * mozilla::IsVoid::value is false; + * mozilla::IsVoid::value is true; + * mozilla::IsVoid::value is false; + * mozilla::IsVoid::value is true. + */ +template +struct IsVoid : detail::IsVoidHelper::Type> {}; + +namespace detail { + +template +struct IsIntegralHelper : FalseType {}; + +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +template<> struct IsIntegralHelper : TrueType {}; +#endif + +} /* namespace detail */ + +/** + * IsIntegral determines whether a type is an integral type. + * + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is false; + * mozilla::IsIntegral::value is false; + * + * Note that the behavior of IsIntegral on char16_t and char32_t is + * unspecified. + */ +template +struct IsIntegral : detail::IsIntegralHelper::Type> +{}; + +template +struct IsSame; + +namespace detail { + +template +struct IsFloatingPointHelper + : IntegralConstant::value || + IsSame::value || + IsSame::value> +{}; + +} // namespace detail + +/** + * IsFloatingPoint determines whether a type is a floating point type (float, + * double, long double). + * + * mozilla::IsFloatingPoint::value is false; + * mozilla::IsFloatingPoint::value is true; + * mozilla::IsFloatingPoint::value is true; + * mozilla::IsFloatingPoint::value is false. + */ +template +struct IsFloatingPoint + : detail::IsFloatingPointHelper::Type> +{}; + +namespace detail { + +template +struct IsArrayHelper : FalseType {}; + +template +struct IsArrayHelper : TrueType {}; + +template +struct IsArrayHelper : TrueType {}; + +} // namespace detail + +/** + * IsArray determines whether a type is an array type, of known or unknown + * length. + * + * mozilla::IsArray::value is false; + * mozilla::IsArray::value is true; + * mozilla::IsArray::value is true. + */ +template +struct IsArray : detail::IsArrayHelper::Type> +{}; + +/** + * IsPointer determines whether a type is a pointer type (but not a pointer-to- + * member type). + * + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is false; + * mozilla::IsPointer::value is false. + */ +template +struct IsPointer : FalseType {}; + +template +struct IsPointer : TrueType {}; + +/** + * IsLvalueReference determines whether a type is an lvalue reference. + * + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is true; + * mozilla::IsLvalueReference::value is false. + */ +template +struct IsLvalueReference : FalseType {}; + +template +struct IsLvalueReference : TrueType {}; + +/** + * IsRvalueReference determines whether a type is an rvalue reference. + * + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is true. + */ +template +struct IsRvalueReference : FalseType {}; + +template +struct IsRvalueReference : TrueType {}; + +namespace detail { + +// __is_enum is a supported extension across all of our supported compilers. +template +struct IsEnumHelper + : IntegralConstant +{}; + +} // namespace detail + +/** + * IsEnum determines whether a type is an enum type. + * + * mozilla::IsEnum::value is true; + * mozilla::IsEnum::value is false; + * mozilla::IsEnum::value is false; + */ +template +struct IsEnum + : detail::IsEnumHelper::Type> +{}; + +namespace detail { + +// __is_class is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template +struct IsClassHelper + : IntegralConstant +{}; + +} // namespace detail + +/** + * IsClass determines whether a type is a class type (but not a union). + * + * struct S {}; + * union U {}; + * mozilla::IsClass::value is false; + * mozilla::IsClass::value is true; + * mozilla::IsClass::value is false; + */ +template +struct IsClass + : detail::IsClassHelper::Type> +{}; + +/* 20.9.4.2 Composite type traits [meta.unary.comp] */ + +/** + * IsReference determines whether a type is an lvalue or rvalue reference. + * + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is true. + */ +template +struct IsReference + : IntegralConstant::value || IsRvalueReference::value> +{}; + +/** + * IsArithmetic determines whether a type is arithmetic. A type is arithmetic + * iff it is an integral type or a floating point type. + * + * mozilla::IsArithmetic::value is true; + * mozilla::IsArithmetic::value is true; + * mozilla::IsArithmetic::value is false. + */ +template +struct IsArithmetic + : IntegralConstant::value || IsFloatingPoint::value> +{}; + +/* 20.9.4.3 Type properties [meta.unary.prop] */ + +/** + * IsConst determines whether a type is const or not. + * + * mozilla::IsConst::value is false; + * mozilla::IsConst::value is true; + * mozilla::IsConst::value is false. + */ +template +struct IsConst : FalseType {}; + +template +struct IsConst : TrueType {}; + +/** + * IsVolatile determines whether a type is volatile or not. + * + * mozilla::IsVolatile::value is false; + * mozilla::IsVolatile::value is true; + * mozilla::IsVolatile::value is false. + */ +template +struct IsVolatile : FalseType {}; + +template +struct IsVolatile : TrueType {}; + +/** + * Traits class for identifying POD types. Until C++11 there's no automatic + * way to detect PODs, so for the moment this is done manually. Users may + * define specializations of this class that inherit from mozilla::TrueType and + * mozilla::FalseType (or equivalently mozilla::IntegralConstant, or conveniently from mozilla::IsPod for composite types) as needed to + * ensure correct IsPod behavior. + */ +template +struct IsPod : public FalseType {}; + +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +#ifdef MOZ_CHAR16_IS_NOT_WCHAR +template<> struct IsPod : TrueType {}; +#endif +template struct IsPod : TrueType {}; + +namespace detail { + +// __is_empty is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template +struct IsEmptyHelper + : IntegralConstant::value && __is_empty(T)> +{}; + +} // namespace detail + +/** + * IsEmpty determines whether a type is a class (but not a union) that is empty. + * + * A class is empty iff it and all its base classes have no non-static data + * members (except bit-fields of length 0) and no virtual member functions, and + * no base class is empty or a virtual base class. + * + * Intuitively, empty classes don't have any data that has to be stored in + * instances of those classes. (The size of the class must still be non-zero, + * because distinct array elements of any type must have different addresses. + * However, if the Empty Base Optimization is implemented by the compiler [most + * compilers implement it, and in certain cases C++11 requires it], the size of + * a class inheriting from an empty |Base| class need not be inflated by + * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or + * vtable pointers that must be stored in each instance for proper behavior. + * + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * union U1 { int x; }; + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * struct E1 {}; + * struct E2 { int : 0 }; + * struct E3 : E1 {}; + * struct E4 : E2 {}; + * static_assert(mozilla::IsEmpty::value && + * mozilla::IsEmpty::value && + * mozilla::IsEmpty::value && + * mozilla::IsEmpty::value, + * "all empty"); + * union U2 { E1 e1; }; + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * struct NE1 { int x; }; + * struct NE2 : virtual E1 {}; + * struct NE3 : E2 { virtual ~NE3() {} }; + * struct NE4 { virtual void f() {} }; + * static_assert(!mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value, + * "all empty"); + */ +template +struct IsEmpty : detail::IsEmptyHelper::Type> +{}; + + +namespace detail { + +template::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> +struct IsSignedHelper; + +// Floating point is signed. +template +struct IsSignedHelper : TrueType {}; + +// Integral is conditionally signed. +template +struct IsSignedHelper + : IntegralConstant +{}; + +// Non-floating point, non-integral is not signed. +template +struct IsSignedHelper : FalseType {}; + +} // namespace detail + +/** + * IsSigned determines whether a type is a signed arithmetic type. |char| is + * considered a signed type if it has the same representation as |signed char|. + * + * mozilla::IsSigned::value is true; + * mozilla::IsSigned::value is false; + * mozilla::IsSigned::value is false; + * mozilla::IsSigned::value is true. + */ +template +struct IsSigned : detail::IsSignedHelper {}; + +namespace detail { + +template::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> +struct IsUnsignedHelper; + +// Floating point is not unsigned. +template +struct IsUnsignedHelper : FalseType {}; + +// Integral is conditionally unsigned. +template +struct IsUnsignedHelper + : IntegralConstant::value || bool(NoCV(1) < NoCV(-1)))> +{}; + +// Non-floating point, non-integral is not unsigned. +template +struct IsUnsignedHelper : FalseType {}; + +} // namespace detail + +/** + * IsUnsigned determines whether a type is an unsigned arithmetic type. + * + * mozilla::IsUnsigned::value is false; + * mozilla::IsUnsigned::value is true; + * mozilla::IsUnsigned::value is true; + * mozilla::IsUnsigned::value is false. + */ +template +struct IsUnsigned : detail::IsUnsignedHelper {}; + +/* 20.9.5 Type property queries [meta.unary.prop.query] */ + +/* 20.9.6 Relationships between types [meta.rel] */ + +/** + * IsSame tests whether two types are the same type. + * + * mozilla::IsSame::value is true; + * mozilla::IsSame::value is true; + * mozilla::IsSame::value is false; + * mozilla::IsSame::value is true; + * mozilla::IsSame::value is false; + * mozilla::IsSame::value is true. + */ +template +struct IsSame : FalseType {}; + +template +struct IsSame : TrueType {}; + +namespace detail { + +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) + +template +struct BaseOfTester : IntegralConstant {}; + +#else + +// The trickery used to implement IsBaseOf here makes it possible to use it for +// the cases of private and multiple inheritance. This code was inspired by the +// sample code here: +// +// http://stackoverflow.com/questions/2910979/how-is-base-of-works +template +struct BaseOfHelper +{ +public: + operator Base*() const; + operator Derived*(); +}; + +template +struct BaseOfTester +{ +private: + template + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper(), int())) == sizeof(char); +}; + +template +struct BaseOfTester +{ +private: + template + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper(), int())) == sizeof(char); +}; + +template +struct BaseOfTester : FalseType {}; + +template +struct BaseOfTester : TrueType {}; + +template +struct BaseOfTester : TrueType {}; + +#endif + +} /* namespace detail */ + +/* + * IsBaseOf allows to know whether a given class is derived from another. + * + * Consider the following class definitions: + * + * class A {}; + * class B : public A {}; + * class C {}; + * + * mozilla::IsBaseOf::value is true; + * mozilla::IsBaseOf::value is false; + */ +template +struct IsBaseOf + : IntegralConstant::value> +{}; + +namespace detail { + +template +struct ConvertibleTester +{ +private: + static From create(); + + template + static char test(To to); + + template + static int test(...); + +public: + static const bool value = + sizeof(test(create())) == sizeof(char); +}; + +} // namespace detail + +/** + * IsConvertible determines whether a value of type From will implicitly convert + * to a value of type To. For example: + * + * struct A {}; + * struct B : public A {}; + * struct C {}; + * + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false. + * + * For obscure reasons, you can't use IsConvertible when the types being tested + * are related through private inheritance, and you'll get a compile error if + * you try. Just don't do it! + */ +template +struct IsConvertible + : IntegralConstant::value> +{}; + +/* 20.9.7 Transformations between types [meta.trans] */ + +/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */ + +/** + * RemoveConst removes top-level const qualifications on a type. + * + * mozilla::RemoveConst::Type is int; + * mozilla::RemoveConst::Type is int; + * mozilla::RemoveConst::Type is const int*; + * mozilla::RemoveConst::Type is int*. + */ +template +struct RemoveConst +{ + typedef T Type; +}; + +template +struct RemoveConst +{ + typedef T Type; +}; + +/** + * RemoveVolatile removes top-level volatile qualifications on a type. + * + * mozilla::RemoveVolatile::Type is int; + * mozilla::RemoveVolatile::Type is int; + * mozilla::RemoveVolatile::Type is volatile int*; + * mozilla::RemoveVolatile::Type is int*. + */ +template +struct RemoveVolatile +{ + typedef T Type; +}; + +template +struct RemoveVolatile +{ + typedef T Type; +}; + +/** + * RemoveCV removes top-level const and volatile qualifications on a type. + * + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int*. + */ +template +struct RemoveCV +{ + typedef typename RemoveConst::Type>::Type Type; +}; + +/* 20.9.7.2 Reference modifications [meta.trans.ref] */ + +/** + * Converts reference types to the underlying types. + * + * mozilla::RemoveReference::Type is T; + * mozilla::RemoveReference::Type is T; + * mozilla::RemoveReference::Type is T; + */ + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct Conditional; + +namespace detail { + +enum Voidness { TIsVoid, TIsNotVoid }; + +template::value ? TIsVoid : TIsNotVoid> +struct AddLvalueReferenceHelper; + +template +struct AddLvalueReferenceHelper +{ + typedef void Type; +}; + +template +struct AddLvalueReferenceHelper +{ + typedef T& Type; +}; + +} // namespace detail + +/** + * AddLvalueReference adds an lvalue & reference to T if one isn't already + * present. (Note: adding an lvalue reference to an rvalue && reference in + * essence replaces the && with a &&, per C+11 reference collapsing rules. For + * example, int&& would become int&.) + * + * The final computed type will only *not* be an lvalue reference if T is void. + * + * mozilla::AddLvalueReference::Type is int&; + * mozilla::AddLvalueRference::Type is volatile int&; + * mozilla::AddLvalueReference::Type is void*&; + * mozilla::AddLvalueReference::Type is void; + * mozilla::AddLvalueReference::Type is struct S&. + */ +template +struct AddLvalueReference + : detail::AddLvalueReferenceHelper +{}; + +/* 20.9.7.3 Sign modifications [meta.trans.sign] */ + +template +struct EnableIf; + +namespace detail { + +template +struct WithC : Conditional +{}; + +template +struct WithV : Conditional +{}; + + +template +struct WithCV : WithC::Type> +{}; + +template +struct CorrespondingSigned; + +template<> +struct CorrespondingSigned { typedef signed char Type; }; +template<> +struct CorrespondingSigned { typedef signed char Type; }; +template<> +struct CorrespondingSigned { typedef short Type; }; +template<> +struct CorrespondingSigned { typedef int Type; }; +template<> +struct CorrespondingSigned { typedef long Type; }; +template<> +struct CorrespondingSigned { typedef long long Type; }; + +template::Type, + bool IsSignedIntegerType = IsSigned::value && + !IsSame::value> +struct MakeSigned; + +template +struct MakeSigned +{ + typedef T Type; +}; + +template +struct MakeSigned + : WithCV::value, IsVolatile::value, + typename CorrespondingSigned::Type> +{}; + +} // namespace detail + +/** + * MakeSigned produces the corresponding signed integer type for a given + * integral type T, with the const/volatile qualifiers of T. T must be a + * possibly-const/volatile-qualified integral type that isn't bool. + * + * If T is already a signed integer type (not including char!), then T is + * produced. + * + * Otherwise, if T is an unsigned integer type, the signed variety of T, with + * T's const/volatile qualifiers, is produced. + * + * Otherwise, the integral type of the same size as T, with the lowest rank, + * with T's const/volatile qualifiers, is produced. (This basically only acts + * to produce signed char when T = char.) + * + * mozilla::MakeSigned::Type is signed long; + * mozilla::MakeSigned::Type is volatile int; + * mozilla::MakeSigned::Type is const signed short; + * mozilla::MakeSigned::Type is const signed char; + * mozilla::MakeSigned is an error; + * mozilla::MakeSigned is an error. + */ +template +struct MakeSigned + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeSigned + >::Type +{}; + +namespace detail { + +template +struct CorrespondingUnsigned; + +template<> +struct CorrespondingUnsigned { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned short Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned int Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned long Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned long long Type; }; + + +template::Type, + bool IsUnsignedIntegerType = IsUnsigned::value && + !IsSame::value> +struct MakeUnsigned; + +template +struct MakeUnsigned +{ + typedef T Type; +}; + +template +struct MakeUnsigned + : WithCV::value, IsVolatile::value, + typename CorrespondingUnsigned::Type> +{}; + +} // namespace detail + +/** + * MakeUnsigned produces the corresponding unsigned integer type for a given + * integral type T, with the const/volatile qualifiers of T. T must be a + * possibly-const/volatile-qualified integral type that isn't bool. + * + * If T is already an unsigned integer type (not including char!), then T is + * produced. + * + * Otherwise, if T is an signed integer type, the unsigned variety of T, with + * T's const/volatile qualifiers, is produced. + * + * Otherwise, the unsigned integral type of the same size as T, with the lowest + * rank, with T's const/volatile qualifiers, is produced. (This basically only + * acts to produce unsigned char when T = char.) + * + * mozilla::MakeUnsigned::Type is unsigned long; + * mozilla::MakeUnsigned::Type is volatile unsigned int; + * mozilla::MakeUnsigned::Type is const unsigned short; + * mozilla::MakeUnsigned::Type is const unsigned char; + * mozilla::MakeUnsigned is an error; + * mozilla::MakeUnsigned is an error. + */ +template +struct MakeUnsigned + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeUnsigned + >::Type +{}; + +/* 20.9.7.4 Array modifications [meta.trans.arr] */ + +/** + * RemoveExtent produces either the type of the elements of the array T, or T + * itself. + * + * mozilla::RemoveExtent::Type is int; + * mozilla::RemoveExtent::Type is const int; + * mozilla::RemoveExtent::Type is volatile int; + * mozilla::RemoveExtent::Type is long[17]. + */ +template +struct RemoveExtent +{ + typedef T Type; +}; + +template +struct RemoveExtent +{ + typedef T Type; +}; + +template +struct RemoveExtent +{ + typedef T Type; +}; + +/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ + +/* 20.9.7.6 Other transformations [meta.trans.other] */ + +/** + * EnableIf is a struct containing a typedef of T if and only if B is true. + * + * mozilla::EnableIf::Type is int; + * mozilla::EnableIf::Type is a compile-time error. + * + * Use this template to implement SFINAE-style (Substitution Failure Is not An + * Error) requirements. For example, you might use it to impose a restriction + * on a template parameter: + * + * template + * class PodVector // vector optimized to store POD (memcpy-able) types + * { + * EnableIf::value, T>::Type* vector; + * size_t length; + * ... + * }; + */ +template +struct EnableIf +{}; + +template +struct EnableIf +{ + typedef T Type; +}; + +/** + * Conditional selects a class between two, depending on a given boolean value. + * + * mozilla::Conditional::Type is A; + * mozilla::Conditional::Type is B; + */ +template +struct Conditional +{ + typedef A Type; +}; + +template +struct Conditional +{ + typedef B Type; +}; + +} /* namespace mozilla */ + +#endif /* mozilla_TypeTraits_h */ diff --git a/libazure/include/mozilla/TypedEnum.h b/libazure/mozilla/TypedEnum.h similarity index 60% rename from libazure/include/mozilla/TypedEnum.h rename to libazure/mozilla/TypedEnum.h index 889960a..d84cd90 100644 --- a/libazure/include/mozilla/TypedEnum.h +++ b/libazure/mozilla/TypedEnum.h @@ -1,46 +1,19 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Macros to emulate C++11 typed enums and enum classes. */ -#ifndef mozilla_TypedEnum_h_ -#define mozilla_TypedEnum_h_ +#ifndef mozilla_TypedEnum_h +#define mozilla_TypedEnum_h -#include "mozilla/Attributes.h" +#include "mozilla/TypedEnumInternal.h" +#include "mozilla/MacroArgs.h" #if defined(__cplusplus) -#if defined(__clang__) - /* - * Per Clang documentation, "Note that marketing version numbers should not - * be used to check for language features, as different vendors use different - * numbering schemes. Instead, use the feature checking macros." - */ -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_extension(cxx_strong_enums) -# define MOZ_HAVE_CXX11_ENUM_TYPE -# define MOZ_HAVE_CXX11_STRONG_ENUMS -# endif -#elif defined(__GNUC__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 1) -# define MOZ_HAVE_CXX11_ENUM_TYPE -# define MOZ_HAVE_CXX11_STRONG_ENUMS -# endif -# endif -#elif defined(_MSC_VER) -# if _MSC_VER >= 1400 -# define MOZ_HAVE_CXX11_ENUM_TYPE -# endif -# if _MSC_VER >= 1700 -# define MOZ_HAVE_CXX11_STRONG_ENUMS -# endif -#endif - /** * MOZ_ENUM_TYPE specifies the underlying numeric type for an enum. It's * specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in @@ -71,7 +44,7 @@ * strongly-typed enumeration feature of C++11 ("enum class"). If supported * by the compiler, an enum defined using these macros will not be implicitly * converted to any other type, and its enumerators will be scoped using the - * enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName, type) in place of + * enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing * "};". For example, * @@ -86,21 +59,53 @@ * fail. In other compilers, Enum itself will actually be defined as a class, * and some implicit conversions will fail while others will succeed. * - * The type argument specifies the underlying type for the enum where - * supported, as with MOZ_ENUM_TYPE(). For simplicity, it is currently - * mandatory. As with MOZ_ENUM_TYPE(), it will do nothing on compilers that do - * not support it. + * The optional type argument specifies the underlying type for the enum where + * supported, as with MOZ_ENUM_TYPE(). As with MOZ_ENUM_TYPE(), it will do + * nothing on compilers that do not support it. + * + * MOZ_{BEGIN,END}_ENUM_CLASS doesn't work for defining enum classes nested + * inside classes. To define an enum class nested inside another class, use + * MOZ_{BEGIN,END}_NESTED_ENUM_CLASS, and place a MOZ_FINISH_NESTED_ENUM_CLASS + * in namespace scope to handle bits that can only be implemented with + * namespace-scoped code. For example: + * + * class FooBar + * { + * MOZ_BEGIN_NESTED_ENUM_CLASS(Enum, int32_t) + * A, + * B = 6 + * MOZ_END_NESTED_ENUM_CLASS(Enum) + * }; * - * Note that the workaround implemented here is not compatible with enums - * nested inside a class. + * MOZ_FINISH_NESTED_ENUM_CLASS(FooBar::Enum) */ #if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) /* * All compilers that support strong enums also support an explicit * underlying type, so no extra check is needed. */ -# define MOZ_BEGIN_ENUM_CLASS(Name, type) enum class Name : type { -# define MOZ_END_ENUM_CLASS(Name) }; + + /* Single-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \ + enum class Name { + /* Two-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \ + enum class Name : type { +# define MOZ_END_NESTED_ENUM_CLASS(Name) \ + }; +# define MOZ_FINISH_NESTED_ENUM_CLASS(Name) /* nothing */ + + /* + * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes + * as template parameter types. For that, we need integer types. + * In the present case where the compiler supports strong enums, + * these are already integer types so there is nothing more to do. + */ +# define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name + /* + * See the comment below about MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE. + */ +# define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) Name #else /** * We need Name to both name a type, and scope the provided enumerator @@ -137,21 +142,35 @@ * return Enum::A; * } */ -# define MOZ_BEGIN_ENUM_CLASS(Name, type) \ + + /* Single-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \ class Name \ { \ - public: \ - enum Enum MOZ_ENUM_TYPE(type) \ - { -# define MOZ_END_ENUM_CLASS(Name) \ - }; \ - Name() {} \ - Name(Enum aEnum) : mEnum(aEnum) {} \ - explicit Name(int num) : mEnum((Enum)num) {} \ - operator Enum() const { return mEnum; } \ - private: \ - Enum mEnum; \ - }; \ + public: \ + enum Enum \ + { + /* Two-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \ + class Name \ + { \ + public: \ + enum Enum MOZ_ENUM_TYPE(type) \ + { +# define MOZ_END_NESTED_ENUM_CLASS(Name) \ + }; \ + Name() {} \ + MOZ_CONSTEXPR Name(Enum aEnum) : mEnum(aEnum) {} \ + template \ + explicit MOZ_CONSTEXPR Name(Other num) : mEnum((Enum)num) {} \ + MOZ_CONSTEXPR operator Enum() const { return mEnum; } \ + explicit MOZ_CONSTEXPR Name(const mozilla::CastableTypedEnumResult& aOther) \ + : mEnum(aOther.get()) \ + {} \ + private: \ + Enum mEnum; \ + }; +# define MOZ_FINISH_NESTED_ENUM_CLASS(Name) \ inline int operator+(const int&, const Name::Enum&) MOZ_DELETE; \ inline int operator+(const Name::Enum&, const int&) MOZ_DELETE; \ inline int operator-(const int&, const Name::Enum&) MOZ_DELETE; \ @@ -185,7 +204,6 @@ inline bool operator&&(const Name::Enum&, const bool&) MOZ_DELETE; \ inline bool operator||(const bool&, const Name::Enum&) MOZ_DELETE; \ inline bool operator||(const Name::Enum&, const bool&) MOZ_DELETE; \ - inline int operator~(const Name::Enum&) MOZ_DELETE; \ inline int operator&(const int&, const Name::Enum&) MOZ_DELETE; \ inline int operator&(const Name::Enum&, const int&) MOZ_DELETE; \ inline int operator|(const int&, const Name::Enum&) MOZ_DELETE; \ @@ -206,8 +224,58 @@ inline int& operator^=(int&, const Name::Enum&) MOZ_DELETE; \ inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \ inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE; + + /* + * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes + * as template parameter types. For that, we need integer types. + * In the present case, the integer type is the Enum nested type. + */ +# define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name::Enum + /* + * MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE is a variant of MOZ_ENUM_CLASS_ENUM_TYPE + * to be used when the enum class at hand depends on template parameters. + * + * Indeed, if T depends on template parameters, in order to name a nested type + * in T, C++ does not allow to just write "T::NestedType". Instead, we have + * to write "typename T::NestedType". The role of this macro is to add + * this "typename" keywords where needed. + * + * Example: + * + * template + * struct S {}; + * + * MOZ_BEGIN_ENUM_CLASS(E) + * Foo, + * Bar + * MOZ_END_ENUM_CLASS(E) + * + * S s; + * + * In this example, the second template parameter to S is meant to be of type + * T, but on non-C++11 compilers, type T is a class type, not an integer + * type, so it is not accepted as the type of a constant template parameter. + * One would then want to use MOZ_ENUM_CLASS_ENUM_TYPE(T), but that doesn't + * work either as T depends on template parameters (more specifically here, T + * _is_ a template parameter) so as MOZ_ENUM_CLASS_ENUM_TYPE(T) expands to + * T::Enum, we are missing the required "typename" keyword. So here, + * MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE is needed. + */ +# define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) typename Name::Enum #endif +# define MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(a, b) a b +# define MOZ_BEGIN_NESTED_ENUM_CLASS(...) \ + MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER, \ + __VA_ARGS__), \ + (__VA_ARGS__)) + +# define MOZ_BEGIN_ENUM_CLASS(...) MOZ_BEGIN_NESTED_ENUM_CLASS(__VA_ARGS__) +# define MOZ_END_ENUM_CLASS(Name) \ + MOZ_END_NESTED_ENUM_CLASS(Name) \ + MOZ_FINISH_NESTED_ENUM_CLASS(Name) + #endif /* __cplusplus */ -#endif /* mozilla_TypedEnum_h_ */ +#endif /* mozilla_TypedEnum_h */ diff --git a/libazure/mozilla/TypedEnumBits.h b/libazure/mozilla/TypedEnumBits.h new file mode 100644 index 0000000..1f439f1 --- /dev/null +++ b/libazure/mozilla/TypedEnumBits.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags. + */ + +#ifndef mozilla_TypedEnumBits_h +#define mozilla_TypedEnumBits_h + +#include "mozilla/IntegerTypeTraits.h" +#include "mozilla/TypedEnumInternal.h" + +namespace mozilla { + +#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ +template \ +MOZ_CONSTEXPR ReturnType \ +operator Op(const OtherType& aE, const CastableTypedEnumResult& aR) \ +{ \ + return ReturnType(aE Op OtherType(aR)); \ +} \ +template \ +MOZ_CONSTEXPR ReturnType \ +operator Op(const CastableTypedEnumResult& aR, const OtherType& aE) \ +{ \ + return ReturnType(OtherType(aR) Op aE); \ +} \ +template \ +MOZ_CONSTEXPR ReturnType \ +operator Op(const CastableTypedEnumResult& aR1, \ + const CastableTypedEnumResult& aR2) \ +{ \ + return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ +} + +MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool) +MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool) + +template +MOZ_CONSTEXPR CastableTypedEnumResult +operator ~(const CastableTypedEnumResult& aR) +{ + return CastableTypedEnumResult(~(E(aR))); +} + +#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ +template \ +E& \ +operator Op(E& aR1, \ + const CastableTypedEnumResult& aR2) \ +{ \ + return aR1 Op E(aR2); \ +} + +MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=) +MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=) +MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=) + +#undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP + +#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP + +#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS + +#define MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(Op, ReturnType) \ +template \ +MOZ_CONSTEXPR ReturnType \ +operator Op(typename E::Enum aE, const CastableTypedEnumResult& aR) \ +{ \ + return ReturnType(aE Op E(aR)); \ +} \ +template \ +MOZ_CONSTEXPR ReturnType \ +operator Op(const CastableTypedEnumResult& aR, typename E::Enum aE) \ +{ \ + return ReturnType(E(aR) Op aE); \ +} + +MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(|, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(&, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(^, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(==, bool) +MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(!=, bool) + +#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11 + +#endif // not MOZ_HAVE_CXX11_STRONG_ENUMS + +namespace detail { +template +struct UnsignedIntegerTypeForEnum + : UnsignedStdintTypeForSize +{}; +} + +} // namespace mozilla + +#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator Op(Name a, Name b) \ + { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(U(a) Op U(b))); \ + } \ + \ + inline Name& \ + operator Op##=(Name& a, Name b) \ + { \ + return a = a Op b; \ + } + +#define MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator~(Name a) \ + { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(~(U(a)))); \ + } + +#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS +# define MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, Op) \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator Op(Name a, Name::Enum b) \ + { \ + return a Op Name(b); \ + } \ + \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator Op(Name::Enum a, Name b) \ + { \ + return Name(a) Op b; \ + } \ + \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator Op(Name::Enum a, Name::Enum b) \ + { \ + return Name(a) Op Name(b); \ + } \ + \ + inline Name& \ + operator Op##=(Name& a, Name::Enum b) \ + { \ + return a = a Op Name(b); \ + } + +# define MOZ_MAKE_ENUM_CLASS_OPS_EXTRA_NON_CXX11(Name) \ + MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, |) \ + MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, &) \ + MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, ^) \ + inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + operator~(Name::Enum a) \ + { \ + return ~(Name(a)); \ + } +#endif + +/** + * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators + * for the given enum type. Use this to enable using an enum type as bit-field. + */ +#ifdef MOZ_HAVE_CXX11_STRONG_ENUMS +# define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ + MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name) +#else +# define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ + MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name) \ + MOZ_MAKE_ENUM_CLASS_OPS_EXTRA_NON_CXX11(Name) +#endif + +#endif // mozilla_TypedEnumBits_h diff --git a/libazure/mozilla/TypedEnumInternal.h b/libazure/mozilla/TypedEnumInternal.h new file mode 100644 index 0000000..8c88cb5 --- /dev/null +++ b/libazure/mozilla/TypedEnumInternal.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Internal stuff needed by TypedEnum.h and TypedEnumBits.h. */ + +// NOTE: When we can assume C++11 enum class support and TypedEnum.h goes away, +// we should then consider folding TypedEnumInternal.h into TypedEnumBits.h. + +#ifndef mozilla_TypedEnumInternal_h +#define mozilla_TypedEnumInternal_h + +#include "mozilla/Attributes.h" + +#if defined(__cplusplus) + +#if defined(__clang__) + /* + * Per Clang documentation, "Note that marketing version numbers should not + * be used to check for language features, as different vendors use different + * numbering schemes. Instead, use the feature checking macros." + */ +# ifndef __has_extension +# define __has_extension __has_feature /* compatibility, for older versions of clang */ +# endif +# if __has_extension(cxx_strong_enums) +# define MOZ_HAVE_CXX11_ENUM_TYPE +# define MOZ_HAVE_CXX11_STRONG_ENUMS +# endif +#elif defined(__GNUC__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3) +# define MOZ_HAVE_CXX11_ENUM_TYPE +# define MOZ_HAVE_CXX11_STRONG_ENUMS +# endif +# endif +#elif defined(_MSC_VER) +# if _MSC_VER >= 1400 +# define MOZ_HAVE_CXX11_ENUM_TYPE +# endif +# if _MSC_VER >= 1700 +# define MOZ_HAVE_CXX11_STRONG_ENUMS +# endif +#endif + +namespace mozilla { + +/* + * The problem that CastableTypedEnumResult aims to solve is that + * typed enums are not convertible to bool, and there is no way to make them + * be, yet user code wants to be able to write + * + * if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1) + * + * There are different approaches to solving this. Most of them require + * adapting user code. For example, we could implement operator! and have + * the user write + * + * if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2) + * + * Or we could supply a IsNonZero() or Any() function returning whether + * an enum value is nonzero, and have the user write + * + * if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3) + * + * But instead, we choose to preserve the original user syntax (1) as it + * is inherently more readable, and to ease porting existing code to typed + * enums. We achieve this by having operator& and other binary bitwise + * operators have as return type a class, CastableTypedEnumResult, + * that wraps a typed enum but adds bool convertibility. + */ +template +class CastableTypedEnumResult +{ +private: + const E mValue; + +public: + explicit MOZ_CONSTEXPR CastableTypedEnumResult(E aValue) + : mValue(aValue) + {} + + MOZ_CONSTEXPR operator E() const { return mValue; } + + template + MOZ_EXPLICIT_CONVERSION MOZ_CONSTEXPR + operator DestinationType() const { return DestinationType(mValue); } + + MOZ_CONSTEXPR bool operator !() const { return !bool(mValue); } + +#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS + // This get() method is used to implement a constructor in the + // non-c++11 fallback path for MOZ_BEGIN_ENUM_CLASS, taking a + // CastableTypedEnumResult. If we try to implement it using the + // above conversion operator E(), then at least clang 3.3 + // (when forced to take the non-c++11 fallback path) compiles + // this constructor to an infinite recursion. So we introduce this + // get() method, that does exactly the same as the conversion operator, + // to work around this. + MOZ_CONSTEXPR E get() const { return mValue; } +#endif +}; + +} // namespace mozilla + +#endif // __cplusplus + +#endif // mozilla_TypedEnumInternal_h diff --git a/libazure/include/mozilla/Types.h b/libazure/mozilla/Types.h similarity index 84% rename from libazure/include/mozilla/Types.h rename to libazure/mozilla/Types.h index 56e5cb8..e7e18ab 100644 --- a/libazure/include/mozilla/Types.h +++ b/libazure/mozilla/Types.h @@ -1,28 +1,22 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* mfbt foundational types and macros. */ -#ifndef mozilla_Types_h_ -#define mozilla_Types_h_ +#ifndef mozilla_Types_h +#define mozilla_Types_h /* * This header must be valid C and C++, includable by code embedding either * SpiderMonkey or Gecko. */ -/* - * Expose all the integer types defined in C99's (and the integer - * limit and constant macros, if compiling C code or if compiling C++ code and - * the right __STDC_*_MACRO has been defined for each). These are all usable - * throughout mfbt code, and throughout Mozilla code more generally. - */ -#include "mozilla/StandardInteger.h" - -/* Also expose size_t. */ +/* Expose all types and size_t. */ #include +#include /* Implement compiler and linker macros needed for APIs. */ @@ -43,7 +37,7 @@ * These macros are designed for use by library interfaces -- not for normal * methods or data used cross-file. */ -#if defined(WIN32) || defined(XP_OS2) +#if defined(WIN32) # define MOZ_EXPORT __declspec(dllexport) #else /* Unix */ # ifdef HAVE_VISIBILITY_ATTRIBUTE @@ -69,16 +63,12 @@ # else # define MOZ_IMPORT_API __declspec(dllimport) # endif -#elif defined(XP_OS2) -# define MOZ_IMPORT_API __declspec(dllimport) #else # define MOZ_IMPORT_API MOZ_EXPORT #endif #if defined(_WIN32) && !defined(__MWERKS__) # define MOZ_IMPORT_DATA __declspec(dllimport) -#elif defined(XP_OS2) -# define MOZ_IMPORT_DATA __declspec(dllimport) #else # define MOZ_IMPORT_DATA MOZ_EXPORT #endif @@ -133,4 +123,12 @@ # define MOZ_END_EXTERN_C #endif -#endif /* mozilla_Types_h_ */ +/* + * GCC's typeof is available when decltype is not. + */ +#if defined(__GNUC__) && defined(__cplusplus) && \ + !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L +# define decltype __typeof__ +#endif + +#endif /* mozilla_Types_h */ diff --git a/libazure/mozilla/UniquePtr.h b/libazure/mozilla/UniquePtr.h new file mode 100644 index 0000000..c288ee6 --- /dev/null +++ b/libazure/mozilla/UniquePtr.h @@ -0,0 +1,805 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Smart pointer managing sole ownership of a resource. */ + +#ifndef mozilla_UniquePtr_h +#define mozilla_UniquePtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/Move.h" +#include "mozilla/NullPtr.h" +#include "mozilla/Pair.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +template class DefaultDelete; +template> class UniquePtr; + +} // namespace mozilla + +namespace mozilla { + +/** + * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be + * transferred out of a UniquePtr through explicit action, but otherwise the + * resource is destroyed when the UniquePtr is destroyed. + * + * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr + * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr + * obviously *can't* copy ownership of its singly-owned resource. So what + * happens if you try to copy one? Bizarrely, ownership is implicitly + * *transferred*, preserving single ownership but breaking code that assumes a + * copy of an object is identical to the original. (This is why auto_ptr is + * prohibited in STL containers.) + * + * UniquePtr solves this problem by being *movable* rather than copyable. + * Instead of passing a |UniquePtr u| directly to the constructor or assignment + * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* + * ownership out of |u|, into the target of the construction/assignment. After + * the transfer completes, |u| contains |nullptr| and may be safely destroyed. + * This preserves single ownership but also allows UniquePtr to be moved by + * algorithms that have been made move-safe. (Note: if |u| is instead a + * temporary expression, don't use |Move()|: just pass the expression, because + * it's already move-ready. For more information see Move.h.) + * + * UniquePtr is also better than std::auto_ptr in that the deletion operation is + * customizable. An optional second template parameter specifies a class that + * (through its operator()(T*)) implements the desired deletion policy. If no + * policy is specified, mozilla::DefaultDelete is used -- which will either + * |delete| or |delete[]| the resource, depending whether the resource is an + * array. Custom deletion policies ideally should be empty classes (no member + * fields, no member fields in base classes, no virtual methods/inheritance), + * because then UniquePtr can be just as efficient as a raw pointer. + * + * Use of UniquePtr proceeds like so: + * + * UniquePtr g1; // initializes to nullptr + * g1.reset(new int); // switch resources using reset() + * g1 = nullptr; // clears g1, deletes the int + * + * UniquePtr g2(new int); // owns that int + * int* p = g2.release(); // g2 leaks its int -- still requires deletion + * delete p; // now freed + * + * struct S { int x; S(int x) : x(x) {} }; + * UniquePtr g3, g4(new S(5)); + * g3 = Move(g4); // g3 owns the S, g4 cleared + * S* p = g3.get(); // g3 still owns |p| + * assert(g3->x == 5); // operator-> works (if .get() != nullptr) + * assert((*g3).x == 5); // also operator* (again, if not cleared) + * Swap(g3, g4); // g4 now owns the S, g3 cleared + * g3.swap(g4); // g3 now owns the S, g4 cleared + * UniquePtr g5(Move(g3)); // g5 owns the S, g3 cleared + * g5.reset(); // deletes the S, g5 cleared + * + * struct FreePolicy { void operator()(void* p) { free(p); } }; + * UniquePtr g6(static_cast(malloc(sizeof(int)))); + * int* ptr = g6.get(); + * g6 = nullptr; // calls free(ptr) + * + * Now, carefully note a few things you *can't* do: + * + * UniquePtr b1; + * b1 = new int; // BAD: can only assign another UniquePtr + * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() + * + * UniquePtr b2(b1); // BAD: can't copy a UniquePtr + * UniquePtr b3 = b1; // BAD: can't copy-assign a UniquePtr + * + * (Note that changing a UniquePtr to store a direct |new| expression is + * permitted, but usually you should use MakeUnique, defined at the end of this + * header.) + * + * A few miscellaneous notes: + * + * UniquePtr, when not instantiated for an array type, can be move-constructed + * and move-assigned, not only from itself but from "derived" UniquePtr + * instantiations where U converts to T and E converts to D. If you want to use + * this, you're going to have to specify a deletion policy for both UniquePtr + * instantations, and T pretty much has to have a virtual destructor. In other + * words, this doesn't work: + * + * struct Base { virtual ~Base() {} }; + * struct Derived : Base {}; + * + * UniquePtr b1; + * // BAD: DefaultDelete and DefaultDelete don't interconvert + * UniquePtr d1(Move(b)); + * + * UniquePtr b2; + * UniquePtr> d2(Move(b2)); // okay + * + * UniquePtr is specialized for array types. Specializing with an array type + * creates a smart-pointer version of that array -- not a pointer to such an + * array. + * + * UniquePtr arr(new int[5]); + * arr[0] = 4; + * + * What else is different? Deletion of course uses |delete[]|. An operator[] + * is provided. Functionality that doesn't make sense for arrays is removed. + * The constructors and mutating methods only accept array pointers (not T*, U* + * that converts to T*, or UniquePtr or UniquePtr) or |nullptr|. + * + * It's perfectly okay to return a UniquePtr from a method to assure the related + * resource is properly deleted. You'll need to use |Move()| when returning a + * local UniquePtr. Otherwise you can return |nullptr|, or you can return + * |UniquePtr(ptr)|. + * + * UniquePtr will commonly be a member of a class, with lifetime equivalent to + * that of that class. If you want to expose the related resource, you could + * expose a raw pointer via |get()|, but ownership of a raw pointer is + * inherently unclear. So it's better to expose a |const UniquePtr&| instead. + * This prohibits mutation but still allows use of |get()| when needed (but + * operator-> is preferred). Of course, you can only use this smart pointer as + * long as the enclosing class instance remains live -- no different than if you + * exposed the |get()| raw pointer. + * + * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| + * argument. To specify an inout parameter (where the method may or may not + * take ownership of the resource, or reset it), or to specify an out parameter + * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| + * argument. To unconditionally transfer ownership of a UniquePtr + * into a method, use a |UniquePtr| argument. To conditionally transfer + * ownership of a resource into a method, should the method want it, use a + * |UniquePtr&&| argument. + */ +template +class UniquePtr +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair mTuple; + + Pointer& ptr() { return mTuple.first(); } + const Pointer& ptr() const { return mTuple.first(); } + + DeleterType& del() { return mTuple.second(); } + const DeleterType& del() const { return mTuple.second(); } + +public: + /** + * Construct a UniquePtr containing |nullptr|. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + UniquePtr(Pointer aPtr, + typename Conditional::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr! Ideally + // you should make deletion use the same function every time, using a + // deleter policy: + // + // // BAD, won't compile with MSVC10, deleter doesn't need to be a + // // variable at all + // typedef void (&FreeSignature)(void*); + // UniquePtr ptr((int*) malloc(sizeof(int)), free); + // + // // GOOD, compiles with MSVC10, deletion behavior statically known and + // // optimizable + // struct DeleteByFreeing + // { + // void operator()(void* aPtr) { free(aPtr); } + // }; + // + // If deletion really, truly, must be a variable: you might be able to work + // around this with a deleter class that contains the function reference. + // But this workaround is untried and untested, because variable deletion + // behavior really isn't something you should use. + UniquePtr(Pointer aPtr, + typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference::value, + "rvalue deleter can't be stored by reference"); + } + + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + {} + + template + UniquePtr(N, + typename EnableIf::value, int>::Type aDummy = 0) + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + template + UniquePtr(UniquePtr&& aOther, + typename EnableIf::Pointer, + Pointer>::value && + !IsArray::value && + (IsReference::value + ? IsSame::value + : IsConvertible::value), + int>::Type aDummy = 0) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + { + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + template + UniquePtr& operator=(UniquePtr&& aOther) + { + static_assert(IsConvertible::Pointer, + Pointer>::value, + "incompatible UniquePtr pointees"); + static_assert(!IsArray::value, + "can't assign from UniquePtr holding an array"); + + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(NullptrT aNull) + { + MOZ_ASSERT(aNull == nullptr); + reset(nullptr); + return *this; + } + + T& operator*() const { return *get(); } + Pointer operator->() const + { + MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); + return get(); + } + + Pointer get() const { return ptr(); } + + DeleterType& getDeleter() { return del(); } + const DeleterType& getDeleter() const { return del(); } + +private: + typedef void (UniquePtr::* ConvertibleToBool)(double, char); + void nonNull(double, char) {} + +public: + operator ConvertibleToBool() const + { + return get() != nullptr ? &UniquePtr::nonNull : nullptr; + } + + Pointer release() + { + Pointer p = ptr(); + ptr() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = ptr(); + ptr() = aPtr; + if (old != nullptr) { + getDeleter()(old); + } + } + + void swap(UniquePtr& aOther) + { + mTuple.swap(aOther.mTuple); + } + +private: + UniquePtr(const UniquePtr& aOther) MOZ_DELETE; // construct using Move()! + void operator=(const UniquePtr& aOther) MOZ_DELETE; // assign using Move()! +}; + +// In case you didn't read the comment by the main definition (you should!): the +// UniquePtr specialization exists to manage array pointers. It deletes +// such pointers using delete[], it will reject construction and modification +// attempts using U* or U[]. Otherwise it works like the normal UniquePtr. +template +class UniquePtr +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair mTuple; + +public: + /** + * Construct a UniquePtr containing nullptr. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + +private: + // delete[] knows how to handle *only* an array of a single class type. For + // delete[] to work correctly, it must know the size of each element, the + // fields and base classes of each element requiring destruction, and so on. + // So forbid all overloads which would end up invoking delete[] on a pointer + // of the wrong type. + template + UniquePtr(U&& aU, + typename EnableIf::value && + IsConvertible::value, + int>::Type aDummy = 0) + MOZ_DELETE; + +public: + UniquePtr(Pointer aPtr, + typename Conditional::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr! See the + // comment by this constructor in the non-T[] specialization above. + UniquePtr(Pointer aPtr, + typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference::value, + "rvalue deleter can't be stored by reference"); + } + +private: + // Forbidden for the same reasons as stated above. + template + UniquePtr(U&& aU, V&& aV, + typename EnableIf::value && + IsConvertible::value, + int>::Type aDummy = 0) + MOZ_DELETE; + +public: + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + {} + + template + UniquePtr(N, + typename EnableIf::value, int>::Type aDummy = 0) + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(NullptrT) + { + reset(); + return *this; + } + + T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } + Pointer get() const { return mTuple.first(); } + + DeleterType& getDeleter() { return mTuple.second(); } + const DeleterType& getDeleter() const { return mTuple.second(); } + +private: + typedef void (UniquePtr::* ConvertibleToBool)(double, char); + void nonNull(double, char) {} + +public: + operator ConvertibleToBool() const + { + return get() != nullptr ? &UniquePtr::nonNull : nullptr; + } + + Pointer release() + { + Pointer p = mTuple.first(); + mTuple.first() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = mTuple.first(); + mTuple.first() = aPtr; + if (old != nullptr) { + mTuple.second()(old); + } + } + +private: + // Kill off all remaining overloads that aren't true nullptr (the overload + // above should handle that) or emulated nullptr (which acts like int/long + // on gcc 4.4/4.5). + template + void reset(U, + typename EnableIf::value && + !IsSame::Type>::value, + int>::Type aDummy = 0) + MOZ_DELETE; + +public: + void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } + +private: + UniquePtr(const UniquePtr& aOther) MOZ_DELETE; // construct using Move()! + void operator=(const UniquePtr& aOther) MOZ_DELETE; // assign using Move()! +}; + +/** A default deletion policy using plain old operator delete. */ +template +class DefaultDelete +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + template + DefaultDelete(const DefaultDelete& aOther, + typename EnableIf::value, + int>::Type aDummy = 0) + {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete aPtr; + } +}; + +/** A default deletion policy using operator delete[]. */ +template +class DefaultDelete +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete[] aPtr; + } + +private: + template + void operator()(U* aPtr) const MOZ_DELETE; +}; + +template +void +Swap(UniquePtr& aX, UniquePtr& aY) +{ + aX.swap(aY); +} + +template +bool +operator==(const UniquePtr& aX, const UniquePtr& aY) +{ + return aX.get() == aY.get(); +} + +template +bool +operator!=(const UniquePtr& aX, const UniquePtr& aY) +{ + return aX.get() != aY.get(); +} + +template +bool +operator==(const UniquePtr& aX, NullptrT aNull) +{ + MOZ_ASSERT(aNull == nullptr); + return !aX; +} + +template +bool +operator==(NullptrT aNull, const UniquePtr& aX) +{ + MOZ_ASSERT(aNull == nullptr); + return !aX; +} + +template +bool +operator!=(const UniquePtr& aX, NullptrT aNull) +{ + MOZ_ASSERT(aNull == nullptr); + return bool(aX); +} + +template +bool +operator!=(NullptrT aNull, const UniquePtr& aX) +{ + MOZ_ASSERT(aNull == nullptr); + return bool(aX); +} + +// No operator<, operator>, operator<=, operator>= for now because simplicity. + +namespace detail { + +template +struct UniqueSelector +{ + typedef UniquePtr SingleObject; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr UnknownBound; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr KnownBound; +}; + +} // namespace detail + +/** + * MakeUnique is a helper function for allocating new'd objects and arrays, + * returning a UniquePtr containing the resulting pointer. The semantics of + * MakeUnique(...) are as follows. + * + * If Type is an array T[n]: + * Disallowed, deleted, no overload for you! + * If Type is an array T[]: + * MakeUnique(size_t) is the only valid overload. The pointer returned + * is as if by |new T[n]()|, which value-initializes each element. (If T + * isn't a class type, this will zero each element. If T is a class type, + * then roughly speaking, each element will be constructed using its default + * constructor. See C++11 [dcl.init]p7 for the full gory details.) + * If Type is non-array T: + * The arguments passed to MakeUnique(...) are forwarded into a + * |new T(...)| call, initializing the T as would happen if executing + * |T(...)|. (Note: literal nullptr must not be provided as an argument to + * MakeUnique, because nullptr may be emulated. See Move.h for details.) + * + * There are various benefits to using MakeUnique instead of |new| expressions. + * + * First, MakeUnique eliminates use of |new| from code entirely. If objects are + * only created through UniquePtr, then (assuming all explicit release() calls + * are safe, including transitively, and no type-safety casting funniness) + * correctly maintained ownership of the UniquePtr guarantees no leaks are + * possible. (This pays off best if a class is only ever created through a + * factory method on the class, using a private constructor.) + * + * Second, initializing a UniquePtr using a |new| expression requires renaming + * the new'd type, whereas MakeUnique in concert with the |auto| keyword names + * it only once: + * + * UniquePtr ptr1(new char()); // repetitive + * auto ptr2 = MakeUnique(); // shorter + * + * Of course this assumes the reader understands the operation MakeUnique + * performs. In the long run this is probably a reasonable assumption. In the + * short run you'll have to use your judgment about what readers can be expected + * to know, or to quickly look up. + * + * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In + * contrast you can't assign a pointer into a UniquePtr without using the + * cumbersome reset(). + * + * UniquePtr p; + * p = new char; // ERROR + * p.reset(new char); // works, but fugly + * p = MakeUnique(); // preferred + * + * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. + * An exception thrown after |new T| succeeds will leak that memory, unless the + * pointer is assigned to an object that will manage its ownership. UniquePtr + * ably serves this function.) + */ + +// We don't have variadic template support everywhere, so just hard-code arities +// 0-8 for now. If you need more arguments, feel free to add the extra +// overloads (and deletions for the T = E[N] case). +// +// Beware! Due to lack of true nullptr support in gcc 4.4 and 4.5, passing +// literal nullptr to MakeUnique will not work on some platforms. See Move.h +// for more details. + +template +typename detail::UniqueSelector::SingleObject +MakeUnique() +{ + return UniquePtr(new T()); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& aA1) +{ + return UniquePtr(new T(Forward(aA1))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& aA1, A2&& aA2) +{ + return UniquePtr(new T(Forward(aA1), Forward(aA2))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3) +{ + return UniquePtr(new T(Forward(aA1), Forward(aA2), + Forward(aA3))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4) +{ + return UniquePtr(new T(Forward(aA1), Forward(aA2), + Forward(aA3), Forward(aA4))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4, A5&& aA5) +{ + return UniquePtr(new T(Forward(aA1), Forward(aA2), + Forward(aA3), Forward(aA4), + Forward(aA5))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6) +{ + return UniquePtr(new T(Forward(a1), Forward(a2), + Forward(a3), Forward(a4), + Forward(a5), Forward(a6))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7) +{ + return UniquePtr(new T(Forward(a1), Forward(a2), + Forward(a3), Forward(a4), + Forward(a5), Forward(a6), + Forward(a7))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7, + A8&& a8) +{ + return UniquePtr(new T(Forward(a1), Forward(a2), + Forward(a3), Forward(a4), + Forward(a5), Forward(a6), + Forward(a7), Forward(a8))); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUnique(decltype(sizeof(int)) aN) +{ + typedef typename RemoveExtent::Type ArrayType; + return UniquePtr(new ArrayType[aN]()); +} + +template +typename detail::UniqueSelector::KnownBound +MakeUnique() MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& aA1) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& aA1, A2&& aA2) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4, A5&& aA5) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, + A6&& a6) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, + A7&& a7) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, + A7&& a7, A8&& a8) MOZ_DELETE; + +} // namespace mozilla + +#endif /* mozilla_UniquePtr_h */ diff --git a/libazure/mozilla/Util.h b/libazure/mozilla/Util.h new file mode 100644 index 0000000..b4cf2e4 --- /dev/null +++ b/libazure/mozilla/Util.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Miscellaneous uncategorized functionality. Please add new functionality to + * new headers, or to other appropriate existing headers, not here. + */ + +#ifndef mozilla_Util_h +#define mozilla_Util_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" + +#ifdef __cplusplus + +#include "mozilla/Alignment.h" + +namespace mozilla { + +/* + * Safely subtract two pointers when it is known that end >= begin. This avoids + * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB + * set, the unsigned subtraction followed by right shift will produce -1, or + * size_t(-1), instead of the real difference. + */ +template +MOZ_ALWAYS_INLINE size_t +PointerRangeSize(T* begin, T* end) +{ + MOZ_ASSERT(end >= begin); + return (size_t(end) - size_t(begin)) / sizeof(T); +} + +/* + * Compute the length of an array with constant length. (Use of this method + * with a non-array pointer will not compile.) + * + * Beware of the implicit trailing '\0' when using this with string constants. + */ +template +MOZ_CONSTEXPR size_t +ArrayLength(T (&arr)[N]) +{ + return N; +} + +/* + * Compute the address one past the last element of a constant-length array. + * + * Beware of the implicit trailing '\0' when using this with string constants. + */ +template +MOZ_CONSTEXPR T* +ArrayEnd(T (&arr)[N]) +{ + return arr + ArrayLength(arr); +} + +} /* namespace mozilla */ + +#endif /* __cplusplus */ + +/* + * MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files + * that can't use C++ template functions and for static_assert() calls that + * can't call ArrayLength() when it is not a C++11 constexpr function. + */ +#ifdef MOZ_HAVE_CXX11_CONSTEXPR +# define MOZ_ARRAY_LENGTH(array) mozilla::ArrayLength(array) +#else +# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) +#endif + +#endif /* mozilla_Util_h */ diff --git a/libazure/mozilla/Vector.h b/libazure/mozilla/Vector.h new file mode 100644 index 0000000..3e7745d --- /dev/null +++ b/libazure/mozilla/Vector.h @@ -0,0 +1,1278 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A type/length-parametrized vector class. */ + +#ifndef mozilla_Vector_h +#define mozilla_Vector_h + +#include "mozilla/Alignment.h" +#include "mozilla/AllocPolicy.h" +#include "mozilla/ArrayUtils.h" // for PointerRangeSize +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/Move.h" +#include "mozilla/NullPtr.h" +#include "mozilla/ReentrancyGuard.h" +#include "mozilla/TemplateLib.h" +#include "mozilla/TypeTraits.h" + +#include // for placement new + +/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4345) +#endif + +namespace mozilla { + +template +class VectorBase; + +namespace detail { + +/* + * Check that the given capacity wastes the minimal amount of space if + * allocated on the heap. This means that aCapacity*sizeof(T) is as close to a + * power-of-two as possible. growStorageBy() is responsible for ensuring this. + */ +template +static bool CapacityHasExcessSpace(size_t aCapacity) +{ + size_t size = aCapacity * sizeof(T); + return RoundUpPow2(size) - size >= sizeof(T); +} + +/* + * This template class provides a default implementation for vector operations + * when the element type is not known to be a POD, as judged by IsPod. + */ +template +struct VectorImpl +{ + /* Destroys constructed objects in the range [aBegin, aEnd). */ + static inline void destroy(T* aBegin, T* aEnd) + { + MOZ_ASSERT(aBegin <= aEnd); + for (T* p = aBegin; p < aEnd; ++p) { + p->~T(); + } + } + + /* Constructs objects in the uninitialized range [aBegin, aEnd). */ + static inline void initialize(T* aBegin, T* aEnd) + { + MOZ_ASSERT(aBegin <= aEnd); + for (T* p = aBegin; p < aEnd; ++p) { + new(p) T(); + } + } + + /* + * Copy-constructs objects in the uninitialized range + * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). + */ + template + static inline void copyConstruct(T* aDst, + const U* aSrcStart, const U* aSrcEnd) + { + MOZ_ASSERT(aSrcStart <= aSrcEnd); + for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + new(aDst) T(*p); + } + } + + /* + * Move-constructs objects in the uninitialized range + * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). + */ + template + static inline void moveConstruct(T* aDst, U* aSrcStart, U* aSrcEnd) + { + MOZ_ASSERT(aSrcStart <= aSrcEnd); + for (U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + new(aDst) T(Move(*p)); + } + } + + /* + * Copy-constructs objects in the uninitialized range [aDst, aDst+aN) from + * the same object aU. + */ + template + static inline void copyConstructN(T* aDst, size_t aN, const U& aU) + { + for (T* end = aDst + aN; aDst < end; ++aDst) { + new(aDst) T(aU); + } + } + + /* + * Grows the given buffer to have capacity aNewCap, preserving the objects + * constructed in the range [begin, end) and updating aV. Assumes that (1) + * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will + * not overflow. + */ + static inline bool + growTo(VectorBase& aV, size_t aNewCap) + { + MOZ_ASSERT(!aV.usingInlineStorage()); + MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); + T* newbuf = aV.template pod_malloc(aNewCap); + if (!newbuf) { + return false; + } + T* dst = newbuf; + T* src = aV.beginNoCheck(); + for (; src < aV.endNoCheck(); ++dst, ++src) { + new(dst) T(Move(*src)); + } + VectorImpl::destroy(aV.beginNoCheck(), aV.endNoCheck()); + aV.free_(aV.mBegin); + aV.mBegin = newbuf; + /* aV.mLength is unchanged. */ + aV.mCapacity = aNewCap; + return true; + } +}; + +/* + * This partial template specialization provides a default implementation for + * vector operations when the element type is known to be a POD, as judged by + * IsPod. + */ +template +struct VectorImpl +{ + static inline void destroy(T*, T*) {} + + static inline void initialize(T* aBegin, T* aEnd) + { + /* + * You would think that memset would be a big win (or even break even) + * when we know T is a POD. But currently it's not. This is probably + * because |append| tends to be given small ranges and memset requires + * a function call that doesn't get inlined. + * + * memset(aBegin, 0, sizeof(T) * (aEnd - aBegin)); + */ + MOZ_ASSERT(aBegin <= aEnd); + for (T* p = aBegin; p < aEnd; ++p) { + new(p) T(); + } + } + + template + static inline void copyConstruct(T* aDst, + const U* aSrcStart, const U* aSrcEnd) + { + /* + * See above memset comment. Also, notice that copyConstruct is + * currently templated (T != U), so memcpy won't work without + * requiring T == U. + * + * memcpy(aDst, aSrcStart, sizeof(T) * (aSrcEnd - aSrcStart)); + */ + MOZ_ASSERT(aSrcStart <= aSrcEnd); + for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + *aDst = *p; + } + } + + template + static inline void moveConstruct(T* aDst, + const U* aSrcStart, const U* aSrcEnd) + { + copyConstruct(aDst, aSrcStart, aSrcEnd); + } + + static inline void copyConstructN(T* aDst, size_t aN, const T& aT) + { + for (T* end = aDst + aN; aDst < end; ++aDst) { + *aDst = aT; + } + } + + static inline bool + growTo(VectorBase& aV, size_t aNewCap) + { + MOZ_ASSERT(!aV.usingInlineStorage()); + MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); + T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aNewCap); + if (!newbuf) { + return false; + } + aV.mBegin = newbuf; + /* aV.mLength is unchanged. */ + aV.mCapacity = aNewCap; + return true; + } +}; + +} // namespace detail + +/* + * A CRTP base class for vector-like classes. Unless you really really want + * your own vector class -- and you almost certainly don't -- you should use + * mozilla::Vector instead! + * + * See mozilla::Vector for interface requirements. + */ +template +class VectorBase : private AllocPolicy +{ + /* utilities */ + + static const bool kElemIsPod = IsPod::value; + typedef detail::VectorImpl Impl; + friend struct detail::VectorImpl; + + bool growStorageBy(size_t aIncr); + bool convertToHeapStorage(size_t aNewCap); + + /* magic constants */ + + static const int kMaxInlineBytes = 1024; + + /* compute constants */ + + /* + * Consider element size to be 1 for buffer sizing if there are 0 inline + * elements. This allows us to compile when the definition of the element + * type is not visible here. + * + * Explicit specialization is only allowed at namespace scope, so in order + * to keep everything here, we use a dummy template parameter with partial + * specialization. + */ + template + struct ElemSize + { + static const size_t value = sizeof(T); + }; + template + struct ElemSize<0, Dummy> + { + static const size_t value = 1; + }; + + static const size_t kInlineCapacity = + tl::Min::value>::value; + + /* Calculate inline buffer size; avoid 0-sized array. */ + static const size_t kInlineBytes = + tl::Max<1, kInlineCapacity * ElemSize::value>::value; + + /* member data */ + + /* + * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin, + * mBegin + mLength) hold valid constructed T objects. The range [mBegin + + * mLength, mBegin + mCapacity) holds uninitialized memory. The range + * [mBegin + mLength, mBegin + mReserved) also holds uninitialized memory + * previously allocated by a call to reserve(). + */ + T* mBegin; + + /* Number of elements in the vector. */ + size_t mLength; + + /* Max number of elements storable in the vector without resizing. */ + size_t mCapacity; + +#ifdef DEBUG + /* Max elements of reserved or used space in this vector. */ + size_t mReserved; +#endif + + /* Memory used for inline storage. */ + AlignedStorage mStorage; + +#ifdef DEBUG + friend class ReentrancyGuard; + bool mEntered; +#endif + + /* private accessors */ + + bool usingInlineStorage() const + { + return mBegin == const_cast(this)->inlineStorage(); + } + + T* inlineStorage() + { + return static_cast(mStorage.addr()); + } + + T* beginNoCheck() const + { + return mBegin; + } + + T* endNoCheck() + { + return mBegin + mLength; + } + + const T* endNoCheck() const + { + return mBegin + mLength; + } + +#ifdef DEBUG + size_t reserved() const + { + MOZ_ASSERT(mReserved <= mCapacity); + MOZ_ASSERT(mLength <= mReserved); + return mReserved; + } +#endif + + /* Append operations guaranteed to succeed due to pre-reserved space. */ + template void internalAppend(U&& aU); + template + void internalAppendAll(const VectorBase& aU); + void internalAppendN(const T& aT, size_t aN); + template void internalAppend(const U* aBegin, size_t aLength); + +public: + static const size_t sMaxInlineStorage = N; + + typedef T ElementType; + + explicit VectorBase(AllocPolicy = AllocPolicy()); + explicit VectorBase(ThisVector&&); /* Move constructor. */ + ThisVector& operator=(ThisVector&&); /* Move assignment. */ + ~VectorBase(); + + /* accessors */ + + const AllocPolicy& allocPolicy() const { return *this; } + + AllocPolicy& allocPolicy() { return *this; } + + enum { InlineLength = N }; + + size_t length() const { return mLength; } + + bool empty() const { return mLength == 0; } + + size_t capacity() const { return mCapacity; } + + T* begin() + { + MOZ_ASSERT(!mEntered); + return mBegin; + } + + const T* begin() const + { + MOZ_ASSERT(!mEntered); + return mBegin; + } + + T* end() + { + MOZ_ASSERT(!mEntered); + return mBegin + mLength; + } + + const T* end() const + { + MOZ_ASSERT(!mEntered); + return mBegin + mLength; + } + + T& operator[](size_t aIndex) + { + MOZ_ASSERT(!mEntered); + MOZ_ASSERT(aIndex < mLength); + return begin()[aIndex]; + } + + const T& operator[](size_t aIndex) const + { + MOZ_ASSERT(!mEntered); + MOZ_ASSERT(aIndex < mLength); + return begin()[aIndex]; + } + + T& back() + { + MOZ_ASSERT(!mEntered); + MOZ_ASSERT(!empty()); + return *(end() - 1); + } + + const T& back() const + { + MOZ_ASSERT(!mEntered); + MOZ_ASSERT(!empty()); + return *(end() - 1); + } + + class Range + { + friend class VectorBase; + T* mCur; + T* mEnd; + Range(T* aCur, T* aEnd) + : mCur(aCur) + , mEnd(aEnd) + { + MOZ_ASSERT(aCur <= aEnd); + } + + public: + Range() {} + bool empty() const { return mCur == mEnd; } + size_t remain() const { return PointerRangeSize(mCur, mEnd); } + T& front() const { MOZ_ASSERT(!empty()); return *mCur; } + void popFront() { MOZ_ASSERT(!empty()); ++mCur; } + T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; } + }; + + Range all() { return Range(begin(), end()); } + + /* mutators */ + + /** + * Given that the vector is empty and has no inline storage, grow to + * |capacity|. + */ + bool initCapacity(size_t aRequest); + + /** + * If reserve(length() + N) succeeds, the N next appends are guaranteed to + * succeed. + */ + bool reserve(size_t aRequest); + + /** + * Destroy elements in the range [end() - aIncr, end()). Does not deallocate + * or unreserve storage for those elements. + */ + void shrinkBy(size_t aIncr); + + /** Grow the vector by aIncr elements. */ + bool growBy(size_t aIncr); + + /** Call shrinkBy or growBy based on whether newSize > length(). */ + bool resize(size_t aNewLength); + + /** + * Increase the length of the vector, but don't initialize the new elements + * -- leave them as uninitialized memory. + */ + bool growByUninitialized(size_t aIncr); + bool resizeUninitialized(size_t aNewLength); + + /** Shorthand for shrinkBy(length()). */ + void clear(); + + /** Clears and releases any heap-allocated storage. */ + void clearAndFree(); + + /** + * If true, appending |aNeeded| elements won't reallocate elements storage. + * This *doesn't* mean that infallibleAppend may be used! You still must + * reserve the extra space, even if this method indicates that appends won't + * need to reallocate elements storage. + */ + bool canAppendWithoutRealloc(size_t aNeeded) const; + + /** Potentially fallible append operations. */ + + /** + * This can take either a T& or a T&&. Given a T&&, it moves |aU| into the + * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are + * not amused.") + */ + template bool append(U&& aU); + + template + bool appendAll(const VectorBase& aU); + bool appendN(const T& aT, size_t aN); + template bool append(const U* aBegin, const U* aEnd); + template bool append(const U* aBegin, size_t aLength); + + /* + * Guaranteed-infallible append operations for use upon vectors whose + * memory has been pre-reserved. Don't use this if you haven't reserved the + * memory! + */ + template void infallibleAppend(U&& aU) + { + internalAppend(Forward(aU)); + } + void infallibleAppendN(const T& aT, size_t aN) + { + internalAppendN(aT, aN); + } + template void infallibleAppend(const U* aBegin, const U* aEnd) + { + internalAppend(aBegin, PointerRangeSize(aBegin, aEnd)); + } + template void infallibleAppend(const U* aBegin, size_t aLength) + { + internalAppend(aBegin, aLength); + } + + void popBack(); + + T popCopy(); + + /** + * Transfers ownership of the internal buffer used by this vector to the + * caller. (It's the caller's responsibility to properly deallocate this + * buffer, in accordance with this vector's AllocPolicy.) After this call, + * the vector is empty. Since the returned buffer may need to be allocated + * (if the elements are currently stored in-place), the call can fail, + * returning nullptr. + * + * N.B. Although a T*, only the range [0, length()) is constructed. + */ + T* extractRawBuffer(); + + /** + * Transfer ownership of an array of objects into the vector. The caller + * must have allocated the array in accordance with this vector's + * AllocPolicy. + * + * N.B. This call assumes that there are no uninitialized elements in the + * passed array. + */ + void replaceRawBuffer(T* aP, size_t aLength); + + /** + * Places |aVal| at position |aP|, shifting existing elements from |aP| onward + * one position higher. On success, |aP| should not be reused because it'll + * be a dangling pointer if reallocation of the vector storage occurred; the + * return value should be used instead. On failure, nullptr is returned. + * + * Example usage: + * + * if (!(p = vec.insert(p, val))) { + * + * } + * + * + * This is inherently a linear-time operation. Be careful! + */ + template + T* insert(T* aP, U&& aVal); + + /** + * Removes the element |aT|, which must fall in the bounds [begin, end), + * shifting existing elements from |aT + 1| onward one position lower. + */ + void erase(T* aT); + + /** + * Removes the elements [|aBegin|, |aEnd|), which must fall in the bounds + * [begin, end), shifting existing elements from |aEnd + 1| onward to aBegin's + * old position. + */ + void erase(T* aBegin, T* aEnd); + + /** + * Measure the size of the vector's heap-allocated storage. + */ + size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; + + /** + * Like sizeOfExcludingThis, but also measures the size of the vector + * object (which must be heap-allocated) itself. + */ + size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; + + void swap(ThisVector& aOther); + +private: + VectorBase(const VectorBase&) MOZ_DELETE; + void operator=(const VectorBase&) MOZ_DELETE; + + /* Move-construct/assign only from our derived class, ThisVector. */ + VectorBase(VectorBase&&) MOZ_DELETE; + void operator=(VectorBase&&) MOZ_DELETE; +}; + +/* This does the re-entrancy check plus several other sanity checks. */ +#define MOZ_REENTRANCY_GUARD_ET_AL \ + ReentrancyGuard g(*this); \ + MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \ + MOZ_ASSERT(reserved() <= mCapacity); \ + MOZ_ASSERT(mLength <= reserved()); \ + MOZ_ASSERT(mLength <= mCapacity) + +/* Vector Implementation */ + +template +MOZ_ALWAYS_INLINE +VectorBase::VectorBase(AP aAP) + : AP(aAP) + , mLength(0) + , mCapacity(kInlineCapacity) +#ifdef DEBUG + , mReserved(kInlineCapacity) + , mEntered(false) +#endif +{ + mBegin = static_cast(mStorage.addr()); +} + +/* Move constructor. */ +template +MOZ_ALWAYS_INLINE +VectorBase::VectorBase(TV&& aRhs) + : AllocPolicy(Move(aRhs)) +#ifdef DEBUG + , mEntered(false) +#endif +{ + mLength = aRhs.mLength; + mCapacity = aRhs.mCapacity; +#ifdef DEBUG + mReserved = aRhs.mReserved; +#endif + + if (aRhs.usingInlineStorage()) { + /* We can't move the buffer over in this case, so copy elements. */ + mBegin = static_cast(mStorage.addr()); + Impl::moveConstruct(mBegin, aRhs.beginNoCheck(), aRhs.endNoCheck()); + /* + * Leave aRhs's mLength, mBegin, mCapacity, and mReserved as they are. + * The elements in its in-line storage still need to be destroyed. + */ + } else { + /* + * Take src's buffer, and turn src into an empty vector using + * in-line storage. + */ + mBegin = aRhs.mBegin; + aRhs.mBegin = static_cast(aRhs.mStorage.addr()); + aRhs.mCapacity = kInlineCapacity; + aRhs.mLength = 0; +#ifdef DEBUG + aRhs.mReserved = kInlineCapacity; +#endif + } +} + +/* Move assignment. */ +template +MOZ_ALWAYS_INLINE TV& +VectorBase::operator=(TV&& aRhs) +{ + MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited"); + TV* tv = static_cast(this); + tv->~TV(); + new(tv) TV(Move(aRhs)); + return *tv; +} + +template +MOZ_ALWAYS_INLINE +VectorBase::~VectorBase() +{ + MOZ_REENTRANCY_GUARD_ET_AL; + Impl::destroy(beginNoCheck(), endNoCheck()); + if (!usingInlineStorage()) { + this->free_(beginNoCheck()); + } +} + +/* + * This function will create a new heap buffer with capacity aNewCap, + * move all elements in the inline buffer to this new buffer, + * and fail on OOM. + */ +template +inline bool +VectorBase::convertToHeapStorage(size_t aNewCap) +{ + MOZ_ASSERT(usingInlineStorage()); + + /* Allocate buffer. */ + MOZ_ASSERT(!detail::CapacityHasExcessSpace(aNewCap)); + T* newBuf = this->template pod_malloc(aNewCap); + if (!newBuf) { + return false; + } + + /* Copy inline elements into heap buffer. */ + Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + + /* Switch in heap buffer. */ + mBegin = newBuf; + /* mLength is unchanged. */ + mCapacity = aNewCap; + return true; +} + +template +MOZ_NEVER_INLINE bool +VectorBase::growStorageBy(size_t aIncr) +{ + MOZ_ASSERT(mLength + aIncr > mCapacity); + MOZ_ASSERT_IF(!usingInlineStorage(), + !detail::CapacityHasExcessSpace(mCapacity)); + + /* + * When choosing a new capacity, its size should is as close to 2**N bytes + * as possible. 2**N-sized requests are best because they are unlikely to + * be rounded up by the allocator. Asking for a 2**N number of elements + * isn't as good, because if sizeof(T) is not a power-of-two that would + * result in a non-2**N request size. + */ + + size_t newCap; + + if (aIncr == 1) { + if (usingInlineStorage()) { + /* This case occurs in ~70--80% of the calls to this function. */ + size_t newSize = + tl::RoundUpPow2<(kInlineCapacity + 1) * sizeof(T)>::value; + newCap = newSize / sizeof(T); + goto convert; + } + + if (mLength == 0) { + /* This case occurs in ~0--10% of the calls to this function. */ + newCap = 1; + goto grow; + } + + /* This case occurs in ~15--20% of the calls to this function. */ + + /* + * Will mLength * 4 *sizeof(T) overflow? This condition limits a vector + * to 1GB of memory on a 32-bit system, which is a reasonable limit. It + * also ensures that + * + * static_cast(end()) - static_cast(begin()) + * + * doesn't overflow ptrdiff_t (see bug 510319). + */ + if (mLength & tl::MulOverflowMask<4 * sizeof(T)>::value) { + this->reportAllocOverflow(); + return false; + } + + /* + * If we reach here, the existing capacity will have a size that is already + * as close to 2^N as sizeof(T) will allow. Just double the capacity, and + * then there might be space for one more element. + */ + newCap = mLength * 2; + if (detail::CapacityHasExcessSpace(newCap)) { + newCap += 1; + } + } else { + /* This case occurs in ~2% of the calls to this function. */ + size_t newMinCap = mLength + aIncr; + + /* Did mLength + aIncr overflow? Will newCap * sizeof(T) overflow? */ + if (newMinCap < mLength || + newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value) + { + this->reportAllocOverflow(); + return false; + } + + size_t newMinSize = newMinCap * sizeof(T); + size_t newSize = RoundUpPow2(newMinSize); + newCap = newSize / sizeof(T); + } + + if (usingInlineStorage()) { +convert: + return convertToHeapStorage(newCap); + } + +grow: + return Impl::growTo(*this, newCap); +} + +template +inline bool +VectorBase::initCapacity(size_t aRequest) +{ + MOZ_ASSERT(empty()); + MOZ_ASSERT(usingInlineStorage()); + if (aRequest == 0) { + return true; + } + T* newbuf = this->template pod_malloc(aRequest); + if (!newbuf) { + return false; + } + mBegin = newbuf; + mCapacity = aRequest; +#ifdef DEBUG + mReserved = aRequest; +#endif + return true; +} + +template +inline bool +VectorBase::reserve(size_t aRequest) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + if (aRequest > mCapacity && !growStorageBy(aRequest - mLength)) { + return false; + } +#ifdef DEBUG + if (aRequest > mReserved) { + mReserved = aRequest; + } + MOZ_ASSERT(mLength <= mReserved); + MOZ_ASSERT(mReserved <= mCapacity); +#endif + return true; +} + +template +inline void +VectorBase::shrinkBy(size_t aIncr) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + MOZ_ASSERT(aIncr <= mLength); + Impl::destroy(endNoCheck() - aIncr, endNoCheck()); + mLength -= aIncr; +} + +template +MOZ_ALWAYS_INLINE bool +VectorBase::growBy(size_t aIncr) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + if (aIncr > mCapacity - mLength && !growStorageBy(aIncr)) { + return false; + } + MOZ_ASSERT(mLength + aIncr <= mCapacity); + T* newend = endNoCheck() + aIncr; + Impl::initialize(endNoCheck(), newend); + mLength += aIncr; +#ifdef DEBUG + if (mLength > mReserved) { + mReserved = mLength; + } +#endif + return true; +} + +template +MOZ_ALWAYS_INLINE bool +VectorBase::growByUninitialized(size_t aIncr) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + if (aIncr > mCapacity - mLength && !growStorageBy(aIncr)) { + return false; + } + MOZ_ASSERT(mLength + aIncr <= mCapacity); + mLength += aIncr; +#ifdef DEBUG + if (mLength > mReserved) { + mReserved = mLength; + } +#endif + return true; +} + +template +inline bool +VectorBase::resize(size_t aNewLength) +{ + size_t curLength = mLength; + if (aNewLength > curLength) { + return growBy(aNewLength - curLength); + } + shrinkBy(curLength - aNewLength); + return true; +} + +template +MOZ_ALWAYS_INLINE bool +VectorBase::resizeUninitialized(size_t aNewLength) +{ + size_t curLength = mLength; + if (aNewLength > curLength) { + return growByUninitialized(aNewLength - curLength); + } + shrinkBy(curLength - aNewLength); + return true; +} + +template +inline void +VectorBase::clear() +{ + MOZ_REENTRANCY_GUARD_ET_AL; + Impl::destroy(beginNoCheck(), endNoCheck()); + mLength = 0; +} + +template +inline void +VectorBase::clearAndFree() +{ + clear(); + + if (usingInlineStorage()) { + return; + } + this->free_(beginNoCheck()); + mBegin = static_cast(mStorage.addr()); + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = kInlineCapacity; +#endif +} + +template +inline bool +VectorBase::canAppendWithoutRealloc(size_t aNeeded) const +{ + return mLength + aNeeded <= mCapacity; +} + +template +template +MOZ_ALWAYS_INLINE void +VectorBase::internalAppendAll( + const VectorBase& aOther) +{ + internalAppend(aOther.begin(), aOther.length()); +} + +template +template +MOZ_ALWAYS_INLINE void +VectorBase::internalAppend(U&& aU) +{ + MOZ_ASSERT(mLength + 1 <= mReserved); + MOZ_ASSERT(mReserved <= mCapacity); + new(endNoCheck()) T(Forward(aU)); + ++mLength; +} + +template +MOZ_ALWAYS_INLINE bool +VectorBase::appendN(const T& aT, size_t aNeeded) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + if (mLength + aNeeded > mCapacity && !growStorageBy(aNeeded)) { + return false; + } +#ifdef DEBUG + if (mLength + aNeeded > mReserved) { + mReserved = mLength + aNeeded; + } +#endif + internalAppendN(aT, aNeeded); + return true; +} + +template +MOZ_ALWAYS_INLINE void +VectorBase::internalAppendN(const T& aT, size_t aNeeded) +{ + MOZ_ASSERT(mLength + aNeeded <= mReserved); + MOZ_ASSERT(mReserved <= mCapacity); + Impl::copyConstructN(endNoCheck(), aNeeded, aT); + mLength += aNeeded; +} + +template +template +inline T* +VectorBase::insert(T* aP, U&& aVal) +{ + MOZ_ASSERT(begin() <= aP); + MOZ_ASSERT(aP <= end()); + size_t pos = aP - begin(); + MOZ_ASSERT(pos <= mLength); + size_t oldLength = mLength; + if (pos == oldLength) { + if (!append(Forward(aVal))) { + return nullptr; + } + } else { + T oldBack = Move(back()); + if (!append(Move(oldBack))) { /* Dup the last element. */ + return nullptr; + } + for (size_t i = oldLength; i > pos; --i) { + (*this)[i] = Move((*this)[i - 1]); + } + (*this)[pos] = Forward(aVal); + } + return begin() + pos; +} + +template +inline void +VectorBase::erase(T* aIt) +{ + MOZ_ASSERT(begin() <= aIt); + MOZ_ASSERT(aIt < end()); + while (aIt + 1 < end()) { + *aIt = Move(*(aIt + 1)); + ++aIt; + } + popBack(); +} + +template +inline void +VectorBase::erase(T* aBegin, T* aEnd) +{ + MOZ_ASSERT(begin() <= aBegin); + MOZ_ASSERT(aBegin <= aEnd); + MOZ_ASSERT(aEnd <= end()); + while (aEnd < end()) { + *aBegin++ = Move(*aEnd++); + } + shrinkBy(aEnd - aBegin); +} + +template +template +MOZ_ALWAYS_INLINE bool +VectorBase::append(const U* aInsBegin, const U* aInsEnd) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd); + if (mLength + aNeeded > mCapacity && !growStorageBy(aNeeded)) { + return false; + } +#ifdef DEBUG + if (mLength + aNeeded > mReserved) { + mReserved = mLength + aNeeded; + } +#endif + internalAppend(aInsBegin, aNeeded); + return true; +} + +template +template +MOZ_ALWAYS_INLINE void +VectorBase::internalAppend(const U* aInsBegin, size_t aInsLength) +{ + MOZ_ASSERT(mLength + aInsLength <= mReserved); + MOZ_ASSERT(mReserved <= mCapacity); + Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength); + mLength += aInsLength; +} + +template +template +MOZ_ALWAYS_INLINE bool +VectorBase::append(U&& aU) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + if (mLength == mCapacity && !growStorageBy(1)) { + return false; + } +#ifdef DEBUG + if (mLength + 1 > mReserved) { + mReserved = mLength + 1; + } +#endif + internalAppend(Forward(aU)); + return true; +} + +template +template +MOZ_ALWAYS_INLINE bool +VectorBase::appendAll(const VectorBase& aOther) +{ + return append(aOther.begin(), aOther.length()); +} + +template +template +MOZ_ALWAYS_INLINE bool +VectorBase::append(const U* aInsBegin, size_t aInsLength) +{ + return append(aInsBegin, aInsBegin + aInsLength); +} + +template +MOZ_ALWAYS_INLINE void +VectorBase::popBack() +{ + MOZ_REENTRANCY_GUARD_ET_AL; + MOZ_ASSERT(!empty()); + --mLength; + endNoCheck()->~T(); +} + +template +MOZ_ALWAYS_INLINE T +VectorBase::popCopy() +{ + T ret = back(); + popBack(); + return ret; +} + +template +inline T* +VectorBase::extractRawBuffer() +{ + T* ret; + if (usingInlineStorage()) { + ret = this->template pod_malloc(mLength); + if (!ret) { + return nullptr; + } + Impl::copyConstruct(ret, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + /* mBegin, mCapacity are unchanged. */ + mLength = 0; + } else { + ret = mBegin; + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = kInlineCapacity; +#endif + } + return ret; +} + +template +inline void +VectorBase::replaceRawBuffer(T* aP, size_t aLength) +{ + MOZ_REENTRANCY_GUARD_ET_AL; + + /* Destroy what we have. */ + Impl::destroy(beginNoCheck(), endNoCheck()); + if (!usingInlineStorage()) { + this->free_(beginNoCheck()); + } + + /* Take in the new buffer. */ + if (aLength <= kInlineCapacity) { + /* + * We convert to inline storage if possible, even though aP might + * otherwise be acceptable. Maybe this behaviour should be + * specifiable with an argument to this function. + */ + mBegin = static_cast(mStorage.addr()); + mLength = aLength; + mCapacity = kInlineCapacity; + Impl::moveConstruct(mBegin, aP, aP + aLength); + Impl::destroy(aP, aP + aLength); + this->free_(aP); + } else { + mBegin = aP; + mLength = aLength; + mCapacity = aLength; + } +#ifdef DEBUG + mReserved = aLength; +#endif +} + +template +inline size_t +VectorBase::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + return usingInlineStorage() ? 0 : aMallocSizeOf(beginNoCheck()); +} + +template +inline size_t +VectorBase::sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const +{ + return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); +} + +template +inline void +VectorBase::swap(TV& aOther) +{ + static_assert(N == 0, + "still need to implement this for N != 0"); + + // This only works when inline storage is always empty. + if (!usingInlineStorage() && aOther.usingInlineStorage()) { + aOther.mBegin = mBegin; + mBegin = inlineStorage(); + } else if (usingInlineStorage() && !aOther.usingInlineStorage()) { + mBegin = aOther.mBegin; + aOther.mBegin = aOther.inlineStorage(); + } else if (!usingInlineStorage() && !aOther.usingInlineStorage()) { + Swap(mBegin, aOther.mBegin); + } else { + // This case is a no-op, since we'd set both to use their inline storage. + } + + Swap(mLength, aOther.mLength); + Swap(mCapacity, aOther.mCapacity); +#ifdef DEBUG + Swap(mReserved, aOther.mReserved); +#endif +} + +/* + * STL-like container providing a short-lived, dynamic buffer. Vector calls the + * constructors/destructors of all elements stored in its internal buffer, so + * non-PODs may be safely used. Additionally, Vector will store the first N + * elements in-place before resorting to dynamic allocation. + * + * T requirements: + * - default and copy constructible, assignable, destructible + * - operations do not throw + * N requirements: + * - any value, however, N is clamped to min/max values + * AllocPolicy: + * - see "Allocation policies" in AllocPolicy.h (defaults to + * mozilla::MallocAllocPolicy) + * + * Vector is not reentrant: T member functions called during Vector member + * functions must not call back into the same object! + */ +template +class Vector + : public VectorBase > +{ + typedef VectorBase Base; + +public: + explicit Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {} + Vector(Vector&& vec) : Base(Move(vec)) {} + Vector& operator=(Vector&& aOther) + { + return Base::operator=(Move(aOther)); + } +}; + +} // namespace mozilla + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* mozilla_Vector_h */ diff --git a/libazure/mozilla/WeakPtr.h b/libazure/mozilla/WeakPtr.h new file mode 100644 index 0000000..58960ad --- /dev/null +++ b/libazure/mozilla/WeakPtr.h @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Weak pointer functionality, implemented as a mixin for use with any class. */ + +/** + * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting + * its lifetime. It works by creating a single shared reference counted object + * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo' + * clear the pointer in the WeakReference without having to know about all of + * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime + * of 'Foo'. + * + * PLEASE NOTE: This weak pointer implementation is not thread-safe. + * + * Note that when deriving from SupportsWeakPtr you should add + * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your + * class, where ClassName is the name of your class. + * + * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional + * dereference, and an additional heap allocated pointer sized object shared + * between all of the WeakPtrs. + * + * Example of usage: + * + * // To have a class C support weak pointers, inherit from + * // SupportsWeakPtr. + * class C : public SupportsWeakPtr + * { + * public: + * MOZ_DECLARE_REFCOUNTED_TYPENAME(C) + * int mNum; + * void act(); + * }; + * + * C* ptr = new C(); + * + * // Get weak pointers to ptr. The first time a weak pointer + * // is obtained, a reference counted WeakReference object is created that + * // can live beyond the lifetime of 'ptr'. The WeakReference + * // object will be notified of 'ptr's destruction. + * WeakPtr weak = ptr; + * WeakPtr other = ptr; + * + * // Test a weak pointer for validity before using it. + * if (weak) { + * weak->mNum = 17; + * weak->act(); + * } + * + * // Destroying the underlying object clears weak pointers to it. + * delete ptr; + * + * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); + * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); + * + * WeakPtr is typesafe and may be used with any class. It is not required that + * the class be reference-counted or allocated in any particular way. + * + * The API was loosely inspired by Chromium's weak_ptr.h: + * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h + */ + +#ifndef mozilla_WeakPtr_h +#define mozilla_WeakPtr_h + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/NullPtr.h" +#include "mozilla/RefPtr.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +template class WeakPtr; +template class SupportsWeakPtr; + +namespace detail { + +// This can live beyond the lifetime of the class derived from +// SupportsWeakPtr. +template +class WeakReference : public ::mozilla::RefCounted > +{ +public: + explicit WeakReference(T* p) : mPtr(p) {} + + T* get() const { return mPtr; } + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING +#ifdef XP_WIN +#define snprintf _snprintf +#endif + const char* typeName() const + { + static char nameBuffer[1024]; + const char* innerType = mPtr->typeName(); + // We could do fancier length checks at runtime, but innerType is + // controlled by us so we can ensure that this never causes a buffer + // overflow by this assertion. + MOZ_ASSERT(strlen(innerType) + sizeof("WeakReference<>") < + ArrayLength(nameBuffer), + "Exceedingly large type name"); + snprintf(nameBuffer, ArrayLength(nameBuffer), "WeakReference<%s>", + innerType); + // This is usually not OK, but here we are returning a pointer to a static + // buffer which will immediately be used by the caller. + return nameBuffer; + } + + size_t typeSize() const { return sizeof(*this); } +#undef snprintf +#endif + +private: + friend class mozilla::SupportsWeakPtr; + + void detach() { mPtr = nullptr; } + + T* mPtr; +}; + +} // namespace detail + +template +class SupportsWeakPtr +{ +protected: + ~SupportsWeakPtr() + { + static_assert(IsBaseOf, T>::value, + "T must derive from SupportsWeakPtr"); + if (mSelfReferencingWeakPtr) { + mSelfReferencingWeakPtr.mRef->detach(); + } + } + +private: + const WeakPtr& SelfReferencingWeakPtr() + { + if (!mSelfReferencingWeakPtr) { + mSelfReferencingWeakPtr.mRef = new detail::WeakReference(static_cast(this)); + } + return mSelfReferencingWeakPtr; + } + + const WeakPtr& SelfReferencingWeakPtr() const + { + const WeakPtr& p = const_cast(this)->SelfReferencingWeakPtr(); + return reinterpret_cast&>(p); + } + + friend class WeakPtr; + friend class WeakPtr; + + WeakPtr mSelfReferencingWeakPtr; +}; + +template +class WeakPtr +{ + typedef detail::WeakReference WeakReference; + +public: + WeakPtr& operator=(const WeakPtr& aOther) + { + mRef = aOther.mRef; + return *this; + } + + WeakPtr(const WeakPtr& aOther) + { + *this = aOther; + } + + WeakPtr& operator=(T* aOther) + { + return *this = aOther->SelfReferencingWeakPtr(); + } + + MOZ_IMPLICIT WeakPtr(T* aOther) + { + *this = aOther; + } + + // Ensure that mRef is dereferenceable in the uninitialized state. + WeakPtr() : mRef(new WeakReference(nullptr)) {} + + operator T*() const { return mRef->get(); } + T& operator*() const { return *mRef->get(); } + + T* operator->() const { return mRef->get(); } + + T* get() const { return mRef->get(); } + +private: + friend class SupportsWeakPtr; + + explicit WeakPtr(const RefPtr& aOther) : mRef(aOther) {} + + RefPtr mRef; +}; + +} // namespace mozilla + +#endif /* mozilla_WeakPtr_h */ diff --git a/libazure/mozilla/WindowsVersion.h b/libazure/mozilla/WindowsVersion.h new file mode 100644 index 0000000..fcf24ac --- /dev/null +++ b/libazure/mozilla/WindowsVersion.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_WindowsVersion_h +#define mozilla_WindowsVersion_h + +#include "mozilla/Attributes.h" +#include +#include + +namespace mozilla { + +inline bool +IsWindowsVersionOrLater(uint32_t aVersion) +{ + static uint32_t minVersion = 0; + static uint32_t maxVersion = UINT32_MAX; + + if (minVersion >= aVersion) { + return true; + } + + if (aVersion >= maxVersion) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + info.dwMajorVersion = aVersion >> 24; + info.dwMinorVersion = (aVersion >> 16) & 0xFF; + info.wServicePackMajor = (aVersion >> 8) & 0xFF; + info.wServicePackMinor = aVersion & 0xFF; + + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if (VerifyVersionInfo(&info, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + conditionMask)) { + minVersion = aVersion; + return true; + } + + maxVersion = aVersion; + return false; +} + +inline bool +IsWindowsBuildOrLater(uint32_t aBuild) +{ + static uint32_t minBuild = 0; + static uint32_t maxBuild = UINT32_MAX; + + if (minBuild >= aBuild) { + return true; + } + + if (aBuild >= maxBuild) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + info.dwBuildNumber = aBuild; + + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + + if (VerifyVersionInfo(&info, VER_BUILDNUMBER, conditionMask)) { + minBuild = aBuild; + return true; + } + + maxBuild = aBuild; + return false; +} + +MOZ_ALWAYS_INLINE bool +IsXPSP3OrLater() +{ + return IsWindowsVersionOrLater(0x05010300ul); +} + +MOZ_ALWAYS_INLINE bool +IsWin2003OrLater() +{ + return IsWindowsVersionOrLater(0x05020000ul); +} + +MOZ_ALWAYS_INLINE bool +IsWin2003SP2OrLater() +{ + return IsWindowsVersionOrLater(0x05020200ul); +} + +MOZ_ALWAYS_INLINE bool +IsVistaOrLater() +{ + return IsWindowsVersionOrLater(0x06000000ul); +} + +MOZ_ALWAYS_INLINE bool +IsVistaSP1OrLater() +{ + return IsWindowsVersionOrLater(0x06000100ul); +} + +MOZ_ALWAYS_INLINE bool +IsWin7OrLater() +{ + return IsWindowsVersionOrLater(0x06010000ul); +} + +MOZ_ALWAYS_INLINE bool +IsWin7SP1OrLater() +{ + return IsWindowsVersionOrLater(0x06010100ul); +} + +MOZ_ALWAYS_INLINE bool +IsWin8OrLater() +{ + return IsWindowsVersionOrLater(0x06020000ul); +} + +MOZ_ALWAYS_INLINE bool +IsNotWin7PreRTM() +{ + return IsWin7SP1OrLater() || !IsWin7OrLater() || + IsWindowsBuildOrLater(7600); +} + +} // namespace mozilla + +#endif /* mozilla_WindowsVersion_h */ diff --git a/libazure/mozilla/lz4.h b/libazure/mozilla/lz4.h new file mode 100644 index 0000000..bf67801 --- /dev/null +++ b/libazure/mozilla/lz4.h @@ -0,0 +1,276 @@ +/* + LZ4 - Fast LZ compression algorithm + Header File + Copyright (C) 2011-2014, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + + +/************************************** + Version +**************************************/ +#define LZ4_VERSION_MAJOR 1 /* for major interface/format changes */ +#define LZ4_VERSION_MINOR 2 /* for minor interface/format changes */ +#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ + + +/************************************** + Tuning parameter +**************************************/ +/* + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#define LZ4_MEMORY_USAGE 14 + + +/************************************** + Simple Functions +**************************************/ + +int LZ4_compress (const char* source, char* dest, int inputSize); +int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxOutputSize); + +/* +LZ4_compress() : + Compresses 'inputSize' bytes from 'source' into 'dest'. + Destination buffer must be already allocated, + and must be sized to handle worst cases situations (input data not compressible) + Worst case size evaluation is provided by function LZ4_compressBound() + inputSize : Max supported value is LZ4_MAX_INPUT_VALUE + return : the number of bytes written in buffer dest + or 0 if the compression fails + +LZ4_decompress_safe() : + compressedSize : is obviously the source size + maxOutputSize : is the size of the destination buffer, which must be already allocated. + return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + If the destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits : + it never writes outside of output buffer, and never reads outside of input buffer. + Therefore, it is protected against malicious data packets. +*/ + + +/* +Note : + Should you prefer to explicitly allocate compression-table memory using your own allocation method, + use the streaming functions provided below, simply reset the memory area between each call to LZ4_compress_continue() +*/ + + +/************************************** + Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/* +LZ4_compressBound() : + Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible) + primarily useful for memory allocation of output buffer. + macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation). + + isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +*/ +int LZ4_compressBound(int isize); + + +/* +LZ4_compress_limitedOutput() : + Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. + If it cannot achieve it, compression will stop, and result of the function will be zero. + This function never writes outside of provided output buffer. + + inputSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxOutputSize : is the size of the destination buffer (which must be already allocated) + return : the number of bytes written in buffer 'dest' + or 0 if the compression fails +*/ +int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); + + +/* +LZ4_decompress_fast() : + originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function is a bit faster than LZ4_decompress_safe() + It provides fast decompression and fully respect memory boundaries for properly formed compressed data. + It does not provide full protection against intentionnally modified data stream. + Use this function in a trusted environment (data to decode comes from a trusted source). +*/ +int LZ4_decompress_fast (const char* source, char* dest, int originalSize); + + +/* +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'compressedSize' at position 'source' + into output buffer 'dest' of size 'maxOutputSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +*/ +int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxOutputSize); + + +/*********************************************** + Experimental Streaming Compression Functions +***********************************************/ + +#define LZ4_STREAMSIZE_U32 ((1 << (LZ4_MEMORY_USAGE-2)) + 8) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_stream_t + * information structure to track an LZ4 stream. + * important : set this structure content to zero before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMSIZE_U32]; } LZ4_stream_t; + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStream + * provides a pointer (void*) towards an initialized LZ4_stream_t structure. + * LZ4_free just frees it. + */ +void* LZ4_createStream(); +int LZ4_free (void* LZ4_stream); + + +/* + * LZ4_loadDict + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed (same effect as init). + * Return : 1 if OK, 0 if error + */ +int LZ4_loadDict (void* LZ4_stream, const char* dictionary, int dictSize); + +/* + * LZ4_compress_continue + * Compress data block 'source', using blocks compressed before as dictionary to improve compression ratio + * Previous data blocks are assumed to still be present at their previous location. + */ +int LZ4_compress_continue (void* LZ4_stream, const char* source, char* dest, int inputSize); + +/* + * LZ4_compress_limitedOutput_continue + * Same as before, but also specify a maximum target compressed size (maxOutputSize) + * If objective cannot be met, compression exits, and returns a zero. + */ +int LZ4_compress_limitedOutput_continue (void* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* + * LZ4_saveDict + * If previously compressed data block is not guaranteed to remain at its previous memory location + * save it into a safe place (char* safeBuffer) + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call again LZ4_compress_continue() + * Return : 1 if OK, 0 if error + * Note : any dictSize > 64 KB will be interpreted as 64KB. + */ +int LZ4_saveDict (void* LZ4_stream, char* safeBuffer, int dictSize); + + +/************************************************ + Experimental Streaming Decompression Functions +************************************************/ + +#define LZ4_STREAMDECODESIZE_U32 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_streamDecode_t + * information structure to track an LZ4 stream. + * important : set this structure content to zero before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMDECODESIZE_U32]; } LZ4_streamDecode_t; + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode() + * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. + * LZ4_free just frees it. + */ +void* LZ4_createStreamDecode(); +int LZ4_free (void* LZ4_stream); /* yes, it's the same one as for compression */ + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setDictDecode() +*/ +int LZ4_decompress_safe_continue (void* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize); +int LZ4_decompress_fast_continue (void* LZ4_streamDecode, const char* source, char* dest, int originalSize); + +/* + * LZ4_setDictDecode + * Use this function to instruct where to find the dictionary. + * This function can be used to specify a static dictionary, + * or to instruct where to find some previously decoded data saved into a different memory space. + * Setting a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setDictDecode (void* LZ4_streamDecode, const char* dictionary, int dictSize); + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as + a combination of LZ4_setDictDecode() followed by LZ4_decompress_x_continue() + all together into a single function call. + It doesn't use nor update an LZ4_streamDecode_t structure. +*/ +int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize); +int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); + + + +#if defined (__cplusplus) +} +#endif diff --git a/libazure/mozilla/lz4_encoder.h b/libazure/mozilla/lz4_encoder.h new file mode 100644 index 0000000..ee87cbb --- /dev/null +++ b/libazure/mozilla/lz4_encoder.h @@ -0,0 +1,258 @@ +/* + LZ4 Encoder - Part of LZ4 compression algorithm + Copyright (C) 2011-2013, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + - LZ4 source repository : http://code.google.com/p/lz4/ +*/ + +/* lz4_encoder.h must be included into lz4.c + The objective of this file is to create a single LZ4 compression function source + which will be instanciated multiple times with minor variations + depending on a set of #define. +*/ + + + +//**************************** +// Check required defines +//**************************** + +#ifndef FUNCTION_NAME +# error "FUNTION_NAME is not defined" +#endif + + +//**************************** +// Local definitions +//**************************** + +#ifdef COMPRESS_64K +# define HASHLOG (MEMORY_USAGE-1) +# define CURRENT_H_TYPE U16 +# define CURRENTBASE(base) const BYTE* const base = ip +#else +# define HASHLOG (MEMORY_USAGE-2) +# define CURRENT_H_TYPE HTYPE +# define CURRENTBASE(base) INITBASE(base) +#endif + +#define HASHTABLE_NBCELLS (1U<> ((MINMATCH*8)-HASHLOG)) +#define LZ4_HASHVALUE(p) LZ4_HASH(A32(p)) + + + +//**************************** +// Function code +//**************************** + +int FUNCTION_NAME( +#ifdef USE_HEAPMEMORY + void* ctx, +#endif + const char* source, + char* dest, + int inputSize +#ifdef LIMITED_OUTPUT + ,int maxOutputSize +#endif + ) +{ +#ifdef USE_HEAPMEMORY + CURRENT_H_TYPE* HashTable = (CURRENT_H_TYPE*)ctx; +#else + CURRENT_H_TYPE HashTable[HASHTABLE_NBCELLS] = {0}; +#endif + + const BYTE* ip = (BYTE*) source; + CURRENTBASE(base); + const BYTE* anchor = ip; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; +#define matchlimit (iend - LASTLITERALS) + + BYTE* op = (BYTE*) dest; +#ifdef LIMITED_OUTPUT + BYTE* const oend = op + maxOutputSize; +#endif + + int length; + const int skipStrength = SKIPSTRENGTH; + U32 forwardH; + + + // Init + if (inputSizeLZ4_64KLIMIT) return 0; // Size too large (not within 64K limit) +#endif +#ifdef USE_HEAPMEMORY + memset((void*)HashTable, 0, HASHTABLESIZE); +#endif + + // First Byte + HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base); + ip++; forwardH = LZ4_HASHVALUE(ip); + + // Main Loop + for ( ; ; ) + { + int findMatchAttempts = (1U << skipStrength) + 3; + const BYTE* forwardIp = ip; + const BYTE* ref; + BYTE* token; + + // Find a match + do { + U32 h = forwardH; + int step = findMatchAttempts++ >> skipStrength; + ip = forwardIp; + forwardIp = ip + step; + + if unlikely(forwardIp > mflimit) { goto _last_literals; } + + forwardH = LZ4_HASHVALUE(forwardIp); + ref = base + HashTable[h]; + HashTable[h] = (CURRENT_H_TYPE)(ip - base); + + } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); + + // Catch up + while ((ip>anchor) && (ref>(BYTE*)source) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; } + + // Encode Literal length + length = (int)(ip - anchor); + token = op++; +#ifdef LIMITED_OUTPUT + if unlikely(op + length + (2 + 1 + LASTLITERALS) + (length>>8) > oend) return 0; // Check output limit +#endif + if (length>=(int)RUN_MASK) + { + int len = length-RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(length<>8) > oend) return 0; // Check output limit +#endif + if (length>=(int)ML_MASK) + { + *token += ML_MASK; + length -= ML_MASK; + for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; } + if (length >= 255) { length-=255; *op++ = 255; } + *op++ = (BYTE)length; + } + else *token += (BYTE)length; + + // Test end of chunk + if (ip > mflimit) { anchor = ip; break; } + + // Fill table + HashTable[LZ4_HASHVALUE(ip-2)] = (CURRENT_H_TYPE)(ip - 2 - base); + + // Test next position + ref = base + HashTable[LZ4_HASHVALUE(ip)]; + HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base); + if ((ref >= ip - MAX_DISTANCE) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } + + // Prepare next loop + anchor = ip++; + forwardH = LZ4_HASHVALUE(ip); + } + +_last_literals: + // Encode Last Literals + { + int lastRun = (int)(iend - anchor); +#ifdef LIMITED_OUTPUT + if (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) return 0; // Check output limit +#endif + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun< +inline void +operator<<(const unused_t& /*unused*/, const T& /*unused*/) +{ +} + +} + +#endif // mozilla_unused_h diff --git a/libazure/nvpr/Clip.cpp b/libazure/nvpr/Clip.cpp new file mode 100644 index 0000000..cb777bf --- /dev/null +++ b/libazure/nvpr/Clip.cpp @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Clip.h" +#include "DrawTargetNVpr.h" +#include "GL.h" +#include "Matrix.h" + +namespace mozilla { +namespace gfx { +namespace nvpr { + +ScissorClip::ScissorClip(DrawTargetNVpr* aDrawTarget, + TemporaryRef aPrevious, + const Matrix& aTransform, + const Rect& aClipRect, bool& aSuccess) + : Clip(aDrawTarget, aPrevious) +{ + aSuccess = false; + + if (!aTransform.IsRectilinear()) { + return; + } + + if (!aTransform.TransformBounds(aClipRect).ToIntRect(&mScissorRect)) { + return; + } + + if (mPrevious) { + mScissorRect.IntersectRect(mScissorRect, mPrevious->mScissorRect); + } + + aSuccess = true; +} + +PlanesClip::PlanesClip(DrawTargetNVpr* aDrawTarget, + TemporaryRef aPrevious, + const Matrix& aTransform, + ConvexPolygon& aPolygon, bool& aSuccess) + : Clip(aDrawTarget, aPrevious) +{ + mPolygon.Swap(aPolygon); + + aSuccess = false; + + mPolygon.Transform(aTransform); + if (mPrevious) { + mPolygon.Intersect(mPrevious->Polygon()); + } + + if (mPolygon.NumSides() > gl->MaxClipPlanes()) { + return; + } + + mPolygonId = gl->GetUniqueId(); + + aSuccess = true; +} + +void StencilClip::ApplyToStencilBuffer() +{ + MOZ_ASSERT(!mOwnClipBit); + MOZ_ASSERT(gl->IsCurrent()); + + gl->SetTransform(mTransform, mTransformId); + gl->SetColorWriteMask(GL::WRITE_NONE); + gl->SetShaderProgram(0); + + mOwnClipBit = mDrawTarget->ReserveStencilClipBit(); + if (mOwnClipBit) { + // We own a stencil bit plane for clipping. Now we etch in our path. + const GLubyte existingClipBits = ~(mOwnClipBit | (mOwnClipBit - 1)) & 0xff; + + gl->ConfigurePathStencilTest(existingClipBits); + gl->StencilFillPathNV(*mPath, GL_COUNT_UP_NV, + (mPath->GetFillRule() == FillRule::FILL_WINDING) + ? mOwnClipBit - 1 : 0x1); + + gl->EnableStencilTest(GL::PASS_IF_NOT_EQUAL, mOwnClipBit, mOwnClipBit - 1, + GL::REPLACE_PASSING_WITH_COMPARAND, + mOwnClipBit | (mOwnClipBit - 1)); + gl->CoverFillPathNV(*mPath, GL_BOUNDING_BOX_NV); + + return; + } + + // There aren't enough stencil bit planes left for us to get our own. We have + // to destructively intersect our path into an existing clip bit. + const StencilClip* lastClipBitOwner = GetLastClipBitOwner(); + MOZ_ASSERT(lastClipBitOwner); + + const GLubyte sharedClipBit = lastClipBitOwner->mOwnClipBit; + const GLubyte existingClipBits = ~(sharedClipBit - 1) & 0xff; + + gl->ConfigurePathStencilTest(existingClipBits); + gl->StencilFillPathNV(*mPath, GL_COUNT_UP_NV, + (mPath->GetFillRule() == FillRule::FILL_WINDING) + ? sharedClipBit - 1 : 0x1); + + gl->SetTransform(lastClipBitOwner->mTransform, lastClipBitOwner->mTransformId); + + gl->EnableStencilTest(GL::PASS_IF_NOT_EQUAL, sharedClipBit, sharedClipBit - 1, + GL::REPLACE_PASSING_CLEAR_FAILING, + sharedClipBit | (sharedClipBit - 1)); + gl->CoverFillPathNV(*lastClipBitOwner->mPath, GL_BOUNDING_BOX_NV); +} + +void StencilClip::RestoreStencilBuffer() +{ + if (!mOwnClipBit) { + // We destroyed the previous clip state when we intersected our path into an + // existing clip bit in the stencil buffer. We have to clear that bit plane + // and then etch the previous path(s) back into it again. + MOZ_ASSERT(mPrevious); + mPrevious->RestoreStencilBuffer(); + mPrevious->ApplyToStencilBuffer(); + return; + } + + MOZ_ASSERT(gl->IsCurrent()); + + gl->SetTransform(mTransform, mTransformId); + gl->SetColorWriteMask(GL::WRITE_NONE); + gl->SetShaderProgram(0); + + // In order to reset the stencil buffer to the previous clipping state, we + // need to clear our bit plane as well as any stencil data from future clips. + const GLuint newFreeBits = mOwnClipBit | (mOwnClipBit - 1); + gl->EnableStencilTest(GL::PASS_IF_NOT_ZERO, newFreeBits, + GL::CLEAR_PASSING_VALUES, newFreeBits); + gl->CoverFillPathNV(*mPath, GL_BOUNDING_BOX_NV); + + mDrawTarget->ReleaseStencilClipBits(newFreeBits); + mOwnClipBit = 0; +} + +} +} +} diff --git a/libazure/nvpr/Clip.h b/libazure/nvpr/Clip.h new file mode 100644 index 0000000..e4f0fbc --- /dev/null +++ b/libazure/nvpr/Clip.h @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_CLIP_H_ +#define MOZILLA_GFX_NVPR_CLIP_H_ + +#include "2D.h" +#include "ConvexPolygon.h" +#include "Line.h" +#include "PathNVpr.h" +#include + +namespace mozilla { +namespace gfx { + +class DrawTargetNVpr; +class PathNVpr; + +namespace nvpr { + +template +class Clip : public RefCounted { +public: + Clip(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious) + : mPrevious(aPrevious) + , mDrawTarget(aDrawTarget) + {} + + SubclassType* GetPrevious() const { return mPrevious.get(); } + TemporaryRef Pop() { return mPrevious.forget(); } + +protected: + DrawTargetNVpr* const mDrawTarget; + RefPtr mPrevious; +}; + +/** + * 'Scissor clips' are a stack of pixel-aligned clip rects that use glScissor. + */ +class ScissorClip : public Clip { +public: + static TemporaryRef + Create(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, const Rect& aClipRect) + { + bool success; + RefPtr clip = new ScissorClip(aDrawTarget, aPrevious, + aTransform, aClipRect, success); + return success ? clip.forget() : nullptr; + } + + const IntRect& ScissorRect() const { return mScissorRect; } + +private: + ScissorClip(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, const Rect& aClipRect, + bool& aSuccess); + + IntRect mScissorRect; +}; + +/** + * 'Planes clips' are a stack of convex polygons stored in device space. We + * compute the intersection of all polygons in the stack and then use OpenGL + * clipping planes to clip to that intersection. + */ +class PlanesClip : public Clip { +public: + static TemporaryRef + Create(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, ConvexPolygon&& aPassPolygon) + { + bool success; + RefPtr clip = new PlanesClip(aDrawTarget, aPrevious, aTransform, + aPassPolygon, success); + return success ? clip.forget() : nullptr; + } + + const ConvexPolygon& Polygon() const { return mPolygon; } + UniqueId PolygonId() const { return mPolygonId; } + +private: + PlanesClip(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, ConvexPolygon& aPassPolygon, + bool& aSuccess); + + ConvexPolygon mPolygon; + UniqueId mPolygonId; +}; + +/** + * A 'stencil clip' etches its path into a bit plane of the stencil buffer. When + * a stencil bit clip is active, we configure NV_path_rendering to discard + * samples not in the clip path (samples where the clip bit is not set). When + * there are two stencil bit clips, each gets its own bit plane, but with three + * or more they start sharing a clip bit (by etching in just the intersection of + * paths). That way there are always at least 6 bits left for winding numbers. + */ +class StencilClip : public Clip { +public: + static TemporaryRef + Create(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, UniqueId aTransformId, + TemporaryRef aPath) + { + return new StencilClip(aDrawTarget, aPrevious, aTransform, aTransformId, aPath); + } + + void ApplyToStencilBuffer(); + + void RestoreStencilBuffer(); + +private: + StencilClip* GetLastClipBitOwner() + { + return mOwnClipBit ? this : mPrevious->GetLastClipBitOwner(); + } + + StencilClip(DrawTargetNVpr* aDrawTarget, TemporaryRef aPrevious, + const Matrix& aTransform, UniqueId aTransformId, + TemporaryRef aPath) + : Clip(aDrawTarget, aPrevious) + , mTransform(aTransform) + , mTransformId(aTransformId) + , mPath(aPath) + , mOwnClipBit(0) + {} + + const Matrix mTransform; + const UniqueId mTransformId; + RefPtr mPath; + GLubyte mOwnClipBit; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_CLIP_H_ */ diff --git a/libazure/nvpr/ConvexPolygon.cpp b/libazure/nvpr/ConvexPolygon.cpp new file mode 100644 index 0000000..33a83c3 --- /dev/null +++ b/libazure/nvpr/ConvexPolygon.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ConvexPolygon.h" + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +static inline Float +CrossProduct(const Point& aPt1, const Point& aPt2, const Point& aPt3) +{ + return (aPt2.x - aPt1.x) * (aPt3.y - aPt2.y) + - (aPt2.y - aPt1.y) * (aPt3.y - aPt2.x); +} + +static inline Point +Intersection(const Point& aPt1, const Line& aLine, const Point& aPt2) +{ + const Point v = aPt2 - aPt1; + const Float t = (aLine.C - aPt1.x * aLine.A - aPt1.y * aLine.B) + / (v.x * aLine.A + v.y * aLine.B); + return aPt1 + v * t; +} + + +ConvexPolygon::ConvexPolygon(const ConvexPolygon& aPolygon) + : mPoints(aPolygon.mPoints) +{ +} + +ConvexPolygon::ConvexPolygon(ConvexPolygon&& aPolygon) +{ + Swap(aPolygon); +} + +ConvexPolygon::ConvexPolygon(const Rect& aRect) +{ + if (!aRect.width || !aRect.height) { + return; + } + + mPoints.reserve(4); + mPoints.push_back(aRect.BottomRight()); + mPoints.push_back(aRect.TopRight()); + mPoints.push_back(aRect.TopLeft()); + mPoints.push_back(aRect.BottomLeft()); + + EnsureAntiClockwise(); +} + +ConvexPolygon::ConvexPolygon(const vector& aPoints) +{ + if (aPoints.size() < 3) { + return; + } + + mPoints.reserve(aPoints.size()); + + Float previousCross = 0; + + for (size_t i = 0; i < aPoints.size(); i++) { + Float cross = CrossProduct(aPoints[i ? i - 1 : aPoints.size() - 1], + aPoints[i], + aPoints[i + 1 < aPoints.size() ? i + 1 : 0]); + + if (!cross) { + // This point is irrelevant since it's between two colinear points. + continue; + } + + if (previousCross && (previousCross > 0) != (cross > 0)) { + // The polygon is not convex. + mPoints.clear(); + return; + } + + mPoints.push_back(aPoints[i]); + previousCross = cross; + } + + EnsureAntiClockwise(); +} + +ConvexPolygon& +ConvexPolygon::operator =(const ConvexPolygon& aPolygon) +{ + mPoints = aPolygon.mPoints; + mSides.clear(); + return *this; +} + +ConvexPolygon& +ConvexPolygon::operator =(ConvexPolygon&& aPolygon) +{ + Swap(aPolygon); + return *this; +} + +void +ConvexPolygon::EnsureAntiClockwise() +{ + if (mPoints.size() < 3) { + return; + } + + if (CrossProduct(mPoints[0], mPoints[1], mPoints[2]) < 0) { + // The points are clockwise. + reverse(mPoints.begin(), mPoints.end()); + } +} + +const Line* +ConvexPolygon::Sides() const +{ + if (mSides.empty() && mPoints.size() >= 3) { + for (size_t i = 1; i < mPoints.size(); i++) { + mSides.push_back(Line(mPoints[i - 1], mPoints[i])); + } + mSides.push_back(Line(mPoints.back(), mPoints.front())); + } + + return mSides.data(); +} + +void +ConvexPolygon::Transform(const Matrix& aTransform) +{ + if (aTransform.IsIdentity()) { + return; + } + + for (Point& point : mPoints) { + point = aTransform * point; + } + + mSides.clear(); + EnsureAntiClockwise(); +} + +void +ConvexPolygon::Intersect(const ConvexPolygon& aPolygon) +{ + if (mPoints.size() < 3) { + return; + } + + // This algorithm is O(N^2), but it's perfectly acceptable and maybe even + // faster for the size of polygons we expect to be dealing with. + for (Line& line : aPolygon.mSides) { + Clip(line); + } +} + +void +ConvexPolygon::Clip(const Line& aLine) +{ + if (mPoints.size() < 3) { + return; + } + + const Point firstPoint = mPoints.front(); + const bool firstInside = aLine.A * firstPoint.x + + aLine.B * firstPoint.y >= aLine.C; + + Point previousPoint = firstPoint; + bool previousInside = firstInside; + + size_t newSize = 0; + + // Start on the point at index 1 so we can update the points in-place. + for (size_t i = 1; i < mPoints.size(); i++) { + const Point point = mPoints[i]; + const bool inside = aLine.A * point.x + aLine.B * point.y >= aLine.C; + + if (previousInside != inside) { + MOZ_ASSERT(newSize <= i); + mPoints[newSize++] = Intersection(previousPoint, aLine, point); + } + + if (inside) { + MOZ_ASSERT(newSize <= i); + mPoints[newSize++] = point; + } + + previousPoint = point; + previousInside = inside; + } + + // Finally add the first point that we initially skipped. + if (previousInside != firstInside) { + MOZ_ASSERT(newSize <= mPoints.size()); + if (newSize == mPoints.size()) { + mPoints.resize(mPoints.size() + 1); + } + mPoints[newSize++] = Intersection(previousPoint, aLine, firstPoint); + } + + if (firstInside) { + MOZ_ASSERT(newSize <= mPoints.size()); + if (newSize == mPoints.size()) { + mPoints.resize(mPoints.size() + 1); + } + mPoints[newSize++] = firstPoint; + } + + mPoints.resize(newSize); + mSides.clear(); +} + +void +ConvexPolygon::Swap(ConvexPolygon& aPolygon) +{ + swap(mPoints, aPolygon.mPoints); + swap(mSides, aPolygon.mSides); +} + +} +} +} + diff --git a/libazure/nvpr/ConvexPolygon.h b/libazure/nvpr/ConvexPolygon.h new file mode 100644 index 0000000..bfd3b20 --- /dev/null +++ b/libazure/nvpr/ConvexPolygon.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_CONVEXPOLYGON_H_ +#define MOZILLA_GFX_NVPR_CONVEXPOLYGON_H_ + +#include "Types.h" +#include "Line.h" +#include "Matrix.h" +#include "Point.h" +#include "Rect.h" +#include + +namespace mozilla { +namespace gfx { +namespace nvpr { + +class ConvexPolygon { +public: + ConvexPolygon() {} + ConvexPolygon(const ConvexPolygon& aPolygon); + ConvexPolygon(ConvexPolygon&& aPolygon); + ConvexPolygon(const Rect& aRect); + ConvexPolygon(const std::vector& aPoints); + + ConvexPolygon& operator =(const ConvexPolygon& aPolygon); + ConvexPolygon& operator =(ConvexPolygon&& aPolygon); + + bool IsEmpty() const { return mPoints.empty(); } + size_t NumSides() const { return mPoints.size(); } + const Point* Points() const { return mPoints.data(); } + const Line* Sides() const; + + void Transform(const Matrix& aTransform); + void Intersect(const ConvexPolygon& aPolygon); + void Clip(const Line& aLine); + + void Swap(ConvexPolygon& aPolygon); + +private: + void EnsureAntiClockwise(); + + std::vector mPoints; + mutable std::vector mSides; +}; + +} +} +} + +namespace std +{ + template<> + inline void swap(mozilla::gfx::nvpr::ConvexPolygon& aPolygon1, + mozilla::gfx::nvpr::ConvexPolygon& aPolygon2) + { + aPolygon1.Swap(aPolygon2); + } +} + +#endif /* MOZILLA_GFX_NVPR_CONVEXPOLYGON_H_ */ diff --git a/libazure/nvpr/GL.cpp b/libazure/nvpr/GL.cpp new file mode 100644 index 0000000..7fc8891 --- /dev/null +++ b/libazure/nvpr/GL.cpp @@ -0,0 +1,805 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GL.h" +#include "ConvexPolygon.h" +#include "Line.h" +#include "Logging.h" +#include +#include +#include +#include + +using namespace std; + +#ifdef WIN32 +#define STDCALL __stdcall +#else +#define STDCALL +#endif + +namespace mozilla { +namespace gfx { + +static void STDCALL GLDebugCallback(GLenum aSource, GLenum aType, GLuint aId, + GLenum aSeverity, GLsizei aLength, + const GLchar* aMessage, + const void* aUserParam) +{ + if (aSeverity == GL_DEBUG_SEVERITY_LOW) { + return; + } + + gfxWarning() << "OpenGL Debug Callback:"; + gfxWarning() << " Source: 0x" << hex << aSource; + gfxWarning() << " Type: 0x" << hex << aType; + gfxWarning() << " Id: " << aId; + gfxWarning() << " Severity: 0x" << hex << aSeverity; + gfxWarning() << " Message: " << aMessage; + gfxWarning() << ""; +} + +static void RectToClientArray(GLfloat* aClientArray, + const Point& aPosition, const Size& aSize) +{ + aClientArray[0] = aPosition.x; + aClientArray[1] = aPosition.y; + aClientArray[2] = aPosition.x + aSize.width; + aClientArray[3] = aPosition.y; + aClientArray[4] = aPosition.x + aSize.width; + aClientArray[5] = aPosition.y + aSize.height; + aClientArray[6] = aPosition.x; + aClientArray[7] = aPosition.y + aSize.height; +} + + +namespace nvpr { + +GL* gl = nullptr; + +GL::GL() + : mIsValid(false) + , mNextUniqueId(1) + , mReadFramebuffer(0) + , mDrawFramebuffer(0) + , mTransformId(0) + , mColorWriteMask(WRITE_COLOR_AND_ALPHA) + , mNumClipPlanes(0) + , mClipPolygonId(0) + , mColor(1, 1, 1, 1) + , mScissorTestEnabled(false) + , mStencilTestEnabled(false) + , mStencilTest(ALWAYS_PASS) + , mStencilComparand(0) + , mStencilTestMask(~0) + , mStencilOp(LEAVE_UNCHANGED) + , mStencilWriteMask(~0) + , mPathStencilFuncBits(0) + , mBlendMode(CompositionOp::OP_SOURCE) + , mMultisampleEnabled(true) + , mShaderProgram(0) +{ + memset(mTexGenComponents, 0, sizeof(mTexGenComponents)); + memset(mTexGenTransformIds, 0, sizeof(mTexGenTransformIds)); + memset(mTexGenCoefficients, 0, sizeof(mTexGenCoefficients)); + memset(mActiveTextureTargets, 0, sizeof(mActiveTextureTargets)); + memset(mBoundTextures, 0, sizeof(mBoundTextures)); + memset(mTexCoordArraysEnabled, 0, sizeof(mTexCoordArraysEnabled)); +} + +void GL::Initialize() +{ + MOZ_ASSERT(IsCurrent()); + + GLint majorVersion; + GetIntegerv(GL_MAJOR_VERSION, &majorVersion); + if (majorVersion < 4) { + return; + } + + if (majorVersion == 4) { + GLint minorVersion; + GetIntegerv(GL_MINOR_VERSION, &minorVersion); + if (minorVersion < 3) { + return; + } + } + + memset(mSupportedExtensions, 0, sizeof(mSupportedExtensions)); + stringstream extensions(reinterpret_cast(GetString(GL_EXTENSIONS))); + istream_iterator iter(extensions); + istream_iterator end; + + for (; iter != end; iter++) { + const string& extension = *iter; + + if (*iter == "GL_EXT_texture_filter_anisotropic") { + mSupportedExtensions[EXT_texture_filter_anisotropic] = true; + continue; + } + + if (*iter == "GL_EXT_direct_state_access") { + mSupportedExtensions[EXT_direct_state_access] = true; + continue; + } + + if (*iter == "GL_ARB_texture_storage") { + mSupportedExtensions[ARB_texture_storage] = true; + continue; + } + + if (*iter == "GL_NV_path_rendering") { + mSupportedExtensions[NV_path_rendering] = true; + continue; + } + + if (*iter == "GL_NV_blend_equation_advanced") { + mSupportedExtensions[NV_blend_equation_advanced] = true; + continue; + } + + if (*iter == "GL_NV_blend_equation_advanced_coherent") { + mSupportedExtensions[NV_blend_equation_advanced_coherent] = true; + continue; + } + } + + if (!HasExtension(GL::EXT_direct_state_access) + || !HasExtension(GL::ARB_texture_storage) + || !HasExtension(GL::NV_path_rendering) + || !HasExtension(GL::NV_blend_equation_advanced)) { + return; + } + + GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); + GetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + GetIntegerv(GL_MAX_CLIP_PLANES, &mMaxClipPlanes); + + if (HasExtension(EXT_texture_filter_anisotropic)) { + GetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mMaxAnisotropy); + } else { + mMaxAnisotropy = 1; + } + + GenFramebuffers(1, &mTextureFramebuffer1D); + GenFramebuffers(1, &mTextureFramebuffer2D); + + EnableClientState(GL_VERTEX_ARRAY); + + Enable(GL_BLEND); + + DebugMessageCallback(GLDebugCallback, nullptr); + DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); + Enable(GL_DEBUG_OUTPUT); + + mIsValid = true; +} + +GL::~GL() +{ + // No need to delete the GL objects. They automatically went away when the + // context was destroyed. +} + +void +GL::SetSize(const IntSize& aSize) +{ + MOZ_ASSERT(IsCurrent()); + + if (mSize == aSize) { + return; + } + + Viewport(0, 0, aSize.width, aSize.height); + MatrixLoadIdentityEXT(GL_PROJECTION); + MatrixOrthoEXT(GL_PROJECTION, 0, aSize.width, 0, aSize.height, -1, 1); + mSize = aSize; +} + +void +GL::SetFramebuffer(GLenum aFramebufferTarget, GLuint aFramebuffer) +{ + MOZ_ASSERT(IsCurrent()); + + bool clearTextureFramebuffer1D; + bool clearTextureFramebuffer2D; + + switch (aFramebufferTarget) { + case GL_FRAMEBUFFER: + if (mReadFramebuffer == aFramebuffer && mDrawFramebuffer == aFramebuffer) { + return; + } + + BindFramebuffer(GL_FRAMEBUFFER, aFramebuffer); + + clearTextureFramebuffer1D = (aFramebuffer != mTextureFramebuffer1D) + && (mDrawFramebuffer == mTextureFramebuffer1D + || mReadFramebuffer == mTextureFramebuffer1D); + clearTextureFramebuffer2D = (aFramebuffer != mTextureFramebuffer2D) + && (mDrawFramebuffer == mTextureFramebuffer2D + || mReadFramebuffer == mTextureFramebuffer2D); + mReadFramebuffer = mDrawFramebuffer = aFramebuffer; + break; + + case GL_READ_FRAMEBUFFER: + if (mReadFramebuffer == aFramebuffer) { + return; + } + + BindFramebuffer(GL_READ_FRAMEBUFFER, aFramebuffer); + + clearTextureFramebuffer1D = (mReadFramebuffer == mTextureFramebuffer1D); + clearTextureFramebuffer2D = (mReadFramebuffer == mTextureFramebuffer2D); + mReadFramebuffer = aFramebuffer; + break; + + case GL_DRAW_FRAMEBUFFER: + if (mDrawFramebuffer == aFramebuffer) { + return; + } + + BindFramebuffer(GL_DRAW_FRAMEBUFFER, aFramebuffer); + + clearTextureFramebuffer1D = (mDrawFramebuffer == mTextureFramebuffer1D); + clearTextureFramebuffer2D = (mDrawFramebuffer == mTextureFramebuffer2D); + mDrawFramebuffer = aFramebuffer; + break; + + default: + MOZ_ASSERT(!"Invalid framebuffer target."); + break; + } + + if (clearTextureFramebuffer1D) { + NamedFramebufferTexture1DEXT(mTextureFramebuffer1D, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_1D, 0, 0); + } + + if (clearTextureFramebuffer2D) { + NamedFramebufferTexture2DEXT(mTextureFramebuffer2D, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + } +} + +void +GL::SetFramebufferToTexture(GLenum aFramebufferTarget, + GLenum aTextureTarget, GLuint aTextureId) +{ + MOZ_ASSERT(IsCurrent()); + + switch (aTextureTarget) { + case GL_TEXTURE_1D: + NamedFramebufferTexture1DEXT(mTextureFramebuffer1D, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_1D, aTextureId, 0); + SetFramebuffer(aFramebufferTarget, mTextureFramebuffer1D); + break; + + case GL_TEXTURE_2D: + NamedFramebufferTexture2DEXT(mTextureFramebuffer2D, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, aTextureId, 0); + SetFramebuffer(aFramebufferTarget, mTextureFramebuffer2D); + break; + + default: + MOZ_ASSERT(!"Invalid texture target."); + break; + } +} + +void +GL::SetTransform(const Matrix& aTransform, UniqueId aTransformId) +{ + MOZ_ASSERT(IsCurrent()); + + if (mTransformId == aTransformId) { + return; + } + + const GLfloat matrix[] = { + aTransform._11, aTransform._12, 0, 0, + aTransform._21, aTransform._22, 0, 0, + 0, 0, 1, 0, + aTransform._31, aTransform._32, 0, 1 + }; + + MatrixLoadfEXT(GL_MODELVIEW, matrix); + + mTransformId = aTransformId; +} + +void +GL::ScaleTransform(GLfloat x, GLfloat y) +{ + MOZ_ASSERT(IsCurrent()); + + MatrixScalefEXT(GL_MODELVIEW, x, y, 1); + mTransformId = GetUniqueId(); +} + +void +GL::SetTransformToIdentity() +{ + MOZ_ASSERT(IsCurrent()); + + if (mTransformId == 0) { + return; + } + + MatrixLoadIdentityEXT(GL_MODELVIEW); + mTransformId = 0; +} + +void +GL::SetColorWriteMask(ColorWriteMask aColorWriteMask) +{ + MOZ_ASSERT(IsCurrent()); + + if (mColorWriteMask == aColorWriteMask) { + return; + } + + ColorMask(aColorWriteMask & WRITE_RED, aColorWriteMask & WRITE_GREEN, + aColorWriteMask & WRITE_BLUE, aColorWriteMask & WRITE_ALPHA); + mColorWriteMask = aColorWriteMask; +} + +void +GL::SetClearColor(const Color& aColor) +{ + MOZ_ASSERT(IsCurrent()); + + if (!memcmp(&mClearColor, &aColor, sizeof(Color))) { + return; + } + + if (aColor.a == 1) { + ClearColor(aColor.r, aColor.g, aColor.b, 1); + } else { + const float a = aColor.a; + ClearColor(a * aColor.r, a * aColor.g, a * aColor.b, a); + } + + mClearColor = aColor; +} + +void +GL::SetClearColor(const Color& aColor, GLfloat aAlpha) +{ + SetClearColor(Color(aColor.r, aColor.g, aColor.b, aAlpha * aColor.a)); +} + +void +GL::EnableScissorTest(const IntRect& aScissorRect) +{ + MOZ_ASSERT(IsCurrent()); + + if (!mScissorTestEnabled) { + Enable(GL_SCISSOR_TEST); + mScissorTestEnabled = true; + } + + if (!mScissorRect.IsEqualInterior(aScissorRect)) { + Scissor(aScissorRect.x, aScissorRect.y, aScissorRect.width, aScissorRect.height); + mScissorRect = aScissorRect; + } +} + +void +GL::DisableScissorTest() +{ + MOZ_ASSERT(IsCurrent()); + + if (!mScissorTestEnabled) { + return; + } + + Disable(GL_SCISSOR_TEST); + mScissorTestEnabled = false; +} + +void +GL::EnableClipPlanes(const ConvexPolygon& aPolygon, UniqueId aPolygonId) +{ + MOZ_ASSERT(IsCurrent()); + MOZ_ASSERT(aPolygon.NumSides() <= mMaxClipPlanes); + + if (mClipPolygonId == aPolygonId) { + return; + } + + if (aPolygon.IsEmpty()) { + if (!mNumClipPlanes) { + Enable(GL_CLIP_PLANE0); + } else { + for (size_t i = 1; i < mNumClipPlanes; i++) { + Disable(GL_CLIP_PLANE0 + i); + } + } + + mNumClipPlanes = 1; + + // We specify a single clip plane equation that fails for all vertices. + const double planeEquation[] = {0, 0, 0, -1}; + ClipPlane(GL_CLIP_PLANE0, planeEquation); + + mClipPolygonId = aPolygonId; + + return; + } + + for (size_t i = mNumClipPlanes; i < aPolygon.NumSides(); i++) { + Enable(GL_CLIP_PLANE0 + i); + } + for (size_t i = aPolygon.NumSides(); i < mNumClipPlanes; i++) { + Disable(GL_CLIP_PLANE0 + i); + } + + mNumClipPlanes = aPolygon.NumSides(); + + for (size_t i = 0; i < aPolygon.NumSides(); i++) { + const Line& line = aPolygon.Sides()[i]; + const double planeEquation[] = {line.A, line.B, 0, -line.C}; + ClipPlane(GL_CLIP_PLANE0 + i, planeEquation); + } + + mClipPolygonId = aPolygonId; +} + +void +GL::DisableClipPlanes() +{ + MOZ_ASSERT(IsCurrent()); + + for (size_t i = 0; i < mNumClipPlanes; i++) { + Disable(GL_CLIP_PLANE0 + i); + } + + mNumClipPlanes = 0; + mClipPolygonId = 0; +} + +void +GL::EnableStencilTest(UnaryStencilTest aTest, GLuint aTestMask, + StencilOperation aOp, GLuint aWriteMask) +{ + switch (aTest) { + case PASS_IF_NOT_ZERO: + EnableStencilTest(PASS_IF_NOT_EQUAL, 0, aTestMask, aOp, aWriteMask); + return; + case PASS_IF_ALL_SET: + EnableStencilTest(PASS_IF_EQUAL, aTestMask, aTestMask, aOp, aWriteMask); + return; + } +} + +void +GL::EnableStencilTest(BinaryStencilTest aTest, + GLint aComparand, GLuint aTestMask, + StencilOperation aOp, GLuint aWriteMask) +{ + MOZ_ASSERT(IsCurrent()); + + if (!mStencilTestEnabled) { + Enable(GL_STENCIL_TEST); + mStencilTestEnabled = true; + } + + if (mStencilTest != aTest || mStencilComparand != aComparand + || mStencilTestMask != aTestMask) { + GLenum func; + switch (aTest) { + default: + MOZ_ASSERT(!"Invalid stencil test"); + case ALWAYS_PASS: + func = GL_ALWAYS; + break; + case PASS_IF_EQUAL: + func = GL_EQUAL; + break; + case PASS_IF_NOT_EQUAL: + func = GL_NOTEQUAL; + break; + } + + StencilFunc(func, aComparand, aTestMask); + + mStencilTest = aTest; + mStencilComparand = aComparand; + mStencilTestMask = aTestMask; + } + + if (mStencilOp != aOp) { + switch (aOp) { + case LEAVE_UNCHANGED: + StencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + break; + case CLEAR_PASSING_VALUES: + StencilOp(GL_KEEP, GL_ZERO, GL_ZERO); + break; + case REPLACE_PASSING_WITH_COMPARAND: + StencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + break; + case REPLACE_PASSING_CLEAR_FAILING: + StencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); + break; + } + + mStencilOp = aOp; + } + + if (mStencilWriteMask != aWriteMask) { + StencilMask(aWriteMask); + mStencilWriteMask = aWriteMask; + } +} + +void +GL::DisableStencilTest() +{ + MOZ_ASSERT(IsCurrent()); + + if (!mStencilTestEnabled) { + return; + } + + Disable(GL_STENCIL_TEST); + mStencilTestEnabled = false; +} + +void +GL::ConfigurePathStencilTest(GLubyte aClipBits) +{ + MOZ_ASSERT(IsCurrent()); + + if (mPathStencilFuncBits == aClipBits) { + return; + } + + if (!aClipBits) { + PathStencilFuncNV(GL_ALWAYS, 0, 0); + } else { + PathStencilFuncNV(GL_EQUAL, aClipBits, aClipBits); + } + + mPathStencilFuncBits = aClipBits; +} + +void +GL::SetShaderProgram(GLuint aShaderProgram) +{ + MOZ_ASSERT(IsCurrent()); + + if (mShaderProgram == aShaderProgram) { + return; + } + + UseProgram(aShaderProgram); + mShaderProgram = aShaderProgram; +} + +void +GL::DeleteShaderProgram(GLuint aShaderProgram) +{ + MOZ_ASSERT(IsCurrent()); + + if (mShaderProgram == aShaderProgram) { + SetShaderProgram(0); + } + + DeleteProgram(aShaderProgram); +} + +void +GL::SetBlendMode(CompositionOp aBlendMode) +{ + if (mBlendMode == aBlendMode) { + return; + } + + switch (aBlendMode) { + default: MOZ_ASSERT(!"Invalid blend mode"); + case CompositionOp::OP_OVER: BlendEquation(GL_SRC_OVER_NV); break; + case CompositionOp::OP_ADD: BlendEquation(GL_PLUS_NV); break; + case CompositionOp::OP_ATOP: BlendEquation(GL_SRC_ATOP_NV); break; + case CompositionOp::OP_OUT: BlendEquation(GL_SRC_OUT_NV); break; + case CompositionOp::OP_IN: BlendEquation(GL_SRC_IN_NV); break; + case CompositionOp::OP_SOURCE: BlendEquation(GL_SRC_NV); break; + case CompositionOp::OP_DEST_IN: BlendEquation(GL_DST_IN_NV); break; + case CompositionOp::OP_DEST_OUT: BlendEquation(GL_DST_OUT_NV); break; + case CompositionOp::OP_DEST_OVER: BlendEquation(GL_DST_OVER_NV); break; + case CompositionOp::OP_DEST_ATOP: BlendEquation(GL_DST_ATOP_NV); break; + case CompositionOp::OP_XOR: BlendEquation(GL_XOR); break; + case CompositionOp::OP_MULTIPLY: BlendEquation(GL_MULTIPLY_NV); break; + case CompositionOp::OP_SCREEN: BlendEquation(GL_SCREEN_NV); break; + case CompositionOp::OP_OVERLAY: BlendEquation(GL_OVERLAY_NV); break; + case CompositionOp::OP_DARKEN: BlendEquation(GL_DARKEN_NV); break; + case CompositionOp::OP_LIGHTEN: BlendEquation(GL_LIGHTEN_NV); break; + case CompositionOp::OP_COLOR_DODGE: BlendEquation(GL_COLORDODGE_NV); break; + case CompositionOp::OP_COLOR_BURN: BlendEquation(GL_COLORBURN_NV); break; + case CompositionOp::OP_HARD_LIGHT: BlendEquation(GL_HARDLIGHT_NV); break; + case CompositionOp::OP_SOFT_LIGHT: BlendEquation(GL_SOFTLIGHT_NV); break; + case CompositionOp::OP_DIFFERENCE: BlendEquation(GL_DIFFERENCE_NV); break; + case CompositionOp::OP_EXCLUSION: BlendEquation(GL_EXCLUSION_NV); break; + case CompositionOp::OP_HUE: BlendEquation(GL_HSL_HUE_NV); break; + case CompositionOp::OP_SATURATION: BlendEquation(GL_HSL_SATURATION_NV); break; + case CompositionOp::OP_COLOR: BlendEquation(GL_HSL_COLOR_NV); break; + case CompositionOp::OP_LUMINOSITY: BlendEquation(GL_HSL_LUMINOSITY_NV); break; + } + + mBlendMode = aBlendMode; +} + +void +GL::BlendBarrier() +{ + if (HasExtension(NV_blend_equation_advanced_coherent)) { + return; + } + + BlendBarrierNV(); +} + +void +GL::EnableMultisample() +{ + if (mMultisampleEnabled) { + return; + } + + Enable(GL_MULTISAMPLE); + mMultisampleEnabled = true; +} + +void +GL::DisableMultisample() +{ + if (!mMultisampleEnabled) { + return; + } + + Disable(GL_MULTISAMPLE); + mMultisampleEnabled = false; +} + +void +GL::SetTexture(TextureUnit aTextureUnit, GLenum aTextureTarget, + GLuint aTextureId) +{ + MOZ_ASSERT(IsCurrent()); + + if (mActiveTextureTargets[aTextureUnit] == aTextureTarget + && mBoundTextures[aTextureUnit] == aTextureId) { + return; + } + + if (mActiveTextureTargets[aTextureUnit] + && mActiveTextureTargets[aTextureUnit] != aTextureTarget) { + BindMultiTextureEXT(GL_TEXTURE0 + aTextureUnit, + mActiveTextureTargets[aTextureUnit], 0); + } + + BindMultiTextureEXT(GL_TEXTURE0 + aTextureUnit, aTextureTarget, aTextureId); + mActiveTextureTargets[aTextureUnit] = aTextureTarget; + mBoundTextures[aTextureUnit] = aTextureId; +} + +void +GL::DeleteTexture(GLuint aTextureId) +{ + MOZ_ASSERT(IsCurrent()); + + DeleteTextures(1, &aTextureId); + + for (size_t i = 0; i < TEXTURE_UNIT_COUNT; i++) { + if (mBoundTextures[i] == aTextureId) { + mActiveTextureTargets[i] = 0; + mBoundTextures[i] = 0; + } + } +} + +void +GL::SetTexGen(TextureUnit aTextureUnit, TexGenComponents aComponents, + const GLfloat* aCoefficients) +{ + MOZ_ASSERT(IsCurrent()); + + if (mTexGenComponents[aTextureUnit] == aComponents) { + if (!aComponents) { + return; + } + if (mTexGenTransformIds[aTextureUnit] == mTransformId + && !memcmp(mTexGenCoefficients[aTextureUnit], aCoefficients, + aComponents * 3 * sizeof(GLfloat))) { + return; + } + } + + for (int i = mTexGenComponents[aTextureUnit]; i < aComponents; i++) { + Enablei(GL_TEXTURE_GEN_S + i, aTextureUnit); + } + for (int i = aComponents; i < mTexGenComponents[aTextureUnit]; i++) { + Disablei(GL_TEXTURE_GEN_S + i, aTextureUnit); + } + for (int i = 0; i < aComponents; i++) { + const GLfloat plane[] = {aCoefficients[3 * i], aCoefficients[3 * i + 1], + 0, aCoefficients[3 * i + 2]}; + MultiTexGenfvEXT(GL_TEXTURE0 + aTextureUnit, GL_S + i, GL_EYE_PLANE, plane); + } + + PathTexGenNV(GL_TEXTURE0 + aTextureUnit, GL_EYE_LINEAR, + aComponents, aCoefficients); + + mTexGenComponents[aTextureUnit] = aComponents; + mTexGenTransformIds[aTextureUnit] = mTransformId; + memcpy(mTexGenCoefficients[aTextureUnit], aCoefficients, + aComponents * 3 * sizeof(GLfloat)); +} + +void +GL::EnableTexCoordArray(TextureUnit aTextureUnit, const GLfloat* aTexCoords) +{ + if (!mTexCoordArraysEnabled[aTextureUnit]) { + EnableClientStateiEXT(GL_TEXTURE_COORD_ARRAY, aTextureUnit); + mTexCoordArraysEnabled[aTextureUnit] = true; + } + + MultiTexCoordPointerEXT(GL_TEXTURE0 + aTextureUnit, 2, GL_FLOAT, 0, aTexCoords); +} + +void +GL::EnableTexCoordArrayToRect(TextureUnit aTextureUnit, + const Point& aPosition, const Size& aSize) +{ + RectToClientArray(mTexCoordRectArray[aTextureUnit], aPosition, aSize); + EnableTexCoordArray(aTextureUnit, mTexCoordRectArray[aTextureUnit]); +} + +void +GL::EnableTexCoordArrayToRect(TextureUnit aTextureUnit, const Rect& aRect) +{ + EnableTexCoordArrayToRect(aTextureUnit, aRect.TopLeft(), aRect.Size()); +} + +void +GL::EnableTexCoordArrayToUnitRect(TextureUnit aTextureUnit) +{ + EnableTexCoordArrayToRect(aTextureUnit, Rect(0, 0, 1, 1)); +} + +void +GL::DisableTexCoordArray(TextureUnit aTextureUnit) +{ + if (!mTexCoordArraysEnabled[aTextureUnit]) { + return; + } + + DisableClientStateiEXT(GL_TEXTURE_COORD_ARRAY, aTextureUnit); + mTexCoordArraysEnabled[aTextureUnit] = false; +} + +void +GL::SetVertexArray(const GLfloat* aVertices) +{ + VertexPointer(2, GL_FLOAT, 0, aVertices); +} + +void +GL::SetVertexArrayToRect(const Point& aPosition, const Size& aSize) +{ + RectToClientArray(mVertexRectArray, aPosition, aSize); + SetVertexArray(mVertexRectArray); +} + +void +GL::SetVertexArrayToRect(const Rect& aRect) +{ + SetVertexArrayToRect(aRect.TopLeft(), aRect.Size()); +} + +} +} +} diff --git a/libazure/nvpr/GL.h b/libazure/nvpr/GL.h new file mode 100644 index 0000000..2f52342 --- /dev/null +++ b/libazure/nvpr/GL.h @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_GL_H_ +#define MOZILLA_GFX_NVPR_GL_H_ + +#include "2D.h" +#include "GLDefs.h" +#include +#include + +namespace mozilla { +namespace gfx { +namespace nvpr { + +typedef uint64_t UniqueId; + +class ConvexPolygon; + +struct UserData { + class Object { public: virtual ~Object() {} }; + + std::unique_ptr mPathCache; + std::unique_ptr mColorRampData; + std::unique_ptr mFonts; + std::unique_ptr mPaintShaders; + std::unique_ptr mShadowShaders; +}; + +class GL +{ +public: + bool IsValid() const { return mIsValid; } + + bool IsCurrent() const; + void MakeCurrent() const; + + bool BlitTextureToForeignTexture(const IntSize& aSize, GLuint aSourceTextureId, + void* aForeignContext, GLuint aForeignTextureId); + + enum Extension { + EXT_texture_filter_anisotropic, + EXT_direct_state_access, + ARB_texture_storage, + NV_path_rendering, + NV_blend_equation_advanced, + NV_blend_equation_advanced_coherent, + EXTENSION_COUNT + }; + bool HasExtension(Extension aExtension) const + { + return mSupportedExtensions[aExtension]; + } + + GLint MaxRenderbufferSize() const { return mMaxRenderbufferSize; } + GLint MaxTextureSize() const { return mMaxTextureSize; } + GLint MaxClipPlanes() const { return mMaxClipPlanes; } + GLint MaxAnisotropy() const { return mMaxAnisotropy; } + + template T& + GetUserObject(std::unique_ptr UserData::*aObject) + { + std::unique_ptr& object = mUserData.*aObject; + if (!object) { + object.reset(new T()); + } + return static_cast(*object.get()); + } + + UniqueId GetUniqueId() { return mNextUniqueId++; } + UniqueId TransformId() const { return mTransformId; } + UniqueId ClipPolygonId() const { return mClipPolygonId; } + + void SetSize(const IntSize& aSize); + + void SetFramebuffer(GLenum aFramebufferTarget, GLuint aFramebuffer); + void SetFramebufferToTexture(GLenum aFramebufferTarget, GLenum aTextureTarget, + GLuint aTextureId); + + void SetTransform(const Matrix& aTransform, UniqueId aTransformId); + void ScaleTransform(GLfloat x, GLfloat y); + void SetTransformToIdentity(); + + enum ColorWriteMaskBit { WRITE_NONE = 0x0, WRITE_RED = 0x1, WRITE_GREEN = 0x2, + WRITE_BLUE = 0x4, WRITE_ALPHA = 0x8, + WRITE_COLOR_AND_ALPHA = 0xf }; + typedef unsigned ColorWriteMask; + void SetColorWriteMask(ColorWriteMask aColorWriteMask); + + void SetClearColor(const Color& aColor); + void SetClearColor(const Color& aColor, GLfloat aAlpha); + + void EnableScissorTest(const IntRect& aScissorRect); + void DisableScissorTest(); + + void EnableClipPlanes(const ConvexPolygon& aPolygon, UniqueId aPolygonId); + void DisableClipPlanes(); + + enum UnaryStencilTest { PASS_IF_NOT_ZERO, PASS_IF_ALL_SET }; + enum BinaryStencilTest { ALWAYS_PASS, PASS_IF_EQUAL, PASS_IF_NOT_EQUAL }; + enum StencilOperation { LEAVE_UNCHANGED, CLEAR_PASSING_VALUES, + REPLACE_PASSING_WITH_COMPARAND, + REPLACE_PASSING_CLEAR_FAILING }; + void EnableStencilTest(UnaryStencilTest aTest, GLuint aTestMask, + StencilOperation aOp, GLuint aWriteMask = ~0); + void EnableStencilTest(BinaryStencilTest aTest, + GLint aComparand, GLuint aTestMask, + StencilOperation aOp, GLuint aWriteMask = ~0); + void DisableStencilTest(); + + void ConfigurePathStencilTest(GLubyte aClipBits); + + void SetShaderProgram(GLuint aShaderProgram); + void DeleteShaderProgram(GLuint aShaderProgram); + + void SetBlendMode(CompositionOp aBlendMode); + void BlendBarrier(); + + void EnableMultisample(); + void DisableMultisample(); + + enum TextureUnit { UNIT_0, UNIT_1, TEXTURE_UNIT_COUNT }; + void SetTexture(TextureUnit aTextureUnit, GLenum aTextureTarget, + GLuint aTextureId); + void DeleteTexture(GLuint aTextureId); + + enum TexGenComponents { TEXGEN_NONE, TEXGEN_S, TEXGEN_ST }; + void SetTexGen(TextureUnit aTextureUnit, TexGenComponents aComponents, + const GLfloat* aCoefficients = nullptr); + + void EnableTexCoordArray(TextureUnit aTextureUnit, const GLfloat* aTexCoords); + void EnableTexCoordArrayToRect(TextureUnit aTextureUnit, + const Point& aPosition, const Size& aSize); + void EnableTexCoordArrayToRect(TextureUnit aTextureUnit, const Rect& aRect); + void EnableTexCoordArrayToUnitRect(TextureUnit aTextureUnit); + void DisableTexCoordArray(TextureUnit aTextureUnit); + + void SetVertexArray(const GLfloat* aVertices); + void SetVertexArrayToRect(const Point& aPosition, const Size& aSize); + void SetVertexArrayToRect(const Rect& aRect); + +protected: + GL(); + virtual ~GL(); + + void Initialize(); + +private: + bool mIsValid; + bool mSupportedExtensions[EXTENSION_COUNT]; + GLint mMaxRenderbufferSize; + GLint mMaxTextureSize; + GLint mMaxClipPlanes; + GLint mMaxAnisotropy; + UserData mUserData; + UniqueId mNextUniqueId; + GLuint mTextureFramebuffer1D; + GLuint mTextureFramebuffer2D; + GLfloat mTexCoordRectArray[TEXTURE_UNIT_COUNT][8]; + GLfloat mVertexRectArray[8]; + + // GL state. + IntSize mSize; + GLuint mReadFramebuffer; + GLuint mDrawFramebuffer; + UniqueId mTransformId; + size_t mNumClipPlanes; + UniqueId mClipPolygonId; + ColorWriteMask mColorWriteMask; + Color mClearColor; + Color mColor; + bool mScissorTestEnabled; + IntRect mScissorRect; + bool mStencilTestEnabled; + BinaryStencilTest mStencilTest; + GLint mStencilComparand; + GLuint mStencilTestMask; + StencilOperation mStencilOp; + GLuint mStencilWriteMask; + GLubyte mPathStencilFuncBits; + CompositionOp mBlendMode; + bool mMultisampleEnabled; + GLuint mShaderProgram; + unsigned mTexGenComponents[TEXTURE_UNIT_COUNT]; + UniqueId mTexGenTransformIds[TEXTURE_UNIT_COUNT]; + GLfloat mTexGenCoefficients[TEXTURE_UNIT_COUNT][6]; + GLenum mActiveTextureTargets[TEXTURE_UNIT_COUNT]; + GLenum mBoundTextures[TEXTURE_UNIT_COUNT]; + bool mTexCoordArraysEnabled[TEXTURE_UNIT_COUNT]; + +#define FOR_ALL_PUBLIC_GL_ENTRY_POINTS(MACRO) \ + MACRO(GenTextures) \ + MACRO(CreateShader) \ + MACRO(ShaderSource) \ + MACRO(CompileShader) \ + MACRO(GetIntegerv) \ + MACRO(GetShaderiv) \ + MACRO(GetShaderInfoLog) \ + MACRO(GetProgramiv) \ + MACRO(GetProgramInfoLog) \ + MACRO(CreateProgram) \ + MACRO(AttachShader) \ + MACRO(LinkProgram) \ + MACRO(DeleteShader) \ + MACRO(GetUniformLocation) \ + MACRO(ProgramUniform1iEXT) \ + MACRO(ProgramUniform1fEXT) \ + MACRO(ProgramUniform1fvEXT) \ + MACRO(ProgramUniform2fvEXT) \ + MACRO(ProgramUniform4fvEXT) \ + MACRO(GenRenderbuffers) \ + MACRO(DeleteRenderbuffers) \ + MACRO(Clear) \ + MACRO(DrawArrays) \ + MACRO(BlitFramebuffer) \ + MACRO(Rectf) \ + MACRO(GenFramebuffers) \ + MACRO(DeleteFramebuffers) \ + MACRO(PixelStorei) \ + MACRO(ClipPlane) \ + MACRO(GetString) \ + MACRO(Flush) \ + MACRO(Finish) \ + MACRO(TextureStorage1DEXT) \ + MACRO(TextureSubImage1DEXT) \ + MACRO(GenerateTextureMipmapEXT) \ + MACRO(TextureParameteriEXT) \ + MACRO(NamedRenderbufferStorageMultisampleEXT) \ + MACRO(NamedFramebufferRenderbufferEXT) \ + MACRO(TextureImage2DEXT) \ + MACRO(TextureSubImage2DEXT) \ + MACRO(GetTextureImageEXT) \ + MACRO(GenPathsNV) \ + MACRO(PathCommandsNV) \ + MACRO(PathGlyphRangeNV) \ + MACRO(GetPathMetricRangeNV) \ + MACRO(StencilStrokePathNV) \ + MACRO(CoverStrokePathNV) \ + MACRO(StencilFillPathInstancedNV) \ + MACRO(CoverFillPathInstancedNV) \ + MACRO(StencilFillPathNV) \ + MACRO(CoverFillPathNV) \ + MACRO(DeletePathsNV) \ + MACRO(PathParameterfNV) \ + MACRO(PathParameteriNV) \ + MACRO(PathDashArrayNV) \ + MACRO(IsPointInFillPathNV) \ + MACRO(IsPointInStrokePathNV) \ + MACRO(GetPathParameterfvNV) \ + MACRO(TransformPathNV) \ + MACRO(GetPathParameterivNV) \ + MACRO(GetPathCommandsNV) \ + MACRO(GetPathCoordsNV) + +#define FOR_ALL_PRIVATE_GL_ENTRY_POINTS(MACRO) \ + MACRO(DeleteTextures) \ + MACRO(DeleteProgram) \ + MACRO(EnableClientState) \ + MACRO(DebugMessageCallback) \ + MACRO(DebugMessageControl) \ + MACRO(Viewport) \ + MACRO(BindFramebuffer) \ + MACRO(ColorMask) \ + MACRO(Scissor) \ + MACRO(StencilFunc) \ + MACRO(StencilOp) \ + MACRO(StencilMask) \ + MACRO(ClearColor) \ + MACRO(UseProgram) \ + MACRO(BlendEquation) \ + MACRO(Enable) \ + MACRO(Disable) \ + MACRO(Enablei) \ + MACRO(Disablei) \ + MACRO(VertexPointer) \ + MACRO(MatrixOrthoEXT) \ + MACRO(MatrixLoadfEXT) \ + MACRO(MatrixPushEXT) \ + MACRO(MatrixPopEXT) \ + MACRO(MatrixLoadIdentityEXT) \ + MACRO(NamedFramebufferTexture1DEXT) \ + MACRO(NamedFramebufferTexture2DEXT) \ + MACRO(MultiTexGenfvEXT) \ + MACRO(BindMultiTextureEXT) \ + MACRO(EnableClientStateiEXT) \ + MACRO(DisableClientStateiEXT) \ + MACRO(MultiTexCoordPointerEXT) \ + MACRO(PathStencilFuncNV) \ + MACRO(PathTexGenNV) \ + MACRO(BlendBarrierNV) \ + MACRO(MatrixScalefEXT) + +#define DECLARE_GL_METHOD(NAME) \ + GL##NAME NAME; + +public: + FOR_ALL_PUBLIC_GL_ENTRY_POINTS(DECLARE_GL_METHOD); + +protected: + FOR_ALL_PRIVATE_GL_ENTRY_POINTS(DECLARE_GL_METHOD); + +#undef DECLARE_GL_METHOD + + GL(const GL&); + GL& operator =(const GL&); +}; + +extern GL* gl; +void InitializeGLIfNeeded(); + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_GL_H_ */ diff --git a/libazure/nvpr/GLDefs.h b/libazure/nvpr/GLDefs.h new file mode 100644 index 0000000..da1230a --- /dev/null +++ b/libazure/nvpr/GLDefs.h @@ -0,0 +1,3184 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_GLDEFS_H_ +#define MOZILLA_GFX_NVPR_GLDEFS_H_ + +#include + +#ifdef WIN32 +#define GLAPIENTRY __stdcall +#else +#define GLAPIENTRY +#endif + +// OpenGL 1.1 +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; /* 1-byte signed */ +typedef short GLshort; /* 2-byte signed */ +typedef int GLint; /* 4-byte signed */ +typedef unsigned char GLubyte; /* 1-byte unsigned */ +typedef unsigned short GLushort; /* 2-byte unsigned */ +typedef unsigned int GLuint; /* 4-byte unsigned */ +typedef int GLsizei; /* 4-byte signed */ +typedef float GLfloat; /* single precision float */ +typedef float GLclampf; /* single precision float in [0,1] */ +typedef double GLdouble; /* double precision float */ +typedef double GLclampd; /* double precision float in [0,1] */ + +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_DOUBLE 0x140A +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_MATRIX_MODE 0x0BA0 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_LIST_MODE 0x0B30 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_SHININESS 0x1601 +#define GL_EMISSION 0x1600 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_SHADE_MODEL 0x0B54 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_NORMALIZE 0x0BA1 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_ACCUM 0x0100 +#define GL_ADD 0x0104 +#define GL_LOAD 0x0101 +#define GL_MULT 0x0103 +#define GL_RETURN 0x0102 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND_DST 0x0BE0 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_FEEDBACK 0x1C01 +#define GL_RENDER 0x1C00 +#define GL_SELECT 0x1C02 +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_FOG 0x0B60 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_COLOR 0x0B66 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_LINEAR 0x2601 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 +#define GL_LOGIC_OP 0x0BF1 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_CLEAR 0x1500 +#define GL_SET 0x150F +#define GL_COPY 0x1503 +#define GL_COPY_INVERTED 0x150C +#define GL_NOOP 0x1505 +#define GL_INVERT 0x150A +#define GL_AND 0x1501 +#define GL_NAND 0x150E +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_XOR 0x1506 +#define GL_EQUIV 0x1509 +#define GL_AND_REVERSE 0x1502 +#define GL_AND_INVERTED 0x1504 +#define GL_OR_REVERSE 0x150B +#define GL_OR_INVERTED 0x150D +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_INDEX 0x1901 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_NONE 0 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_COLOR_INDEX 0x1900 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_ALPHA_BITS 0x0D55 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_INDEX_BITS 0x0D51 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_READ_BUFFER 0x0C02 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_BITMAP 0x1A00 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_DITHER 0x0BD0 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_MODE 0x0C30 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_RENDER_MODE 0x0C40 +#define GL_RGBA_MODE 0x0C31 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_FOG_HINT 0x0C54 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#define GL_TEXTURE_ENV 0x2300 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_LINEAR 0x2400 +#define GL_EYE_PLANE 0x2502 +#define GL_SPHERE_MAP 0x2402 +#define GL_DECAL 0x2101 +#define GL_MODULATE 0x2100 +#define GL_NEAREST 0x2600 +#define GL_REPEAT 0x2901 +#define GL_CLAMP 0x2900 +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CURRENT_BIT 0x00000001 +#define GL_POINT_BIT 0x00000002 +#define GL_LINE_BIT 0x00000004 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_HINT_BIT 0x00008000 +#define GL_EVAL_BIT 0x00010000 +#define GL_LIST_BIT 0x00020000 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_ALL_ATTRIB_BITS 0x000FFFFF +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_ALL_CLIENT_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF + +typedef void (GLAPIENTRY * GLClearIndex) (GLfloat c); +typedef void (GLAPIENTRY * GLClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (GLAPIENTRY * GLClear) (GLbitfield mask); +typedef void (GLAPIENTRY * GLIndexMask) (GLuint mask); +typedef void (GLAPIENTRY * GLColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAPIENTRY * GLAlphaFunc) (GLenum func, GLclampf ref); +typedef void (GLAPIENTRY * GLBlendFunc) (GLenum sfactor, GLenum dfactor); +typedef void (GLAPIENTRY * GLLogicOp) (GLenum opcode); +typedef void (GLAPIENTRY * GLCullFace) (GLenum mode); +typedef void (GLAPIENTRY * GLFrontFace) (GLenum mode); +typedef void (GLAPIENTRY * GLPointSize) (GLfloat size); +typedef void (GLAPIENTRY * GLLineWidth) (GLfloat width); +typedef void (GLAPIENTRY * GLLineStipple) (GLint factor, GLushort pattern); +typedef void (GLAPIENTRY * GLPolygonMode) (GLenum face, GLenum mode); +typedef void (GLAPIENTRY * GLPolygonOffset) (GLfloat factor, GLfloat units); +typedef void (GLAPIENTRY * GLPolygonStipple) (const GLubyte *mask); +typedef void (GLAPIENTRY * GLGetPolygonStipple) (GLubyte *mask); +typedef void (GLAPIENTRY * GLEdgeFlag) (GLboolean flag); +typedef void (GLAPIENTRY * GLEdgeFlagv) (const GLboolean *flag); +typedef void (GLAPIENTRY * GLScissor) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLClipPlane) (GLenum plane, const GLdouble *equation); +typedef void (GLAPIENTRY * GLGetClipPlane) (GLenum plane, GLdouble *equation); +typedef void (GLAPIENTRY * GLDrawBuffer) (GLenum mode); +typedef void (GLAPIENTRY * GLReadBuffer) (GLenum mode); +typedef void (GLAPIENTRY * GLEnable) (GLenum cap); +typedef void (GLAPIENTRY * GLDisable) (GLenum cap); +typedef GLboolean (GLAPIENTRY * GLIsEnabled) (GLenum cap); +typedef void (GLAPIENTRY * GLEnableClientState) (GLenum cap); +typedef void (GLAPIENTRY * GLDisableClientState) (GLenum cap); +typedef void (GLAPIENTRY * GLGetBooleanv) (GLenum pname, GLboolean *params); +typedef void (GLAPIENTRY * GLGetDoublev) (GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * GLGetFloatv) (GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetIntegerv) (GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLPushAttrib) (GLbitfield mask); +typedef void (GLAPIENTRY * GLPopAttrib) (void); +typedef void (GLAPIENTRY * GLPushClientAttrib) (GLbitfield mask); +typedef void (GLAPIENTRY * GLPopClientAttrib) (void); +typedef GLint (GLAPIENTRY * GLRenderMode) (GLenum mode); +typedef GLenum (GLAPIENTRY * GLGetError) (void); +typedef const GLubyte * (GLAPIENTRY * GLGetString) (GLenum name); +typedef void (GLAPIENTRY * GLFinish) (void); +typedef void (GLAPIENTRY * GLFlush) (void); +typedef void (GLAPIENTRY * GLHint) (GLenum target, GLenum mode); +typedef void (GLAPIENTRY * GLClearDepth) (GLclampd depth); +typedef void (GLAPIENTRY * GLDepthFunc) (GLenum func); +typedef void (GLAPIENTRY * GLDepthMask) (GLboolean flag); +typedef void (GLAPIENTRY * GLDepthRange) (GLclampd near_val, GLclampd far_val); +typedef void (GLAPIENTRY * GLClearAccum) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAPIENTRY * GLAccum) (GLenum op, GLfloat value); +typedef void (GLAPIENTRY * GLMatrixMode) (GLenum mode); +typedef void (GLAPIENTRY * GLOrtho) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +typedef void (GLAPIENTRY * GLFrustum) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +typedef void (GLAPIENTRY * GLViewport) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLPushMatrix) (void); +typedef void (GLAPIENTRY * GLPopMatrix) (void); +typedef void (GLAPIENTRY * GLLoadIdentity) (void); +typedef void (GLAPIENTRY * GLLoadMatrixd) (const GLdouble *m); +typedef void (GLAPIENTRY * GLLoadMatrixf) (const GLfloat *m); +typedef void (GLAPIENTRY * GLMultMatrixd) (const GLdouble *m); +typedef void (GLAPIENTRY * GLMultMatrixf) (const GLfloat *m); +typedef void (GLAPIENTRY * GLRotated) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLRotatef) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLScaled) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLScalef) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLTranslated) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLTranslatef) (GLfloat x, GLfloat y, GLfloat z); +typedef GLboolean (GLAPIENTRY * GLIsList) (GLuint list); +typedef void (GLAPIENTRY * GLDeleteLists) (GLuint list, GLsizei range); +typedef GLuint (GLAPIENTRY * GLGenLists) (GLsizei range); +typedef void (GLAPIENTRY * GLNewList) (GLuint list, GLenum mode); +typedef void (GLAPIENTRY * GLEndList) (void); +typedef void (GLAPIENTRY * GLCallList) (GLuint list); +typedef void (GLAPIENTRY * GLCallLists) (GLsizei n, GLenum type, const GLvoid *lists); +typedef void (GLAPIENTRY * GLListBase) (GLuint base); +typedef void (GLAPIENTRY * GLBegin) (GLenum mode); +typedef void (GLAPIENTRY * GLEnd) (void); +typedef void (GLAPIENTRY * GLVertex2d) (GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLVertex2f) (GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * GLVertex2i) (GLint x, GLint y); +typedef void (GLAPIENTRY * GLVertex2s) (GLshort x, GLshort y); +typedef void (GLAPIENTRY * GLVertex3d) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLVertex3f) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLVertex3i) (GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * GLVertex3s) (GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * GLVertex4d) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLVertex4f) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * GLVertex4i) (GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * GLVertex4s) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAPIENTRY * GLVertex2dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLVertex2fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLVertex2iv) (const GLint *v); +typedef void (GLAPIENTRY * GLVertex2sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLVertex3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLVertex3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLVertex3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLVertex3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLVertex4dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLVertex4fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLVertex4iv) (const GLint *v); +typedef void (GLAPIENTRY * GLVertex4sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLNormal3b) (GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (GLAPIENTRY * GLNormal3d) (GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (GLAPIENTRY * GLNormal3f) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (GLAPIENTRY * GLNormal3i) (GLint nx, GLint ny, GLint nz); +typedef void (GLAPIENTRY * GLNormal3s) (GLshort nx, GLshort ny, GLshort nz); +typedef void (GLAPIENTRY * GLNormal3bv) (const GLbyte *v); +typedef void (GLAPIENTRY * GLNormal3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLNormal3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLNormal3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLNormal3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLIndexd) (GLdouble c); +typedef void (GLAPIENTRY * GLIndexf) (GLfloat c); +typedef void (GLAPIENTRY * GLIndexi) (GLint c); +typedef void (GLAPIENTRY * GLIndexs) (GLshort c); +typedef void (GLAPIENTRY * GLIndexub) (GLubyte c); +typedef void (GLAPIENTRY * GLIndexdv) (const GLdouble *c); +typedef void (GLAPIENTRY * GLIndexfv) (const GLfloat *c); +typedef void (GLAPIENTRY * GLIndexiv) (const GLint *c); +typedef void (GLAPIENTRY * GLIndexsv) (const GLshort *c); +typedef void (GLAPIENTRY * GLIndexubv) (const GLubyte *c); +typedef void (GLAPIENTRY * GLColor3b) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAPIENTRY * GLColor3d) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAPIENTRY * GLColor3f) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAPIENTRY * GLColor3i) (GLint red, GLint green, GLint blue); +typedef void (GLAPIENTRY * GLColor3s) (GLshort red, GLshort green, GLshort blue); +typedef void (GLAPIENTRY * GLColor3ub) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAPIENTRY * GLColor3ui) (GLuint red, GLuint green, GLuint blue); +typedef void (GLAPIENTRY * GLColor3us) (GLushort red, GLushort green, GLushort blue); +typedef void (GLAPIENTRY * GLColor4b) (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +typedef void (GLAPIENTRY * GLColor4d) (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +typedef void (GLAPIENTRY * GLColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAPIENTRY * GLColor4i) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (GLAPIENTRY * GLColor4s) (GLshort red, GLshort green, GLshort blue, GLshort alpha); +typedef void (GLAPIENTRY * GLColor4ub) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +typedef void (GLAPIENTRY * GLColor4ui) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +typedef void (GLAPIENTRY * GLColor4us) (GLushort red, GLushort green, GLushort blue, GLushort alpha); +typedef void (GLAPIENTRY * GLColor3bv) (const GLbyte *v); +typedef void (GLAPIENTRY * GLColor3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLColor3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLColor3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLColor3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLColor3ubv) (const GLubyte *v); +typedef void (GLAPIENTRY * GLColor3uiv) (const GLuint *v); +typedef void (GLAPIENTRY * GLColor3usv) (const GLushort *v); +typedef void (GLAPIENTRY * GLColor4bv) (const GLbyte *v); +typedef void (GLAPIENTRY * GLColor4dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLColor4fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLColor4iv) (const GLint *v); +typedef void (GLAPIENTRY * GLColor4sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLColor4ubv) (const GLubyte *v); +typedef void (GLAPIENTRY * GLColor4uiv) (const GLuint *v); +typedef void (GLAPIENTRY * GLColor4usv) (const GLushort *v); +typedef void (GLAPIENTRY * GLTexCoord1d) (GLdouble s); +typedef void (GLAPIENTRY * GLTexCoord1f) (GLfloat s); +typedef void (GLAPIENTRY * GLTexCoord1i) (GLint s); +typedef void (GLAPIENTRY * GLTexCoord1s) (GLshort s); +typedef void (GLAPIENTRY * GLTexCoord2d) (GLdouble s, GLdouble t); +typedef void (GLAPIENTRY * GLTexCoord2f) (GLfloat s, GLfloat t); +typedef void (GLAPIENTRY * GLTexCoord2i) (GLint s, GLint t); +typedef void (GLAPIENTRY * GLTexCoord2s) (GLshort s, GLshort t); +typedef void (GLAPIENTRY * GLTexCoord3d) (GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAPIENTRY * GLTexCoord3f) (GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAPIENTRY * GLTexCoord3i) (GLint s, GLint t, GLint r); +typedef void (GLAPIENTRY * GLTexCoord3s) (GLshort s, GLshort t, GLshort r); +typedef void (GLAPIENTRY * GLTexCoord4d) (GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAPIENTRY * GLTexCoord4f) (GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAPIENTRY * GLTexCoord4i) (GLint s, GLint t, GLint r, GLint q); +typedef void (GLAPIENTRY * GLTexCoord4s) (GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAPIENTRY * GLTexCoord1dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLTexCoord1fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLTexCoord1iv) (const GLint *v); +typedef void (GLAPIENTRY * GLTexCoord1sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLTexCoord2dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLTexCoord2fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLTexCoord2iv) (const GLint *v); +typedef void (GLAPIENTRY * GLTexCoord2sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLTexCoord3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLTexCoord3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLTexCoord3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLTexCoord3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLTexCoord4dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLTexCoord4fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLTexCoord4iv) (const GLint *v); +typedef void (GLAPIENTRY * GLTexCoord4sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLRasterPos2d) (GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLRasterPos2f) (GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * GLRasterPos2i) (GLint x, GLint y); +typedef void (GLAPIENTRY * GLRasterPos2s) (GLshort x, GLshort y); +typedef void (GLAPIENTRY * GLRasterPos3d) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLRasterPos3f) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLRasterPos3i) (GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * GLRasterPos3s) (GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * GLRasterPos4d) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLRasterPos4f) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * GLRasterPos4i) (GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * GLRasterPos4s) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAPIENTRY * GLRasterPos2dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLRasterPos2fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLRasterPos2iv) (const GLint *v); +typedef void (GLAPIENTRY * GLRasterPos2sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLRasterPos3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLRasterPos3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLRasterPos3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLRasterPos3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLRasterPos4dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLRasterPos4fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLRasterPos4iv) (const GLint *v); +typedef void (GLAPIENTRY * GLRasterPos4sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLRectd) (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +typedef void (GLAPIENTRY * GLRectf) (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +typedef void (GLAPIENTRY * GLRecti) (GLint x1, GLint y1, GLint x2, GLint y2); +typedef void (GLAPIENTRY * GLRects) (GLshort x1, GLshort y1, GLshort x2, GLshort y2); +typedef void (GLAPIENTRY * GLRectdv) (const GLdouble *v1, const GLdouble *v2); +typedef void (GLAPIENTRY * GLRectfv) (const GLfloat *v1, const GLfloat *v2); +typedef void (GLAPIENTRY * GLRectiv) (const GLint *v1, const GLint *v2); +typedef void (GLAPIENTRY * GLRectsv) (const GLshort *v1, const GLshort *v2); +typedef void (GLAPIENTRY * GLVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLNormalPointer) (GLenum type, GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLIndexPointer) (GLenum type, GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLTexCoordPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLEdgeFlagPointer) (GLsizei stride, const GLvoid *ptr); +typedef void (GLAPIENTRY * GLGetPointerv) (GLenum pname, GLvoid **params); +typedef void (GLAPIENTRY * GLArrayElement) (GLint i); +typedef void (GLAPIENTRY * GLDrawArrays) (GLenum mode, GLint first, GLsizei count); +typedef void (GLAPIENTRY * GLDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (GLAPIENTRY * GLInterleavedArrays) (GLenum format, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLShadeModel) (GLenum mode); +typedef void (GLAPIENTRY * GLLightf) (GLenum light, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLLighti) (GLenum light, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLLightfv) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLLightiv) (GLenum light, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetLightfv) (GLenum light, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetLightiv) (GLenum light, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLLightModelf) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLLightModeli) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLLightModelfv) (GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLLightModeliv) (GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLMaterialf) (GLenum face, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLMateriali) (GLenum face, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLMaterialfv) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLMaterialiv) (GLenum face, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetMaterialfv) (GLenum face, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetMaterialiv) (GLenum face, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLColorMaterial) (GLenum face, GLenum mode); +typedef void (GLAPIENTRY * GLPixelZoom) (GLfloat xfactor, GLfloat yfactor); +typedef void (GLAPIENTRY * GLPixelStoref) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLPixelStorei) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLPixelTransferf) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLPixelTransferi) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLPixelMapfv) (GLenum map, GLsizei mapsize, const GLfloat *values); +typedef void (GLAPIENTRY * GLPixelMapuiv) (GLenum map, GLsizei mapsize, const GLuint *values); +typedef void (GLAPIENTRY * GLPixelMapusv) (GLenum map, GLsizei mapsize, const GLushort *values); +typedef void (GLAPIENTRY * GLGetPixelMapfv) (GLenum map, GLfloat *values); +typedef void (GLAPIENTRY * GLGetPixelMapuiv) (GLenum map, GLuint *values); +typedef void (GLAPIENTRY * GLGetPixelMapusv) (GLenum map, GLushort *values); +typedef void (GLAPIENTRY * GLBitmap) (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +typedef void (GLAPIENTRY * GLReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * GLDrawPixels) (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +typedef void (GLAPIENTRY * GLStencilFunc) (GLenum func, GLint ref, GLuint mask); +typedef void (GLAPIENTRY * GLStencilMask) (GLuint mask); +typedef void (GLAPIENTRY * GLStencilOp) (GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAPIENTRY * GLClearStencil) (GLint s); +typedef void (GLAPIENTRY * GLTexGend) (GLenum coord, GLenum pname, GLdouble param); +typedef void (GLAPIENTRY * GLTexGenf) (GLenum coord, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLTexGeni) (GLenum coord, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLTexGendv) (GLenum coord, GLenum pname, const GLdouble *params); +typedef void (GLAPIENTRY * GLTexGenfv) (GLenum coord, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLTexGeniv) (GLenum coord, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetTexGendv) (GLenum coord, GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * GLGetTexGenfv) (GLenum coord, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTexGeniv) (GLenum coord, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLTexEnvf) (GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLTexEnvi) (GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLTexEnvfv) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLTexEnviv) (GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetTexEnvfv) (GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTexEnviv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLTexParameterf) (GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLTexParameteri) (GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLTexParameterfv) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLTexParameteriv) (GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetTexParameterfv) (GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTexParameteriv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetTexLevelParameterfv) (GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTexLevelParameteriv) (GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLTexImage1D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * GLGenTextures) (GLsizei n, GLuint *textures); +typedef void (GLAPIENTRY * GLDeleteTextures) (GLsizei n, const GLuint *textures); +typedef void (GLAPIENTRY * GLBindTexture) (GLenum target, GLuint texture); +typedef void (GLAPIENTRY * GLPrioritizeTextures) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +typedef GLboolean (GLAPIENTRY * GLAreTexturesResident) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef GLboolean (GLAPIENTRY * GLIsTexture) (GLuint texture); +typedef void (GLAPIENTRY * GLTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAPIENTRY * GLCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAPIENTRY * GLCopyTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAPIENTRY * GLCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLMap1d) (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +typedef void (GLAPIENTRY * GLMap1f) (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +typedef void (GLAPIENTRY * GLMap2d) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +typedef void (GLAPIENTRY * GLMap2f) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +typedef void (GLAPIENTRY * GLGetMapdv) (GLenum target, GLenum query, GLdouble *v); +typedef void (GLAPIENTRY * GLGetMapfv) (GLenum target, GLenum query, GLfloat *v); +typedef void (GLAPIENTRY * GLGetMapiv) (GLenum target, GLenum query, GLint *v); +typedef void (GLAPIENTRY * GLEvalCoord1d) (GLdouble u); +typedef void (GLAPIENTRY * GLEvalCoord1f) (GLfloat u); +typedef void (GLAPIENTRY * GLEvalCoord1dv) (const GLdouble *u); +typedef void (GLAPIENTRY * GLEvalCoord1fv) (const GLfloat *u); +typedef void (GLAPIENTRY * GLEvalCoord2d) (GLdouble u, GLdouble v); +typedef void (GLAPIENTRY * GLEvalCoord2f) (GLfloat u, GLfloat v); +typedef void (GLAPIENTRY * GLEvalCoord2dv) (const GLdouble *u); +typedef void (GLAPIENTRY * GLEvalCoord2fv) (const GLfloat *u); +typedef void (GLAPIENTRY * GLMapGrid1d) (GLint un, GLdouble u1, GLdouble u2); +typedef void (GLAPIENTRY * GLMapGrid1f) (GLint un, GLfloat u1, GLfloat u2); +typedef void (GLAPIENTRY * GLMapGrid2d) (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +typedef void (GLAPIENTRY * GLMapGrid2f) (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +typedef void (GLAPIENTRY * GLEvalPoint1) (GLint i); +typedef void (GLAPIENTRY * GLEvalPoint2) (GLint i, GLint j); +typedef void (GLAPIENTRY * GLEvalMesh1) (GLenum mode, GLint i1, GLint i2); +typedef void (GLAPIENTRY * GLEvalMesh2) (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +typedef void (GLAPIENTRY * GLFogf) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLFogi) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLFogfv) (GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLFogiv) (GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLFeedbackBuffer) (GLsizei size, GLenum type, GLfloat *buffer); +typedef void (GLAPIENTRY * GLPassThrough) (GLfloat token); +typedef void (GLAPIENTRY * GLSelectBuffer) (GLsizei size, GLuint *buffer); +typedef void (GLAPIENTRY * GLInitNames) (void); +typedef void (GLAPIENTRY * GLLoadName) (GLuint name); +typedef void (GLAPIENTRY * GLPushName) (GLuint name); +typedef void (GLAPIENTRY * GLPopName) (void); + + +// OpenGL 1.2 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D + +typedef void (GLAPIENTRY * GLBlendColor) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAPIENTRY * GLBlendEquation) (GLenum mode); +typedef void (GLAPIENTRY * GLDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (GLAPIENTRY * GLTexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + + +// OpenGL 1.3 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF + +typedef void (GLAPIENTRY * GLActiveTexture) (GLenum texture); +typedef void (GLAPIENTRY * GLSampleCoverage) (GLfloat value, GLboolean invert); +typedef void (GLAPIENTRY * GLCompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLCompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLCompressedTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLCompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLCompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLCompressedTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * GLGetCompressedTexImage) (GLenum target, GLint level, GLvoid *img); +typedef void (GLAPIENTRY * GLClientActiveTexture) (GLenum texture); +typedef void (GLAPIENTRY * GLMultiTexCoord1d) (GLenum target, GLdouble s); +typedef void (GLAPIENTRY * GLMultiTexCoord1dv) (GLenum target, const GLdouble *v); +typedef void (GLAPIENTRY * GLMultiTexCoord1f) (GLenum target, GLfloat s); +typedef void (GLAPIENTRY * GLMultiTexCoord1fv) (GLenum target, const GLfloat *v); +typedef void (GLAPIENTRY * GLMultiTexCoord1i) (GLenum target, GLint s); +typedef void (GLAPIENTRY * GLMultiTexCoord1iv) (GLenum target, const GLint *v); +typedef void (GLAPIENTRY * GLMultiTexCoord1s) (GLenum target, GLshort s); +typedef void (GLAPIENTRY * GLMultiTexCoord1sv) (GLenum target, const GLshort *v); +typedef void (GLAPIENTRY * GLMultiTexCoord2d) (GLenum target, GLdouble s, GLdouble t); +typedef void (GLAPIENTRY * GLMultiTexCoord2dv) (GLenum target, const GLdouble *v); +typedef void (GLAPIENTRY * GLMultiTexCoord2f) (GLenum target, GLfloat s, GLfloat t); +typedef void (GLAPIENTRY * GLMultiTexCoord2fv) (GLenum target, const GLfloat *v); +typedef void (GLAPIENTRY * GLMultiTexCoord2i) (GLenum target, GLint s, GLint t); +typedef void (GLAPIENTRY * GLMultiTexCoord2iv) (GLenum target, const GLint *v); +typedef void (GLAPIENTRY * GLMultiTexCoord2s) (GLenum target, GLshort s, GLshort t); +typedef void (GLAPIENTRY * GLMultiTexCoord2sv) (GLenum target, const GLshort *v); +typedef void (GLAPIENTRY * GLMultiTexCoord3d) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAPIENTRY * GLMultiTexCoord3dv) (GLenum target, const GLdouble *v); +typedef void (GLAPIENTRY * GLMultiTexCoord3f) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAPIENTRY * GLMultiTexCoord3fv) (GLenum target, const GLfloat *v); +typedef void (GLAPIENTRY * GLMultiTexCoord3i) (GLenum target, GLint s, GLint t, GLint r); +typedef void (GLAPIENTRY * GLMultiTexCoord3iv) (GLenum target, const GLint *v); +typedef void (GLAPIENTRY * GLMultiTexCoord3s) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (GLAPIENTRY * GLMultiTexCoord3sv) (GLenum target, const GLshort *v); +typedef void (GLAPIENTRY * GLMultiTexCoord4d) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAPIENTRY * GLMultiTexCoord4dv) (GLenum target, const GLdouble *v); +typedef void (GLAPIENTRY * GLMultiTexCoord4f) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAPIENTRY * GLMultiTexCoord4fv) (GLenum target, const GLfloat *v); +typedef void (GLAPIENTRY * GLMultiTexCoord4i) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (GLAPIENTRY * GLMultiTexCoord4iv) (GLenum target, const GLint *v); +typedef void (GLAPIENTRY * GLMultiTexCoord4s) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAPIENTRY * GLMultiTexCoord4sv) (GLenum target, const GLshort *v); +typedef void (GLAPIENTRY * GLLoadTransposeMatrixf) (const GLfloat *m); +typedef void (GLAPIENTRY * GLLoadTransposeMatrixd) (const GLdouble *m); +typedef void (GLAPIENTRY * GLMultTransposeMatrixf) (const GLfloat *m); +typedef void (GLAPIENTRY * GLMultTransposeMatrixd) (const GLdouble *m); + + +// OpenGL 1.4 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E + +typedef void (GLAPIENTRY * GLBlendFuncSeparate) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (GLAPIENTRY * GLMultiDrawArrays) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (GLAPIENTRY * GLMultiDrawElements) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount); +typedef void (GLAPIENTRY * GLPointParameterf) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLPointParameterfv) (GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLPointParameteri) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLPointParameteriv) (GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLFogCoordf) (GLfloat coord); +typedef void (GLAPIENTRY * GLFogCoordfv) (const GLfloat *coord); +typedef void (GLAPIENTRY * GLFogCoordd) (GLdouble coord); +typedef void (GLAPIENTRY * GLFogCoorddv) (const GLdouble *coord); +typedef void (GLAPIENTRY * GLFogCoordPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLSecondaryColor3b) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAPIENTRY * GLSecondaryColor3bv) (const GLbyte *v); +typedef void (GLAPIENTRY * GLSecondaryColor3d) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAPIENTRY * GLSecondaryColor3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLSecondaryColor3f) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAPIENTRY * GLSecondaryColor3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLSecondaryColor3i) (GLint red, GLint green, GLint blue); +typedef void (GLAPIENTRY * GLSecondaryColor3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLSecondaryColor3s) (GLshort red, GLshort green, GLshort blue); +typedef void (GLAPIENTRY * GLSecondaryColor3sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLSecondaryColor3ub) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAPIENTRY * GLSecondaryColor3ubv) (const GLubyte *v); +typedef void (GLAPIENTRY * GLSecondaryColor3ui) (GLuint red, GLuint green, GLuint blue); +typedef void (GLAPIENTRY * GLSecondaryColor3uiv) (const GLuint *v); +typedef void (GLAPIENTRY * GLSecondaryColor3us) (GLushort red, GLushort green, GLushort blue); +typedef void (GLAPIENTRY * GLSecondaryColor3usv) (const GLushort *v); +typedef void (GLAPIENTRY * GLSecondaryColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLWindowPos2d) (GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLWindowPos2dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLWindowPos2f) (GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * GLWindowPos2fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLWindowPos2i) (GLint x, GLint y); +typedef void (GLAPIENTRY * GLWindowPos2iv) (const GLint *v); +typedef void (GLAPIENTRY * GLWindowPos2s) (GLshort x, GLshort y); +typedef void (GLAPIENTRY * GLWindowPos2sv) (const GLshort *v); +typedef void (GLAPIENTRY * GLWindowPos3d) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLWindowPos3dv) (const GLdouble *v); +typedef void (GLAPIENTRY * GLWindowPos3f) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLWindowPos3fv) (const GLfloat *v); +typedef void (GLAPIENTRY * GLWindowPos3i) (GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * GLWindowPos3iv) (const GLint *v); +typedef void (GLAPIENTRY * GLWindowPos3s) (GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * GLWindowPos3sv) (const GLshort *v); + + +// OpenGL 1.5 +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; + +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A + +typedef void (GLAPIENTRY * GLGenQueries) (GLsizei n, GLuint *ids); +typedef void (GLAPIENTRY * GLDeleteQueries) (GLsizei n, const GLuint *ids); +typedef GLboolean (GLAPIENTRY * GLIsQuery) (GLuint id); +typedef void (GLAPIENTRY * GLBeginQuery) (GLenum target, GLuint id); +typedef void (GLAPIENTRY * GLEndQuery) (GLenum target); +typedef void (GLAPIENTRY * GLGetQueryiv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetQueryObjectiv) (GLuint id, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetQueryObjectuiv) (GLuint id, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLBindBuffer) (GLenum target, GLuint buffer); +typedef void (GLAPIENTRY * GLDeleteBuffers) (GLsizei n, const GLuint *buffers); +typedef void (GLAPIENTRY * GLGenBuffers) (GLsizei n, GLuint *buffers); +typedef GLboolean (GLAPIENTRY * GLIsBuffer) (GLuint buffer); +typedef void (GLAPIENTRY * GLBufferData) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (GLAPIENTRY * GLBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void (GLAPIENTRY * GLGetBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void * (GLAPIENTRY * GLMapBuffer) (GLenum target, GLenum access); +typedef GLboolean (GLAPIENTRY * GLUnmapBuffer) (GLenum target); +typedef void (GLAPIENTRY * GLGetBufferParameteriv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetBufferPointerv) (GLenum target, GLenum pname, GLvoid **params); + + +// OpenGL 2.0 +typedef char GLchar; + +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 + +typedef void (GLAPIENTRY * GLBlendEquationSeparate) (GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAPIENTRY * GLDrawBuffers) (GLsizei n, const GLenum *bufs); +typedef void (GLAPIENTRY * GLStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (GLAPIENTRY * GLStencilFuncSeparate) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (GLAPIENTRY * GLStencilMaskSeparate) (GLenum face, GLuint mask); +typedef void (GLAPIENTRY * GLAttachShader) (GLuint program, GLuint shader); +typedef void (GLAPIENTRY * GLBindAttribLocation) (GLuint program, GLuint index, const GLchar *name); +typedef void (GLAPIENTRY * GLCompileShader) (GLuint shader); +typedef GLuint (GLAPIENTRY * GLCreateProgram) (void); +typedef GLuint (GLAPIENTRY * GLCreateShader) (GLenum type); +typedef void (GLAPIENTRY * GLDeleteProgram) (GLuint program); +typedef void (GLAPIENTRY * GLDeleteShader) (GLuint shader); +typedef void (GLAPIENTRY * GLDetachShader) (GLuint program, GLuint shader); +typedef void (GLAPIENTRY * GLDisableVertexAttribArray) (GLuint index); +typedef void (GLAPIENTRY * GLEnableVertexAttribArray) (GLuint index); +typedef void (GLAPIENTRY * GLGetActiveAttrib) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (GLAPIENTRY * GLGetActiveUniform) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (GLAPIENTRY * GLGetAttachedShaders) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (GLAPIENTRY * GLGetAttribLocation) (GLuint program, const GLchar *name); +typedef void (GLAPIENTRY * GLGetProgramiv) (GLuint program, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetProgramInfoLog) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (GLAPIENTRY * GLGetShaderiv) (GLuint shader, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetShaderInfoLog) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (GLAPIENTRY * GLGetShaderSource) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (GLAPIENTRY * GLGetUniformLocation) (GLuint program, const GLchar *name); +typedef void (GLAPIENTRY * GLGetUniformfv) (GLuint program, GLint location, GLfloat *params); +typedef void (GLAPIENTRY * GLGetUniformiv) (GLuint program, GLint location, GLint *params); +typedef void (GLAPIENTRY * GLGetVertexAttribdv) (GLuint index, GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * GLGetVertexAttribfv) (GLuint index, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetVertexAttribiv) (GLuint index, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid **pointer); +typedef GLboolean (GLAPIENTRY * GLIsProgram) (GLuint program); +typedef GLboolean (GLAPIENTRY * GLIsShader) (GLuint shader); +typedef void (GLAPIENTRY * GLLinkProgram) (GLuint program); +typedef void (GLAPIENTRY * GLShaderSource) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (GLAPIENTRY * GLUseProgram) (GLuint program); +typedef void (GLAPIENTRY * GLUniform1f) (GLint location, GLfloat v0); +typedef void (GLAPIENTRY * GLUniform2f) (GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAPIENTRY * GLUniform3f) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAPIENTRY * GLUniform4f) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAPIENTRY * GLUniform1i) (GLint location, GLint v0); +typedef void (GLAPIENTRY * GLUniform2i) (GLint location, GLint v0, GLint v1); +typedef void (GLAPIENTRY * GLUniform3i) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAPIENTRY * GLUniform4i) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAPIENTRY * GLUniform1fv) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniform2fv) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniform3fv) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniform4fv) (GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniform1iv) (GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLUniform2iv) (GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLUniform3iv) (GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLUniform4iv) (GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLUniformMatrix2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLValidateProgram) (GLuint program); +typedef void (GLAPIENTRY * GLVertexAttrib1d) (GLuint index, GLdouble x); +typedef void (GLAPIENTRY * GLVertexAttrib1dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttrib1f) (GLuint index, GLfloat x); +typedef void (GLAPIENTRY * GLVertexAttrib1fv) (GLuint index, const GLfloat *v); +typedef void (GLAPIENTRY * GLVertexAttrib1s) (GLuint index, GLshort x); +typedef void (GLAPIENTRY * GLVertexAttrib1sv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttrib2d) (GLuint index, GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLVertexAttrib2dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttrib2f) (GLuint index, GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * GLVertexAttrib2fv) (GLuint index, const GLfloat *v); +typedef void (GLAPIENTRY * GLVertexAttrib2s) (GLuint index, GLshort x, GLshort y); +typedef void (GLAPIENTRY * GLVertexAttrib2sv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttrib3d) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLVertexAttrib3dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttrib3f) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLVertexAttrib3fv) (GLuint index, const GLfloat *v); +typedef void (GLAPIENTRY * GLVertexAttrib3s) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * GLVertexAttrib3sv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Nbv) (GLuint index, const GLbyte *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Niv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Nsv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Nub) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (GLAPIENTRY * GLVertexAttrib4Nubv) (GLuint index, const GLubyte *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Nuiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttrib4Nusv) (GLuint index, const GLushort *v); +typedef void (GLAPIENTRY * GLVertexAttrib4bv) (GLuint index, const GLbyte *v); +typedef void (GLAPIENTRY * GLVertexAttrib4d) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLVertexAttrib4dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttrib4f) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * GLVertexAttrib4fv) (GLuint index, const GLfloat *v); +typedef void (GLAPIENTRY * GLVertexAttrib4iv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttrib4s) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAPIENTRY * GLVertexAttrib4sv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttrib4ubv) (GLuint index, const GLubyte *v); +typedef void (GLAPIENTRY * GLVertexAttrib4uiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttrib4usv) (GLuint index, const GLushort *v); +typedef void (GLAPIENTRY * GLVertexAttribPointer) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); + + +// OpenGL 2.1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B + +typedef void (GLAPIENTRY * GLUniformMatrix2x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix3x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix2x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix4x2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix3x4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLUniformMatrix4x3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + +// OpenGL 3.0 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 + +typedef void (GLAPIENTRY * GLColorMaski) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (GLAPIENTRY * GLGetBooleani_v) (GLenum target, GLuint index, GLboolean *data); +typedef void (GLAPIENTRY * GLGetIntegeri_v) (GLenum target, GLuint index, GLint *data); +typedef void (GLAPIENTRY * GLEnablei) (GLenum target, GLuint index); +typedef void (GLAPIENTRY * GLDisablei) (GLenum target, GLuint index); +typedef GLboolean (GLAPIENTRY * GLIsEnabledi) (GLenum target, GLuint index); +typedef void (GLAPIENTRY * GLBeginTransformFeedback) (GLenum primitiveMode); +typedef void (GLAPIENTRY * GLEndTransformFeedback) (void); +typedef void (GLAPIENTRY * GLBindBufferRange) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAPIENTRY * GLBindBufferBase) (GLenum target, GLuint index, GLuint buffer); +typedef void (GLAPIENTRY * GLTransformFeedbackVaryings) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (GLAPIENTRY * GLGetTransformFeedbackVarying) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (GLAPIENTRY * GLClampColor) (GLenum target, GLenum clamp); +typedef void (GLAPIENTRY * GLBeginConditionalRender) (GLuint id, GLenum mode); +typedef void (GLAPIENTRY * GLEndConditionalRender) (void); +typedef void (GLAPIENTRY * GLVertexAttribIPointer) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLGetVertexAttribIiv) (GLuint index, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetVertexAttribIuiv) (GLuint index, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLVertexAttribI1i) (GLuint index, GLint x); +typedef void (GLAPIENTRY * GLVertexAttribI2i) (GLuint index, GLint x, GLint y); +typedef void (GLAPIENTRY * GLVertexAttribI3i) (GLuint index, GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * GLVertexAttribI4i) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * GLVertexAttribI1ui) (GLuint index, GLuint x); +typedef void (GLAPIENTRY * GLVertexAttribI2ui) (GLuint index, GLuint x, GLuint y); +typedef void (GLAPIENTRY * GLVertexAttribI3ui) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (GLAPIENTRY * GLVertexAttribI4ui) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (GLAPIENTRY * GLVertexAttribI1iv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttribI2iv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttribI3iv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttribI4iv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLVertexAttribI1uiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttribI2uiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttribI3uiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttribI4uiv) (GLuint index, const GLuint *v); +typedef void (GLAPIENTRY * GLVertexAttribI4bv) (GLuint index, const GLbyte *v); +typedef void (GLAPIENTRY * GLVertexAttribI4sv) (GLuint index, const GLshort *v); +typedef void (GLAPIENTRY * GLVertexAttribI4ubv) (GLuint index, const GLubyte *v); +typedef void (GLAPIENTRY * GLVertexAttribI4usv) (GLuint index, const GLushort *v); +typedef void (GLAPIENTRY * GLGetUniformuiv) (GLuint program, GLint location, GLuint *params); +typedef void (GLAPIENTRY * GLBindFragDataLocation) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (GLAPIENTRY * GLGetFragDataLocation) (GLuint program, const GLchar *name); +typedef void (GLAPIENTRY * GLUniform1ui) (GLint location, GLuint v0); +typedef void (GLAPIENTRY * GLUniform2ui) (GLint location, GLuint v0, GLuint v1); +typedef void (GLAPIENTRY * GLUniform3ui) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAPIENTRY * GLUniform4ui) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAPIENTRY * GLUniform1uiv) (GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLUniform2uiv) (GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLUniform3uiv) (GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLUniform4uiv) (GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLTexParameterIiv) (GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLTexParameterIuiv) (GLenum target, GLenum pname, const GLuint *params); +typedef void (GLAPIENTRY * GLGetTexParameterIiv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetTexParameterIuiv) (GLenum target, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLClearBufferiv) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (GLAPIENTRY * GLClearBufferuiv) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (GLAPIENTRY * GLClearBufferfv) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (GLAPIENTRY * GLClearBufferfi) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte * (GLAPIENTRY * GLGetStringi) (GLenum name, GLuint index); +typedef GLboolean (GLAPIENTRY * GLIsRenderbuffer) (GLuint renderbuffer); +typedef void (GLAPIENTRY * GLBindRenderbuffer) (GLenum target, GLuint renderbuffer); +typedef void (GLAPIENTRY * GLDeleteRenderbuffers) (GLsizei n, const GLuint *renderbuffers); +typedef void (GLAPIENTRY * GLGenRenderbuffers) (GLsizei n, GLuint *renderbuffers); +typedef void (GLAPIENTRY * GLRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLGetRenderbufferParameteriv) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (GLAPIENTRY * GLIsFramebuffer) (GLuint framebuffer); +typedef void (GLAPIENTRY * GLBindFramebuffer) (GLenum target, GLuint framebuffer); +typedef void (GLAPIENTRY * GLDeleteFramebuffers) (GLsizei n, const GLuint *framebuffers); +typedef void (GLAPIENTRY * GLGenFramebuffers) (GLsizei n, GLuint *framebuffers); +typedef GLenum (GLAPIENTRY * GLCheckFramebufferStatus) (GLenum target); +typedef void (GLAPIENTRY * GLFramebufferTexture1D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLFramebufferTexture2D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLFramebufferTexture3D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAPIENTRY * GLFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAPIENTRY * GLGetFramebufferAttachmentParameteriv) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGenerateMipmap) (GLenum target); +typedef void (GLAPIENTRY * GLBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (GLAPIENTRY * GLRenderbufferStorageMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLFramebufferTextureLayer) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void * (GLAPIENTRY * GLMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAPIENTRY * GLFlushMappedBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (GLAPIENTRY * GLBindVertexArray) (GLuint array); +typedef void (GLAPIENTRY * GLDeleteVertexArrays) (GLsizei n, const GLuint *arrays); +typedef void (GLAPIENTRY * GLGenVertexArrays) (GLsizei n, GLuint *arrays); +typedef GLboolean (GLAPIENTRY * GLIsVertexArray) (GLuint array); + + +// OpenGL 3.1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu + +typedef void (GLAPIENTRY * GLDrawArraysInstanced) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (GLAPIENTRY * GLDrawElementsInstanced) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +typedef void (GLAPIENTRY * GLTexBuffer) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAPIENTRY * GLPrimitiveRestartIndex) (GLuint index); +typedef void (GLAPIENTRY * GLCopyBufferSubData) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (GLAPIENTRY * GLGetUniformIndices) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (GLAPIENTRY * GLGetActiveUniformsiv) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetActiveUniformName) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (GLAPIENTRY * GLGetUniformBlockIndex) (GLuint program, const GLchar *uniformBlockName); +typedef void (GLAPIENTRY * GLGetActiveUniformBlockiv) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetActiveUniformBlockName) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (GLAPIENTRY * GLUniformBlockBinding) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + + +// OpenGL 3.2 +typedef struct __GLsync *GLsync; +typedef uint64_t GLuint64; +typedef int64_t GLint64; + +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 + +typedef void (GLAPIENTRY * GLDrawElementsBaseVertex) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (GLAPIENTRY * GLDrawRangeElementsBaseVertex) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (GLAPIENTRY * GLDrawElementsInstancedBaseVertex) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); +typedef void (GLAPIENTRY * GLMultiDrawElementsBaseVertex) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (GLAPIENTRY * GLProvokingVertex) (GLenum mode); +typedef GLsync (GLAPIENTRY * GLFenceSync) (GLenum condition, GLbitfield flags); +typedef GLboolean (GLAPIENTRY * GLIsSync) (GLsync sync); +typedef void (GLAPIENTRY * GLDeleteSync) (GLsync sync); +typedef GLenum (GLAPIENTRY * GLClientWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAPIENTRY * GLWaitSync) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (GLAPIENTRY * GLGetInteger64v) (GLenum pname, GLint64 *params); +typedef void (GLAPIENTRY * GLGetSynciv) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (GLAPIENTRY * GLGetInteger64i_v) (GLenum target, GLuint index, GLint64 *data); +typedef void (GLAPIENTRY * GLGetBufferParameteri64v) (GLenum target, GLenum pname, GLint64 *params); +typedef void (GLAPIENTRY * GLFramebufferTexture) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLTexImage2DMultisample) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLTexImage3DMultisample) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLGetMultisamplefv) (GLenum pname, GLuint index, GLfloat *val); +typedef void (GLAPIENTRY * GLSampleMaski) (GLuint index, GLbitfield mask); + + +// OpenGL 3.3 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F + +typedef void (GLAPIENTRY * GLBindFragDataLocationIndexed) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (GLAPIENTRY * GLGetFragDataIndex) (GLuint program, const GLchar *name); +typedef void (GLAPIENTRY * GLGenSamplers) (GLsizei count, GLuint *samplers); +typedef void (GLAPIENTRY * GLDeleteSamplers) (GLsizei count, const GLuint *samplers); +typedef GLboolean (GLAPIENTRY * GLIsSampler) (GLuint sampler); +typedef void (GLAPIENTRY * GLBindSampler) (GLuint unit, GLuint sampler); +typedef void (GLAPIENTRY * GLSamplerParameteri) (GLuint sampler, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLSamplerParameteriv) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (GLAPIENTRY * GLSamplerParameterf) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLSamplerParameterfv) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (GLAPIENTRY * GLSamplerParameterIiv) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (GLAPIENTRY * GLSamplerParameterIuiv) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (GLAPIENTRY * GLGetSamplerParameteriv) (GLuint sampler, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetSamplerParameterIiv) (GLuint sampler, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetSamplerParameterfv) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetSamplerParameterIuiv) (GLuint sampler, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLQueryCounter) (GLuint id, GLenum target); +typedef void (GLAPIENTRY * GLGetQueryObjecti64v) (GLuint id, GLenum pname, GLint64 *params); +typedef void (GLAPIENTRY * GLGetQueryObjectui64v) (GLuint id, GLenum pname, GLuint64 *params); +typedef void (GLAPIENTRY * GLVertexAttribDivisor) (GLuint index, GLuint divisor); +typedef void (GLAPIENTRY * GLVertexAttribP1ui) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAPIENTRY * GLVertexAttribP1uiv) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexAttribP2ui) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAPIENTRY * GLVertexAttribP2uiv) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexAttribP3ui) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAPIENTRY * GLVertexAttribP3uiv) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexAttribP4ui) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (GLAPIENTRY * GLVertexAttribP4uiv) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexP2ui) (GLenum type, GLuint value); +typedef void (GLAPIENTRY * GLVertexP2uiv) (GLenum type, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexP3ui) (GLenum type, GLuint value); +typedef void (GLAPIENTRY * GLVertexP3uiv) (GLenum type, const GLuint *value); +typedef void (GLAPIENTRY * GLVertexP4ui) (GLenum type, GLuint value); +typedef void (GLAPIENTRY * GLVertexP4uiv) (GLenum type, const GLuint *value); +typedef void (GLAPIENTRY * GLTexCoordP1ui) (GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLTexCoordP1uiv) (GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLTexCoordP2ui) (GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLTexCoordP2uiv) (GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLTexCoordP3ui) (GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLTexCoordP3uiv) (GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLTexCoordP4ui) (GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLTexCoordP4uiv) (GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP1ui) (GLenum texture, GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP1uiv) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP2ui) (GLenum texture, GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP2uiv) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP3ui) (GLenum texture, GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP3uiv) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP4ui) (GLenum texture, GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLMultiTexCoordP4uiv) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLNormalP3ui) (GLenum type, GLuint coords); +typedef void (GLAPIENTRY * GLNormalP3uiv) (GLenum type, const GLuint *coords); +typedef void (GLAPIENTRY * GLColorP3ui) (GLenum type, GLuint color); +typedef void (GLAPIENTRY * GLColorP3uiv) (GLenum type, const GLuint *color); +typedef void (GLAPIENTRY * GLColorP4ui) (GLenum type, GLuint color); +typedef void (GLAPIENTRY * GLColorP4uiv) (GLenum type, const GLuint *color); +typedef void (GLAPIENTRY * GLSecondaryColorP3ui) (GLenum type, GLuint color); +typedef void (GLAPIENTRY * GLSecondaryColorP3uiv) (GLenum type, const GLuint *color); + + +// OpenGL 4.0 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 + +typedef void (GLAPIENTRY * GLMinSampleShading) (GLfloat value); +typedef void (GLAPIENTRY * GLBlendEquationi) (GLuint buf, GLenum mode); +typedef void (GLAPIENTRY * GLBlendEquationSeparatei) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (GLAPIENTRY * GLBlendFunci) (GLuint buf, GLenum src, GLenum dst); +typedef void (GLAPIENTRY * GLBlendFuncSeparatei) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (GLAPIENTRY * GLDrawArraysIndirect) (GLenum mode, const GLvoid *indirect); +typedef void (GLAPIENTRY * GLDrawElementsIndirect) (GLenum mode, GLenum type, const GLvoid *indirect); +typedef void (GLAPIENTRY * GLUniform1d) (GLint location, GLdouble x); +typedef void (GLAPIENTRY * GLUniform2d) (GLint location, GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLUniform3d) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLUniform4d) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLUniform1dv) (GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniform2dv) (GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniform3dv) (GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniform4dv) (GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix2dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix3dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix4dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix2x3dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix2x4dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix3x2dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix3x4dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix4x2dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLUniformMatrix4x3dv) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLGetUniformdv) (GLuint program, GLint location, GLdouble *params); +typedef GLint (GLAPIENTRY * GLGetSubroutineUniformLocation) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (GLAPIENTRY * GLGetSubroutineIndex) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (GLAPIENTRY * GLGetActiveSubroutineUniformiv) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (GLAPIENTRY * GLGetActiveSubroutineUniformName) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (GLAPIENTRY * GLGetActiveSubroutineName) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (GLAPIENTRY * GLUniformSubroutinesuiv) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (GLAPIENTRY * GLGetUniformSubroutineuiv) (GLenum shadertype, GLint location, GLuint *params); +typedef void (GLAPIENTRY * GLGetProgramStageiv) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +typedef void (GLAPIENTRY * GLPatchParameteri) (GLenum pname, GLint value); +typedef void (GLAPIENTRY * GLPatchParameterfv) (GLenum pname, const GLfloat *values); +typedef void (GLAPIENTRY * GLBindTransformFeedback) (GLenum target, GLuint id); +typedef void (GLAPIENTRY * GLDeleteTransformFeedbacks) (GLsizei n, const GLuint *ids); +typedef void (GLAPIENTRY * GLGenTransformFeedbacks) (GLsizei n, GLuint *ids); +typedef GLboolean (GLAPIENTRY * GLIsTransformFeedback) (GLuint id); +typedef void (GLAPIENTRY * GLPauseTransformFeedback) (void); +typedef void (GLAPIENTRY * GLResumeTransformFeedback) (void); +typedef void (GLAPIENTRY * GLDrawTransformFeedback) (GLenum mode, GLuint id); +typedef void (GLAPIENTRY * GLDrawTransformFeedbackStream) (GLenum mode, GLuint id, GLuint stream); +typedef void (GLAPIENTRY * GLBeginQueryIndexed) (GLenum target, GLuint index, GLuint id); +typedef void (GLAPIENTRY * GLEndQueryIndexed) (GLenum target, GLuint index); +typedef void (GLAPIENTRY * GLGetQueryIndexediv) (GLenum target, GLuint index, GLenum pname, GLint *params); + + +// OpenGL 4.1 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 + +typedef void (GLAPIENTRY * GLReleaseShaderCompiler) (void); +typedef void (GLAPIENTRY * GLShaderBinary) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +typedef void (GLAPIENTRY * GLGetShaderPrecisionFormat) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (GLAPIENTRY * GLDepthRangef) (GLfloat n, GLfloat f); +typedef void (GLAPIENTRY * GLClearDepthf) (GLfloat d); +typedef void (GLAPIENTRY * GLGetProgramBinary) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +typedef void (GLAPIENTRY * GLProgramBinary) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +typedef void (GLAPIENTRY * GLProgramParameteri) (GLuint program, GLenum pname, GLint value); +typedef void (GLAPIENTRY * GLUseProgramStages) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (GLAPIENTRY * GLActiveShaderProgram) (GLuint pipeline, GLuint program); +typedef GLuint (GLAPIENTRY * GLCreateShaderProgramv) (GLenum type, GLsizei count, const GLchar *const*strings); +typedef void (GLAPIENTRY * GLBindProgramPipeline) (GLuint pipeline); +typedef void (GLAPIENTRY * GLDeleteProgramPipelines) (GLsizei n, const GLuint *pipelines); +typedef void (GLAPIENTRY * GLGenProgramPipelines) (GLsizei n, GLuint *pipelines); +typedef GLboolean (GLAPIENTRY * GLIsProgramPipeline) (GLuint pipeline); +typedef void (GLAPIENTRY * GLGetProgramPipelineiv) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLProgramUniform1i) (GLuint program, GLint location, GLint v0); +typedef void (GLAPIENTRY * GLProgramUniform1iv) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform1f) (GLuint program, GLint location, GLfloat v0); +typedef void (GLAPIENTRY * GLProgramUniform1fv) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform1d) (GLuint program, GLint location, GLdouble v0); +typedef void (GLAPIENTRY * GLProgramUniform1dv) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniform1ui) (GLuint program, GLint location, GLuint v0); +typedef void (GLAPIENTRY * GLProgramUniform1uiv) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform2i) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (GLAPIENTRY * GLProgramUniform2iv) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform2f) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAPIENTRY * GLProgramUniform2fv) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform2d) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (GLAPIENTRY * GLProgramUniform2dv) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniform2ui) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (GLAPIENTRY * GLProgramUniform2uiv) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform3i) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAPIENTRY * GLProgramUniform3iv) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform3f) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAPIENTRY * GLProgramUniform3fv) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform3d) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (GLAPIENTRY * GLProgramUniform3dv) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniform3ui) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAPIENTRY * GLProgramUniform3uiv) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform4i) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAPIENTRY * GLProgramUniform4iv) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform4f) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAPIENTRY * GLProgramUniform4fv) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform4d) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (GLAPIENTRY * GLProgramUniform4dv) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniform4ui) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAPIENTRY * GLProgramUniform4uiv) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x3fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x2fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x4fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x2fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x4fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x3fv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x3dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x2dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x4dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x2dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x4dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x3dv) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (GLAPIENTRY * GLValidateProgramPipeline) (GLuint pipeline); +typedef void (GLAPIENTRY * GLGetProgramPipelineInfoLog) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (GLAPIENTRY * GLVertexAttribL1d) (GLuint index, GLdouble x); +typedef void (GLAPIENTRY * GLVertexAttribL2d) (GLuint index, GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * GLVertexAttribL3d) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLVertexAttribL4d) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLVertexAttribL1dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttribL2dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttribL3dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttribL4dv) (GLuint index, const GLdouble *v); +typedef void (GLAPIENTRY * GLVertexAttribLPointer) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLGetVertexAttribLdv) (GLuint index, GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * GLViewportArrayv) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (GLAPIENTRY * GLViewportIndexedf) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (GLAPIENTRY * GLViewportIndexedfv) (GLuint index, const GLfloat *v); +typedef void (GLAPIENTRY * GLScissorArrayv) (GLuint first, GLsizei count, const GLint *v); +typedef void (GLAPIENTRY * GLScissorIndexed) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLScissorIndexedv) (GLuint index, const GLint *v); +typedef void (GLAPIENTRY * GLDepthRangeArrayv) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (GLAPIENTRY * GLDepthRangeIndexed) (GLuint index, GLdouble n, GLdouble f); +typedef void (GLAPIENTRY * GLGetFloati_v) (GLenum target, GLuint index, GLfloat *data); +typedef void (GLAPIENTRY * GLGetDoublei_v) (GLenum target, GLuint index, GLdouble *data); + + +// OpenGL 4.2 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F + +typedef void (GLAPIENTRY * GLDrawArraysInstancedBaseInstance) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAPIENTRY * GLDrawElementsInstancedBaseInstance) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (GLAPIENTRY * GLDrawElementsInstancedBaseVertexBaseInstance) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (GLAPIENTRY * GLGetInternalformati64v) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (GLAPIENTRY * GLGetActiveAtomicCounterBufferiv) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLBindImageTexture) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (GLAPIENTRY * GLMemoryBarrier) (GLbitfield barriers); +typedef void (GLAPIENTRY * GLTexStorage1D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAPIENTRY * GLTexStorage2D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLTexStorage3D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAPIENTRY * GLDrawTransformFeedbackInstanced) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (GLAPIENTRY * GLDrawTransformFeedbackStreamInstanced) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); + + +// OpenGL 4.3 +typedef void (GLAPIENTRY * GLDEBUGPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); + +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_LOCAL_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_LOCAL_WORK_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_DISPLAY_LIST 0x82E7 + +typedef void (GLAPIENTRY * GLClearBufferData) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (GLAPIENTRY * GLClearBufferSubData) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (GLAPIENTRY * GLDispatchCompute) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (GLAPIENTRY * GLDispatchComputeIndirect) (GLintptr indirect); +typedef void (GLAPIENTRY * GLCopyImageSubData) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (GLAPIENTRY * GLFramebufferParameteri) (GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLGetFramebufferParameteriv) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLInvalidateTexSubImage) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GLAPIENTRY * GLInvalidateTexImage) (GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLInvalidateBufferSubData) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (GLAPIENTRY * GLInvalidateBufferData) (GLuint buffer); +typedef void (GLAPIENTRY * GLInvalidateFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (GLAPIENTRY * GLInvalidateSubFramebuffer) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLMultiDrawArraysIndirect) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAPIENTRY * GLMultiDrawElementsIndirect) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (GLAPIENTRY * GLGetProgramInterfaceiv) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (GLAPIENTRY * GLGetProgramResourceIndex) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (GLAPIENTRY * GLGetProgramResourceName) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (GLAPIENTRY * GLGetProgramResourceiv) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (GLAPIENTRY * GLGetProgramResourceLocation) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (GLAPIENTRY * GLGetProgramResourceLocationIndex) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (GLAPIENTRY * GLShaderStorageBlockBinding) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void (GLAPIENTRY * GLTexBufferRange) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (GLAPIENTRY * GLTexStorage2DMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLTexStorage3DMultisample) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLTextureStorage2DMultisampleEXT) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLTextureStorage3DMultisampleEXT) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (GLAPIENTRY * GLTextureView) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (GLAPIENTRY * GLBindVertexBuffer) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (GLAPIENTRY * GLVertexAttribFormat) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (GLAPIENTRY * GLVertexAttribIFormat) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (GLAPIENTRY * GLVertexAttribLFormat) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (GLAPIENTRY * GLVertexAttribBinding) (GLuint attribindex, GLuint bindingindex); +typedef void (GLAPIENTRY * GLVertexBindingDivisor) (GLuint bindingindex, GLuint divisor); +typedef void (GLAPIENTRY * GLDebugMessageControl) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (GLAPIENTRY * GLDebugMessageInsert) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (GLAPIENTRY * GLDebugMessageCallback) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (GLAPIENTRY * GLGetDebugMessageLog) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (GLAPIENTRY * GLPushDebugGroup) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (GLAPIENTRY * GLPopDebugGroup) (void); +typedef void (GLAPIENTRY * GLObjectLabel) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (GLAPIENTRY * GLGetObjectLabel) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (GLAPIENTRY * GLObjectPtrLabel) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (GLAPIENTRY * GLGetObjectPtrLabel) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); + + +// EXT_texture_filter_anisotropic +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + + +// EXT_direct_state_access +#define GL_PROGRAM_MATRIX_EXT 0x8E2D +#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F + +typedef void (GLAPIENTRY * GLMatrixLoadfEXT) (GLenum mode, const GLfloat *m); +typedef void (GLAPIENTRY * GLMatrixLoaddEXT) (GLenum mode, const GLdouble *m); +typedef void (GLAPIENTRY * GLMatrixMultfEXT) (GLenum mode, const GLfloat *m); +typedef void (GLAPIENTRY * GLMatrixMultdEXT) (GLenum mode, const GLdouble *m); +typedef void (GLAPIENTRY * GLMatrixLoadIdentityEXT) (GLenum mode); +typedef void (GLAPIENTRY * GLMatrixRotatefEXT) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLMatrixRotatedEXT) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLMatrixScalefEXT) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLMatrixScaledEXT) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLMatrixTranslatefEXT) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * GLMatrixTranslatedEXT) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * GLMatrixFrustumEXT) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAPIENTRY * GLMatrixOrthoEXT) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAPIENTRY * GLMatrixPopEXT) (GLenum mode); +typedef void (GLAPIENTRY * GLMatrixPushEXT) (GLenum mode); +typedef void (GLAPIENTRY * GLClientAttribDefaultEXT) (GLbitfield mask); +typedef void (GLAPIENTRY * GLPushClientAttribDefaultEXT) (GLbitfield mask); +typedef void (GLAPIENTRY * GLTextureParameterfEXT) (GLuint texture, GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLTextureParameterfvEXT) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLTextureParameteriEXT) (GLuint texture, GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLTextureParameterivEXT) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLTextureImage1DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTextureImage2DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTextureSubImage1DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTextureSubImage2DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyTextureImage1DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAPIENTRY * GLCopyTextureImage2DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAPIENTRY * GLCopyTextureSubImage1DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAPIENTRY * GLCopyTextureSubImage2DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLGetTextureImageEXT) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * GLGetTextureParameterfvEXT) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTextureParameterivEXT) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetTextureLevelParameterfvEXT) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetTextureLevelParameterivEXT) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLTextureImage3DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLTextureSubImage3DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyTextureSubImage3DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLBindMultiTextureEXT) (GLenum texunit, GLenum target, GLuint texture); +typedef void (GLAPIENTRY * GLMultiTexCoordPointerEXT) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * GLMultiTexEnvfEXT) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLMultiTexEnvfvEXT) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLMultiTexEnviEXT) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLMultiTexEnvivEXT) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLMultiTexGendEXT) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +typedef void (GLAPIENTRY * GLMultiTexGendvEXT) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +typedef void (GLAPIENTRY * GLMultiTexGenfEXT) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLMultiTexGenfvEXT) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLMultiTexGeniEXT) (GLenum texunit, GLenum coord, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLMultiTexGenivEXT) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLGetMultiTexEnvfvEXT) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetMultiTexEnvivEXT) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetMultiTexGendvEXT) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * GLGetMultiTexGenfvEXT) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetMultiTexGenivEXT) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLMultiTexParameteriEXT) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * GLMultiTexParameterivEXT) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLMultiTexParameterfEXT) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * GLMultiTexParameterfvEXT) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * GLMultiTexImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLMultiTexImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLMultiTexSubImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLMultiTexSubImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyMultiTexImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAPIENTRY * GLCopyMultiTexImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAPIENTRY * GLCopyMultiTexSubImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAPIENTRY * GLCopyMultiTexSubImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLGetMultiTexImageEXT) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * GLGetMultiTexParameterfvEXT) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetMultiTexParameterivEXT) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetMultiTexLevelParameterfvEXT) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * GLGetMultiTexLevelParameterivEXT) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLMultiTexImage3DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLMultiTexSubImage3DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * GLCopyMultiTexSubImage3DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLEnableClientStateIndexedEXT) (GLenum array, GLuint index); +typedef void (GLAPIENTRY * GLDisableClientStateIndexedEXT) (GLenum array, GLuint index); +typedef void (GLAPIENTRY * GLGetFloatIndexedvEXT) (GLenum target, GLuint index, GLfloat *data); +typedef void (GLAPIENTRY * GLGetDoubleIndexedvEXT) (GLenum target, GLuint index, GLdouble *data); +typedef void (GLAPIENTRY * GLGetPointerIndexedvEXT) (GLenum target, GLuint index, GLvoid **data); +typedef void (GLAPIENTRY * GLEnableIndexedEXT) (GLenum target, GLuint index); +typedef void (GLAPIENTRY * GLDisableIndexedEXT) (GLenum target, GLuint index); +typedef GLboolean (GLAPIENTRY * GLIsEnabledIndexedEXT) (GLenum target, GLuint index); +typedef void (GLAPIENTRY * GLGetIntegerIndexedvEXT) (GLenum target, GLuint index, GLint *data); +typedef void (GLAPIENTRY * GLGetBooleanIndexedvEXT) (GLenum target, GLuint index, GLboolean *data); +typedef void (GLAPIENTRY * GLCompressedTextureImage3DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedTextureImage2DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedTextureImage1DEXT) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedTextureSubImage3DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedTextureSubImage2DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedTextureSubImage1DEXT) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLGetCompressedTextureImageEXT) (GLuint texture, GLenum target, GLint lod, GLvoid *img); +typedef void (GLAPIENTRY * GLCompressedMultiTexImage3DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedMultiTexImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedMultiTexImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedMultiTexSubImage3DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedMultiTexSubImage2DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLCompressedMultiTexSubImage1DEXT) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (GLAPIENTRY * GLGetCompressedMultiTexImageEXT) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); +typedef void (GLAPIENTRY * GLMatrixLoadTransposefEXT) (GLenum mode, const GLfloat *m); +typedef void (GLAPIENTRY * GLMatrixLoadTransposedEXT) (GLenum mode, const GLdouble *m); +typedef void (GLAPIENTRY * GLMatrixMultTransposefEXT) (GLenum mode, const GLfloat *m); +typedef void (GLAPIENTRY * GLMatrixMultTransposedEXT) (GLenum mode, const GLdouble *m); +typedef void (GLAPIENTRY * GLNamedBufferDataEXT) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (GLAPIENTRY * GLNamedBufferSubDataEXT) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void * (GLAPIENTRY * GLMapNamedBufferEXT) (GLuint buffer, GLenum access); +typedef GLboolean (GLAPIENTRY * GLUnmapNamedBufferEXT) (GLuint buffer); +typedef void (GLAPIENTRY * GLGetNamedBufferParameterivEXT) (GLuint buffer, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetNamedBufferPointervEXT) (GLuint buffer, GLenum pname, GLvoid **params); +typedef void (GLAPIENTRY * GLGetNamedBufferSubDataEXT) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void (GLAPIENTRY * GLProgramUniform1fEXT) (GLuint program, GLint location, GLfloat v0); +typedef void (GLAPIENTRY * GLProgramUniform2fEXT) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (GLAPIENTRY * GLProgramUniform3fEXT) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (GLAPIENTRY * GLProgramUniform4fEXT) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (GLAPIENTRY * GLProgramUniform1iEXT) (GLuint program, GLint location, GLint v0); +typedef void (GLAPIENTRY * GLProgramUniform2iEXT) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (GLAPIENTRY * GLProgramUniform3iEXT) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (GLAPIENTRY * GLProgramUniform4iEXT) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (GLAPIENTRY * GLProgramUniform1fvEXT) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform2fvEXT) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform3fvEXT) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform4fvEXT) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniform1ivEXT) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform2ivEXT) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform3ivEXT) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniform4ivEXT) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x3fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x2fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix2x4fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x2fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix3x4fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLProgramUniformMatrix4x3fvEXT) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GLAPIENTRY * GLTextureBufferEXT) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAPIENTRY * GLMultiTexBufferEXT) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (GLAPIENTRY * GLTextureParameterIivEXT) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLTextureParameterIuivEXT) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +typedef void (GLAPIENTRY * GLGetTextureParameterIivEXT) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetTextureParameterIuivEXT) (GLuint texture, GLenum target, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLMultiTexParameterIivEXT) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * GLMultiTexParameterIuivEXT) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +typedef void (GLAPIENTRY * GLGetMultiTexParameterIivEXT) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetMultiTexParameterIuivEXT) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +typedef void (GLAPIENTRY * GLProgramUniform1uiEXT) (GLuint program, GLint location, GLuint v0); +typedef void (GLAPIENTRY * GLProgramUniform2uiEXT) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (GLAPIENTRY * GLProgramUniform3uiEXT) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (GLAPIENTRY * GLProgramUniform4uiEXT) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (GLAPIENTRY * GLProgramUniform1uivEXT) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform2uivEXT) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform3uivEXT) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLProgramUniform4uivEXT) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameters4fvEXT) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameterI4iEXT) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameterI4ivEXT) (GLuint program, GLenum target, GLuint index, const GLint *params); +typedef void (GLAPIENTRY * GLNamedProgramLocalParametersI4ivEXT) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameterI4uiEXT) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameterI4uivEXT) (GLuint program, GLenum target, GLuint index, const GLuint *params); +typedef void (GLAPIENTRY * GLNamedProgramLocalParametersI4uivEXT) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (GLAPIENTRY * GLGetNamedProgramLocalParameterIivEXT) (GLuint program, GLenum target, GLuint index, GLint *params); +typedef void (GLAPIENTRY * GLGetNamedProgramLocalParameterIuivEXT) (GLuint program, GLenum target, GLuint index, GLuint *params); +typedef void (GLAPIENTRY * GLEnableClientStateiEXT) (GLenum array, GLuint index); +typedef void (GLAPIENTRY * GLDisableClientStateiEXT) (GLenum array, GLuint index); +typedef void (GLAPIENTRY * GLGetFloati_vEXT) (GLenum pname, GLuint index, GLfloat *params); +typedef void (GLAPIENTRY * GLGetDoublei_vEXT) (GLenum pname, GLuint index, GLdouble *params); +typedef void (GLAPIENTRY * GLGetPointeri_vEXT) (GLenum pname, GLuint index, GLvoid **params); +typedef void (GLAPIENTRY * GLNamedProgramStringEXT) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameter4dEXT) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameter4dvEXT) (GLuint program, GLenum target, GLuint index, const GLdouble *params); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameter4fEXT) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * GLNamedProgramLocalParameter4fvEXT) (GLuint program, GLenum target, GLuint index, const GLfloat *params); +typedef void (GLAPIENTRY * GLGetNamedProgramLocalParameterdvEXT) (GLuint program, GLenum target, GLuint index, GLdouble *params); +typedef void (GLAPIENTRY * GLGetNamedProgramLocalParameterfvEXT) (GLuint program, GLenum target, GLuint index, GLfloat *params); +typedef void (GLAPIENTRY * GLGetNamedProgramivEXT) (GLuint program, GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGetNamedProgramStringEXT) (GLuint program, GLenum target, GLenum pname, GLvoid *string); +typedef void (GLAPIENTRY * GLNamedRenderbufferStorageEXT) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLGetNamedRenderbufferParameterivEXT) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLNamedRenderbufferStorageMultisampleEXT) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLNamedRenderbufferStorageMultisampleCoverageEXT) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef GLenum (GLAPIENTRY * GLCheckNamedFramebufferStatusEXT) (GLuint framebuffer, GLenum target); +typedef void (GLAPIENTRY * GLNamedFramebufferTexture1DEXT) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLNamedFramebufferTexture2DEXT) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLNamedFramebufferTexture3DEXT) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (GLAPIENTRY * GLNamedFramebufferRenderbufferEXT) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (GLAPIENTRY * GLGetNamedFramebufferAttachmentParameterivEXT) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLGenerateTextureMipmapEXT) (GLuint texture, GLenum target); +typedef void (GLAPIENTRY * GLGenerateMultiTexMipmapEXT) (GLenum texunit, GLenum target); +typedef void (GLAPIENTRY * GLFramebufferDrawBufferEXT) (GLuint framebuffer, GLenum mode); +typedef void (GLAPIENTRY * GLFramebufferDrawBuffersEXT) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (GLAPIENTRY * GLFramebufferReadBufferEXT) (GLuint framebuffer, GLenum mode); +typedef void (GLAPIENTRY * GLGetFramebufferParameterivEXT) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * GLNamedCopyBufferSubDataEXT) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (GLAPIENTRY * GLNamedFramebufferTextureEXT) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (GLAPIENTRY * GLNamedFramebufferTextureLayerEXT) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (GLAPIENTRY * GLNamedFramebufferTextureFaceEXT) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void (GLAPIENTRY * GLTextureRenderbufferEXT) (GLuint texture, GLenum target, GLuint renderbuffer); +typedef void (GLAPIENTRY * GLMultiTexRenderbufferEXT) (GLenum texunit, GLenum target, GLuint renderbuffer); +typedef void (GLAPIENTRY * GLVertexArrayVertexOffsetEXT) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayColorOffsetEXT) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayEdgeFlagOffsetEXT) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayIndexOffsetEXT) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayNormalOffsetEXT) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayTexCoordOffsetEXT) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayMultiTexCoordOffsetEXT) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayFogCoordOffsetEXT) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArraySecondaryColorOffsetEXT) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayVertexAttribOffsetEXT) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLVertexArrayVertexAttribIOffsetEXT) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (GLAPIENTRY * GLEnableVertexArrayEXT) (GLuint vaobj, GLenum array); +typedef void (GLAPIENTRY * GLDisableVertexArrayEXT) (GLuint vaobj, GLenum array); +typedef void (GLAPIENTRY * GLEnableVertexArrayAttribEXT) (GLuint vaobj, GLuint index); +typedef void (GLAPIENTRY * GLDisableVertexArrayAttribEXT) (GLuint vaobj, GLuint index); +typedef void (GLAPIENTRY * GLGetVertexArrayIntegervEXT) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (GLAPIENTRY * GLGetVertexArrayPointervEXT) (GLuint vaobj, GLenum pname, GLvoid **param); +typedef void (GLAPIENTRY * GLGetVertexArrayIntegeri_vEXT) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (GLAPIENTRY * GLGetVertexArrayPointeri_vEXT) (GLuint vaobj, GLuint index, GLenum pname, GLvoid **param); +typedef void * (GLAPIENTRY * GLMapNamedBufferRangeEXT) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (GLAPIENTRY * GLFlushMappedNamedBufferRangeEXT) (GLuint buffer, GLintptr offset, GLsizeiptr length); + + +// ARB_texture_storage +typedef void (GLAPIENTRY * GLTextureStorage1DEXT) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GLAPIENTRY * GLTextureStorage2DEXT) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * GLTextureStorage3DEXT) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + + +// NV_path_rendering +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D + +typedef GLuint (GLAPIENTRY * GLGenPathsNV) (GLsizei range); +typedef void (GLAPIENTRY * GLDeletePathsNV) (GLuint path, GLsizei range); +typedef GLboolean (GLAPIENTRY * GLIsPathNV) (GLuint path); +typedef void (GLAPIENTRY * GLPathCommandsNV) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (GLAPIENTRY * GLPathCoordsNV) (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (GLAPIENTRY * GLPathSubCommandsNV) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (GLAPIENTRY * GLPathSubCoordsNV) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (GLAPIENTRY * GLPathStringNV) (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); +typedef void (GLAPIENTRY * GLPathGlyphsNV) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (GLAPIENTRY * GLPathGlyphRangeNV) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (GLAPIENTRY * GLWeightPathsNV) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (GLAPIENTRY * GLCopyPathNV) (GLuint resultPath, GLuint srcPath); +typedef void (GLAPIENTRY * GLInterpolatePathsNV) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (GLAPIENTRY * GLTransformPathNV) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (GLAPIENTRY * GLPathParameterivNV) (GLuint path, GLenum pname, const GLint *value); +typedef void (GLAPIENTRY * GLPathParameteriNV) (GLuint path, GLenum pname, GLint value); +typedef void (GLAPIENTRY * GLPathParameterfvNV) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (GLAPIENTRY * GLPathParameterfNV) (GLuint path, GLenum pname, GLfloat value); +typedef void (GLAPIENTRY * GLPathDashArrayNV) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (GLAPIENTRY * GLPathStencilFuncNV) (GLenum func, GLint ref, GLuint mask); +typedef void (GLAPIENTRY * GLPathStencilDepthOffsetNV) (GLfloat factor, GLfloat units); +typedef void (GLAPIENTRY * GLStencilFillPathNV) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (GLAPIENTRY * GLStencilStrokePathNV) (GLuint path, GLint reference, GLuint mask); +typedef void (GLAPIENTRY * GLStencilFillPathInstancedNV) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (GLAPIENTRY * GLStencilStrokePathInstancedNV) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (GLAPIENTRY * GLPathCoverDepthFuncNV) (GLenum func); +typedef void (GLAPIENTRY * GLPathColorGenNV) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (GLAPIENTRY * GLPathTexGenNV) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (GLAPIENTRY * GLPathFogGenNV) (GLenum genMode); +typedef void (GLAPIENTRY * GLCoverFillPathNV) (GLuint path, GLenum coverMode); +typedef void (GLAPIENTRY * GLCoverStrokePathNV) (GLuint path, GLenum coverMode); +typedef void (GLAPIENTRY * GLCoverFillPathInstancedNV) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (GLAPIENTRY * GLCoverStrokePathInstancedNV) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (GLAPIENTRY * GLGetPathParameterivNV) (GLuint path, GLenum pname, GLint *value); +typedef void (GLAPIENTRY * GLGetPathParameterfvNV) (GLuint path, GLenum pname, GLfloat *value); +typedef void (GLAPIENTRY * GLGetPathCommandsNV) (GLuint path, GLubyte *commands); +typedef void (GLAPIENTRY * GLGetPathCoordsNV) (GLuint path, GLfloat *coords); +typedef void (GLAPIENTRY * GLGetPathDashArrayNV) (GLuint path, GLfloat *dashArray); +typedef void (GLAPIENTRY * GLGetPathMetricsNV) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (GLAPIENTRY * GLGetPathMetricRangeNV) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (GLAPIENTRY * GLGetPathSpacingNV) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (GLAPIENTRY * GLGetPathColorGenivNV) (GLenum color, GLenum pname, GLint *value); +typedef void (GLAPIENTRY * GLGetPathColorGenfvNV) (GLenum color, GLenum pname, GLfloat *value); +typedef void (GLAPIENTRY * GLGetPathTexGenivNV) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (GLAPIENTRY * GLGetPathTexGenfvNV) (GLenum texCoordSet, GLenum pname, GLfloat *value); +typedef GLboolean (GLAPIENTRY * GLIsPointInFillPathNV) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (GLAPIENTRY * GLIsPointInStrokePathNV) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (GLAPIENTRY * GLGetPathLengthNV) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (GLAPIENTRY * GLPointAlongPathNV) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); + + +// NV_blend_equation_advanced +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_DISJOINT_NV 0x9283 +#define GL_CONJOINT_NV 0x9284 +#define GL_SRC_NV 0x9286 +#define GL_DST_NV 0x9287 +#define GL_SRC_OVER_NV 0x9288 +#define GL_DST_OVER_NV 0x9289 +#define GL_SRC_IN_NV 0x928A +#define GL_DST_IN_NV 0x928B +#define GL_SRC_OUT_NV 0x928C +#define GL_DST_OUT_NV 0x928D +#define GL_SRC_ATOP_NV 0x928E +#define GL_DST_ATOP_NV 0x928F +#define GL_MULTIPLY_NV 0x9294 +#define GL_SCREEN_NV 0x9295 +#define GL_OVERLAY_NV 0x9296 +#define GL_DARKEN_NV 0x9297 +#define GL_LIGHTEN_NV 0x9298 +#define GL_COLORDODGE_NV 0x9299 +#define GL_COLORBURN_NV 0x929A +#define GL_HARDLIGHT_NV 0x929B +#define GL_SOFTLIGHT_NV 0x929C +#define GL_DIFFERENCE_NV 0x929E +#define GL_EXCLUSION_NV 0x92A0 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_PLUS_NV 0x9291 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_MINUS_NV 0x929F +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_CONTRAST_NV 0x92A1 +#define GL_INVERT_OVG_NV 0x92B4 + +typedef void (GLAPIENTRY * GLBlendParameteriNV) (GLenum pname, GLint value); +typedef void (GLAPIENTRY * GLBlendBarrierNV) (void); + +#undef GLAPIENTRY + +#endif /* MOZILLA_GFX_NVPR_GLDEFS_H_ */ diff --git a/libazure/nvpr/GLX.cpp b/libazure/nvpr/GLX.cpp new file mode 100644 index 0000000..bfea7a3 --- /dev/null +++ b/libazure/nvpr/GLX.cpp @@ -0,0 +1,179 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLX.h" +#include "Logging.h" +#include +#include +#include +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +void +InitializeGLIfNeeded() +{ + if (gl) { + return; + } + gl = new GLX(); +} + +template bool +GLX::LoadProcAddress(T C::*aProc, const char* aName) +{ + void (*proc)() = GetProcAddress(reinterpret_cast(aName)); + if (!proc) { + gfxWarning() << "Failed to load GL function " << aName << "."; + proc = nullptr; + return false; + } + this->*aProc = reinterpret_cast(proc); + return true; +} + +GLX::GLX() + : mLibGL(nullptr) + , mDisplay(nullptr) + , mPixmap(0) + , mGLXPixmap(0) + , mContext(nullptr) +{ + memset(mSupportedGLXExtensions, 0, sizeof(mSupportedGLXExtensions)); + + mLibGL = dlopen("libGL.so", RTLD_LAZY); + if (!mLibGL) { + return; + } + +#define LOAD_GLX_METHOD(NAME) \ + NAME = reinterpret_cast(dlsym(mLibGL, "glX"#NAME)); \ + if (!NAME) { \ + gfxWarning() << "Failed to find GLX function " #NAME "."; \ + return; \ + } + + FOR_ALL_GLX_ENTRY_POINTS(LOAD_GLX_METHOD); + +#undef LOAD_GLX_METHOD + + mDisplay = XOpenDisplay(0); + + int nelements; + int screen = DefaultScreen(mDisplay); + GLXFBConfig *fbc = ChooseFBConfig(mDisplay, screen, 0, &nelements); + XVisualInfo *vi = GetVisualFromFBConfig(mDisplay, fbc[0]); + + mPixmap = XCreatePixmap(mDisplay, RootWindow(mDisplay, vi->screen), + 10, 10, vi->depth); + mGLXPixmap = CreateGLXPixmap(mDisplay, vi, mPixmap); + + mContext = CreateContext(mDisplay, vi, 0, true); + + GL::MakeCurrent(); + + stringstream extensions(QueryExtensionsString(mDisplay, screen)); + istream_iterator iter(extensions); + istream_iterator end; + + for (; iter != end; iter++) { + const string& extension = *iter; + + if (*iter == "GLX_NV_copy_image") { + if (LoadProcAddress(&GLX::CopyImageSubDataNV, "glXCopyImageSubDataNV")) { + mSupportedGLXExtensions[NV_copy_image] = true; + } + break; + } + } + +#define LOAD_GL_METHOD(NAME) \ + if (!LoadProcAddress(&GLX::NAME, "gl"#NAME)) { \ + return; \ + } + + FOR_ALL_PUBLIC_GL_ENTRY_POINTS(LOAD_GL_METHOD); + FOR_ALL_PRIVATE_GL_ENTRY_POINTS(LOAD_GL_METHOD); + +#undef LOAD_GL_METHOD + + Initialize(); +} + +GLX::~GLX() +{ + if (mDisplay) { + MakeCurrent(mDisplay, 0, 0); + } + + if (mContext) { + DestroyContext(mDisplay, mContext); + } + + if (mGLXPixmap) { + DestroyGLXPixmap(mDisplay, mGLXPixmap); + } + + if (mPixmap) { + XFreePixmap(mDisplay, mPixmap); + } + + if (mDisplay) { + XCloseDisplay(mDisplay); + } + + if (mLibGL) { + dlclose(mLibGL); + } +} + +bool +GL::IsCurrent() const +{ + const GLX* const glx = static_cast(this); + + return glx->GetCurrentContext() == glx->Context(); +} + +void +GL::MakeCurrent() const +{ + const GLX* const glx = static_cast(this); + + if (IsCurrent()) { + return; + } + + glx->MakeCurrent(glx->Display(), glx->Drawable(), glx->Context()); +} + +bool +GL::BlitTextureToForeignTexture(const IntSize& aSize, GLuint aSourceTextureId, + void* aForeignContext, GLuint aForeignTextureId) +{ + GLX* const glx = static_cast(this); + + if (!glx->HasGLXExtension(GLX::NV_copy_image)) { + return false; + } + + glx->CopyImageSubDataNV(glx->Display(), glx->Context(), aSourceTextureId, + GL_TEXTURE_2D, 0, 0, 0, 0, + static_cast(aForeignContext), + aForeignTextureId, GL_TEXTURE_2D, 0, 0, 0, 0, + aSize.width, aSize.height, 1); + + return true; +} + +} +} +} diff --git a/libazure/nvpr/GLX.h b/libazure/nvpr/GLX.h new file mode 100644 index 0000000..d72fb76 --- /dev/null +++ b/libazure/nvpr/GLX.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_GLX_H_ +#define MOZILLA_GFX_NVPR_GLX_H_ + +#include "GL.h" +#include "GLXDefs.h" + +namespace mozilla { +namespace gfx { +namespace nvpr { + +class GLX : public GL +{ +public: + GLX(); + virtual ~GLX(); + + ::Display* Display() const { return mDisplay; } + GLXPixmap Drawable() const { return mGLXPixmap; } + GLXContext Context() const { return mContext; } + + enum GLXExtension { + NV_copy_image, + GLX_EXTENSION_COUNT + }; + bool HasGLXExtension(GLXExtension aExtension) const + { + return mSupportedGLXExtensions[aExtension]; + } + +#define FOR_ALL_GLX_ENTRY_POINTS(MACRO) \ + MACRO(ChooseFBConfig) \ + MACRO(GetVisualFromFBConfig) \ + MACRO(CreateGLXPixmap) \ + MACRO(DestroyGLXPixmap) \ + MACRO(CreateContext) \ + MACRO(DestroyContext) \ + MACRO(GetProcAddress) \ + MACRO(GetCurrentContext) \ + MACRO(MakeCurrent) \ + MACRO(QueryExtensionsString) + +#define DECLARE_GLX_METHOD(NAME) \ + GLX##NAME NAME; + + FOR_ALL_GLX_ENTRY_POINTS(DECLARE_GLX_METHOD); + +#undef DECLARE_GLX_METHOD + + GLXCopyImageSubDataNV CopyImageSubDataNV; + +private: + template bool + LoadProcAddress(T C::*aProc, const char* aName); + + void* mLibGL; + ::Display* mDisplay; + Pixmap mPixmap; + GLXPixmap mGLXPixmap; + GLXContext mContext; + bool mSupportedGLXExtensions[GLX_EXTENSION_COUNT]; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_GLX_H_ */ diff --git a/libazure/nvpr/GLXDefs.h b/libazure/nvpr/GLXDefs.h new file mode 100644 index 0000000..5578984 --- /dev/null +++ b/libazure/nvpr/GLXDefs.h @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_GLXDEFS_H_ +#define MOZILLA_GFX_NVPR_GLXDEFS_H_ + +#include "GLDefs.h" +#include +#include + +// GLX core +typedef struct __GLXcontextRec *GLXContext; +typedef XID GLXPixmap; +typedef XID GLXDrawable; +typedef struct __GLXFBConfigRec *GLXFBConfig; +typedef XID GLXFBConfigID; +typedef XID GLXContextID; +typedef XID GLXWindow; +typedef XID GLXPbuffer; + +#define GLX_USE_GL 1 +#define GLX_BUFFER_SIZE 2 +#define GLX_LEVEL 3 +#define GLX_RGBA 4 +#define GLX_DOUBLEBUFFER 5 +#define GLX_STEREO 6 +#define GLX_AUX_BUFFERS 7 +#define GLX_RED_SIZE 8 +#define GLX_GREEN_SIZE 9 +#define GLX_BLUE_SIZE 10 +#define GLX_ALPHA_SIZE 11 +#define GLX_DEPTH_SIZE 12 +#define GLX_STENCIL_SIZE 13 +#define GLX_ACCUM_RED_SIZE 14 +#define GLX_ACCUM_GREEN_SIZE 15 +#define GLX_ACCUM_BLUE_SIZE 16 +#define GLX_ACCUM_ALPHA_SIZE 17 +#define GLX_BAD_SCREEN 1 +#define GLX_BAD_ATTRIBUTE 2 +#define GLX_NO_EXTENSION 3 +#define GLX_BAD_VISUAL 4 +#define GLX_BAD_CONTEXT 5 +#define GLX_BAD_VALUE 6 +#define GLX_BAD_ENUM 7 +#define GLX_VENDOR 1 +#define GLX_VERSION 2 +#define GLX_EXTENSIONS 3 +#define GLX_CONFIG_CAVEAT 0x20 +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_X_VISUAL_TYPE 0x22 +#define GLX_TRANSPARENT_TYPE 0x23 +#define GLX_TRANSPARENT_INDEX_VALUE 0x24 +#define GLX_TRANSPARENT_RED_VALUE 0x25 +#define GLX_TRANSPARENT_GREEN_VALUE 0x26 +#define GLX_TRANSPARENT_BLUE_VALUE 0x27 +#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PBUFFER_BIT 0x00000004 +#define GLX_AUX_BUFFERS_BIT 0x00000010 +#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 +#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 +#define GLX_DEPTH_BUFFER_BIT 0x00000020 +#define GLX_STENCIL_BUFFER_BIT 0x00000040 +#define GLX_ACCUM_BUFFER_BIT 0x00000080 +#define GLX_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_PSEUDO_COLOR 0x8004 +#define GLX_STATIC_COLOR 0x8005 +#define GLX_GRAY_SCALE 0x8006 +#define GLX_STATIC_GRAY 0x8007 +#define GLX_TRANSPARENT_RGB 0x8008 +#define GLX_TRANSPARENT_INDEX 0x8009 +#define GLX_VISUAL_ID 0x800B +#define GLX_SCREEN 0x800C +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_DRAWABLE_TYPE 0x8010 +#define GLX_RENDER_TYPE 0x8011 +#define GLX_X_RENDERABLE 0x8012 +#define GLX_FBCONFIG_ID 0x8013 +#define GLX_RGBA_TYPE 0x8014 +#define GLX_COLOR_INDEX_TYPE 0x8015 +#define GLX_MAX_PBUFFER_WIDTH 0x8016 +#define GLX_MAX_PBUFFER_HEIGHT 0x8017 +#define GLX_MAX_PBUFFER_PIXELS 0x8018 +#define GLX_PRESERVED_CONTENTS 0x801B +#define GLX_LARGEST_PBUFFER 0x801C +#define GLX_WIDTH 0x801D +#define GLX_HEIGHT 0x801E +#define GLX_EVENT_MASK 0x801F +#define GLX_DAMAGED 0x8020 +#define GLX_SAVED 0x8021 +#define GLX_WINDOW 0x8022 +#define GLX_PBUFFER 0x8023 +#define GLX_PBUFFER_HEIGHT 0x8040 +#define GLX_PBUFFER_WIDTH 0x8041 +#define GLX_RGBA_BIT 0x00000001 +#define GLX_COLOR_INDEX_BIT 0x00000002 +#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 +#define GLX_SAMPLE_BUFFERS 0x186a0 +#define GLX_SAMPLES 0x186a1 + +typedef XVisualInfo* (* GLXChooseVisual) (Display *dpy, int screen, int *attribList); +typedef GLXContext (* GLXCreateContext) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +typedef void (* GLXDestroyContext) (Display *dpy, GLXContext ctx); +typedef Bool (* GLXMakeCurrent) (Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (* GLXCopyContext) (Display *dpy, GLXContext src, GLXContext dst, unsigned long mask); +typedef void (* GLXSwapBuffers) (Display *dpy, GLXDrawable drawable); +typedef GLXPixmap (* GLXCreateGLXPixmap) (Display *dpy, XVisualInfo *visual, Pixmap pixmap); +typedef void (* GLXDestroyGLXPixmap) (Display *dpy, GLXPixmap pixmap); +typedef Bool (* GLXQueryExtension) (Display *dpy, int *errorb, int *event); +typedef Bool (* GLXQueryVersion) (Display *dpy, int *maj, int *min); +typedef Bool (* GLXIsDirect) (Display *dpy, GLXContext ctx); +typedef int (* GLXGetConfig) (Display *dpy, XVisualInfo *visual, int attrib, int *value); +typedef GLXContext (* GLXGetCurrentContext) (void); +typedef GLXDrawable (* GLXGetCurrentDrawable) (void); +typedef void (* GLXWaitGL) (void); +typedef void (* GLXWaitX) (void); +typedef void (* GLXUseXFont) (Font font, int first, int count, int list); +typedef const char * (* GLXQueryExtensionsString) (Display *dpy, int screen); +typedef const char * (* GLXQueryServerString) (Display *dpy, int screen, int name); +typedef const char * (* GLXGetClientString) (Display *dpy, int name); +typedef Display * (* GLXGetCurrentDisplay) (void); +typedef GLXFBConfig * (* GLXChooseFBConfig) (Display *dpy, int screen, const int *attribList, int *nitems); +typedef int (* GLXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value); +typedef GLXFBConfig * (* GLXGetFBConfigs) (Display *dpy, int screen, int *nelements); +typedef XVisualInfo * (* GLXGetVisualFromFBConfig) (Display *dpy, GLXFBConfig config); +typedef GLXWindow (* GLXCreateWindow) (Display *dpy, GLXFBConfig config, Window win, const int *attribList); +typedef void (* GLXDestroyWindow) (Display *dpy, GLXWindow window); +typedef GLXPixmap (* GLXCreatePixmap) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList); +typedef void (* GLXDestroyPixmap) (Display *dpy, GLXPixmap pixmap); +typedef GLXPbuffer (* GLXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attribList); +typedef void (* GLXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf); +typedef void (* GLXQueryDrawable) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); +typedef GLXContext (* GLXCreateNewContext) (Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct); +typedef Bool (* GLXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef GLXDrawable (* GLXGetCurrentReadDrawable) (void); +typedef int (* GLXQueryContext) (Display *dpy, GLXContext ctx, int attribute, int *value); +typedef void (* GLXSelectEvent) (Display *dpy, GLXDrawable drawable, unsigned long mask); +typedef void (* GLXGetSelectedEvent) (Display *dpy, GLXDrawable drawable, unsigned long *mask); +typedef void (* (* GLXGetProcAddress) (const GLubyte *procname))(void); + + +// GLX_NV_copy_image +typedef void (* GLXCopyImageSubDataNV) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); + + +#endif /* MOZILLA_GFX_NVPR_GLXDEFS_H_ */ diff --git a/libazure/nvpr/Paint.cpp b/libazure/nvpr/Paint.cpp new file mode 100644 index 0000000..b691853 --- /dev/null +++ b/libazure/nvpr/Paint.cpp @@ -0,0 +1,916 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Paint.h" +#include "ShaderProgram.h" +#include "GradientStopsNVpr.h" +#include "SourceSurfaceNVpr.h" +#include "Logging.h" +#include +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +PaintConfig::PaintConfig() + : mPaintMode(MODE_NONE) + , mTexGenComponents(GL::TEXGEN_NONE) +{ +} + +void +PaintConfig::SetToPattern(const Pattern& aPattern) +{ + switch (aPattern.GetType()) { + default: MOZ_ASSERT(!"Invalid pattern type"); + case PatternType::COLOR: + SetToColor(static_cast(aPattern).mColor); + return; + + case PatternType::SURFACE: { + const SurfacePattern& pat(static_cast(aPattern)); + MOZ_ASSERT(pat.mSurface->GetType() == SURFACE_NVPR_TEXTURE); + + SetToTexgenSurface(static_cast(pat.mSurface.get()), + pat.mExtendMode, pat.mFilter, pat.mMatrix); + return; + } + + case PatternType::LINEAR_GRADIENT: { + const LinearGradientPattern& pat( + static_cast(aPattern)); + MOZ_ASSERT(pat.mStops->GetBackendType() == BACKEND_NVPR); + + SetToLinearGradient(static_cast(pat.mStops.get()), + pat.mBegin, pat.mEnd, pat.mMatrix); + return; + } + + case PatternType::RADIAL_GRADIENT: { + const RadialGradientPattern& pat( + static_cast(aPattern)); + MOZ_ASSERT(pat.mStops->GetBackendType() == BACKEND_NVPR); + + if (pat.mRadius1 == 0) { + SetToFocalGradient(static_cast(pat.mStops.get()), + pat.mCenter1, pat.mCenter2, pat.mRadius2, pat.mMatrix); + return; + } + + SetToRadialGradient(static_cast(pat.mStops.get()), + pat.mCenter1, pat.mRadius1, pat.mCenter2, + pat.mRadius2, pat.mMatrix); + return; + } + } +} + +void +PaintConfig::SetToColor(const Color& aColor) +{ + mPaintMode = MODE_SOLID_COLOR; + uColor[0] = aColor.a * aColor.r; + uColor[1] = aColor.a * aColor.g; + uColor[2] = aColor.a * aColor.b; + uColor[3] = aColor.a; +} + +void +PaintConfig::SetToSurface(SourceSurfaceNVpr* aSurface, Filter aFilter) +{ + mPaintMode = MODE_TEXTURE_2D; + mTextureId = *aSurface; + + aSurface->SetWrapMode(ExtendMode::CLAMP); + aSurface->SetFilter(aFilter); +} + +void +PaintConfig::SetToClampedSurface(SourceSurfaceNVpr* aSurface, Filter aFilter, + const Rect& aSamplingBounds) +{ + Rect clampRect = aSamplingBounds; + clampRect.Deflate(0.5f); + clampRect.ScaleInverse(aSurface->GetSize().width, aSurface->GetSize().height); + + mPaintMode = MODE_TEXTURE_2D_CLAMPED; + mTextureId = *aSurface; + uClampRect[0] = clampRect.x; + uClampRect[1] = clampRect.y; + uClampRect[2] = clampRect.XMost(); + uClampRect[3] = clampRect.YMost(); + + aSurface->SetWrapMode(ExtendMode::CLAMP); + aSurface->SetFilter(aFilter); +} + +void +PaintConfig::SetToTexgenSurface(SourceSurfaceNVpr* aSurface, + ExtendMode aExtendMode, Filter aFilter, + const Matrix& aMatrix) +{ + Matrix textureCoords = aMatrix; + textureCoords.Invert(); + textureCoords.PostScale(1.0f / aSurface->GetSize().width, + 1.0f / aSurface->GetSize().height); + + mPaintMode = MODE_TEXTURE_2D; + mTextureId = *aSurface; + mTexGenComponents = GL::TEXGEN_ST; + SetTexGenCoefficients(textureCoords); + + aSurface->SetWrapMode(aExtendMode); + aSurface->SetFilter(aFilter); +} + +void +PaintConfig::SetToLinearGradient(GradientStopsNVpr* aStops, + const Point& aBeginPoint, const Point& aEndPoint, + const Matrix& aMatrix) +{ + const Point beginPoint = aMatrix * aBeginPoint; + const Point vector = aMatrix * (aEndPoint - aBeginPoint); + const float lengthSquared = (vector.x * vector.x + vector.y * vector.y); + + if (!lengthSquared || !*aStops) { + SetToColor(aStops->FinalColor()); + return; + } + + mPaintMode = MODE_TEXTURE_1D; + mTextureId = *aStops; + mTexGenComponents = GL::TEXGEN_S; + mTexGenCoefficients[0] = vector.x / lengthSquared; + mTexGenCoefficients[1] = vector.y / lengthSquared; + mTexGenCoefficients[2] = + -(beginPoint.x * vector.x + beginPoint.y * vector.y) / lengthSquared; +} + +void +PaintConfig::SetToFocalGradient(GradientStopsNVpr* aStops, + const Point& aFocalPoint, + const Point& aEndCenter, float aEndRadius, + const Matrix& aMatrix) +{ + if (!aEndRadius) { + mPaintMode = MODE_NONE; + return; + } + + if (!*aStops) { + // TODO: This doesn't exclude regions not in the gradient from being drawn. + SetToColor(aStops->FinalColor()); + return; + } + + mTextureId = *aStops; + mTexGenComponents = GL::TEXGEN_ST; + + // Setup a transformation where the gradient is the unit-circle. + Matrix gradientCoords; + gradientCoords.PreScale(1 / aEndRadius, 1 / aEndRadius); + gradientCoords.PreTranslate(-aEndCenter.x, -aEndCenter.y); + + Point focalPoint = gradientCoords * aFocalPoint; + const float focalOffsetSquared = focalPoint.x * focalPoint.x + + focalPoint.y * focalPoint.y; + + // The gradient is drawn in 'pattern space' onto an infinite plane. + // aMatrix transforms the pattern-space plane back into user space. + Matrix patternSpace = aMatrix; + patternSpace.Invert(); + + if (fabs(focalOffsetSquared) < 1e-5f) { // The focal point is at [0, 0]. + mPaintMode = MODE_FOCAL_GRAD_CENTERED; + SetTexGenCoefficients(gradientCoords * patternSpace); + return; + } + + // With the following variables inside the unit circle: + // + // f = focal point, normalized to a unit-circle gradient + // p = sample's [x,y] location, normalized to a unit-circle gradient + // + // A shader program can find the sample's gradient offset using the general + // radial gradient equation: + // + // offset = (dot(p - f, f) +/- sqrt(dot(p - f, p - f) - cross(p - f, f)^2)) + // / (1 - dot(f, f)) + // + // Below we massage this equation to make the math more efficient. + + // 1) Rotate the gradient so the focal point is on the x-axis (i.e. f.y == 0): + // + // Now offset = ((p - f).x * f.x +/- sqrt((p - f).x^2 + (p - f).y^2 + // - (p - f).y^2 * f.x^2)) + // / (1 - dot(f, f)) + // + // = ((p - f).x * f.x +/- sqrt((p - f).x^2 + // + (1 - f.x^2) * (p - f).y^2)) + // / (1 - dot(f, f)) + // + Matrix rotation = Matrix::Rotation(-atan2(focalPoint.y, focalPoint.x)); + gradientCoords = gradientCoords * rotation; + focalPoint = Point(sqrt(focalOffsetSquared), 0); + + // 2) Let q = p - f + // + // Now offset = (q.x * f.x +/- sqrt(q.x^2 + (1 - f.x^2) * q.y^2)) + // / (1 - dot(f, f)) + // + Matrix qCoords = gradientCoords; + qCoords.PostTranslate(-focalPoint.x, -focalPoint.y); + + if (fabs(1 - focalOffsetSquared) < 1e-5f) { + // The focal point is touching the circle. We can't use the general equation + // because it would divide by zero. Instead we use a special-case formula + // knowing that f = [0, 1]: + // + // offset = dot(p - f, p - f) / (-2 * (p - f).x) + // + // = dot(q, q) / (-2 * q.x) + // + mPaintMode = MODE_FOCAL_GRAD_TOUCHING; + SetTexGenCoefficients(qCoords * patternSpace); + + return; + } + + // 3) Let a = 1 / (1 - dot(f, f)): + // + // Now offset = a * q.x * f.x + sqrt(a^2 * q.x^2 + a^2 * (1 - f.x^2) * q.y^2)) + // + // (Note that this reverses the sign of the sqrt when a < 0, and that's exacly + // what we want since it allows us to just always use + with it) + // + float a = 1 / (1 - focalOffsetSquared); + + if (a < 0) { // The focal point is outside the circle. + // 4) q.x *= a + // q.y *= a + // + // Now offset = q.x * f.x + sqrt(q.x^2 + (1 - f.x^2) * q.y^2)) + // + qCoords.PostScale(a, a); + + mPaintMode = MODE_FOCAL_GRAD_OUTSIDE; + SetTexGenCoefficients(qCoords * patternSpace); + uFocalX = focalPoint.x; + u1MinuxFx_2 = 1 - focalPoint.x * focalPoint.x; + + return; + } + + // 4) q.x *= a + // q.y *= a * sqrt(1 - f.x^2) + // + // Now offset = q.x * f.x + sqrt(q.x^2 + q.y^2) + // + // = q.x * f.x + length(q) + // + qCoords.PostScale(a, a * sqrt(1 - focalOffsetSquared)); + + mPaintMode = MODE_FOCAL_GRAD_INSIDE; + SetTexGenCoefficients(qCoords * patternSpace); + uFocalX = focalPoint.x; +} + +void +PaintConfig::SetToRadialGradient(GradientStopsNVpr* aStops, + const Point& aBeginCenter, float aBeginRadius, + const Point& aEndCenter, float aEndRadius, + const Matrix& aMatrix) +{ + if (aBeginCenter == aEndCenter && aBeginRadius == aEndRadius) { + mPaintMode = MODE_NONE; + return; + } + + if (!*aStops) { + // TODO: This doesn't exclude regions not in the gradient from being drawn. + SetToColor(aStops->FinalColor()); + return; + } + + // Setup a transformation where the begin circle is the unit-circle. + Matrix gradientCoords; + gradientCoords.PreScale(1 / aBeginRadius, 1 / aBeginRadius); + gradientCoords.PreTranslate(-aBeginCenter.x, -aBeginCenter.y); + + // At this point, the begin circle is the unit-circle and we define the + // following variables: + // + // c = end circle's center + // r = end circle's radius + // p = sample's [x,y] location + // A = dot(c, c) - r^2 + 2 * r - 1 + // + // A shader program can use the this equation to find the gradient offset: + // + // offset = (dot(c, p) + r - 1 +/- sqrt((dot(c, p) + r - 1)^2 + // - 4 * A * (dot(p, p) - 1))) / A + Point endCenter = gradientCoords * aEndCenter; + float endRadius = aEndRadius / aBeginRadius; + float A = endCenter.x * endCenter.x + endCenter.y * endCenter.y + - endRadius * endRadius + 2 * endRadius - 1; + + // TODO: Make a special case for A ~= 0. + + // Let q = (1 / A) * p, B = (r - 1) / A, C = 1 / A + // + // Now d = dot(c, q) + B + // offset = d +/- sqrt(d^2 - A * dot(q, q) + C) + // + // (Note that this reverses the sign of the sqrt when A < 0) + float C = 1 / A; + float B = (endRadius - 1) * C; + Matrix qCoords = gradientCoords; + qCoords.PostScale(C, C); + + mTextureId = *aStops; + mTexGenComponents = GL::TEXGEN_ST; + + // The gradient is drawn in 'pattern space' onto an infinite plane. + // aMatrix transforms the pattern-space plane back into user space. + Matrix patternSpace = aMatrix; + patternSpace.Invert(); + SetTexGenCoefficients(qCoords * patternSpace); + + uEndCenter[0] = endCenter.x; + uEndCenter[1] = endCenter.y; + uA = A; + uB = B; + uC = C; + + if (A >= 0) { + mPaintMode = (aEndRadius - aBeginRadius > 1e-5f) + ? MODE_RADIAL_GRAD_OUTSIDE_DISCARD_LOW + : MODE_RADIAL_GRAD_OUTSIDE_DISCARD_HIGH; + uOffsetLimit = aBeginRadius / (aBeginRadius - aEndRadius); + return; + } + + mPaintMode = (aEndRadius > aBeginRadius) + ? MODE_RADIAL_GRAD_INSIDE_ADD_SQRT + : MODE_RADIAL_GRAD_INSIDE_SUBTRACT_SQRT; +} + +void +PaintConfig::SetTexGenCoefficients(const Matrix& aTransform) +{ + mTexGenCoefficients[0] = aTransform._11; + mTexGenCoefficients[1] = aTransform._21; + mTexGenCoefficients[2] = aTransform._31; + mTexGenCoefficients[3] = aTransform._12; + mTexGenCoefficients[4] = aTransform._22; + mTexGenCoefficients[5] = aTransform._32; +} + + +static string +AppendTextureUnit(const char* aName, GL::TextureUnit aUnit) +{ + stringstream fullName; + fullName << aName << '_' << aUnit; + return fullName.str(); +} + +class PaintShader::ColorFunction : public RefCounted { +public: + static TemporaryRef Create(PaintConfig::PaintMode aPaintMode, + GL::TextureUnit aTextureUnit); + virtual ~ColorFunction() {} + + virtual bool IsEmpty() const { return false; } + + virtual void WriteDeclarations(std::ostream& aOut) const {} + virtual void WriteColorFunction(std::ostream& aOut) const = 0; + virtual void Initialize(GLuint aShaderProgram) {} + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) {} + +protected: + ColorFunction() {} +}; + +class EmptyFunction : public PaintShader::ColorFunction { +public: + virtual bool IsEmpty() const { return true; } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "return vec4(1);" << endl; + } +}; + +class SolidColorFunction : public PaintShader::ColorFunction { +public: + SolidColorFunction(GL::TextureUnit aTextureUnit) + : uColor(AppendTextureUnit("uColor", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + aOut << "uniform vec4 " << uColor << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "return " << uColor << ";" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uColor.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + const GLfloat* color = aConfig.uColor; + + if (color[3] == 1) { + uColor.Set(color); + } else { + const float a = color[3]; + const float premultiplied[] = {a * color[0], a * color[1], a * color[2], a}; + uColor.Set(premultiplied); + } + } + +protected: + UniformVec4 uColor; +}; + +class Texture1DFunction : public PaintShader::ColorFunction { +public: + Texture1DFunction(GL::TextureUnit aTextureUnit) + : mTextureUnit(aTextureUnit) + , uTexture(AppendTextureUnit("uTexture", aTextureUnit).c_str(), aTextureUnit) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + aOut << "uniform sampler1D " << uTexture << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "float texCoord = gl_TexCoord[" << mTextureUnit << "].s;" << endl; + aOut << "return texture1D(" << uTexture << ", texCoord);" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uTexture.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + gl->SetTexture(mTextureUnit, GL_TEXTURE_1D, aConfig.mTextureId); + } + +protected: + GL::TextureUnit mTextureUnit; + UniformSampler uTexture; +}; + +class Texture2DFunction : public PaintShader::ColorFunction { +public: + Texture2DFunction(GL::TextureUnit aTextureUnit) + : mTextureUnit(aTextureUnit) + , uTexture(AppendTextureUnit("uTexture", aTextureUnit).c_str(), aTextureUnit) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + aOut << "uniform sampler2D " << uTexture << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 texCoords = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "return texture2D(" << uTexture << ", texCoords);" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uTexture.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + gl->SetTexture(mTextureUnit, GL_TEXTURE_2D, aConfig.mTextureId); + } + +protected: + GL::TextureUnit mTextureUnit; + UniformSampler uTexture; +}; + +class Texture2DClampedFunction : public Texture2DFunction { +public: + Texture2DClampedFunction(GL::TextureUnit aTextureUnit) + : Texture2DFunction(aTextureUnit) + , uClampRect(AppendTextureUnit("uClampRect", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + Texture2DFunction::WriteDeclarations(aOut); + aOut << "uniform vec4 " << uClampRect << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 texCoords = clamp(gl_TexCoord[" << mTextureUnit << "].st, " + << uClampRect << ".xy, " + << uClampRect << ".zw);" << endl; + aOut << "return texture2D(" << uTexture << ", texCoords);" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uClampRect.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + Texture2DFunction::ApplyFragmentUniforms(aConfig); + uClampRect.Set(aConfig.uClampRect); + } + +protected: + UniformVec4 uClampRect; +}; + +class FocalGradCenteredFunction : public Texture1DFunction { +public: + FocalGradCenteredFunction(GL::TextureUnit aTextureUnit) + : Texture1DFunction(aTextureUnit) + {} + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 p = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float offset = length(p);" << endl; + aOut << "return texture1D(" << uTexture << ", offset);" << endl; + } +}; + +class FocalGradInsideFunction : public Texture1DFunction { +public: + FocalGradInsideFunction(GL::TextureUnit aTextureUnit) + : Texture1DFunction(aTextureUnit) + , uFocalX(AppendTextureUnit("uFocalX", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + Texture1DFunction::WriteDeclarations(aOut); + aOut << "uniform float " << uFocalX << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 q = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float offset = q.x * " << uFocalX << " + length(q);" << endl; + aOut << "return texture1D(" << uTexture << ", offset);" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uFocalX.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + Texture1DFunction::ApplyFragmentUniforms(aConfig); + uFocalX.Set(aConfig.uFocalX); + } + +protected: + UniformFloat uFocalX; +}; + +class FocalGradOutsideFunction : public Texture1DFunction { +public: + FocalGradOutsideFunction(GL::TextureUnit aTextureUnit) + : Texture1DFunction(aTextureUnit) + , uFocalX(AppendTextureUnit("uFocalX", aTextureUnit).c_str()) + , u1MinusFx_2(AppendTextureUnit("u1MinusFx_2", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + Texture1DFunction::WriteDeclarations(aOut); + aOut << "uniform float " << uFocalX << ";" << endl; + aOut << "uniform float " << u1MinusFx_2 << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 q = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float offset = q.x * " << uFocalX << " + sqrt(q.x * q.x + " << u1MinusFx_2 << " * q.y * q.y);" << endl; + aOut << "return offset >= 0 ? texture1D(" << uTexture << ", offset) : 0;" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uFocalX.Initialize(aShaderProgram); + u1MinusFx_2.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + Texture1DFunction::ApplyFragmentUniforms(aConfig); + uFocalX.Set(aConfig.uFocalX); + u1MinusFx_2.Set(aConfig.u1MinuxFx_2); + } + +protected: + UniformFloat uFocalX; + UniformFloat u1MinusFx_2; +}; + +class FocalGradTouchingFunction : public Texture1DFunction { +public: + FocalGradTouchingFunction(GL::TextureUnit aTextureUnit) + : Texture1DFunction(aTextureUnit) + {} + + virtual void WriteColorFunction(std::ostream& aOut) const + { + aOut << "vec2 p = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float offset = dot(q, q) / (-2 * q.x);" << endl; + aOut << "return offset >= 0 ? texture1D(" << uTexture << ", offset) : 0;" << endl; + } +}; + +class RadialGradInsideFunction : public Texture1DFunction { +public: + RadialGradInsideFunction(GL::TextureUnit aTextureUnit, PaintConfig::PaintMode aPaintMode) + : Texture1DFunction(aTextureUnit) + , mPaintMode(aPaintMode) + , uEndCenter(AppendTextureUnit("uEndCenter", aTextureUnit).c_str()) + , uA(AppendTextureUnit("uA", aTextureUnit).c_str()) + , uB(AppendTextureUnit("uB", aTextureUnit).c_str()) + , uC(AppendTextureUnit("uC", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + Texture1DFunction::WriteDeclarations(aOut); + aOut << "uniform vec2 " << uEndCenter << ";" << endl; + aOut << "uniform float " << uA << ";" << endl; + aOut << "uniform float " << uB << ";" << endl; + aOut << "uniform float " << uC << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + const char sign = + mPaintMode == PaintConfig::MODE_RADIAL_GRAD_INSIDE_SUBTRACT_SQRT ? '-' : '+'; + aOut << "vec2 q = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float d = dot(" << uEndCenter << ", q) + " << uB << ";" << endl; + aOut << "float offset = d " << sign << " sqrt(d * d - " << uA << " * dot(q, q) + " << uC << ");" << endl; + aOut << "return texture1D(" << uTexture << ", offset);" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uEndCenter.Initialize(aShaderProgram); + uA.Initialize(aShaderProgram); + uC.Initialize(aShaderProgram); + uB.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + Texture1DFunction::ApplyFragmentUniforms(aConfig); + uEndCenter.Set(aConfig.uEndCenter); + uA.Set(aConfig.uA); + uC.Set(aConfig.uB); + uB.Set(aConfig.uC); + } + +protected: + PaintConfig::PaintMode mPaintMode; + UniformVec2 uEndCenter; + UniformFloat uA; + UniformFloat uB; + UniformFloat uC; +}; + +class RadialGradOutsideFunction : public Texture1DFunction { +public: + RadialGradOutsideFunction(GL::TextureUnit aTextureUnit, PaintConfig::PaintMode aPaintMode) + : Texture1DFunction(aTextureUnit) + , mPaintMode(aPaintMode) + , uEndCenter(AppendTextureUnit("uEndCenter", aTextureUnit).c_str()) + , uA(AppendTextureUnit("uA", aTextureUnit).c_str()) + , uB(AppendTextureUnit("uB", aTextureUnit).c_str()) + , uC(AppendTextureUnit("uC", aTextureUnit).c_str()) + , uOffsetLimit(AppendTextureUnit("uOffsetLimit", aTextureUnit).c_str()) + {} + + virtual void WriteDeclarations(std::ostream& aOut) const + { + aOut << "uniform vec2 " << uEndCenter << ";" << endl; + aOut << "uniform float " << uA << ";" << endl; + aOut << "uniform float " << uB << ";" << endl; + aOut << "uniform float " << uC << ";" << endl; + aOut << "uniform float " << uOffsetLimit << ";" << endl; + } + + virtual void WriteColorFunction(std::ostream& aOut) const + { + const char* op = + mPaintMode == PaintConfig::MODE_RADIAL_GRAD_OUTSIDE_DISCARD_HIGH ? "<=" : ">="; + aOut << "vec2 q = gl_TexCoord[" << mTextureUnit << "].st;" << endl; + aOut << "float d = dot(" << uEndCenter << ", q) + " << uB << ";" << endl; + aOut << "float offset = d + sqrt(d * d - " << uA << " * dot(q, q) + " << uC << ");" << endl; + aOut << "return offset " << op << uOffsetLimit << " ? texture1D(" << uTexture << ", offset) : 0;" << endl; + } + + virtual void Initialize(GLuint aShaderProgram) + { + uEndCenter.Initialize(aShaderProgram); + uA.Initialize(aShaderProgram); + uC.Initialize(aShaderProgram); + uB.Initialize(aShaderProgram); + uOffsetLimit.Initialize(aShaderProgram); + } + + virtual void ApplyFragmentUniforms(const PaintConfig& aConfig) + { + Texture1DFunction::ApplyFragmentUniforms(aConfig); + uEndCenter.Set(aConfig.uEndCenter); + uA.Set(aConfig.uA); + uC.Set(aConfig.uB); + uB.Set(aConfig.uC); + uOffsetLimit.Set(aConfig.uOffsetLimit); + } + +protected: + PaintConfig::PaintMode mPaintMode; + UniformVec2 uEndCenter; + UniformFloat uA; + UniformFloat uB; + UniformFloat uC; + UniformFloat uOffsetLimit; +}; + +TemporaryRef +PaintShader::ColorFunction::Create(PaintConfig::PaintMode aPaintMode, + GL::TextureUnit aTextureUnit) +{ + switch (aPaintMode) { + default: + case PaintConfig::MODE_NONE: + return new EmptyFunction(); + case PaintConfig::MODE_SOLID_COLOR: + return new SolidColorFunction(aTextureUnit); + case PaintConfig::MODE_TEXTURE_1D: + return new Texture1DFunction(aTextureUnit); + case PaintConfig::MODE_TEXTURE_2D: + return new Texture2DFunction(aTextureUnit); + case PaintConfig::MODE_TEXTURE_2D_CLAMPED: + return new Texture2DClampedFunction(aTextureUnit); + case PaintConfig::MODE_FOCAL_GRAD_CENTERED: + return new FocalGradCenteredFunction(aTextureUnit); + case PaintConfig::MODE_FOCAL_GRAD_INSIDE: + return new FocalGradInsideFunction(aTextureUnit); + case PaintConfig::MODE_FOCAL_GRAD_OUTSIDE: + return new FocalGradOutsideFunction(aTextureUnit); + case PaintConfig::MODE_FOCAL_GRAD_TOUCHING: + return new FocalGradTouchingFunction(aTextureUnit); + case PaintConfig::MODE_RADIAL_GRAD_INSIDE_ADD_SQRT: + case PaintConfig::MODE_RADIAL_GRAD_INSIDE_SUBTRACT_SQRT: + return new RadialGradInsideFunction(aTextureUnit, aPaintMode); + case PaintConfig::MODE_RADIAL_GRAD_OUTSIDE_DISCARD_HIGH: + case PaintConfig::MODE_RADIAL_GRAD_OUTSIDE_DISCARD_LOW: + return new RadialGradOutsideFunction(aTextureUnit, aPaintMode); + } +} + + +class AlphaPaintShader : public PaintShader { +public: + AlphaPaintShader(PaintConfig::PaintMode aPaintMode, PaintConfig::PaintMode aMaskMode) + : PaintShader(aPaintMode, aMaskMode) + , uGlobalAlpha("uGlobalAlpha") + {} + + virtual void ApplyFragmentUniforms(const Paint& aPaint) + { + PaintShader::ApplyFragmentUniforms(aPaint); + uGlobalAlpha.Set(aPaint.mGlobalAlpha); + } + +protected: + virtual void WriteDeclarations(std::ostream& aOut) const + { + PaintShader::WriteDeclarations(aOut); + aOut << "uniform float " << uGlobalAlpha << ";" << endl; + } + + virtual void WriteMainFunction(std::ostream& aOut) const + { + PaintShader::WriteMainFunction(aOut); + aOut << "gl_FragColor *= " << uGlobalAlpha << ";" << endl; + } + + virtual void Initialize() + { + PaintShader::Initialize(); + uGlobalAlpha.Initialize(*this); + } + + UniformFloat uGlobalAlpha; +}; + +PaintShader::PaintShader(PaintConfig::PaintMode aPaintMode, PaintConfig::PaintMode aMaskMode) + : mPaint(ColorFunction::Create(aPaintMode, PAINT_UNIT)) + , mMask(ColorFunction::Create(aMaskMode, MASK_UNIT)) +{ +} + +PaintShader::~PaintShader() +{ +} + +void +PaintShader::WriteDeclarations(ostream& aOut) const +{ + mPaint->WriteDeclarations(aOut); + mMask->WriteDeclarations(aOut); +} + +void +PaintShader::WriteMainFunction(ostream& aOut) const +{ + aOut << "gl_FragColor = GetPaintColor();" << endl; + if (!mMask->IsEmpty()) { + aOut << "gl_FragColor *= GetMaskColor().a;" << endl; + } +} + +void +PaintShader::ApplyFragmentUniforms(const Paint& aPaint) +{ + MOZ_ASSERT(gl->IsCurrent()); + + mPaint->ApplyFragmentUniforms(aPaint); + mMask->ApplyFragmentUniforms(aPaint.mMask); +} + +void +PaintShader::Initialize() +{ + ostringstream fragSource; + WriteDeclarations(fragSource); + fragSource << endl; + + fragSource << "vec4 GetPaintColor() {" << endl; + mPaint->WriteColorFunction(fragSource); + fragSource << "}" << endl; + fragSource << endl; + + if (!mMask->IsEmpty()) { + fragSource << "vec4 GetMaskColor() {" << endl; + mMask->WriteColorFunction(fragSource); + fragSource << "}" << endl; + fragSource << endl; + } + + fragSource << "void main(void) {" << endl; + WriteMainFunction(fragSource); + fragSource << "}" << endl; + + ShaderProgram::Initialize(fragSource.str().c_str()); + mPaint->Initialize(*this); + mMask->Initialize(*this); +} + +TemporaryRef +PaintShader::Create(const Paint& aPaint) +{ + RefPtr paintShader = (aPaint.mGlobalAlpha != 1) + ? new AlphaPaintShader(aPaint.mPaintMode, aPaint.mMask.mPaintMode) + : new PaintShader(aPaint.mPaintMode, aPaint.mMask.mPaintMode); + + paintShader->Initialize(); + + return paintShader.forget(); +} + +} +} +} diff --git a/libazure/nvpr/Paint.h b/libazure/nvpr/Paint.h new file mode 100644 index 0000000..e919960 --- /dev/null +++ b/libazure/nvpr/Paint.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_PAINT_SHADER_H_ +#define MOZILLA_GFX_NVPR_PAINT_SHADER_H_ + +#include "2D.h" +#include "ShaderProgram.h" + +namespace mozilla { +namespace gfx { + +class GradientStopsNVpr; +class SourceSurfaceNVpr; + +namespace nvpr { + +struct PaintConfig { + enum PaintMode { + MODE_NONE, + MODE_SOLID_COLOR, + MODE_TEXTURE_1D, + MODE_TEXTURE_2D, + MODE_TEXTURE_2D_CLAMPED, + MODE_FOCAL_GRAD_CENTERED, + MODE_FOCAL_GRAD_INSIDE, + MODE_FOCAL_GRAD_OUTSIDE, + MODE_FOCAL_GRAD_TOUCHING, + MODE_RADIAL_GRAD_INSIDE_ADD_SQRT, + MODE_RADIAL_GRAD_INSIDE_SUBTRACT_SQRT, + MODE_RADIAL_GRAD_OUTSIDE_DISCARD_HIGH, + MODE_RADIAL_GRAD_OUTSIDE_DISCARD_LOW, + MODE_COUNT + }; + + PaintConfig(); + void SetToPattern(const Pattern& aPattern); + void SetToColor(const Color& aColor); + void SetToSurface(SourceSurfaceNVpr* aSurface, Filter aFilter = Filter::LINEAR); + void SetToClampedSurface(SourceSurfaceNVpr* aSurface, Filter aFilter, + const Rect& aSamplingBounds); + void SetToTexgenSurface(SourceSurfaceNVpr* aSurface, ExtendMode aExtendMode, + Filter aFilter, const Matrix& aMatrix); + void SetToLinearGradient(GradientStopsNVpr* aStops, const Point& aBeginPoint, + const Point& aEndPoint, const Matrix& aMatrix); + void SetToFocalGradient(GradientStopsNVpr* aStops, const Point& aFocalPoint, + const Point& aEndCenter, float aEndRadius, + const Matrix& aMatrix); + void SetToRadialGradient(GradientStopsNVpr* aStops, + const Point& aBeginCenter, float aBeginRadius, + const Point& aEndCenter, float aEndRadius, + const Matrix& aMatrix); + void SetTexGenCoefficients(const Matrix& aTransform); + + PaintMode mPaintMode; + GLuint mTextureId; + GL::TexGenComponents mTexGenComponents; + GLfloat mTexGenCoefficients[6]; + union { + struct { + GLfloat uColor[4]; + }; + struct { + GLfloat uClampRect[4]; + }; + struct { + GLfloat uFocalX; + GLfloat u1MinuxFx_2; + }; + struct { + GLfloat uEndCenter[2]; + GLfloat uA; + GLfloat uB; + GLfloat uC; + GLfloat uOffsetLimit; + }; + }; +}; + +struct Paint : public PaintConfig { + Paint() : mGlobalAlpha(1) {} + PaintConfig mMask; + GLfloat mGlobalAlpha; +}; + +class PaintShader : public ShaderProgram { +public: + static const GL::TextureUnit PAINT_UNIT = GL::UNIT_0; + static const GL::TextureUnit MASK_UNIT = GL::UNIT_1; + + class ColorFunction; + + static TemporaryRef Create(const Paint& aPaint); + virtual ~PaintShader(); + + virtual void ApplyFragmentUniforms(const Paint& aPaint); + +protected: + PaintShader(PaintConfig::PaintMode aPaintMode, PaintConfig::PaintMode aMaskMode); + virtual void WriteDeclarations(std::ostream& aOut) const; + virtual void WriteMainFunction(std::ostream& aOut) const; + virtual void Initialize(); + + RefPtr mPaint; + RefPtr mMask; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_PAINT_SHADER_H_ */ diff --git a/libazure/nvpr/ShaderProgram.cpp b/libazure/nvpr/ShaderProgram.cpp new file mode 100644 index 0000000..0eec1b1 --- /dev/null +++ b/libazure/nvpr/ShaderProgram.cpp @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ShaderProgram.h" +#include "Logging.h" +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +ShaderProgram::ShaderProgram() + : mFragmentShader(0) + , mProgramObject(0) +{ +} + +ShaderProgram::~ShaderProgram() +{ + gl->MakeCurrent(); + + if (mProgramObject) { + gl->DeleteShaderProgram(mProgramObject); + } + + if (mFragmentShader) { + gl->DeleteShader(mFragmentShader); + } +} + +void +ShaderProgram::Initialize(const GLchar* aFragmentSource) +{ + MOZ_ASSERT(gl->IsCurrent()); + GLint status; + + mFragmentShader = gl->CreateShader(GL_FRAGMENT_SHADER); + gl->ShaderSource(mFragmentShader, 1, &aFragmentSource, nullptr); + gl->CompileShader(mFragmentShader); + + gl->GetShaderiv(mFragmentShader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + cout << "Failed to compile nvpr shader." << endl; + cout << "----------------------- Shader Source -----------------------" << endl; + cout << aFragmentSource << endl; + + GLint length = 0; + gl->GetShaderiv(mFragmentShader, GL_INFO_LOG_LENGTH, &length); + if (length) { + vector infoLog(length); + gl->GetShaderInfoLog(mFragmentShader, length, nullptr, infoLog.data()); + + cout << "---------------------------- Log ----------------------------" << endl; + cout << infoLog.data() << endl; + } else { + cout << "No shader info log." << endl; + } + + gl->DeleteShader(mFragmentShader); + mFragmentShader = 0; + return; + } + + mProgramObject = gl->CreateProgram(); + gl->AttachShader(mProgramObject, mFragmentShader); + gl->LinkProgram(mProgramObject); + + gl->GetProgramiv(mProgramObject, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + cout << "Failed to link nvpr program." << endl; + cout << "----------------------- Fragment Source -----------------------" << endl; + cout << aFragmentSource << endl; + + GLint length = 0; + gl->GetProgramiv(mProgramObject, GL_INFO_LOG_LENGTH, &length); + if (length) { + vector infoLog(length); + gl->GetProgramInfoLog(mProgramObject, length, nullptr, infoLog.data()); + + cout << "---------------------------- Log ----------------------------" << endl; + cout << infoLog.data() << endl; + } else { + cout << "No shader info log." << endl; + } + + gl->DeleteShaderProgram(mProgramObject); + mProgramObject = 0; + } +} + +Uniform::Uniform(const char* aName) + : mName(aName) + , mLocation(0) +{ +} + +void +Uniform::Initialize(GLuint aShaderProgram) +{ + mShaderProgram = aShaderProgram; + mLocation = gl->GetUniformLocation(aShaderProgram, mName.c_str()); +} + +std::ostream& operator<<(std::ostream& aOut, const Uniform& aUniform) +{ + return aOut << aUniform.mName; +} + +UniformFloat::UniformFloat(const char* aName) + : Uniform(aName) + , mValue(0) +{ +} + +void +UniformFloat::Set(GLfloat aValue) +{ + if (mValue == aValue) { + return; + } + + gl->ProgramUniform1fEXT(mShaderProgram, mLocation, aValue); + mValue = aValue; +} + +UniformFloatArray::UniformFloatArray(const char* aName) + : Uniform(aName) + , mArrayId(0) +{ +} + +void +UniformFloatArray::Set(GLfloat* aValues, GLsizei aCount, UniqueId aArrayId) +{ + if (mArrayId == aArrayId) { + return; + } + + Set(aValues, aCount); + mArrayId = aArrayId; +} + +void +UniformFloatArray::Set(GLfloat* aValues, GLsizei aCount) +{ + gl->ProgramUniform1fvEXT(mShaderProgram, mLocation, aCount, aValues); +} + +UniformVec2::UniformVec2(const char* aName) + : Uniform(aName) +{ + memset(mValues, 0, sizeof(mValues)); +} + +void +UniformVec2::Set(GLfloat aX, GLfloat aY) +{ + const GLfloat values[] = {aX, aY}; + Set(values); +} + +void +UniformVec2::Set(const Point& aXY) +{ + const GLfloat values[] = {aXY.x, aXY.y}; + Set(values); +} + +void +UniformVec2::Set(const GLfloat* aValues) +{ + if (!memcmp(mValues, aValues, sizeof(mValues))) { + return; + } + + gl->ProgramUniform2fvEXT(mShaderProgram, mLocation, 1, aValues); + memcpy(mValues, aValues, sizeof(mValues)); +} + +UniformVec4::UniformVec4(const char* aName) + : Uniform(aName) +{ + memset(mValues, 0, sizeof(mValues)); +} + +void +UniformVec4::Set(GLfloat aX, GLfloat aY, GLfloat aZ, GLfloat aW) +{ + const GLfloat values[] = {aX, aY, aZ, aW}; + Set(values); +} + +void +UniformVec4::Set(const Point& aXY, const Point& aZW) +{ + const GLfloat values[] = {aXY.x, aXY.y, aZW.x, aZW.y}; + Set(values); +} + +void +UniformVec4::Set(const GLfloat* aValues) +{ + if (!memcmp(mValues, aValues, sizeof(mValues))) { + return; + } + + gl->ProgramUniform4fvEXT(mShaderProgram, mLocation, 1, aValues); + memcpy(mValues, aValues, sizeof(mValues)); +} + +UniformSampler::UniformSampler(const char* aName, GL::TextureUnit aTextureUnit) + : Uniform(aName) + , mTextureUnit(aTextureUnit) +{ +} + +void +UniformSampler::Initialize(GLuint aShaderProgram) +{ + Uniform::Initialize(aShaderProgram); + gl->ProgramUniform1iEXT(aShaderProgram, mLocation, mTextureUnit); +} + +} +} +} diff --git a/libazure/nvpr/ShaderProgram.h b/libazure/nvpr/ShaderProgram.h new file mode 100644 index 0000000..09dea17 --- /dev/null +++ b/libazure/nvpr/ShaderProgram.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_SHADER_PROGRAM_H_ +#define MOZILLA_GFX_NVPR_SHADER_PROGRAM_H_ + +#include "2D.h" +#include "GL.h" +#include + +namespace mozilla { +namespace gfx { +namespace nvpr { + +class ShaderProgram : public RefCounted { +public: + ShaderProgram(); + virtual ~ShaderProgram(); + + operator GLuint() { return mProgramObject; } + + void Initialize(const GLchar* aFragmentSource); + +private: + GLuint mFragmentShader; + GLuint mProgramObject; +}; + +class Uniform { +public: + friend std::ostream& operator<<(std::ostream& aOut, const Uniform& aUniform); + + void Initialize(GLuint aShaderProgram); + +protected: + Uniform(const char* aName); + + std::string mName; + GLuint mShaderProgram; + GLint mLocation; +}; + +class UniformFloat : public Uniform { +public: + UniformFloat(const char* aName); + void Set(GLfloat aValue); + +private: + GLfloat mValue; +}; + +class UniformFloatArray : public Uniform { +public: + UniformFloatArray(const char* aName); + void Set(GLfloat* aValues, GLsizei aCount, UniqueId aArrayId); + void Set(GLfloat* aValues, GLsizei aCount); + +private: + UniqueId mArrayId; +}; + +class UniformVec2 : public Uniform { +public: + UniformVec2(const char* aName); + void Set(GLfloat aX, GLfloat aY); + void Set(const Point& aXY); + void Set(const GLfloat* aValues); + +private: + GLfloat mValues[2]; +}; + +class UniformVec4 : public Uniform { +public: + UniformVec4(const char* aName); + void Set(GLfloat aX, GLfloat aY, GLfloat aZ, GLfloat aW); + void Set(const Point& aXY, const Point& aZW); + void Set(const GLfloat* aValues); + +private: + GLfloat mValues[4]; +}; + +class UniformSampler : public Uniform { +public: + UniformSampler(const char* aName, GL::TextureUnit aTextureUnit); + void Initialize(GLuint aShaderProgram); + +protected: + GL::TextureUnit mTextureUnit; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_SHADER_PROGRAM_H_ */ diff --git a/libazure/nvpr/ShadowShaders.cpp b/libazure/nvpr/ShadowShaders.cpp new file mode 100644 index 0000000..0069e13 --- /dev/null +++ b/libazure/nvpr/ShadowShaders.cpp @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ShadowShaders.h" +#include "ShaderProgram.h" +#include "SourceSurfaceNVpr.h" +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +static const char* HorizontalConvolutionShaderSrc = "\ +uniform float uWeights[1 + RADIUS]; \n\ +uniform float uOffsets[RADIUS]; \n\ +uniform float uLod; \n\ +uniform sampler2D uImage; \n\ + \n\ +void main() \n\ +{ \n\ + float convolution = uWeights[0] * textureLod(uImage, gl_TexCoord[0], uLod).a; \n\ + for (int i = 1; i <= RADIUS; i++) { \n\ + vec2 offset = vec2(uOffsets[i - 1], 0); \n\ + convolution += uWeights[i] * (textureLod(uImage, gl_TexCoord[0] + offset, uLod).a \n\ + + textureLod(uImage, gl_TexCoord[0] - offset, uLod).a); \n\ + } \n\ + gl_FragColor[CHANNEL] = convolution; \n\ +} \n\ \n\ +"; + +class ShadowShaders::HorizontalConvolutionShader : public ShaderProgram { +public: + static TemporaryRef + Create(ConvolutionChannel aConvolutionChannel, size_t aRadius) + { + MOZ_ASSERT(gl->IsCurrent()); + + const char channel = aConvolutionChannel == RED ? 'r' : 'a'; + RefPtr shader = new HorizontalConvolutionShader(); + + ostringstream fragSrc; + fragSrc << "#define RADIUS " << aRadius << endl; + fragSrc << "#define CHANNEL " << (aConvolutionChannel == RED ? '0' : '3') << endl; + fragSrc << HorizontalConvolutionShaderSrc; + shader->Initialize(fragSrc.str().c_str()); + + return shader.forget(); + } + + UniformFloatArray uWeights; + UniformFloatArray uOffsets; + UniformFloat uLod; + UniformSampler uImage; + +private: + HorizontalConvolutionShader() + : uWeights("uWeights") + , uOffsets("uOffsets") + , uLod("uLod") + , uImage("uImage", GL::UNIT_0) + {} + + void Initialize(const GLchar* aFragmentSource) + { + ShaderProgram::Initialize(aFragmentSource); + uWeights.Initialize(*this); + uOffsets.Initialize(*this); + uLod.Initialize(*this); + uImage.Initialize(*this); + } +}; + +static const char* ShadowShaderSrc = "\ +uniform float uWeights[1 + RADIUS]; \n\ +uniform float uOffsets[RADIUS]; \n\ +uniform vec4 uClampRect; \n\ +uniform vec4 uShadowColor; \n\ +uniform sampler2D uHorizontalConvolution; \n\ + \n\ +float getSample(float offsetT) \n\ +{ \n\ + vec2 coords = vec2(gl_TexCoord[0].s, gl_TexCoord[0].t + offsetT); \n\ + coords = clamp(coords, uClampRect.xy, uClampRect.zw); \n\ + return texture2D(uHorizontalConvolution, coords)[CHANNEL]; \n\ +} \n\ + \n\ +void main() \n\ +{ \n\ + float alpha = uWeights[0] * getSample(0); \n\ + for (int i = 1; i <= RADIUS; i++) { \n\ + alpha += uWeights[i] * (getSample(uOffsets[i - 1]) + getSample(-uOffsets[i - 1])); \n\ + } \n\ + gl_FragColor = alpha * uShadowColor; \n\ +} \n\ +"; + +class ShadowShaders::ShadowShader : public ShaderProgram { +public: + static TemporaryRef + Create(ConvolutionChannel aConvolutionChannel, size_t aRadius) + { + MOZ_ASSERT(gl->IsCurrent()); + + RefPtr shader = new ShadowShader(); + + ostringstream fragSrc; + fragSrc << "#define RADIUS " << aRadius << endl; + fragSrc << "#define CHANNEL " << (aConvolutionChannel == RED ? '0' : '3') << endl; + fragSrc << ShadowShaderSrc; + shader->Initialize(fragSrc.str().c_str()); + + return shader.forget(); + } + + UniformVec4 uClampRect; + UniformFloatArray uWeights; + UniformFloatArray uOffsets; + UniformVec4 uShadowColor; + UniformSampler uHorizontalConvolution; + +private: + ShadowShader() + : uClampRect("uClampRect") + , uWeights("uWeights") + , uOffsets("uOffsets") + , uShadowColor("uShadowColor") + , uHorizontalConvolution("uHorizontalConvolution", GL::UNIT_0) + {} + + void Initialize(const GLchar* aFragmentSource) + { + ShaderProgram::Initialize(aFragmentSource); + uClampRect.Initialize(*this); + uWeights.Initialize(*this); + uOffsets.Initialize(*this); + uShadowColor.Initialize(*this); + uHorizontalConvolution.Initialize(*this); + } +}; + +ShadowShaders::ShadowShaders() + : mSigma(0) + , mRadius(0) + , mScale(1) + , mFilteredWeightsId(0) +{ + mWeights[0] = 1; +} + +ShadowShaders::~ShadowShaders() +{ +} + +void +ShadowShaders::ConfigureShaders(const IntSize& aFramebufferSize, + const Rect& aShadowRect, + const Color& aShadowColor, + Float aSigma, + ConvolutionChannel aConvolutionChannel, + Rect* aHorizontalConvolutionRect, + GLuint* aHorizontalConvolutionShader, + GLuint* aShadowShader) +{ + MOZ_ASSERT(gl->IsCurrent()); + MOZ_ASSERT(aSigma > 0); + + if (mSigma != aSigma) { + // Compute the right side of a 1D Gaussian blur kernel for aSigma. + size_t radius = 2 * ceil(1.5f * aSigma); + if (radius > kMaxRadius) { + mRadius = kMaxRadius; + mScale = static_cast(radius) / kMaxRadius; + } else { + mRadius = radius; + mScale = 1; + } + + static const float oneOverSqrt2Pi = 0.39894228f; + const float oneOverSigma = 1 / aSigma; + const float a = oneOverSqrt2Pi * oneOverSigma; + const float b = -2 * oneOverSigma * oneOverSigma * mScale * mScale; + + mWeights[0] = a; + float weightSum = mWeights[0]; + for (size_t x = 1; x <= mRadius; x++) { + mWeights[x] = a * exp(x * x * b); + weightSum += 2 * mWeights[x]; + } + + const float weightAdjust = 1 / weightSum; + for (size_t x = 0; x <= mRadius; x++) { + mWeights[x] *= weightAdjust; + } + + // The "filtered weights" and "offsets" are used by the shaders to take + // advantage of texture filtering and perform the convolution in N/2 + // lookups. + mFilteredWeights[0] = mWeights[0]; + for (size_t x = 1; x <= mRadius / 2; x++) { + mFilteredWeights[x] = mWeights[2 * x - 1] + mWeights[2 * x]; + mOffsets[x - 1] = 2 * x - 1 + mWeights[2 * x] / mFilteredWeights[x]; + } + mFilteredWeightsId = gl->GetUniqueId(); + + mSigma = aSigma; + } + + *aHorizontalConvolutionRect = aShadowRect; + aHorizontalConvolutionRect->ScaleInverse(mScale); + + const size_t filteredRadius = mRadius / 2; + float adjustedOffsets[1 + kMaxRadius / 2]; + + if (aHorizontalConvolutionRect && aHorizontalConvolutionShader) { + RefPtr& shader = + mHorizontalConvolutionShaders[filteredRadius][aConvolutionChannel]; + if (!shader) { + shader = HorizontalConvolutionShader::Create(aConvolutionChannel, + filteredRadius); + } + + const GLfloat sampleWidth = mScale / aShadowRect.width; + for (size_t i = 0; i < filteredRadius; i++) { + adjustedOffsets[i] = sampleWidth * mOffsets[i]; + } + + shader->uWeights.Set(mFilteredWeights, 1 + filteredRadius, + mFilteredWeightsId); + shader->uOffsets.Set(adjustedOffsets, filteredRadius); + shader->uLod.Set(2 * (log(mScale) / log(2))); // Double to prefer blurry over blocky. + + *aHorizontalConvolutionShader = *shader; + } + + if (aShadowShader) { + RefPtr& shader = + mShadowShaders[filteredRadius][aConvolutionChannel]; + if (!shader) { + shader = ShadowShader::Create(aConvolutionChannel, filteredRadius); + } + + const Size inverseFramebufferSize(1.0f / aFramebufferSize.width, + 1.0f / aFramebufferSize.height); + + Rect clampRect(*aHorizontalConvolutionRect); + clampRect.Deflate(1); // Deflate by 1 instead of .5 because the convolution + // rect may not lie on pixel boundaries. + clampRect.Scale(inverseFramebufferSize.width, inverseFramebufferSize.height); + + for (size_t i = 0; i < filteredRadius; i++) { + adjustedOffsets[i] = mOffsets[i] * inverseFramebufferSize.height; + } + + shader->uClampRect.Set(clampRect.TopLeft(), clampRect.BottomRight()); + shader->uWeights.Set(mFilteredWeights, 1 + filteredRadius, + mFilteredWeightsId); + shader->uOffsets.Set(adjustedOffsets, 1 + filteredRadius); + shader->uShadowColor.Set(aShadowColor.a * aShadowColor.r, + aShadowColor.a * aShadowColor.g, + aShadowColor.a * aShadowColor.b, + aShadowColor.a); + + *aShadowShader = *shader; + } +} + +} +} +} diff --git a/libazure/nvpr/ShadowShaders.h b/libazure/nvpr/ShadowShaders.h new file mode 100644 index 0000000..35ac6bc --- /dev/null +++ b/libazure/nvpr/ShadowShaders.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_SHADOWSHADERS_H_ +#define MOZILLA_GFX_NVPR_SHADOWSHADERS_H_ + +#include "2D.h" +#include "GL.h" +#include + +namespace mozilla { +namespace gfx { + +class SourceSurfaceNVpr; + +namespace nvpr { + +class ShadowShaders : public nvpr::UserData::Object { + class HorizontalConvolutionShader; + class ShadowShader; + + static const size_t kMaxRadius = 24; + +public: + ShadowShaders(); + ~ShadowShaders(); + + enum ConvolutionChannel { RED, ALPHA, CONVOLUTION_CHANNEL_COUNT }; + void ConfigureShaders(const IntSize& aFramebufferSize, + const Rect& aShadowRect, const Color& aShadowColor, + Float aSigma, ConvolutionChannel aConvolutionChannel, + Rect* aHorizontalConvolutionRect, + GLuint* aHorizontalConvolutionShader, + GLuint* aShadowShader); + +private: + Float mSigma; + size_t mRadius; + Float mScale; + size_t mMaxRadius; + GLfloat mWeights[1 + kMaxRadius]; + GLfloat mFilteredWeights[1 + kMaxRadius / 2]; + GLfloat mOffsets[kMaxRadius / 2]; + UniqueId mFilteredWeightsId; + RefPtr + mHorizontalConvolutionShaders[1 + kMaxRadius / 2][CONVOLUTION_CHANNEL_COUNT]; + RefPtr + mShadowShaders[1 + kMaxRadius / 2][CONVOLUTION_CHANNEL_COUNT]; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_SHADOWSHADERS_H_ */ diff --git a/libazure/nvpr/WGL.cpp b/libazure/nvpr/WGL.cpp new file mode 100644 index 0000000..f68e60f --- /dev/null +++ b/libazure/nvpr/WGL.cpp @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WGL.h" +#include "Logging.h" +#include +#include +#include +#include + +using namespace std; + +namespace mozilla { +namespace gfx { +namespace nvpr { + +void +InitializeGLIfNeeded() +{ + if (gl) { + return; + } + gl = new WGL(); +} + +template bool +WGL::LoadProcAddress(T C::*aProc, const char* aName) +{ + PROC proc = GetProcAddress(aName); + if (!proc) { + // The GL 1.1 functions have to be loaded directly from the dll. + proc = ::GetProcAddress(mGLLibrary, aName); + } + if (!proc) { + gfxWarning() << "Failed to load GL function " << aName << "."; + this->*aProc = nullptr; + return false; + } + this->*aProc = reinterpret_cast(proc); + return true; +} + +WGL::WGL() + : mGLLibrary(0) + , mHWnd(0) + , mDC(0) + , mContext(0) +{ + memset(mSupportedWGLExtensions, 0, sizeof(mSupportedWGLExtensions)); + + mGLLibrary = ::LoadLibrary("opengl32.dll"); + if (!mGLLibrary) { + return; + } + +#define LOAD_WGL_METHOD(NAME) \ + NAME = reinterpret_cast(::GetProcAddress(mGLLibrary, "wgl"#NAME)); \ + if (!NAME) { \ + gfxWarning() << "Failed to find WGL function " #NAME "."; \ + return; \ + } + + FOR_ALL_WGL_ENTRY_POINTS(LOAD_WGL_METHOD); + +#undef LOAD_WGL_METHOD + + HINSTANCE inst = (HINSTANCE)GetModuleHandle(NULL); + + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hInstance = inst; + wc.lpfnWndProc = (WNDPROC) DefWindowProc; + wc.lpszClassName = TEXT("DummyWindow"); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + + if (!RegisterClass(&wc)) { + return; + } + + if (!(mHWnd = CreateWindow(TEXT("DummyWindow"), + TEXT("Dummy OGL Window"), + WS_OVERLAPPEDWINDOW, + 0, 0, 1, 1, + NULL, NULL, + inst, NULL))) { + return; + } + + mDC = ::GetDC(mHWnd); + + PIXELFORMATDESCRIPTOR pfd; + + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.dwFlags = PFD_SUPPORT_OPENGL; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 0; + pfd.cStencilBits = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + + // get the best available match of pixel format for the device context + int iPixelFormat = ChoosePixelFormat(mDC, &pfd); + + // make that the pixel format of the device context + SetPixelFormat(mDC, iPixelFormat, &pfd); + + mContext = CreateContext(mDC); + + DWORD lastError = ::GetLastError(); + + GL::MakeCurrent(); + + if (!LoadProcAddress(&WGL::GetExtensionsStringARB, "wglGetExtensionsStringARB")) { + return; + } + + stringstream extensions(GetExtensionsStringARB(mDC)); + istream_iterator iter(extensions); + istream_iterator end; + + for (; iter != end; iter++) { + const string& extension = *iter; + + if (*iter == "WGL_NV_copy_image") { + if (LoadProcAddress(&WGL::CopyImageSubDataNV, "wglCopyImageSubDataNV")) { + mSupportedWGLExtensions[NV_copy_image] = true; + } + continue; + } + + if (*iter == "WGL_NV_DX_interop2") { + if (LoadProcAddress(&WGL::DXOpenDeviceNV, "wglDXOpenDeviceNV") + && LoadProcAddress(&WGL::DXCloseDeviceNV, "wglDXCloseDeviceNV") + && LoadProcAddress(&WGL::DXRegisterObjectNV, "wglDXRegisterObjectNV") + && LoadProcAddress(&WGL::DXUnregisterObjectNV, "wglDXUnregisterObjectNV") + && LoadProcAddress(&WGL::DXLockObjectsNV, "wglDXLockObjectsNV") + && LoadProcAddress(&WGL::DXUnlockObjectsNV, "wglDXUnlockObjectsNV")) { + mSupportedWGLExtensions[NV_DX_interop2] = true; + } + continue; + } + } + +#define LOAD_GL_METHOD(NAME) \ + if (!LoadProcAddress(&WGL::NAME, "gl"#NAME)) { \ + return; \ + } + + FOR_ALL_PUBLIC_GL_ENTRY_POINTS(LOAD_GL_METHOD); + FOR_ALL_PRIVATE_GL_ENTRY_POINTS(LOAD_GL_METHOD); + +#undef LOAD_GL_METHOD + + Initialize(); +} + +WGL::~WGL() +{ + if (mDC) { + MakeCurrent(mDC, nullptr); + } + + if (mContext) { + DeleteContext(mContext); + } + + if (mDC) { + ::ReleaseDC(mHWnd, mDC); + } + + if (mHWnd) { + DestroyWindow(mHWnd); + } + + if (mGLLibrary) { + ::FreeLibrary(mGLLibrary); + } +} + +bool GL::IsCurrent() const +{ + const WGL* const wgl = static_cast(this); + + return wgl->GetCurrentContext() == wgl->Context(); +} + +void GL::MakeCurrent() const +{ + const WGL* const wgl = static_cast(this); + + if (wgl->IsCurrent()) { + return; + } + + wgl->MakeCurrent(wgl->DC(), wgl->Context()); +} + +bool +GL::BlitTextureToForeignTexture(const IntSize& aSize, GLuint aSourceTextureId, + void* aForeignContext, GLuint aForeignTextureId) +{ + WGL* const wgl = static_cast(this); + + if (!wgl->HasWGLExtension(WGL::NV_copy_image)) { + return false; + } + + wgl->CopyImageSubDataNV(wgl->Context(), aSourceTextureId, GL_TEXTURE_2D, 0, 0, 0, 0, + static_cast(aForeignContext), aForeignTextureId, + GL_TEXTURE_2D, 0, 0, 0, 0, aSize.width, aSize.height, 1); + + return true; +} + +} +} +} diff --git a/libazure/nvpr/WGL.h b/libazure/nvpr/WGL.h new file mode 100644 index 0000000..626f1bd --- /dev/null +++ b/libazure/nvpr/WGL.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_WGL_H_ +#define MOZILLA_GFX_NVPR_WGL_H_ + +#include "GL.h" +#include "WGLDefs.h" + +namespace mozilla { +namespace gfx { +namespace nvpr { + +class WGL : public GL +{ +public: + WGL(); + virtual ~WGL(); + + HDC DC() const { return mDC; } + HGLRC Context() const{ return mContext; } + + enum WGLExtension { + NV_copy_image, + NV_DX_interop2, + WGL_EXTENSION_COUNT + }; + bool HasWGLExtension(WGLExtension aExtension) const + { + return mSupportedWGLExtensions[aExtension]; + } + +#define FOR_ALL_WGL_ENTRY_POINTS(MACRO) \ + MACRO(CreateContext) \ + MACRO(MakeCurrent) \ + MACRO(GetProcAddress) \ + MACRO(DeleteContext) \ + MACRO(GetCurrentContext) + +#define DECLARE_WGL_METHOD(NAME) \ + decltype(&wgl##NAME) NAME; + + FOR_ALL_WGL_ENTRY_POINTS(DECLARE_WGL_METHOD); + +#undef DECLARE_WGL_METHOD + + WGLGetExtensionsStringARB GetExtensionsStringARB; + WGLCopyImageSubDataNV CopyImageSubDataNV; + WGLDXOpenDeviceNV DXOpenDeviceNV; + WGLDXCloseDeviceNV DXCloseDeviceNV; + WGLDXRegisterObjectNV DXRegisterObjectNV; + WGLDXUnregisterObjectNV DXUnregisterObjectNV; + WGLDXLockObjectsNV DXLockObjectsNV; + WGLDXUnlockObjectsNV DXUnlockObjectsNV; + +private: + template bool + LoadProcAddress(T C::*aProc, const char* aName); + + HMODULE mGLLibrary; + HWND mHWnd; + HDC mDC; + HGLRC mContext; + bool mSupportedWGLExtensions[WGL_EXTENSION_COUNT]; +}; + +} +} +} + +#endif /* MOZILLA_GFX_NVPR_WGL_H_ */ diff --git a/libazure/nvpr/WGLDefs.h b/libazure/nvpr/WGLDefs.h new file mode 100644 index 0000000..008c522 --- /dev/null +++ b/libazure/nvpr/WGLDefs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_NVPR_WGLDEFS_H_ +#define MOZILLA_GFX_NVPR_WGLDEFS_H_ + +#include "GLDefs.h" +#include "Windows.h" + +// WGL_ARB_extensions_string +typedef const char * (WINAPI * WGLGetExtensionsStringARB) (HDC hdc); + + +// WGL_NV_copy_image +typedef BOOL (WINAPI * WGLCopyImageSubDataNV) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); + + +// WGL_NV_copy_image +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 + +typedef BOOL (WINAPI * WGLDXSetResourceShareHandleNV) (void *dxObject, HANDLE shareHandle); +typedef HANDLE (WINAPI * WGLDXOpenDeviceNV) (void *dxDevice); +typedef BOOL (WINAPI * WGLDXCloseDeviceNV) (HANDLE hDevice); +typedef HANDLE (WINAPI * WGLDXRegisterObjectNV) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +typedef BOOL (WINAPI * WGLDXUnregisterObjectNV) (HANDLE hDevice, HANDLE hObject); +typedef BOOL (WINAPI * WGLDXObjectAccessNV) (HANDLE hObject, GLenum access); +typedef BOOL (WINAPI * WGLDXLockObjectsNV) (HANDLE hDevice, GLint count, HANDLE *hObjects); +typedef BOOL (WINAPI * WGLDXUnlockObjectsNV) (HANDLE hDevice, GLint count, HANDLE *hObjects); + + +#endif /* MOZILLA_GFX_NVPR_WGLDEFS_H_ */ diff --git a/libazure/perftest/Main.cpp b/libazure/perftest/Main.cpp new file mode 100644 index 0000000..beea192 --- /dev/null +++ b/libazure/perftest/Main.cpp @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SanityChecks.h" +#ifdef WIN32 +#include "TestDrawTargetD2D.h" +#include "TestDrawTargetD2DWarp.h" +#endif +#ifdef USE_SKIA +#include "TestDrawTargetSkiaSoftware.h" +#endif +#ifdef USE_CAIRO +#include "TestDrawTargetCairoImage.h" +#endif + +#include +#include +#include + +struct TestObject { + TestBase *test; + std::string name; +}; + +std::string sGroupNames[] = { "None", "DrawTargets", "Unknown" }; + +using namespace std; + +int +main() +{ + TestObject tests[] = + { + { new SanityChecks(), "Sanity Checks" }, +#ifdef WIN32 + { new TestDrawTargetD2D(), "DrawTarget (D2D)" }, + { new TestDrawTargetD2DWarp(), "DrawTarget (D2D WARP)" }, +#endif +#ifdef USE_SKIA + { new TestDrawTargetSkiaSoftware(), "DrawTarget (Skia Software)" }, +#endif +#ifdef USE_CAIRO + { new TestDrawTargetCairoImage(), "DrawTarget (Cairo Image)" }, +#endif + }; + + bool sGroupInitialized[GROUP_COUNT]; + for (int i = 0; i < GROUP_COUNT; i++) { + sGroupInitialized[i] = false; + } + + int totalFailures = 0; + int totalTests = 0; + stringstream message; + printf("------ STARTING RUNNING TESTS ------\n"); + for (int i = 0; i < sizeof(tests) / sizeof(TestObject); i++) { + ofstream fileStream; + TestGroup group = tests[i].test->GetGroup(); + if (group != GROUP_NONE) { + ios_base::openmode mode = ios_base::binary; + if (sGroupInitialized[group]) { + mode |= ios_base::app; + } + std::string fileName = "PerfData"; + fileName.append(sGroupNames[group]); + fileName.append(".csv"); + fileStream.open(fileName.c_str(), mode); + + if (!sGroupInitialized[group]) { + fileStream.write(",", 1); + for(unsigned int c = 0; c < tests[i].test->mTests.size(); c++) { + fileStream.write(tests[i].test->mTests[c].name.c_str(), tests[i].test->mTests[c].name.size()); + fileStream.write(",", 1); + } + fileStream.write("\n", 1); + } + fileStream.write(tests[i].name.c_str(), tests[i].name.size()); + fileStream.write(",", 1); + sGroupInitialized[group] = true; + } + + message << "--- RUNNING TESTS: " << tests[i].name << " ---\n"; + printf("%s", message.str().c_str()); + message.str(""); + int failures = 0; + totalTests += tests[i].test->RunTests(group != GROUP_NONE ? &fileStream : nullptr); + totalFailures += failures; + + if (group != GROUP_NONE) { + fileStream.write("\n", 1); + } + + // Done with this test! + delete tests[i].test; + } + message << "------ FINISHED RUNNING TESTS ------\nTests run: " << totalTests << "\n"; + printf("%s", message.str().c_str()); + return totalFailures; +} diff --git a/libazure/perftest/SanityChecks.cpp b/libazure/perftest/SanityChecks.cpp new file mode 100644 index 0000000..e6b0f3d --- /dev/null +++ b/libazure/perftest/SanityChecks.cpp @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SanityChecks.h" + +SanityChecks::SanityChecks() +{ + REGISTER_TEST(SanityChecks, Instantaneous); + REGISTER_TEST(SanityChecks, TakeOneSecond); +} + +void +SanityChecks::Instantaneous() +{ +} + +void +SanityChecks::TakeOneSecond() +{ + SleepMS(1000); +} diff --git a/libazure/perftest/SanityChecks.h b/libazure/perftest/SanityChecks.h new file mode 100644 index 0000000..f767348 --- /dev/null +++ b/libazure/perftest/SanityChecks.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestBase.h" + +class SanityChecks : public TestBase +{ +public: + SanityChecks(); + + void Instantaneous(); + void TakeOneSecond(); +}; diff --git a/libazure/perftest/TestBase.cpp b/libazure/perftest/TestBase.cpp new file mode 100644 index 0000000..e405cf6 --- /dev/null +++ b/libazure/perftest/TestBase.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestBase.h" + +#include +#include +#include + +using namespace std; + +const int sN = 10; + +int +TestBase::RunTests(std::ostream *aCSVOutput) +{ + int testsRun = 0; + + Initialize(); + + for(unsigned int i = 0; i < mTests.size(); i++) { + stringstream stream; + stream << "Test (" << mTests[i].name << "): "; + + double *data = new double[sN + 1]; + double average = 0; + + for (int c = 0; c < (sN + 1); c++) { + HighPrecisionMeasurement timer; + + timer.Start(); + // Don't try this at home! We know these are actually pointers to members + // of child clases, so we reinterpret cast those child class pointers to + // TestBase and then call the functions. Because the compiler believes + // these function calls are members of TestBase. + ((*reinterpret_cast((mTests[i].implPointer))).*(mTests[i].funcCall))(); + + data[c] = timer.Measure(); + if (c > 0) { + average += data[c]; + } + } + + average /= sN; + + double sqDiffSum = 0; + for (int c = 1; c < sN + 1; c++) { + sqDiffSum += pow(data[c] - average, 2); + } + + sqDiffSum /= sN; + + if (aCSVOutput) { + stringstream newData; + newData << average << ","; + string str = newData.str(); + aCSVOutput->write(str.c_str(), str.size()); + } + + stream << " " << average << "ms +/- " << (2 * sqrt(sqDiffSum)) << "\n"; + + LogMessage(stream.str()); + + testsRun++; + } + + Finalize(); + + return testsRun; +} + +void +TestBase::LogMessage(string aMessage) +{ + printf("%s", aMessage.c_str()); +} diff --git a/libazure/perftest/TestBase.h b/libazure/perftest/TestBase.h new file mode 100644 index 0000000..a52abe3 --- /dev/null +++ b/libazure/perftest/TestBase.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include +#include + +#ifdef _MSC_VER +// On MSVC otherwise our generic member pointer trick doesn't work. +#pragma pointers_to_members(full_generality, single_inheritance) +#include +#else +#include +#include +#include +#include +#endif + +inline void SleepMS(int aMilliseconds) +{ +#ifdef _MSC_VER + ::Sleep(aMilliseconds); +#else + usleep(1000 * aMilliseconds); +#endif +} + +class HighPrecisionMeasurement +{ +public: + void Start() { +#ifdef WIN32 + ::QueryPerformanceCounter(&mStart); +#else + gettimeofday(&mStart, NULL); +#endif + } + + double Measure() { +#ifdef WIN32 + LARGE_INTEGER end, freq; + ::QueryPerformanceCounter(&end); + ::QueryPerformanceFrequency(&freq); + return (double(end.QuadPart) - double(mStart.QuadPart)) / double(freq.QuadPart) * 1000.00; +#else + struct timeval end; + gettimeofday(&end, NULL); + + long seconds = end.tv_sec - mStart.tv_sec; + long useconds = end.tv_usec - mStart.tv_usec; + double mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5; + return mtime; +#endif + } +private: +#ifdef WIN32 + LARGE_INTEGER mStart; +#else + struct timeval mStart; +#endif +}; + +#define REGISTER_TEST(className, testName) \ + mTests.push_back(Test(static_cast(&className::testName), #testName, this)) + +enum TestGroup +{ + GROUP_NONE, + GROUP_DRAWTARGETS, + GROUP_COUNT +}; + +class TestBase +{ +public: + TestBase() : mGroup(GROUP_NONE) {} + virtual ~TestBase() {} + + typedef void (TestBase::*TestCall)(); + + virtual void Initialize() {} + + int RunTests(std::ostream *aCSVOutput); + + virtual void Finalize() {} + + TestGroup GetGroup() { return mGroup; } + + struct Test { + Test(TestCall aCall, std::string aName, void *aImplPointer) + : funcCall(aCall) + , name(aName) + , implPointer(aImplPointer) + { + } + TestCall funcCall; + std::string name; + void *implPointer; + }; + std::vector mTests; + +protected: + static void LogMessage(std::string aMessage); + + TestGroup mGroup; +private: + // This doesn't really work with our generic member pointer trick. + TestBase(const TestBase &aOther); +}; diff --git a/libazure/perftest/TestDrawTargetBase.cpp b/libazure/perftest/TestDrawTargetBase.cpp new file mode 100644 index 0000000..6714fbf --- /dev/null +++ b/libazure/perftest/TestDrawTargetBase.cpp @@ -0,0 +1,696 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetBase.h" +#include +#include "Tools.h" +#include "Filters.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +TestDrawTargetBase::TestDrawTargetBase() + : mFlush(nullptr) +{ + REGISTER_TEST(TestDrawTargetBase, FillRect50x50x500); + REGISTER_TEST(TestDrawTargetBase, FillRect200x200x500); + REGISTER_TEST(TestDrawTargetBase, FillRect50x50x2000); + REGISTER_TEST(TestDrawTargetBase, FillRect200x200x2000); + REGISTER_TEST(TestDrawTargetBase, FillRect800x800x2000); + REGISTER_TEST(TestDrawTargetBase, FillRect50x50x500Add); + REGISTER_TEST(TestDrawTargetBase, FillRect200x200x500Add); + REGISTER_TEST(TestDrawTargetBase, FillRect50x50x2000Add); + REGISTER_TEST(TestDrawTargetBase, FillRect200x200x2000Add); + REGISTER_TEST(TestDrawTargetBase, CreateGradientStops); + REGISTER_TEST(TestDrawTargetBase, CreateSourceSurfaceForData100x100); + REGISTER_TEST(TestDrawTargetBase, CreateSourceSurfaceForData200x200); + REGISTER_TEST(TestDrawTargetBase, CreateSourceSurfaceForData500x500); + REGISTER_TEST(TestDrawTargetBase, FillRadialSimple); + REGISTER_TEST(TestDrawTargetBase, FillRadialComplex); + REGISTER_TEST(TestDrawTargetBase, FillRadialSimpleUncached); + REGISTER_TEST(TestDrawTargetBase, FillRadialComplexUncached); + REGISTER_TEST(TestDrawTargetBase, DrawTransparentSurfaceUnscaledAligned); + REGISTER_TEST(TestDrawTargetBase, DrawTransparentSurfaceUnscaled); + REGISTER_TEST(TestDrawTargetBase, DrawTransparentSurfaceScaled); + REGISTER_TEST(TestDrawTargetBase, DrawOpaqueSurfaceUnscaledAligned); + REGISTER_TEST(TestDrawTargetBase, DrawOpaqueSurfaceUnscaled); + REGISTER_TEST(TestDrawTargetBase, DrawOpaqueSurfaceScaled); + REGISTER_TEST(TestDrawTargetBase, StrokeRectThin); + REGISTER_TEST(TestDrawTargetBase, StrokeRectThick); + REGISTER_TEST(TestDrawTargetBase, StrokeCurveThin); + REGISTER_TEST(TestDrawTargetBase, StrokeCurveThinUncached); + REGISTER_TEST(TestDrawTargetBase, StrokeCurveThick); + REGISTER_TEST(TestDrawTargetBase, MaskSurface100x100); + REGISTER_TEST(TestDrawTargetBase, MaskSurface500x500); + REGISTER_TEST(TestDrawTargetBase, DrawShadow10x10SmallRadius); + REGISTER_TEST(TestDrawTargetBase, DrawShadow200x200SmallRadius); + REGISTER_TEST(TestDrawTargetBase, DrawShadow10x10LargeRadius); + REGISTER_TEST(TestDrawTargetBase, DrawShadow200x200LargeRadius); + REGISTER_TEST(TestDrawTargetBase, CreateRandom200); + REGISTER_TEST(TestDrawTargetBase, DrawTurbulence500x500x10); + REGISTER_TEST(TestDrawTargetBase, DrawMorphologyFilter200x200x100Radius40); + REGISTER_TEST(TestDrawTargetBase, Premultiply200x200x1000); + REGISTER_TEST(TestDrawTargetBase, Unpremultiply200x200x1000); + REGISTER_TEST(TestDrawTargetBase, ComponentTransfer200x200x1000); + REGISTER_TEST(TestDrawTargetBase, ColorMatrix200x200x1000); + REGISTER_TEST(TestDrawTargetBase, Composite200x200x1000); + REGISTER_TEST(TestDrawTargetBase, CompositeA8Single200x200x1000); + REGISTER_TEST(TestDrawTargetBase, Blend200x200x1000); + REGISTER_TEST(TestDrawTargetBase, Blur500x500x50); + REGISTER_TEST(TestDrawTargetBase, ArithmeticCombine200x200x100); + + mGroup = GROUP_DRAWTARGETS; +} + +void +TestDrawTargetBase::FillSquare(int aSize, int aRepeat, CompositionOp aOp) +{ + for (int i = 0; i < aRepeat; i++) { + mDT->FillRect(Rect(i / 6, i / 4, aSize, aSize), ColorPattern(Color(1.0f, 0, 0, 1.0f)), DrawOptions(0.5f, aOp)); + } + Flush(); +} + +void +TestDrawTargetBase::FillRect50x50x500() +{ + FillSquare(50, 500); +} + +void +TestDrawTargetBase::FillRect200x200x500() +{ + FillSquare(200, 500); +} + +void +TestDrawTargetBase::FillRect50x50x2000() +{ + FillSquare(50, 2000); +} + +void +TestDrawTargetBase::FillRect200x200x2000() +{ + FillSquare(200, 2000); +} + +void +TestDrawTargetBase::FillRect800x800x2000() +{ + FillSquare(800, 2000); +} + +void +TestDrawTargetBase::FillRect50x50x500Add() +{ + FillSquare(50, 500, CompositionOp::OP_ADD); +} + +void +TestDrawTargetBase::FillRect200x200x500Add() +{ + FillSquare(200, 500, CompositionOp::OP_ADD); +} + +void +TestDrawTargetBase::FillRect50x50x2000Add() +{ + FillSquare(50, 2000, CompositionOp::OP_ADD); +} + +void +TestDrawTargetBase::FillRect200x200x2000Add() +{ + FillSquare(200, 2000, CompositionOp::OP_ADD); +} + +void +TestDrawTargetBase::CreateGradientStops() +{ + GradientStop stops[2]; + stops[0].color = Color(1.0f, 0, 0, 1.0f); + stops[0].offset = 0; + stops[1].color = Color(0, 1.0f, 0, 1.0f); + stops[1].offset = 1.0f; + + for (int i = 0; i < 500; i++) { + RefPtr dtStops = mDT->CreateGradientStops(stops, 2); + } +} + +void +TestDrawTargetBase::CreateSourceSurfaceForData100x100() +{ + unsigned char *surfData = new unsigned char[100 * 100 * 4]; + + for (int i = 0; i < 200; i++) { + RefPtr surf = mDT->CreateSourceSurfaceFromData(surfData, IntSize(100, 100), 400, SurfaceFormat::B8G8R8A8); + } + + delete [] surfData; +} + +void +TestDrawTargetBase::CreateSourceSurfaceForData200x200() +{ + unsigned char *surfData = new unsigned char[200 * 200 * 4]; + + for (int i = 0; i < 200; i++) { + RefPtr surf = mDT->CreateSourceSurfaceFromData(surfData, IntSize(200, 200), 800, SurfaceFormat::B8G8R8A8); + } + + delete [] surfData; +} + +void +TestDrawTargetBase::CreateSourceSurfaceForData500x500() +{ + unsigned char *surfData = new unsigned char[500 * 500 * 4]; + + for (int i = 0; i < 200; i++) { + RefPtr surf = mDT->CreateSourceSurfaceFromData(surfData, IntSize(500, 500), 2000, SurfaceFormat::B8G8R8A8); + } + + delete [] surfData; +} + +void +TestDrawTargetBase::FillRadialSimple() +{ + RefPtr stops = CreateSimpleGradientStops(); + for (int i = 0; i < 200; i++) { + mDT->FillRect(Rect(i / 6, i / 4, 500, 500), RadialGradientPattern(Point(250, 250), Point(250, 250), 0, 500, stops)); + } + Flush(); +} + +void +TestDrawTargetBase::FillRadialComplex() +{ + RefPtr stops = CreateSimpleGradientStops(); + for (int i = 0; i < 200; i++) { + mDT->FillRect(Rect(i / 6, i / 4, 500, 500), RadialGradientPattern(Point(250, 250), Point(300, 300), 40, 500, stops)); + } + Flush(); +} + +void +TestDrawTargetBase::FillRadialSimpleUncached() +{ + for (int i = 0; i < 200; i++) { + RefPtr stops = CreateSimpleGradientStops(); + mDT->FillRect(Rect(float(i) / 6, float(i) / 4, 500, 500), RadialGradientPattern(Point(250, 250), Point(250, 250), 0, 500, stops)); + } + Flush(); +} + +void +TestDrawTargetBase::FillRadialComplexUncached() +{ + for (int i = 0; i < 200; i++) { + RefPtr stops = CreateSimpleGradientStops(); + mDT->FillRect(Rect(float(i) / 6, float(i) / 4, 500, 500), RadialGradientPattern(Point(250, 250), Point(300, 300), 40, 500, stops)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawTransparentSurfaceUnscaledAligned() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8A8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(i, i, 400, 400), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawTransparentSurfaceUnscaled() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8A8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(float(i) / 6, float(i) / 4, 400, 400), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawTransparentSurfaceScaled() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8A8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(float(i) / 6, float(i) / 4, 500, 500), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawOpaqueSurfaceUnscaledAligned() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8X8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(i, i, 400, 400), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawOpaqueSurfaceUnscaled() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8X8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(float(i) / 6, float(i) / 4, 400, 400), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::DrawOpaqueSurfaceScaled() +{ + RefPtr surf = CreateSquareRandomSourceSurface(400, SurfaceFormat::B8G8R8X8); + for (int i = 0; i < 200; i++) { + mDT->DrawSurface(surf, Rect(float(i) / 6, float(i) / 4, 500, 500), Rect(0, 0, 400, 400)); + } + Flush(); +} + +void +TestDrawTargetBase::StrokeRectThin() +{ + for (int i = 0; i < 500; i++) { + mDT->StrokeRect(Rect(30, 30, 200, 200), ColorPattern(Color(0, 0, 0, 1)), StrokeOptions(1.0f)); + } + Flush(); +} + +void +TestDrawTargetBase::StrokeRectThick() +{ + for (int i = 0; i < 500; i++) { + mDT->StrokeRect(Rect(30, 30, 200, 200), ColorPattern(Color(0, 0, 0, 1)), StrokeOptions(30.0f)); + } + Flush(); +} + +void +TestDrawTargetBase::StrokeCurveThin() +{ + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(30, 30)); + builder->BezierTo(Point(600, 50), Point(-100, 400), Point(700, 700)); + RefPtr path = builder->Finish(); + for (int i = 0; i < 500; i++) { + mDT->Stroke(path, ColorPattern(Color(0, 0, 0, 1)), StrokeOptions(1.0f)); + } + Flush(); +} + +void +TestDrawTargetBase::StrokeCurveThinUncached() +{ + for (int i = 0; i < 500; i++) { + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(30, 30)); + builder->BezierTo(Point(600, 50), Point(-100, 400), Point(700, 700)); + RefPtr path = builder->Finish(); + mDT->Stroke(path, ColorPattern(Color(0, 0, 0, 1)), StrokeOptions(1.0f)); + } + Flush(); +} + +void +TestDrawTargetBase::StrokeCurveThick() +{ + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(30, 30)); + builder->BezierTo(Point(600, 50), Point(-100, 400), Point(700, 700)); + RefPtr path = builder->Finish(); + for (int i = 0; i < 500; i++) { + mDT->Stroke(path, ColorPattern(Color(0, 0, 0, 1)), StrokeOptions(30.0f)); + } + Flush(); +} + +void +TestDrawTargetBase::MaskSurface100x100() +{ + RefPtr surf = CreateSquareRandomSourceSurface(100, SurfaceFormat::B8G8R8A8); + RefPtr mask = CreateSquareRandomSourceSurface(100, SurfaceFormat::A8); + for (int i = 0; i < 200; i++) { + mDT->MaskSurface(SurfacePattern(surf, ExtendMode::CLAMP), mask, Point()); + } + Flush(); +} + +void +TestDrawTargetBase::MaskSurface500x500() +{ + RefPtr surf = CreateSquareRandomSourceSurface(500, SurfaceFormat::B8G8R8A8); + RefPtr mask = CreateSquareRandomSourceSurface(500, SurfaceFormat::A8); + for (int i = 0; i < 200; i++) { + mDT->MaskSurface(SurfacePattern(surf, ExtendMode::CLAMP), mask, Point()); + } + Flush(); +} + +void +TestDrawTargetBase::DrawShadow10x10SmallRadius() +{ + RefPtr surf = CreateSquareRandomSourceSurface(10, SurfaceFormat::B8G8R8A8); + RefPtr dt = mDT->CreateShadowDrawTarget(IntSize(10, 10), SurfaceFormat::B8G8R8A8, 3.0f); + dt->DrawSurface(surf, Rect(0, 0, 10, 10), Rect(0, 0, 10, 10)); + surf = dt->Snapshot(); + for (int i = 0; i < 200; i++) { + mDT->DrawSurfaceWithShadow(surf, Point(100, 100), Color(0, 0, 0, 1.0f), Point(), 3.0f, CompositionOp::OP_OVER); + } + Flush(); +} + +void +TestDrawTargetBase::DrawShadow200x200SmallRadius() +{ + RefPtr surf = CreateSquareRandomSourceSurface(200, SurfaceFormat::B8G8R8A8); + RefPtr dt = mDT->CreateShadowDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8, 3.0f); + dt->DrawSurface(surf, Rect(0, 0, 200, 200), Rect(0, 0, 200, 200)); + surf = dt->Snapshot(); + for (int i = 0; i < 200; i++) { + mDT->DrawSurfaceWithShadow(surf, Point(100, 100), Color(0, 0, 0, 1.0f), Point(), 3.0f, CompositionOp::OP_OVER); + } + Flush(); +} + +void +TestDrawTargetBase::DrawShadow10x10LargeRadius() +{ + RefPtr surf = CreateSquareRandomSourceSurface(10, SurfaceFormat::B8G8R8A8); + RefPtr dt = mDT->CreateShadowDrawTarget(IntSize(10, 10), SurfaceFormat::B8G8R8A8, 20.0f); + dt->DrawSurface(surf, Rect(0, 0, 10, 10), Rect(0, 0, 10, 10)); + surf = dt->Snapshot(); + for (int i = 0; i < 200; i++) { + mDT->DrawSurfaceWithShadow(surf, Point(100, 100), Color(0, 0, 0, 1.0f), Point(), 20.0f, CompositionOp::OP_OVER); + } + Flush(); +} + +void +TestDrawTargetBase::DrawShadow200x200LargeRadius() +{ + RefPtr surf = CreateSquareRandomSourceSurface(200, SurfaceFormat::B8G8R8A8); + RefPtr dt = mDT->CreateShadowDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8, 20.0f); + dt->DrawSurface(surf, Rect(0, 0, 200, 200), Rect(0, 0, 200, 200)); + surf = dt->Snapshot(); + for (int i = 0; i < 200; i++) { + mDT->DrawSurfaceWithShadow(surf, Point(100, 100), Color(0, 0, 0, 1.0f), Point(), 20.0f, CompositionOp::OP_OVER); + } + Flush(); +} + +void +TestDrawTargetBase::CreateRandom200() +{ + mRandom200 = CreateSquareRandomSourceSurface(200, SurfaceFormat::B8G8R8A8, false); +} + +void +TestDrawTargetBase::DrawTurbulence500x500x10() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::TURBULENCE); + + for (int32_t i = 0; i < 10; i++) { + filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY, Size(0.025, 0.025)); + filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES, 4u); + filter->SetAttribute(ATT_TURBULENCE_SEED, 0u); + filter->SetAttribute(ATT_TURBULENCE_STITCHABLE, false); + filter->SetAttribute(ATT_TURBULENCE_TYPE, (uint32_t)TURBULENCE_TYPE_TURBULENCE); + filter->SetAttribute(ATT_TURBULENCE_RECT, IntRect(0, 0, 500, 500)); + + mDT->DrawFilter(filter, Rect(0, 0, 500, 500), Point()); + } + Flush(); +} + +void +TestDrawTargetBase::DrawMorphologyFilter200x200x100Radius40() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr src = mRandom200; + + for (int32_t i = 0; i < 100; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::MORPHOLOGY); + filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(40, 40)); + filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)MORPHOLOGY_OPERATOR_DILATE); + filter->SetInput(0, src); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::Premultiply200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::PREMULTIPLY); + filter->SetInput(IN_PREMULTIPLY_IN, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::Unpremultiply200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, surf); + dt->DrawFilter(premultiply, Rect(0, 0, 200, 200), Point()); + surf = dt->Snapshot(); + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::UNPREMULTIPLY); + filter->SetInput(IN_UNPREMULTIPLY_IN, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::ComponentTransfer200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + + Float table[256]; + uint8_t c = 0; + for (size_t i = 0; i < 256; i++) { + table[i] = c; + c += 17; + } + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::DISCRETE_TRANSFER); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, table, 256); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, table, 256); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, table, 256); + filter->SetInput(IN_DISCRETE_TRANSFER_IN, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + // Flush(); +} + +void +TestDrawTargetBase::ColorMatrix200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + + Matrix5x4 m(0.1, 0.4, 0.3, 0.2, + 0.4, 0.2, 0.2, 0.1, + 0.2, 0.3, 0.1, 0.4, + 0.3, 0.1, 0.4, 0.2, + 0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::COLOR_MATRIX); + filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, m); + filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT); + filter->SetInput(IN_COLOR_MATRIX_IN, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::Composite200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, surf); + dt->DrawFilter(premultiply, Rect(0, 0, 200, 200), Point()); + surf = dt->Snapshot(); + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::COMPOSITE); + filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_XOR); + filter->SetInput(IN_COMPOSITE_IN_START, surf); + filter->SetInput(IN_COMPOSITE_IN_START + 1, surf); + filter->SetInput(IN_COMPOSITE_IN_START + 2, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::CompositeA8Single200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(200, 200), SurfaceFormat::A8); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, surf); + dt->DrawFilter(premultiply, Rect(0, 0, 200, 200), Point()); + surf = dt->Snapshot(); + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::COMPOSITE); + filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)COMPOSITE_OPERATOR_OVER); + filter->SetInput(IN_COMPOSITE_IN_START, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::Blend200x200x1000() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, surf); + dt->DrawFilter(premultiply, Rect(0, 0, 200, 200), Point()); + surf = dt->Snapshot(); + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::BLEND); + filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)BLEND_MODE_MULTIPLY); + filter->SetInput(IN_BLEND_IN, surf); + filter->SetInput(IN_BLEND_IN2, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::Blur500x500x50() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(500, 500), SurfaceFormat::B8G8R8A8); + RefPtr tile = mDT->CreateFilter(FilterType::TILE); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, mRandom200); + tile->SetAttribute(ATT_TILE_SOURCE_RECT, IntRect(0, 0, 200, 200)); + tile->SetInput(IN_TILE_IN, premultiply); + dt->DrawFilter(tile, Rect(0, 0, 500, 500), Point()); + RefPtr surf = dt->Snapshot(); + + for (int i = 0; i < 50; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::GAUSSIAN_BLUR); + filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, 40.0f); + filter->SetInput(IN_GAUSSIAN_BLUR_IN, surf); + mDT->DrawFilter(filter, Rect(0, 0, 500, 500), Point()); + } + + Flush(); +} + +void +TestDrawTargetBase::ArithmeticCombine200x200x100() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr surf = mRandom200; + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(200, 200), SurfaceFormat::B8G8R8A8); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(IN_PREMULTIPLY_IN, surf); + dt->DrawFilter(premultiply, Rect(0, 0, 200, 200), Point()); + surf = dt->Snapshot(); + Float coeffs[4] = { 0.2f, -0.5f, 0.3f, 0.1f }; + + for (int i = 0; i < 1000; i++) { + RefPtr filter = mDT->CreateFilter(FilterType::ARITHMETIC_COMBINE); + filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS, coeffs, 4); + filter->SetInput(IN_ARITHMETIC_COMBINE_IN, surf); + filter->SetInput(IN_ARITHMETIC_COMBINE_IN2, surf); + mDT->DrawFilter(filter, Rect(0, 0, 200, 200), Point()); + } + + Flush(); +} + +TemporaryRef +TestDrawTargetBase::CreateSquareRandomSourceSurface(int aSize, SurfaceFormat aFormat, bool aLeaveUninitialized) +{ + size_t length = aSize * aSize * BytesPerPixel(aFormat); + unsigned char *surfData = new unsigned char[length]; + + if (!aLeaveUninitialized) { + uint8_t c = 0; + for (size_t i = 0; i < length; i++) { + surfData[i] = c; + c += 113; + if (i % 4 == 0) { + c += 173; + } + } + } + + RefPtr surf = mDT->CreateSourceSurfaceFromData(surfData, IntSize(aSize, aSize), aSize * BytesPerPixel(aFormat), aFormat); + + delete [] surfData; + + return surf; +} + +TemporaryRef +TestDrawTargetBase::CreateSimpleGradientStops() +{ + GradientStop stops[2]; + stops[0].color = Color(1.0f, 0, 0, 1.0f); + stops[0].offset = 0; + stops[1].color = Color(0, 1.0f, 0, 1.0f); + stops[1].offset = 1.0f; + + return mDT->CreateGradientStops(stops, 2); +} diff --git a/libazure/perftest/TestDrawTargetBase.h b/libazure/perftest/TestDrawTargetBase.h new file mode 100644 index 0000000..3b6e33b --- /dev/null +++ b/libazure/perftest/TestDrawTargetBase.h @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "2D.h" +#include "TestBase.h" + +#define DT_WIDTH 1000 +#define DT_HEIGHT 1000 + +typedef void(*FlushFunc)(void*); + +/* This general DrawTarget test class can be reimplemented by a child class + * with optional additional drawtarget-specific tests. And is intended to run + * on a 1000x1000 32 BPP drawtarget. + */ +class TestDrawTargetBase : public TestBase +{ +public: + void FillRect50x50x500(); + void FillRect50x50x2000(); + void FillRect200x200x500(); + void FillRect200x200x2000(); + void FillRect800x800x2000(); + void FillRect50x50x500Add(); + void FillRect50x50x2000Add(); + void FillRect200x200x500Add(); + void FillRect200x200x2000Add(); + void CreateGradientStops(); + void CreateSourceSurfaceForData100x100(); + void CreateSourceSurfaceForData200x200(); + void CreateSourceSurfaceForData500x500(); + void FillRadialSimple(); + void FillRadialComplex(); + void FillRadialSimpleUncached(); + void FillRadialComplexUncached(); + void DrawTransparentSurfaceUnscaledAligned(); + void DrawTransparentSurfaceUnscaled(); + void DrawTransparentSurfaceScaled(); + void DrawOpaqueSurfaceUnscaledAligned(); + void DrawOpaqueSurfaceUnscaled(); + void DrawOpaqueSurfaceScaled(); + void StrokeRectThin(); + void StrokeRectThick(); + void StrokeCurveThin(); + void StrokeCurveThinUncached(); + void StrokeCurveThick(); + void MaskSurface100x100(); + void MaskSurface500x500(); + void DrawShadow10x10SmallRadius(); + void DrawShadow200x200SmallRadius(); + void DrawShadow10x10LargeRadius(); + void DrawShadow200x200LargeRadius(); + void CreateRandom200(); + void DrawTurbulence500x500x10(); + void DrawMorphologyFilter200x200x100Radius40(); + void Premultiply200x200x1000(); + void Unpremultiply200x200x1000(); + void ComponentTransfer200x200x1000(); + void ColorMatrix200x200x1000(); + void Composite200x200x1000(); + void CompositeA8Single200x200x1000(); + void Blend200x200x1000(); + void Blur500x500x50(); + void ArithmeticCombine200x200x100(); + +protected: + FlushFunc mFlush; + + TestDrawTargetBase(); + + void Flush() { + if (mFlush) mFlush(this); + } + + void FillSquare(int aSize, int aRepeat, mozilla::gfx::CompositionOp aOp = mozilla::gfx::CompositionOp::OP_OVER); + mozilla::TemporaryRef CreateSquareRandomSourceSurface(int aSize, mozilla::gfx::SurfaceFormat aFormat, bool aLeaveUninitialized = true); + mozilla::TemporaryRef CreateSimpleGradientStops(); + + mozilla::RefPtr mDT; + mozilla::RefPtr mRandom200; +}; diff --git a/libazure/perftest/TestDrawTargetCairoImage.cpp b/libazure/perftest/TestDrawTargetCairoImage.cpp new file mode 100644 index 0000000..2ec4ace --- /dev/null +++ b/libazure/perftest/TestDrawTargetCairoImage.cpp @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetCairoImage.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +using namespace mozilla::gfx; +TestDrawTargetCairoImage::TestDrawTargetCairoImage() +{ + mDT = Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); +} diff --git a/libazure/perftest/TestDrawTargetCairoImage.h b/libazure/perftest/TestDrawTargetCairoImage.h new file mode 100644 index 0000000..36bc337 --- /dev/null +++ b/libazure/perftest/TestDrawTargetCairoImage.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestDrawTargetBase.h" + +class TestDrawTargetCairoImage : public TestDrawTargetBase +{ +public: + TestDrawTargetCairoImage(); + +private: +}; diff --git a/libazure/src/gfx/2d/unittest/TestDrawTargetD2D.cpp b/libazure/perftest/TestDrawTargetD2D.cpp similarity index 51% rename from libazure/src/gfx/2d/unittest/TestDrawTargetD2D.cpp rename to libazure/perftest/TestDrawTargetD2D.cpp index fd93e93..7a5ccb3 100644 --- a/libazure/src/gfx/2d/unittest/TestDrawTargetD2D.cpp +++ b/libazure/perftest/TestDrawTargetD2D.cpp @@ -2,12 +2,26 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestDrawTargetD2D.h" - -using namespace mozilla::gfx; -TestDrawTargetD2D::TestDrawTargetD2D() -{ + +#include "TestDrawTargetD2D.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +void D2DFlush(void* aTest) +{ + TestDrawTargetD2D* test = static_cast(aTest); + test->Flush(); +} + +using namespace mozilla::gfx; +TestDrawTargetD2D::TestDrawTargetD2D() +{ +} + +void +TestDrawTargetD2D::Initialize() +{ ::D3D10CreateDevice1(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, @@ -15,9 +29,34 @@ TestDrawTargetD2D::TestDrawTargetD2D() D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, D3D10_FEATURE_LEVEL_10_0, D3D10_1_SDK_VERSION, - byRef(mDevice)); - - Factory::SetDirect3D10Device(mDevice); - - mDT = Factory::CreateDrawTarget(BACKEND_DIRECT2D, IntSize(DT_WIDTH, DT_HEIGHT), FORMAT_B8G8R8A8); -} + byRef(mDevice)); + + Factory::SetDirect3D10Device(mDevice); + + mDT = Factory::CreateDrawTarget(BackendType::DIRECT2D, IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + mFlush = D2DFlush; + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + Flush(); +} + +void +TestDrawTargetD2D::Flush() +{ + mDT->Flush(); + + RefPtr query; + D3D10_QUERY_DESC desc; + desc.Query = D3D10_QUERY_EVENT; + desc.MiscFlags = 0; + mDevice->CreateQuery(&desc, byRef(query)); + query->End(); + while (query->GetData(nullptr, 0, 0) == S_FALSE) {} +} + +void +TestDrawTargetD2D::Finalize() +{ + mDT = nullptr; + mDevice = nullptr; +} diff --git a/libazure/src/gfx/2d/unittest/TestDrawTargetD2D.h b/libazure/perftest/TestDrawTargetD2D.h similarity index 89% rename from libazure/src/gfx/2d/unittest/TestDrawTargetD2D.h rename to libazure/perftest/TestDrawTargetD2D.h index 40f5f83..2d280cb 100644 --- a/libazure/src/gfx/2d/unittest/TestDrawTargetD2D.h +++ b/libazure/perftest/TestDrawTargetD2D.h @@ -2,18 +2,24 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include "TestDrawTargetBase.h" - -#include - -class TestDrawTargetD2D : public TestDrawTargetBase -{ -public: - TestDrawTargetD2D(); - -private: - mozilla::RefPtr mDevice; + +#pragma once + +#include "TestDrawTargetBase.h" + +#include + +class TestDrawTargetD2D : public TestDrawTargetBase +{ +public: + TestDrawTargetD2D(); + + void Initialize(); + + void Flush(); + + void Finalize(); + +private: + mozilla::RefPtr mDevice; }; diff --git a/libazure/perftest/TestDrawTargetD2DWarp.cpp b/libazure/perftest/TestDrawTargetD2DWarp.cpp new file mode 100644 index 0000000..4eb6dd2 --- /dev/null +++ b/libazure/perftest/TestDrawTargetD2DWarp.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetD2DWarp.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +static void D2DFlush(void* aTest) +{ + TestDrawTargetD2DWarp* test = static_cast(aTest); + test->Flush(); +} + +using namespace mozilla::gfx; +TestDrawTargetD2DWarp::TestDrawTargetD2DWarp() +{ +} + +void +TestDrawTargetD2DWarp::Initialize() +{ + ::D3D10CreateDevice1(nullptr, + D3D10_DRIVER_TYPE_WARP, + nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT, + D3D10_FEATURE_LEVEL_10_0, + D3D10_1_SDK_VERSION, + byRef(mDevice)); + + Factory::SetDirect3D10Device(mDevice); + + mDT = Factory::CreateDrawTarget(BackendType::DIRECT2D, IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + mFlush = D2DFlush; + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + Flush(); +} + +void +TestDrawTargetD2DWarp::Flush() +{ + mDT->Flush(); + + RefPtr query; + D3D10_QUERY_DESC desc; + desc.Query = D3D10_QUERY_EVENT; + desc.MiscFlags = 0; + mDevice->CreateQuery(&desc, byRef(query)); + query->End(); + while (query->GetData(nullptr, 0, 0) == S_FALSE) {} +} + +void +TestDrawTargetD2DWarp::Finalize() +{ + mDT = nullptr; + mDevice = nullptr; +} diff --git a/libazure/perftest/TestDrawTargetD2DWarp.h b/libazure/perftest/TestDrawTargetD2DWarp.h new file mode 100644 index 0000000..c57a775 --- /dev/null +++ b/libazure/perftest/TestDrawTargetD2DWarp.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestDrawTargetBase.h" + +#include + +class TestDrawTargetD2DWarp : public TestDrawTargetBase +{ +public: + TestDrawTargetD2DWarp(); + + void Initialize(); + + void Flush(); + + void Finalize(); + +private: + mozilla::RefPtr mDevice; +}; diff --git a/libazure/perftest/TestDrawTargetSkiaSoftware.cpp b/libazure/perftest/TestDrawTargetSkiaSoftware.cpp new file mode 100644 index 0000000..63055bf --- /dev/null +++ b/libazure/perftest/TestDrawTargetSkiaSoftware.cpp @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetSkiaSoftware.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +using namespace mozilla::gfx; +TestDrawTargetSkiaSoftware::TestDrawTargetSkiaSoftware() +{ + mDT = Factory::CreateDrawTarget(BackendType::SKIA, IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); +} diff --git a/libazure/perftest/TestDrawTargetSkiaSoftware.h b/libazure/perftest/TestDrawTargetSkiaSoftware.h new file mode 100644 index 0000000..cfe48dd --- /dev/null +++ b/libazure/perftest/TestDrawTargetSkiaSoftware.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestDrawTargetBase.h" + +class TestDrawTargetSkiaSoftware : public TestDrawTargetBase +{ +public: + TestDrawTargetSkiaSoftware(); + +private: +}; diff --git a/libazure/perftest/perftest.vcxproj b/libazure/perftest/perftest.vcxproj new file mode 100644 index 0000000..1117959 --- /dev/null +++ b/libazure/perftest/perftest.vcxproj @@ -0,0 +1,158 @@ + + + + + Debug (With Skia) + Win32 + + + Debug + Win32 + + + Release (With Skia) + Win32 + + + Release + Win32 + + + + {AE3B14C7-6EE2-482A-B7C0-B9F851B8E172} + perftest + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + $(SolutionDir)\..\cairo\src\Release;$(SolutionDir)\..\skia\out\Release;$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + $(SolutionDir)\..\cairo\src\Debug;$(SolutionDir)\..\skia\out\Debug;$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + + Level3 + Disabled + ../ + WIN32;_MBCS;USE_D2D1_1;;%(PreprocessorDefinitions); + + + true + ../$(Configuration)/gfx2d.lib;opengl32.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + ../ + WIN32;_MBCS;USE_D2D1_1;;%(PreprocessorDefinitions);USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD + + + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + Level3 + MaxSpeed + true + true + ../ + USE_NVPR;WIN32;_MBCS;USE_D2D1_1;;%(PreprocessorDefinitions); + + + true + true + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + ../ + WIN32;_MBCS;USE_D2D1_1;;%(PreprocessorDefinitions);USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD + + + true + true + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libazure/perftest/perftest.vcxproj.filters b/libazure/perftest/perftest.vcxproj.filters new file mode 100644 index 0000000..3a33958 --- /dev/null +++ b/libazure/perftest/perftest.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libazure/player2d/TreeItems.cpp b/libazure/player2d/TreeItems.cpp new file mode 100644 index 0000000..5a7ed9b --- /dev/null +++ b/libazure/player2d/TreeItems.cpp @@ -0,0 +1,54 @@ +#include "TreeItems.h" +#include "drawtargetview.h" +#include "sourcesurfaceview.h" +#include "gradientstopsview.h" + +#include + +using namespace mozilla::gfx; +using namespace std; + +QWidget* +DrawTargetItem::CreateViewWidget() +{ + return new DrawTargetView(mRefPtr, mTranslator); +} + +QString +DrawTargetItem::GetTitle() const +{ + stringstream stream; + stream << "DrawTarget (" << mRefPtr << ")"; + + return QString::fromStdString(stream.str()); +} + +QWidget* +SourceSurfaceItem::CreateViewWidget() +{ + return new SourceSurfaceView(mRefPtr, mTranslator); +} + +QString +SourceSurfaceItem::GetTitle() const +{ + stringstream stream; + stream << "SourceSurface (" << mRefPtr << ")"; + + return QString::fromStdString(stream.str()); +} + +QWidget* +GradientStopsItem::CreateViewWidget() +{ + return new GradientStopsView(mRefPtr, mTranslator); +} + +QString +GradientStopsItem::GetTitle() const +{ + stringstream stream; + stream << "GradientStops (" << mRefPtr << ")"; + + return QString::fromStdString(stream.str()); +} diff --git a/libazure/player2d/TreeItems.h b/libazure/player2d/TreeItems.h new file mode 100644 index 0000000..585c7a3 --- /dev/null +++ b/libazure/player2d/TreeItems.h @@ -0,0 +1,91 @@ +#ifndef TREEITEMS_H +#define TREEITEMS_H + +#include "qtreewidget.h" +#include "RecordedEvent.h" + +class EventItem : public QTreeWidgetItem +{ +public: + EventItem(const QStringList &aStrings, QTreeWidget *aView, int64_t aID) + : QTreeWidgetItem(aView, aStrings) + , mID(aID) + {} + + int64_t mID; + double mTiming; +}; + +class ObjectItem : public QTreeWidgetItem +{ +protected: + ObjectItem(QTreeWidget *aView, const QStringList &aStrings, + mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator) + : QTreeWidgetItem(aView, aStrings) + , mRefPtr(aRefPtr) + , mTranslator(aTranslator) + {} + +public: + virtual QWidget *CreateViewWidget() = 0; + + virtual QString GetTitle() const { return ""; } + mozilla::gfx::ReferencePtr GetObjectRef() { return mRefPtr; } + +protected: + mozilla::gfx::ReferencePtr mRefPtr; + mozilla::gfx::Translator *mTranslator; +}; + +class DrawTargetItem : public ObjectItem +{ +public: + DrawTargetItem(const QStringList &aStrings, QTreeWidget *aView, + mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator) + : ObjectItem(aView, aStrings, aRefPtr, aTranslator) + { + } + + virtual QWidget *CreateViewWidget(); + virtual QString GetTitle() const; +}; + +class GradientStopsItem : public ObjectItem +{ +public: + GradientStopsItem(const QStringList &aStrings, QTreeWidget *aView, + mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator) + : ObjectItem(aView, aStrings, aRefPtr, aTranslator) + { + } + + virtual QWidget *CreateViewWidget(); + virtual QString GetTitle() const; +}; + +class PathItem : public ObjectItem +{ +public: + PathItem(const QStringList &aStrings, QTreeWidget *aView, + mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator) + : ObjectItem(aView, aStrings, aRefPtr, aTranslator) + { + } + + virtual QWidget *CreateViewWidget() { return NULL; } +}; + +class SourceSurfaceItem : public ObjectItem +{ +public: + SourceSurfaceItem(const QStringList &aStrings, QTreeWidget *aView, + mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator) + : ObjectItem(aView, aStrings, aRefPtr, aTranslator) + { + } + + virtual QWidget *CreateViewWidget(); + virtual QString GetTitle() const; +}; + +#endif // TREEITEMS_H diff --git a/libazure/player2d/calltiminganalysis.cpp b/libazure/player2d/calltiminganalysis.cpp new file mode 100644 index 0000000..8a66e85 --- /dev/null +++ b/libazure/player2d/calltiminganalysis.cpp @@ -0,0 +1,88 @@ +#include "calltiminganalysis.h" +#include "ui_calltiminganalysis.h" + +#include + +#include "mainwindow.h" + +#include "RecordedEvent.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +CallTimingAnalysis::CallTimingAnalysis(MainWindow *aMainWindow) : + QMainWindow(aMainWindow), + ui(new Ui::CallTimingAnalysis), + mMainWindow(aMainWindow) +{ + setAttribute(Qt::WA_DeleteOnClose); + ui->setupUi(this); +} + +CallTimingAnalysis::~CallTimingAnalysis() +{ + delete ui; +} + +void CallTimingAnalysis::on_pushButton_clicked() +{ + bool ok; + uint32_t start = ui->startCall->text().toInt(&ok); + + if (!ok) { + QMessageBox::critical(this, "Error", "Invalid starting event"); + return; + } + + uint32_t end = ui->endCall->text().toInt(&ok); + if (!ok) { + QMessageBox::critical(this, "Error", "Invalid end event"); + return; + } + + if (end <= start) { + QMessageBox::critical(this, "Error", "End event must be after start event"); + return; + } + if (start >= mMainWindow->mEventItems.size() || + end >= mMainWindow->mEventItems.size()) { + QMessageBox::critical(this, "Error", "Start call or end call out of range"); + return; + } + ui->progressBar->setEnabled(true); + ui->progressBar->setMaximum(end - start); + ui->progressBar->setValue(0); + + ui->resultBox->appendPlainText("Starting analysis..."); + + double total = 0; + + double totals[RecordedEvent::kTotalEventTypes]; + for (uint32_t i = 0; i < RecordedEvent::kTotalEventTypes; i++) { + totals[i] = 0; + } + for (uint32_t i = start; i <= end; i++) { + double stdDev; + EventItem *item = static_cast(mMainWindow->mEventItems[i]); + double avg = mMainWindow->mPBManager.GetEventTiming(item->mID, + ui->preventBatching->checkState() != Qt::Checked, + ui->ignoreFirst->checkState() == Qt::Checked, + ui->forceFlush->checkState() == Qt::Checked, + ui->forceRealization->checkState() == Qt::Checked, &stdDev); + + item->mTiming = avg; + mMainWindow->mEventItems[i]->setText(3, QString::number(avg, 'g', 3) + " +/- " + QString::number(stdDev, 'g', 2) + " ms"); + + total += avg; + ui->progressBar->setValue(i - start); + QApplication::processEvents(); + + totals[mMainWindow->mPBManager.mRecordedEvents[item->mID]->GetType()] += avg; + } + + ui->resultBox->appendPlainText("Total time measured: " + QString::number(total, 'g', 3) + " ms"); + for (uint32_t i = 0; i < RecordedEvent::kTotalEventTypes; i++) { + ui->resultBox->appendPlainText(QString::fromStdString(RecordedEvent::GetEventName((RecordedEvent::EventType)i)) + + ": " + QString::number(totals[i], 'g', 3)); + } +} diff --git a/libazure/player2d/calltiminganalysis.h b/libazure/player2d/calltiminganalysis.h new file mode 100644 index 0000000..1b78c2a --- /dev/null +++ b/libazure/player2d/calltiminganalysis.h @@ -0,0 +1,28 @@ +#ifndef CALLTIMINGANALYSIS_H +#define CALLTIMINGANALYSIS_H + +#include + +namespace Ui { +class CallTimingAnalysis; +} + +class MainWindow; + +class CallTimingAnalysis : public QMainWindow +{ + Q_OBJECT + +public: + explicit CallTimingAnalysis(MainWindow *aMainWindow); + ~CallTimingAnalysis(); + +private slots: + void on_pushButton_clicked(); + +private: + Ui::CallTimingAnalysis *ui; + MainWindow *mMainWindow; +}; + +#endif // CALLTIMINGANALYSIS_H diff --git a/libazure/player2d/calltiminganalysis.ui b/libazure/player2d/calltiminganalysis.ui new file mode 100644 index 0000000..dfed879 --- /dev/null +++ b/libazure/player2d/calltiminganalysis.ui @@ -0,0 +1,148 @@ + + + CallTimingAnalysis + + + + 0 + 0 + 271 + 461 + + + + Call Timing Analysis + + + + + + 100 + 10 + 81 + 20 + + + + + + + 10 + 10 + 81 + 20 + + + + 0 + + + + + false + + + + 10 + 40 + 251 + 21 + + + + 0 + + + + + + 190 + 10 + 75 + 23 + + + + Analyze + + + + + + 10 + 70 + 111 + 18 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This will cause the first measurement to be ignored. This may be useful if calls are expected to create a cached version of something and the efficiency of that cache wants to be factored in.</span></p></body></html> + + + Ignore first timing + + + + + + 10 + 90 + 141 + 18 + + + + This will flush affected DrawTargets between each call causing any batching optimizations that might be done when executing a call to be prevented. This may be useful when investigating how well a call batches with itself. + + + Prevent batching + + + + + + 10 + 110 + 251 + 341 + + + + + + + 140 + 70 + 91 + 17 + + + + Force flush + + + true + + + + + + 140 + 90 + 101 + 17 + + + + Force realization + + + + + + + diff --git a/libazure/player2d/displaymanager.cpp b/libazure/player2d/displaymanager.cpp new file mode 100644 index 0000000..5019142 --- /dev/null +++ b/libazure/player2d/displaymanager.cpp @@ -0,0 +1,5 @@ +#include "displaymanager.h" + +DisplayManager::DisplayManager() +{ +} diff --git a/libazure/player2d/displaymanager.h b/libazure/player2d/displaymanager.h new file mode 100644 index 0000000..7a3ff86 --- /dev/null +++ b/libazure/player2d/displaymanager.h @@ -0,0 +1,15 @@ +#ifndef DISPLAYMANAGER_H +#define DISPLAYMANAGER_H + +#include "2D.h" + +class DisplayManager +{ +public: + DisplayManager(); + +private: + mozilla::RefPtr mCurrentSourceSurface; +}; + +#endif // DISPLAYMANAGER_H diff --git a/libazure/player2d/drawtargetview.cpp b/libazure/player2d/drawtargetview.cpp new file mode 100644 index 0000000..b7a0f48 --- /dev/null +++ b/libazure/player2d/drawtargetview.cpp @@ -0,0 +1,97 @@ +#include "drawtargetview.h" +#include "ui_drawtargetview.h" +#include "2D.h" +#include "RecordedEvent.h" +#include "mainwindow.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +DrawTargetView::DrawTargetView(ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, QWidget *parent) : + SurfaceView(parent), + ui(new Ui::DrawTargetView), + mRefPtr(aRefPtr), + mTranslator(aTranslator), + mClipVisualized(false) +{ + ui->setupUi(this); + ui->dtWidget->SwitchToBackend(int(MainWindow::mMainBackend)); + + connect(ui->dtWidget, SIGNAL(RefillDT()), SLOT(UpdateView())); + connect(this, SIGNAL(SwitchingBackend(uint32_t)), ui->dtWidget, SLOT(SwitchToBackend(uint32_t))); + EventChanged(); +} + +DrawTargetView::~DrawTargetView() +{ + delete ui; +} + +TemporaryRef +DrawTargetView::GetSourceSurface() +{ + DrawTarget *srcDT = mTranslator->LookupDrawTarget(mRefPtr); + + if (!srcDT) { + return nullptr; + } + + RefPtr oldSurf; + if (mClipVisualized) { + oldSurf = srcDT->Snapshot(); + Matrix mat = srcDT->GetTransform(); + srcDT->SetTransform(Matrix()); + srcDT->FillRect(Rect(0, 0, srcDT->GetSize().width, srcDT->GetSize().height), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + srcDT->SetTransform(mat); + } + + RefPtr surf = srcDT->Snapshot(); + + if (mClipVisualized) { + srcDT->CopySurface(oldSurf, IntRect(0, 0, srcDT->GetSize().width, srcDT->GetSize().height), IntPoint()); + } + return surf; +} + +DrawTargetWidget* +DrawTargetView::GetDestDTWidget() const +{ + return ui->dtWidget; +} + +QScrollBar* +DrawTargetView::GetHorizontalScrollBar() const +{ + return ui->horizontalScrollBar; +} + +QScrollBar* +DrawTargetView::GetVerticalScrollBar() const +{ + return ui->verticalScrollBar; +} + +void DrawTargetView::on_actionVisualize_Clip_triggered(bool checked) +{ + mClipVisualized = checked; + UpdateView(); +} + +void +DrawTargetView::EventChanged() +{ + DrawTarget *srcDT = mTranslator->LookupDrawTarget(mRefPtr); + + Matrix transform; + if (srcDT) { + transform = srcDT->GetTransform(); + } + + ui->l11->setText(QString::number(transform._11)); + ui->l12->setText(QString::number(transform._12)); + ui->l21->setText(QString::number(transform._21)); + ui->l22->setText(QString::number(transform._22)); + ui->l31->setText(QString::number(transform._31)); + ui->l32->setText(QString::number(transform._32)); +} diff --git a/libazure/player2d/drawtargetview.h b/libazure/player2d/drawtargetview.h new file mode 100644 index 0000000..83638fc --- /dev/null +++ b/libazure/player2d/drawtargetview.h @@ -0,0 +1,42 @@ +#ifndef DRAWTARGETVIEW_H +#define DRAWTARGETVIEW_H + +#include "surfaceview.h" + +namespace Ui { +class DrawTargetView; +} + +namespace mozilla { +namespace gfx { +class Translator; +} +} + +class DrawTargetView : public SurfaceView +{ + Q_OBJECT + +public: + explicit DrawTargetView(mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, + QWidget *parent = 0); + ~DrawTargetView(); + + virtual mozilla::TemporaryRef GetSourceSurface(); + virtual DrawTargetWidget *GetDestDTWidget() const; + virtual QScrollBar *GetHorizontalScrollBar() const; + virtual QScrollBar *GetVerticalScrollBar() const; + +protected slots: + void on_actionVisualize_Clip_triggered(bool aChecked); + void EventChanged(); + +private: + Ui::DrawTargetView *ui; + + mozilla::gfx::ReferencePtr mRefPtr; + mozilla::gfx::Translator *mTranslator; + bool mClipVisualized; +}; + +#endif // DRAWTARGETVIEW_H diff --git a/libazure/player2d/drawtargetview.ui b/libazure/player2d/drawtargetview.ui new file mode 100644 index 0000000..c1718c9 --- /dev/null +++ b/libazure/player2d/drawtargetview.ui @@ -0,0 +1,275 @@ + + + DrawTargetView + + + + 0 + 0 + 512 + 399 + + + + Form + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + + + + 0 + 0 + + + + toolBar + + + + + + + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + 0 + + + 0 + + + 0 + + + Qt::Vertical + + + + + + + + 80 + 16777215 + + + + + + 4 + 10 + 32 + 16 + + + + a + + + + + + 46 + 10 + 32 + 16 + + + + b + + + + + + 4 + 30 + 32 + 16 + + + + c + + + + + + 46 + 30 + 32 + 16 + + + + d + + + + + + 4 + 50 + 32 + 16 + + + + e + + + + + + 46 + 50 + 32 + 16 + + + + f + + + + + + + + + :/icons/icons/zoom_best_fit.ico:/icons/icons/zoom_best_fit.ico + + + Fit To Window + + + Resize this DrawTarget to fit in the window + + + + + + :/icons/icons/zoom_in.ico:/icons/icons/zoom_in.ico + + + Zoom In + + + Zoom In + + + + + + :/icons/icons/zoom_out.ico:/icons/icons/zoom_out.ico + + + Zoom Out + + + Zoom Out + + + + + + :/icons/icons/zoom_original.ico:/icons/icons/zoom_original.ico + + + Original Size + + + Original Size + + + + + true + + + + :/icons/icons/vis_clip.ico:/icons/icons/vis_clip.ico + + + Visualize Clip + + + Visualize currently clipped area + + + + + + DrawTargetWidget + QWidget +
drawtargetwidget.h
+ 1 +
+
+ + + + + + verticalScrollBar + valueChanged(int) + DrawTargetView + UpdateView() + + + 503 + 202 + + + 255 + 199 + + + + + horizontalScrollBar + valueChanged(int) + DrawTargetView + UpdateView() + + + 247 + 390 + + + 255 + 199 + + + + + + UpdateView() + on_actionFit_To_Window_triggered() + +
diff --git a/libazure/player2d/drawtargetwidget.cpp b/libazure/player2d/drawtargetwidget.cpp new file mode 100644 index 0000000..65b1fdf --- /dev/null +++ b/libazure/player2d/drawtargetwidget.cpp @@ -0,0 +1,158 @@ +#include "drawtargetwidget.h" + +#ifdef WIN32 +#include +#include +#endif + +#include "qpainter.h" +#include "qevent.h" +#include "mainwindow.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +DrawTargetWidget::DrawTargetWidget(QWidget *parent) : + QWidget(parent, Qt::SubWindow), + mDT(NULL), + mMainWindow(NULL), + mType(BackendType::NONE) +{ +} + +void +DrawTargetWidget::InitDT() +{ + setAttribute(Qt::WA_NoSystemBackground, false); + setAttribute(Qt::WA_OpaquePaintEvent, false); + setAttribute(Qt::WA_PaintOnScreen, false); +#ifdef WIN32 + mSwapChain = nullptr; + + if (mType == BackendType::DIRECT2D) { + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_OpaquePaintEvent); + setAttribute(Qt::WA_PaintOnScreen); + + RefPtr dxgiDevice; + RefPtr dxgiAdapter; + + Factory::GetDirect3D10Device()->QueryInterface((IDXGIDevice**)byRef(dxgiDevice)); + dxgiDevice->GetAdapter(byRef(dxgiAdapter)); + + RefPtr dxgiFactory; + dxgiAdapter->GetParent(IID_PPV_ARGS((IDXGIFactory**)byRef(dxgiFactory))); + + DXGI_SWAP_CHAIN_DESC swapDesc; + ::ZeroMemory(&swapDesc, sizeof(swapDesc)); + swapDesc.BufferDesc.Width = 0; + swapDesc.BufferDesc.Height = 0; + swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + swapDesc.BufferDesc.RefreshRate.Numerator = 60; + swapDesc.BufferDesc.RefreshRate.Denominator = 1; + swapDesc.SampleDesc.Count = 1; + swapDesc.SampleDesc.Quality = 0; + swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapDesc.BufferCount = 1; + swapDesc.OutputWindow = (HWND)winId(); + swapDesc.Windowed = TRUE; + + dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, byRef(mSwapChain)); + + ID3D10Texture2D *texture; + mSwapChain->GetBuffer(0, IID_ID3D10Texture2D, (void**)&texture); + mDT = Factory::CreateDrawTargetForD3D10Texture(texture, SurfaceFormat::B8G8R8X8); + texture->Release(); + + mSwapChain->Present(0, 0); + } else +#endif + { + mDT = Factory::CreateDrawTarget(mType, IntSize(width(),height()), SurfaceFormat::B8G8R8X8); + } +} + +#ifdef WIN32 +#if QT_VERSION >= 0x050000 +bool +DrawTargetWidget::nativeEvent(const QByteArray & eventType, void * message, long * result) +{ + return winEvent((MSG*)message, result); +} +#endif + +bool +DrawTargetWidget::winEvent(MSG* message, long* result) +{ + if (mDT && mDT->GetType() == BackendType::DIRECT2D) { + if (message->hwnd == (HWND)this->effectiveWinId() && message->message == WM_SIZE) { + InitDT(); + RefillDT(); + } else if (message->hwnd == (HWND)this->effectiveWinId() && message->message == WM_PAINT) { + PAINTSTRUCT pt; + ::BeginPaint(message->hwnd, &pt); + ::EndPaint(message->hwnd, &pt); + redraw(); + return true; + } else if (message->hwnd == (HWND)this->effectiveWinId() && message->message == WM_WINDOWPOSCHANGED) { + ::InvalidateRect((HWND)effectiveWinId(), NULL, FALSE); + } + } + + return false; +} +#endif + +void +DrawTargetWidget::refresh() +{ + if (mDT && mDT->GetType() == BackendType::DIRECT2D) { + redraw(); + } else { + repaint(); + } +} + +void +DrawTargetWidget::redraw() +{ +#ifdef WIN32 + if (mSwapChain) { + mSwapChain->Present(0, 0); + } +#endif + + if (mDT && mDT->GetType() != BackendType::DIRECT2D) { + QPainter painter(this); + + RefPtr srcSurf = mDT->Snapshot(); + RefPtr dataSrc = srcSurf->GetDataSurface(); + QImage qimage(dataSrc->GetData(), width(), height(), dataSrc->Stride(), QImage::Format_RGB32); + painter.drawImage(QRect(0,0,width(), height()), qimage); + } +} + +void +DrawTargetWidget::resizeEvent(QResizeEvent * aEvent) +{ +// On windows this is handled by winEvent + + if (mDT && mDT->GetType() != BackendType::DIRECT2D) { + InitDT(); + RefillDT(); + } +} + +void +DrawTargetWidget::paintEvent(QPaintEvent *aEvent) +{ + redraw(); +} + +void +DrawTargetWidget::SwitchToBackend(uint32_t aType) +{ + mType = BackendType(aType); + InitDT(); + RefillDT(); +} diff --git a/libazure/player2d/drawtargetwidget.h b/libazure/player2d/drawtargetwidget.h new file mode 100644 index 0000000..2591ebc --- /dev/null +++ b/libazure/player2d/drawtargetwidget.h @@ -0,0 +1,54 @@ +#ifndef DRAWTARGETWIDGET_H +#define DRAWTARGETWIDGET_H + +#include +#ifdef WIN32 +#include +#endif + +struct ID3D10Device1; +struct IDXGISwapChain; + +#include "2D.h" + +class MainWindow; + +class DrawTargetWidget : public QWidget +{ + Q_OBJECT +public: + explicit DrawTargetWidget(QWidget *parent = 0); + + void InitDT(); + + void SetMainWindow(MainWindow *aWindow) { mMainWindow = aWindow; } + +#ifdef WIN32 + bool nativeEvent(const QByteArray & eventType, void * message, long * result); + bool winEvent(MSG* message, long* result); +#endif + void refresh(); + void redraw(); + void paintEvent(QPaintEvent *event); + virtual QPaintEngine *paintEngine() const { return nullptr; } + virtual void resizeEvent(QResizeEvent * aEvent); + + mozilla::gfx::DrawTarget *GetDT() { return mDT; } + +signals: + void RefillDT(); + +public slots: + void SwitchToBackend(uint32_t aType); + +private: + mozilla::RefPtr mDT; +#ifdef WIN32 + mozilla::RefPtr mSwapChain; +#endif + + mozilla::gfx::BackendType mType; + MainWindow *mMainWindow; +}; + +#endif // DRAWTARGETWIDGET_H diff --git a/libazure/player2d/gradientstopsview.cpp b/libazure/player2d/gradientstopsview.cpp new file mode 100644 index 0000000..7d51d4f --- /dev/null +++ b/libazure/player2d/gradientstopsview.cpp @@ -0,0 +1,67 @@ +#include "gradientstopsview.h" +#include "ui_gradientstopsview.h" + +#include "mainwindow.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +GradientStopsView::GradientStopsView(ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, QWidget *parent) : + QWidget(parent), + ui(new Ui::GradientStopsView), + mTranslator(aTranslator), + mRefPtr(aRefPtr) +{ + ui->setupUi(this); + ui->dtWidget->InitDT(); + ui->dtWidget->SwitchToBackend(int(MainWindow::mMainBackend)); + + connect(this, SIGNAL(SwitchingBackend(uint32_t)), ui->dtWidget, SLOT(SwitchToBackend(uint32_t))); + connect(ui->dtWidget, SIGNAL(RefillDT()), SLOT(UpdateView())); +} + +GradientStopsView::~GradientStopsView() +{ + delete ui; +} + +void +GradientStopsView::EventChanged() +{ +} + +void +GradientStopsView::UpdateView() +{ + DrawTarget *dt = ui->dtWidget->GetDT(); + + dt->FillRect(Rect(0, 0, 100000, 100000), ColorPattern(Color(0.5f, 0.5f, 0.5f, 1.0f))); + + RefPtr stops = mTranslator->LookupGradientStops(mRefPtr); + + ui->listWidget->clear(); + if (!stops) { + dt->Flush(); + ui->dtWidget->redraw(); + ui->listWidget->addItem("Dead"); + return; + } + + IntSize dstSize = dt->GetSize(); + + RefPtr tmpdt = dt->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::B8G8R8X8); + tmpdt->FillRect(Rect(0, 0, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); + tmpdt->FillRect(Rect(10, 10, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); + tmpdt->FillRect(Rect(10, 0, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); + tmpdt->FillRect(Rect(0, 10, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); + RefPtr src = tmpdt->Snapshot(); + tmpdt = NULL; + + Rect dstRect(0, 0, dstSize.width, dstSize.height); + dt->FillRect(dstRect, SurfacePattern(src, ExtendMode::REPEAT)); + + dt->FillRect(dstRect, LinearGradientPattern(Point(0, dstSize.height / 2), Point(dstSize.width, dstSize.height / 2), stops)); + + dt->Flush(); + ui->dtWidget->redraw(); +} diff --git a/libazure/player2d/gradientstopsview.h b/libazure/player2d/gradientstopsview.h new file mode 100644 index 0000000..bcc1199 --- /dev/null +++ b/libazure/player2d/gradientstopsview.h @@ -0,0 +1,35 @@ +#ifndef GRADIENTSTOPSVIEW_H +#define GRADIENTSTOPSVIEW_H + +#include +#include "2D.h" +#include "RecordedEvent.h" + +namespace Ui { +class GradientStopsView; +} + +class GradientStopsView : public QWidget +{ + Q_OBJECT + +public: + explicit GradientStopsView(mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, QWidget *parent = 0); + ~GradientStopsView(); + +public slots: + void UpdateView(); + +protected slots: + void EventChanged(); + +signals: + void SwitchingBackend(uint32_t aType); + +private: + Ui::GradientStopsView *ui; + mozilla::gfx::Translator *mTranslator; + mozilla::gfx::ReferencePtr mRefPtr; +}; + +#endif // GRADIENTSTOPSVIEW_H diff --git a/libazure/player2d/gradientstopsview.ui b/libazure/player2d/gradientstopsview.ui new file mode 100644 index 0000000..76e0392 --- /dev/null +++ b/libazure/player2d/gradientstopsview.ui @@ -0,0 +1,42 @@ + + + GradientStopsView + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + 0 + 50 + + + + + + + + + + + + DrawTargetWidget + QWidget +
drawtargetwidget.h
+ 1 +
+
+ + +
diff --git a/libazure/player2d/icons/back.ico b/libazure/player2d/icons/back.ico new file mode 100644 index 0000000..c995eba Binary files /dev/null and b/libazure/player2d/icons/back.ico differ diff --git a/libazure/player2d/icons/forward.ico b/libazure/player2d/icons/forward.ico new file mode 100644 index 0000000..cf368af Binary files /dev/null and b/libazure/player2d/icons/forward.ico differ diff --git a/libazure/player2d/icons/vis_clip.ico b/libazure/player2d/icons/vis_clip.ico new file mode 100644 index 0000000..3600b86 Binary files /dev/null and b/libazure/player2d/icons/vis_clip.ico differ diff --git a/libazure/player2d/icons/zoom_best_fit.ico b/libazure/player2d/icons/zoom_best_fit.ico new file mode 100644 index 0000000..3ed95f1 Binary files /dev/null and b/libazure/player2d/icons/zoom_best_fit.ico differ diff --git a/libazure/player2d/icons/zoom_in.ico b/libazure/player2d/icons/zoom_in.ico new file mode 100644 index 0000000..2a1b7c9 Binary files /dev/null and b/libazure/player2d/icons/zoom_in.ico differ diff --git a/libazure/player2d/icons/zoom_original.ico b/libazure/player2d/icons/zoom_original.ico new file mode 100644 index 0000000..cf89cba Binary files /dev/null and b/libazure/player2d/icons/zoom_original.ico differ diff --git a/libazure/player2d/icons/zoom_out.ico b/libazure/player2d/icons/zoom_out.ico new file mode 100644 index 0000000..5cc8638 Binary files /dev/null and b/libazure/player2d/icons/zoom_out.ico differ diff --git a/libazure/player2d/main.cpp b/libazure/player2d/main.cpp new file mode 100644 index 0000000..5c0ba30 --- /dev/null +++ b/libazure/player2d/main.cpp @@ -0,0 +1,25 @@ +#include +#include "mainwindow.h" + +#include "drawtargetwidget.h" +#include +#include + +#ifdef QT_STATIC +#if QT_VERSION < 0x050000 +Q_IMPORT_PLUGIN(qico) +#endif +#endif + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + + w.show(); + w.DefaultArrangement(); + + Q_INIT_RESOURCE(resources); + + return a.exec(); +} diff --git a/libazure/player2d/mainwindow.cpp b/libazure/player2d/mainwindow.cpp new file mode 100644 index 0000000..9ea12a5 --- /dev/null +++ b/libazure/player2d/mainwindow.cpp @@ -0,0 +1,613 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "QFileDialog" +#include "qmessagebox.h" +#include + +#ifdef WIN32 +#include +#include +#endif + +#include "RecordedEvent.h" +#include "PathRecording.h" + +#include "drawtargetwidget.h" +#include "qmdisubwindow.h" +#include "redundancyanalysis.h" +#include "calltiminganalysis.h" + +using namespace std; +using namespace mozilla; +using namespace mozilla::gfx; + +ID3D10Device1 *MainWindow::sDevice = NULL; +BackendType MainWindow::mMainBackend = BackendType::NONE; + +QString +NameForBackend(uint32_t aType) +{ + switch (aType) { + case BackendType::NONE: + return "None"; + case BackendType::CAIRO: + return "Cairo"; + case BackendType::DIRECT2D: + return "Direct2D"; + case BackendType::DIRECT2D1_1: + return "Direct2D 1.1"; + case BackendType::COREGRAPHICS: + return "Quartz"; + case BackendType::COREGRAPHICS_ACCELERATED: + return "Accelerated Quartz"; + case BackendType::SKIA: + return "Skia"; + case BackendType::NVPR: + return "NVidia Path Rendering"; + default: + return "Unknown"; + } +} + +void +BackendSwitch::selected(bool aChecked) +{ + if (aChecked) { + if (mSimulation) { + static_cast(parentWidget())->SwitchSimulationBackend(mType); + } else { + static_cast(parentWidget())->SwitchToBackend(mType); + } + } +} + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + mAutomatedItemChange(false) +{ + ui->setupUi(this); + + for (int i = 0; i < sBackendCount; i++) { + mBackends[i] = new BackendSwitch(NameForBackend(i), BackendType(i), false, this); + mSimulationBackends[i] = new BackendSwitch(NameForBackend(i), BackendType(i), true, this); + } + +#ifdef WIN32 + if (!sDevice) { + ::D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, + D3D10_CREATE_DEVICE_BGRA_SUPPORT, D3D10_FEATURE_LEVEL_10_0, + D3D10_1_SDK_VERSION, &sDevice); + + if (!sDevice) { + // EEEP! + } + Factory::SetDirect3D10Device(sDevice); + + RefPtr device; + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3 + }; + + + HRESULT hr = ::D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + featureLevels, sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL), + D3D11_SDK_VERSION, byRef(device), nullptr, nullptr); + + Factory::SetDirect3D11Device(device); + } + ui->menuBackend->addAction(mBackends[int(BackendType::DIRECT2D)]); + ui->menuSimulationBackend->addAction(mSimulationBackends[int(BackendType::DIRECT2D)]); + ui->menuBackend->addAction(mBackends[int(BackendType::DIRECT2D1_1)]); + ui->menuSimulationBackend->addAction(mSimulationBackends[int(BackendType::DIRECT2D1_1)]); +#elif __APPLE__ + //ui->menuBackend->addAction(mBackends[BackendType::COREGRAPHICS]); + //RefPtr refDT = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, IntSize(1, 1), FORMAT_B8G8R8A8); + //mPBManager.SetBaseDT(refDT); + // TODO Add a way to select backends +#endif +#ifdef USE_CAIRO + ui->menuBackend->addAction(mBackends[int(BackendType::CAIRO)]); + ui->menuSimulationBackend->addAction(mSimulationBackends[int(BackendType::CAIRO)]); +#endif +#ifdef USE_SKIA + ui->menuBackend->addAction(mBackends[int(BackendType::SKIA)]); + ui->menuSimulationBackend->addAction(mSimulationBackends[int(BackendType::SKIA)]); +#endif +#ifdef USE_NVPR + ui->menuBackend->addAction(mBackends[int(BackendType::NVPR)]); + ui->menuSimulationBackend->addAction(mSimulationBackends[int(BackendType::NVPR)]); +#endif + + ui->menuBackend->actions()[0]->toggle(); + ui->menuSimulationBackend->actions()[0]->toggle(); + + QWidget *targetWidget = new QWidget(); + ui->viewWidget->addTab(targetWidget, "Event Target"); + targetWidget->setLayout(new QHBoxLayout(targetWidget)); + targetWidget->layout()->setContentsMargins(0, 0, 0, 0); + + connect(&mPBManager, SIGNAL(EventDisablingUpdated(int32_t)), this, SLOT(UpdateEventColor(int32_t))); + ui->objectTree->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->objectTree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ObjectContextMenu(const QPoint &))); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +DrawTargetWidget * +MainWindow::GetDTWidget() +{ + return NULL; +} + +void +MainWindow::DefaultArrangement() +{ + QList list = ui->mdiArea->subWindowList(); + list[1]->move(QPoint(0, 150)); + list[1]->resize(QSize(350, ui->mdiArea->size().height() - 150)); + list[2]->move(QPoint(0, 0)); + list[2]->resize(QSize(ui->mdiArea->size().width(), 150)); + list[0]->move(350, 150); + list[0]->resize(ui->mdiArea->size().width() - 350, ui->mdiArea->size().height() - 250); + list[3]->move(350, ui->mdiArea->size().height() - 100); + list[3]->resize(ui->mdiArea->size().width() - 350, 100); +} + +void +MainWindow::UpdateObjects() +{ + QStringList list; + list.push_back(""); + list.push_back("DrawTarget"); + list.push_back(""); + + ui->objectTree->clear(); + + { + PlaybackManager::DTMap::iterator iter = mPBManager.mDrawTargets.begin(); + + for (;mPBManager.mDrawTargets.end() != iter; iter++) { + list[0] = QString::fromStdString(StringFromPtr(iter->first)); + stringstream stream; + stream << iter->second->GetSize().width << " x " << iter->second->GetSize().height; + list[2] = QString::fromStdString(stream.str()); + new DrawTargetItem(list, ui->objectTree, iter->first, &mPBManager); + } + } + + { + PlaybackManager::PathMap::iterator iter = mPBManager.mPaths.begin(); + + list[1] = "Path"; + for (;mPBManager.mPaths.end() != iter; iter++) { + list[0] = QString::fromStdString(StringFromPtr(iter->first)); + list[2] = ""; + new PathItem(list, ui->objectTree, iter->first, &mPBManager); + } + } + + { + PlaybackManager::SourceSurfaceMap::iterator iter = mPBManager.mSourceSurfaces.begin(); + + list[1] = "SourceSurface"; + for (;mPBManager.mSourceSurfaces.end() != iter; iter++) { + list[0] = QString::fromStdString(StringFromPtr(iter->first)); + stringstream stream; + stream << iter->second->GetSize().width << " x " << iter->second->GetSize().height; + list[2] = QString::fromStdString(stream.str()); + new SourceSurfaceItem(list, ui->objectTree, iter->first, &mPBManager); + } + } + + { + PlaybackManager::GradientStopsMap::iterator iter = mPBManager.mGradientStops.begin(); + + list[1] = "GradientStops"; + list[2] = ""; + for (;mPBManager.mGradientStops.end() != iter; iter++) { + list[0] = QString::fromStdString(StringFromPtr(iter->first)); + new GradientStopsItem(list, ui->objectTree, iter->first, &mPBManager); + } + } +} + +void +MainWindow::FilterToObject(ReferencePtr aObject) +{ + if (!aObject) { + foreach(QTreeWidgetItem *item, mEventItems) { + item->setHidden(false); + } + return; + } + + foreach(QTreeWidgetItem *item, mEventItems) { + int64_t idx = static_cast(item)->mID; + + if (mPBManager.mRecordedEvents[idx]->GetObjectRef() != aObject) { + item->setHidden(true); + } else { + item->setHidden(false); + } + } +} + +void +MainWindow::resizeEvent(QResizeEvent *) +{ + DefaultArrangement(); +} + +void +MainWindow::SwitchToBackend(BackendType aType) +{ + for (int i = 0; i < sBackendCount; i++) { + if (mBackends[i]) { + if (i != int(aType)) { + mBackends[i]->setChecked(false); + } + } + } + + mPBManager.PlaybackToEvent(0); + + mMainBackend = aType; + + SwitchingBackend(int(aType)); + + QApplication::processEvents(); + + QTreeWidgetItem *item = ui->treeWidget->currentItem(); + if (item) { + int64_t idx = static_cast(item)->mID; + + mPBManager.PlaybackToEvent(idx + 1); + } +} + +void +MainWindow::SwitchSimulationBackend(BackendType aType) +{ + for (int i = 0; i < sBackendCount; i++) { + if (mSimulationBackends[i]) { + if (i != int(aType)) { + mSimulationBackends[i]->setChecked(false); + } + } + } + + mPBManager.PlaybackToEvent(0); + RefPtr refDT = Factory::CreateDrawTarget(aType, IntSize(1, 1), SurfaceFormat::B8G8R8A8); + mPBManager.SetBaseDT(refDT); + + QTreeWidgetItem *item = ui->treeWidget->currentItem(); + if (item) { + int64_t idx = static_cast(item)->mID; + + mPBManager.PlaybackToEvent(idx + 1); + } +} + +void MainWindow::on_actionOpen_Recording_triggered() +{ + mEventItems.clear(); + ui->treeWidget->clear(); + + QString fileName = QFileDialog::getOpenFileName(this, "Open File Recording", QString(), "*.aer"); + + ifstream inputFile; + + ui->comboBox->clear(); + ui->comboBox->addItem("All"); + + inputFile.open(fileName.toStdString().c_str(), istream::in | istream::binary); + + inputFile.seekg(0, ios::end); + int length = inputFile.tellg(); + inputFile.seekg(0, ios::beg); + int64_t i = 0; + ui->treeWidget->setColumnWidth(0, 50); + ui->treeWidget->setColumnWidth(2, 150); + + QList objects; + + uint32_t magicInt; + ReadElement(inputFile, magicInt); + if (magicInt != 0xc001feed) { + QMessageBox::critical(this, "Error", "File is not a valid recording"); + return; + } + + uint16_t majorRevision; + uint16_t minorRevision; + ReadElement(inputFile, majorRevision); + ReadElement(inputFile, minorRevision); + + if (majorRevision != kMajorRevision) { + QMessageBox::critical(this, "Error", "Recording was made with a different major revision"); + return; + } + + if (minorRevision > kMinorRevision) { + QMessageBox::critical(this, "Error", "Recording was made with a later minor revision"); + return; + } + + while (inputFile.tellg() < length) { + + if (inputFile.tellg() < 0) { + QMessageBox::critical(this, "Error", "Stream error: File could not be parsed"); + return; + } + + int32_t type; + ReadElement(inputFile, type); + + RecordedEvent *newEvent = RecordedEvent::LoadEventFromStream(inputFile, (RecordedEvent::EventType)type); + + QStringList list; + list.push_back(QString::number(i)); + list.push_back(QString::fromStdString(StringFromPtr(newEvent->GetObjectRef()))); + list.push_back(QString::fromStdString(newEvent->GetName())); + EventItem *item = + new EventItem(list, ui->treeWidget, i++); + item->setTextColor(0, QColor(180, 180, 180, 255)); + mPBManager.AddEvent(newEvent); + mEventItems.push_back(item); + + if (mObjects.find(newEvent->GetObjectRef()) == mObjects.end()) { + objects.push_back(newEvent->GetObjectRef()); + } + mObjects.insert(newEvent->GetObjectRef()); + } + + qSort(objects); + + foreach(ReferencePtr ptr, objects) { + QVariant itemData = QVariant(qulonglong(ptr.mLongPtr)); + QString str = "0x" + QString::fromStdString(StringFromPtr(ptr)); + ui->comboBox->addItem(str, itemData); + } + DefaultArrangement(); +} + +void MainWindow::SetTargetView(ReferencePtr aEvent) +{ + ObjectItem *objItem = nullptr; + + QStringList list; + if (mPBManager.mDrawTargets.count(aEvent)) { + objItem = new DrawTargetItem(list, ui->objectTree, aEvent, &mPBManager); + } else if (mPBManager.mPaths.count(aEvent)) { + objItem = new PathItem(list, ui->objectTree, aEvent, &mPBManager); + } else if (mPBManager.mSourceSurfaces.count(aEvent)) { + objItem = new SourceSurfaceItem(list, ui->objectTree, aEvent, &mPBManager); + } else if (mPBManager.mGradientStops.count(aEvent)) { + objItem = new GradientStopsItem(list, ui->objectTree, aEvent, &mPBManager); + } + + QWidget* targetWidget = ui->viewWidget->widget(0); + + QWidget* currentTarget = targetWidget->findChild(); + + if (currentTarget) { + uint64_t tabObjItem = currentTarget->property("objectref").value(); + if (aEvent.mLongPtr == tabObjItem) { + return; + } + + targetWidget->layout()->removeWidget(currentTarget); + + delete currentTarget; + } + + if (!objItem) { + return; + } + + QWidget* newTarget = objItem->CreateViewWidget(); + + if (!newTarget) { + return; + } + + newTarget->setProperty("objectref", qVariantFromValue(aEvent.mLongPtr)); + newTarget->setParent(targetWidget); + targetWidget->layout()->addWidget(newTarget); + + QObject::connect(this, SIGNAL(UpdateViews()), newTarget, SLOT(UpdateView())); + QObject::connect(this, SIGNAL(EventChange()), newTarget, SLOT(EventChanged())); + QObject::connect(this, SIGNAL(SwitchingBackend(uint32_t)), newTarget, SIGNAL(SwitchingBackend(uint32_t))); +} + +void MainWindow::on_treeWidget_itemSelectionChanged() +{ + QTreeWidgetItem *item = ui->treeWidget->currentItem(); + int64_t idx = static_cast(item)->mID; + + mPBManager.PlaybackToEvent(idx + 1); + + if (!mAutomatedItemChange) { + mEventPlayHistory.push_back(idx); + mCurrentHistoryPosition = mEventPlayHistory.size() - 1; + } + + stringstream stream; + mPBManager.mRecordedEvents[idx]->OutputSimpleEventInfo(stream); + ui->textEventInfo->setText(QString::fromStdString(stream.str())); + + UpdateViews(); + UpdateObjects(); + EventChange(); + + SetTargetView(mPBManager.mRecordedEvents[idx]->GetObjectRef()); + + activateWindow(); +} + +void MainWindow::on_objectTree_itemDoubleClicked(QTreeWidgetItem *item, int) +{ + ObjectItem *objItem = static_cast(item); + + for (int i = 0; i < ui->viewWidget->count(); i++) { + QWidget *tab = ui->viewWidget->widget(i); + void *tabObjItem = tab->property("objectref").value(); + if (objItem->GetObjectRef() == tabObjItem) { + ui->viewWidget->setCurrentIndex(i); + return; + } + } + + QWidget *newTab = objItem->CreateViewWidget(); + if (!newTab) { + return; + } + newTab->setProperty("objectref", qVariantFromValue(objItem->GetObjectRef())); + ui->viewWidget->addTab(newTab, objItem->GetTitle()); + ui->viewWidget->setCurrentIndex(ui->viewWidget->count() - 1); + + QObject::connect(this, SIGNAL(UpdateViews()), newTab, SLOT(UpdateView())); + QObject::connect(this, SIGNAL(EventChange()), newTab, SLOT(EventChanged())); + QObject::connect(this, SIGNAL(SwitchingBackend(uint32_t)), newTab, SIGNAL(SwitchingBackend(uint32_t))); +} + +void MainWindow::on_viewWidget_tabCloseRequested(int index) +{ + QWidget *widget = ui->viewWidget->widget(index); + ui->viewWidget->removeTab(index); + delete widget; +} + +void MainWindow::on_actionExit_triggered() +{ + QApplication::closeAllWindows(); +} + +void MainWindow::on_actionAnalyze_Redundancy_triggered() +{ + QWidget *widget = new RedundancyAnalysis(&mPBManager, this); + widget->show(); +} + +void +MainWindow::UpdateEventColor(int32_t aID) +{ + if (aID == -1) { + for (uint32_t i = 0; i < mEventItems.size(); i++) { + if (mPBManager.IsEventDisabled(i)) { + mEventItems[i]->setTextColor(2, QColor(255, 0, 0)); + } else { + mEventItems[i]->setTextColor(2, QColor(0, 0, 0)); + } + } + return; + } + if (mPBManager.IsEventDisabled(aID)) { + mEventItems[aID]->setTextColor(2, QColor(255, 0, 0)); + } else { + mEventItems[aID]->setTextColor(2, QColor(0, 0, 0)); + } +} + +void MainWindow::on_actionBack_triggered() +{ + if (--mCurrentHistoryPosition < 0) { + mCurrentHistoryPosition = 0; + } + + mAutomatedItemChange = true; + ui->treeWidget->setCurrentItem(mEventItems[mEventPlayHistory[mCurrentHistoryPosition]]); + mAutomatedItemChange = false; +} + +void MainWindow::on_actionForward_triggered() +{ + if (++mCurrentHistoryPosition >= mEventPlayHistory.size()) { + mCurrentHistoryPosition = mEventPlayHistory.size() - 1; + } + + mAutomatedItemChange = true; + ui->treeWidget->setCurrentItem(mEventItems[mEventPlayHistory[mCurrentHistoryPosition]]); + mAutomatedItemChange = false; +} + +void MainWindow::on_lineEdit_textChanged(const QString &) +{ + +} + +void MainWindow::on_pushButton_clicked() +{ + bool ok; + + uint32_t eventid = ui->lineEdit->text().toUInt(&ok); + + if (!ok) { + return; + } + + if (eventid < 0 || eventid >= mEventItems.size()) { + return; + } + + ui->treeWidget->setCurrentItem(mEventItems[eventid]); +} + +void MainWindow::on_comboBox_currentIndexChanged(int index) +{ + if (index == 0) { + FilterToObject(nullptr); + return; + } + + QVariant itemData = ui->comboBox->itemData(index); + + ReferencePtr obj = (void*)(itemData.toULongLong()); + + FilterToObject(obj); +} + +void +MainWindow::ObjectContextMenu(const QPoint &aPoint) +{ + QMenu *menu = new QMenu; + menu->addAction(tr("Filter by object"), this, SLOT(FilterByCurrentObject())); + menu->exec(ui->objectTree->mapToGlobal(aPoint)); +} + +void +MainWindow::FilterByCurrentObject() +{ + ObjectItem *objItem = + static_cast(ui->objectTree->currentItem()); + + if (!objItem) { + return; + } + + FilterToObject(objItem->GetObjectRef()); + for (int i = 1; i < ui->comboBox->count(); i++) { + ReferencePtr obj = (void*)(ui->comboBox->itemData(i).toULongLong()); + + if (obj == objItem->GetObjectRef()) { + ui->comboBox->setCurrentIndex(i); + break; + } + } +} + +void MainWindow::on_actionAnalyze_Call_Timings_triggered() +{ + QWidget *widget = new CallTimingAnalysis(this); + widget->show(); +} diff --git a/libazure/player2d/mainwindow.h b/libazure/player2d/mainwindow.h new file mode 100644 index 0000000..3df4ac3 --- /dev/null +++ b/libazure/player2d/mainwindow.h @@ -0,0 +1,117 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +#include "playbackmanager.h" +#include "displaymanager.h" +#include "TreeItems.h" + +namespace Ui { +class MainWindow; +} + +class DrawTargetWidget; +class CallTimingAnalysis; + +const uint32_t sBackendCount = int(mozilla::gfx::BackendType::NVPR) + 1; + +class BackendSwitch : public QAction +{ + Q_OBJECT +public: + BackendSwitch(const QString &aName, mozilla::gfx::BackendType aType, + bool aSimulation, QObject *aParent) + : QAction(aName, aParent) + , mType(aType) + , mSimulation(aSimulation) + { + setCheckable(true); + connect(this, SIGNAL(toggled(bool)), this, SLOT(selected(bool))); + } + +private slots: + void selected(bool aChecked); +private: + mozilla::gfx::BackendType mType; + bool mSimulation; +}; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + DrawTargetWidget *GetDTWidget(); + + void DefaultArrangement(); + void UpdateObjects(); + void FilterToObject(mozilla::gfx::ReferencePtr aObject); + + virtual void resizeEvent(QResizeEvent *); + + void SwitchToBackend(mozilla::gfx::BackendType aType); + void SwitchSimulationBackend(mozilla::gfx::BackendType aType); + + static mozilla::gfx::BackendType mMainBackend; + +signals: + void UpdateViews(); + void EventChange(); + void SwitchingBackend(uint32_t aType); + +private slots: + void on_actionOpen_Recording_triggered(); + + void on_treeWidget_itemSelectionChanged(); + + void on_objectTree_itemDoubleClicked(QTreeWidgetItem *item, int column); + + void on_viewWidget_tabCloseRequested(int index); + + void on_actionExit_triggered(); + + void on_actionAnalyze_Redundancy_triggered(); + + void UpdateEventColor(int32_t aID); + + void on_actionBack_triggered(); + + void on_actionForward_triggered(); + + void on_lineEdit_textChanged(const QString &arg1); + + void on_pushButton_clicked(); + + void on_comboBox_currentIndexChanged(int index); + + void ObjectContextMenu(const QPoint &aPoint); + + void FilterByCurrentObject(); + void on_actionAnalyze_Call_Timings_triggered(); + + void SetTargetView(mozilla::gfx::ReferencePtr aEvent); +private: + friend class CallTimingAnalysis; + + static ID3D10Device1 *sDevice; + + Ui::MainWindow *ui; + PlaybackManager mPBManager; + DisplayManager mDPManager; + std::vector mEventItems; + + std::vector mEventPlayHistory; + hash_set mObjects; + int32_t mCurrentHistoryPosition; + bool mAutomatedItemChange; + + BackendSwitch *mBackends[sBackendCount]; + BackendSwitch *mSimulationBackends[sBackendCount]; +}; + +#endif // MAINWINDOW_H diff --git a/libazure/player2d/mainwindow.ui b/libazure/player2d/mainwindow.ui new file mode 100644 index 0000000..97b0a75 --- /dev/null +++ b/libazure/player2d/mainwindow.ui @@ -0,0 +1,370 @@ + + + MainWindow + + + + 0 + 0 + 910 + 555 + + + + MainWindow + + + QMainWindow::AnimatedDocks + + + false + + + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + QMdiArea::SubWindowView + + + + View + + + + 0 + + + 0 + + + + + + 16777215 + 16777215 + + + + -1 + + + true + + + + + + + + Drawing Events + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + 130 + 0 + + + + + + + + + 0 + 0 + + + + + 80 + 16777215 + + + + + + + + + 30 + 16777215 + + + + Go + + + + + + + + + + + 0 + 0 + + + + toolBar + + + + 16 + 16 + + + + + + + + + + false + + + false + + + false + + + 4 + + + 60 + + + 50 + + + + # + + + + + Object + + + + + Event + + + + + Time + + + + + + + + + Objects + + + + 0 + + + 0 + + + + + false + + + false + + + false + + + 80 + + + + Address + + + + + Type + + + + + Size + + + + + + + + + Event Information + + + + 0 + + + 0 + + + + + true + + + + + + + + + + + + + 0 + 0 + 910 + 20 + + + + + File + + + + + + + + Tools + + + + + + + Backend + + + + + Simulation Backend + + + + + + + + + + Open Recording + + + + + Exit + + + + + Analyze Redundancy + + + + + + :/icons/icons/back.ico:/icons/icons/back.ico + + + Back + + + Go back to last played command + + + + + + :/icons/icons/forward.ico:/icons/icons/forward.ico + + + Forward + + + Go forward one played command + + + + + Analyze Call Timings + + + + + true + + + Direct2D + + + + + Hm + + + + + + + + + diff --git a/libazure/player2d/playbackmanager.cpp b/libazure/player2d/playbackmanager.cpp new file mode 100644 index 0000000..675ac5f --- /dev/null +++ b/libazure/player2d/playbackmanager.cpp @@ -0,0 +1,402 @@ +#include "playbackmanager.h" + +#include "timer.h" + +#ifdef WIN32 +#include + +#endif + +using namespace mozilla; +using namespace mozilla::gfx; + +PlaybackManager::PlaybackManager() + : mCurrentEvent(0) +{ +} + +PlaybackManager::~PlaybackManager() +{ +} + +DrawTarget* +PlaybackManager::LookupDrawTarget(ReferencePtr aRefPtr) +{ + DTMap::iterator iter = mDrawTargets.find(aRefPtr); + + if (iter != mDrawTargets.end()) { + return iter->second; + } + + return NULL; +} + +Path* +PlaybackManager::LookupPath(ReferencePtr aRefPtr) +{ + PathMap::iterator iter = mPaths.find(aRefPtr); + + if (iter != mPaths.end()) { + return iter->second; + } + + return NULL; +} + +FilterNode* +PlaybackManager::LookupFilterNode(ReferencePtr aRefPtr) +{ + FilterNodeMap::iterator iter = mFilterNodes.find(aRefPtr); + + if (iter != mFilterNodes.end()) { + return iter->second; + } + + return NULL; +} + +SourceSurface* +PlaybackManager::LookupSourceSurface(ReferencePtr aRefPtr) +{ + SourceSurfaceMap::iterator iter = mSourceSurfaces.find(aRefPtr); + + if (iter != mSourceSurfaces.end()) { + return iter->second; + } + + return NULL; +} + +GradientStops* +PlaybackManager::LookupGradientStops(ReferencePtr aRefPtr) +{ + GradientStopsMap::iterator iter = mGradientStops.find(aRefPtr); + + if (iter != mGradientStops.end()) { + return iter->second; + } + + return NULL; +} + +ScaledFont* +PlaybackManager::LookupScaledFont(ReferencePtr aRefPtr) +{ + ScaledFontMap::iterator iter = mScaledFonts.find(aRefPtr); + + if (iter != mScaledFonts.end()) { + return iter->second; + } + + return NULL; +} + +FontType +PlaybackManager::GetDesiredFontType() +{ + switch (mBaseDT->GetType()) { + case BackendType::DIRECT2D: + return FontType::DWRITE; + case BackendType::CAIRO: + return FontType::CAIRO; + case BackendType::SKIA: + return FontType::SKIA; + case BackendType::NVPR: + return FontType::NVPR; + default: + MOZ_ASSERT(false); + return FontType::DWRITE; + } +} + +void +PlaybackManager::PlaybackToEvent(int aID) +{ + PlayToEvent(aID); +} + +bool +PlaybackManager::IsClipPush(uint32_t aID, int32_t aRefID) +{ + if (aRefID != -1 && mRecordedEvents[aID]->GetObjectRef() != mRecordedEvents[aRefID]->GetObjectRef()) { + return false; + } + return mRecordedEvents[aID]->GetType() == RecordedEvent::PUSHCLIP || + mRecordedEvents[aID]->GetType() == RecordedEvent::PUSHCLIPRECT; +} + +bool +PlaybackManager::IsClipPop(uint32_t aID, int32_t aRefID) +{ + if (aRefID != -1 && mRecordedEvents[aID]->GetObjectRef() != mRecordedEvents[aRefID]->GetObjectRef()) { + return false; + } + return mRecordedEvents[aID]->GetType() == RecordedEvent::POPCLIP; +} + +bool +PlaybackManager::FindCorrespondingClipID(uint32_t aID, uint32_t *aOtherID) +{ + if (IsClipPush(aID)) { + int32_t clipRecord = 1; + uint32_t id = aID; + + while (++id < mRecordedEvents.size()) { + if (IsClipPush(id, aID)) { + clipRecord++; + } + if (IsClipPop(id, aID)) { + clipRecord--; + } + if (!clipRecord) { + *aOtherID = id; + return true; + } + } + } + if (IsClipPop(aID)) { + int32_t clipRecord = 1; + uint32_t id = aID; + + while (--id >= 0) { + if (IsClipPush(id, aID)) { + clipRecord--; + } + if (IsClipPop(id, aID)) { + clipRecord++; + } + if (!clipRecord) { + *aOtherID = id; + return true; + } + } + } + + return false; +} + +void +PlaybackManager::DisableEvent(uint32_t aID) +{ + mDisabledEvents.insert(aID); + EventDisablingUpdated(int32_t(aID)); + + if (!IsClipPush(aID) && !IsClipPop(aID)) { + return; + } + + uint32_t correspondingID; + if (FindCorrespondingClipID(aID, &correspondingID)) { + mDisabledEvents.insert(correspondingID); + EventDisablingUpdated(int32_t(correspondingID)); + } +} + +void +PlaybackManager::EnableEvent(uint32_t aID) +{ + mDisabledEvents.erase(aID); + EventDisablingUpdated(int32_t(aID)); + if (!IsClipPush(aID) && !IsClipPop(aID)) { + return; + } + + uint32_t correspondingID; + if (FindCorrespondingClipID(aID, &correspondingID)) { + mDisabledEvents.erase(correspondingID); + EventDisablingUpdated(int32_t(correspondingID)); + } +} + +void +PlaybackManager::EnableAllEvents() +{ + mDisabledEvents.clear(); + EventDisablingUpdated(-1); +} + +bool +PlaybackManager::IsEventDisabled(uint32_t aID) +{ + return mDisabledEvents.find(aID) != mDisabledEvents.end() && CanDisableEvent(mRecordedEvents[aID]); +} + +void +PlaybackManager::PlayToEvent(uint32_t aID) +{ + if (mCurrentEvent > aID) { + mDrawTargets.clear(); + mSourceSurfaces.clear(); + mPaths.clear(); + mGradientStops.clear(); + mCurrentEvent = 0; + } + for (int i = mCurrentEvent; i < aID; i++) { + if (!IsEventDisabled(i) || !CanDisableEvent(mRecordedEvents[i])) { + PlaybackEvent(mRecordedEvents[i]); + } + } + + mCurrentEvent = aID; +} + +void +PlaybackManager::PlaybackEvent(RecordedEvent *aEvent) +{ + aEvent->PlayEvent(this); +} + +double +PlaybackManager::GetEventTiming(uint32_t aID, bool aAllowBatching, bool aIgnoreFirst, + bool aDoFlush, bool aForceCompletion, double *aStdDev) +{ + if (!aID) { + return 0; + } + + uint32_t currentEvent = mCurrentEvent; + + HighPrecisionMeasurement timer; + const int sIterations = 50; + const int N = 10; + + double results[sIterations]; + + DrawTarget *destinedDT = nullptr; + + // We need to ensure clips still always get pushed and popped in pairs! + RecordedEvent *popEvent = nullptr; + RecordedEvent *pushEvent = nullptr; + if (IsClipPop(aID)) { + uint32_t pushID; + if (!FindCorrespondingClipID(aID, &pushID)) { + // EEP! This is bad. + MOZ_ASSERT(false); + } + pushEvent = mRecordedEvents[pushID]; + } else if (IsClipPush(aID)) { + uint32_t popID; + if (!FindCorrespondingClipID(aID, &popID)) { + // EEP! This is bad. + MOZ_ASSERT(false); + } + popEvent = mRecordedEvents[popID]; + } + + for (int c = 0; c < N; c++) { + PlayToEvent(0); + PlayToEvent(aID); + + if (mRecordedEvents[aID]->GetDestinedDT()) { + destinedDT = LookupDrawTarget(mRecordedEvents[aID]->GetDestinedDT()); + } + + if (aIgnoreFirst) { + // Execute the call once to ignore the first execution. + if (pushEvent) { + PlaybackEvent(pushEvent); + } + + PlaybackEvent(mRecordedEvents[aID]); + + if (popEvent) { + PlaybackEvent(popEvent); + } + } + + timer.Start(); + for (int i = 0; i < sIterations; i++) { + + if (pushEvent) { + PlaybackEvent(pushEvent); + } + + PlaybackEvent(mRecordedEvents[aID]); + + if (popEvent) { + PlaybackEvent(popEvent); + } + + if (!aAllowBatching) { + if (destinedDT) { + destinedDT->Flush(); + } + } + } + if (destinedDT && aDoFlush) { + destinedDT->Flush(); + } + if (aForceCompletion) { + ForceCompletion(); + } + results[c] = timer.Measure(); + } + + double average = 0; + for (int i = 0; i < N; i++) { + average += results[i]; + } + + // Bjacob suggested we work with the median here instead of the mean, + // making us less sensitive to outliers. This is probably a good idea and + // should be looked in to. + + average /= double(N); + + double sqDiffSum = 0; + for (int i = 0; i < N; i++) { + sqDiffSum += pow(results[i] - average, 2); + } + + sqDiffSum /= double(N); + + *aStdDev = sqrt(sqDiffSum) / double(sIterations); + + PlayToEvent(0); + PlayToEvent(currentEvent + 1); + + return average / double(sIterations); +} + +bool +PlaybackManager::CanDisableEvent(RecordedEvent *aEvent) +{ + switch (aEvent->GetType()) { + case RecordedEvent::CLEARRECT: + case RecordedEvent::COPYSURFACE: + case RecordedEvent::DRAWSURFACE: + case RecordedEvent::DRAWSURFACEWITHSHADOW: + case RecordedEvent::DRAWFILTER: + case RecordedEvent::FILL: + case RecordedEvent::FILLGLYPHS: + case RecordedEvent::FILLRECT: + case RecordedEvent::STROKE: + case RecordedEvent::SETTRANSFORM: + case RecordedEvent::STROKERECT: + case RecordedEvent::STROKELINE: + case RecordedEvent::MASK: + case RecordedEvent::PUSHCLIP: + case RecordedEvent::PUSHCLIPRECT: + case RecordedEvent::POPCLIP: + return true; + default: + return false; + } +} + +void +PlaybackManager::ForceCompletion() +{ +#ifdef WIN32 + if (mBaseDT->GetType() == BackendType::DIRECT2D) { + ID3D10Device1 *device = Factory::GetDirect3D10Device(); + RefPtr query; + D3D10_QUERY_DESC desc; + desc.Query = D3D10_QUERY_EVENT; + desc.MiscFlags = 0; + device->CreateQuery(&desc, byRef(query)); + query->End(); + while (query->GetData(nullptr, 0, 0) == S_FALSE) {} + } +#endif +} diff --git a/libazure/player2d/playbackmanager.h b/libazure/player2d/playbackmanager.h new file mode 100644 index 0000000..61c261a --- /dev/null +++ b/libazure/player2d/playbackmanager.h @@ -0,0 +1,114 @@ +#ifndef PLAYBACKMANAGER_H +#define PLAYBACKMANAGER_H + +#include +#include "RecordedEvent.h" +#include "Filters.h" + +#include +#ifdef __GNUC__ +#include +using __gnu_cxx::hash_set; +namespace __gnu_cxx { +#define DEFINE_TRIVIAL_HASH(integral_type) \ + template<> \ + struct hash { \ + std::size_t operator()(integral_type value) const { \ + return (std::size_t)(value); \ + } \ + } +DEFINE_TRIVIAL_HASH(void*); +} +#else +#include +using std::hash_set; +#endif +#include + +class PlaybackManager : public QObject, public mozilla::gfx::Translator +{ + Q_OBJECT +public: + PlaybackManager(); + ~PlaybackManager(); + + typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::gfx::Path Path; + typedef mozilla::gfx::SourceSurface SourceSurface; + typedef mozilla::gfx::FilterNode FilterNode; + typedef mozilla::gfx::GradientStops GradientStops; + typedef mozilla::gfx::ScaledFont ScaledFont; + + // Translator + virtual DrawTarget *LookupDrawTarget(mozilla::gfx::ReferencePtr aRefPtr); + virtual Path *LookupPath(mozilla::gfx::ReferencePtr aRefPtr); + virtual SourceSurface *LookupSourceSurface(mozilla::gfx::ReferencePtr aRefPtr); + virtual FilterNode *LookupFilterNode(mozilla::gfx::ReferencePtr aRefPtr); + virtual GradientStops *LookupGradientStops(mozilla::gfx::ReferencePtr aRefPtr); + virtual ScaledFont *LookupScaledFont(mozilla::gfx::ReferencePtr aRefPtr); + virtual DrawTarget *GetReferenceDrawTarget() { return mBaseDT; } + virtual mozilla::gfx::FontType GetDesiredFontType(); + virtual void AddDrawTarget(mozilla::gfx::ReferencePtr aRefPtr, DrawTarget *aDT) { mDrawTargets[aRefPtr] = aDT; } + virtual void RemoveDrawTarget(mozilla::gfx::ReferencePtr aRefPtr) { mDrawTargets.erase(aRefPtr); } + virtual void AddPath(mozilla::gfx::ReferencePtr aRefPtr, Path *aPath) { mPaths[aRefPtr] = aPath; } + virtual void AddSourceSurface(mozilla::gfx::ReferencePtr aRefPtr, SourceSurface *aSurface) { mSourceSurfaces[aRefPtr] = aSurface; } + virtual void RemoveSourceSurface(mozilla::gfx::ReferencePtr aRefPtr) { mSourceSurfaces.erase(aRefPtr); } + virtual void RemovePath(mozilla::gfx::ReferencePtr aRefPtr) { mPaths.erase(aRefPtr); } + virtual void AddGradientStops(mozilla::gfx::ReferencePtr aRefPtr, GradientStops *aStops) { mGradientStops[aRefPtr] = aStops; } + virtual void RemoveGradientStops(mozilla::gfx::ReferencePtr aRefPtr) { mGradientStops.erase(aRefPtr); } + virtual void AddScaledFont(mozilla::gfx::ReferencePtr aRefPtr, ScaledFont *aStops) { mScaledFonts[aRefPtr] = aStops; } + virtual void RemoveScaledFont(mozilla::gfx::ReferencePtr aRefPtr) { mScaledFonts.erase(aRefPtr); } + virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, FilterNode *aNode) { mFilterNodes[aRefPtr] = aNode; } + virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) { mFilterNodes.erase(aRefPtr); } + + + void SetBaseDT(DrawTarget *aBaseDT) { mBaseDT = aBaseDT; } + void AddEvent(mozilla::gfx::RecordedEvent *aEvent) { mRecordedEvents.push_back(aEvent); } + + void PlaybackToEvent(int aID); + + void DisableEvent(uint32_t aID); + void EnableEvent(uint32_t aID); + void EnableAllEvents(); + bool IsEventDisabled(uint32_t aID); + double GetEventTiming(uint32_t aID, bool aAllowBatching, bool aIgnoreFirst, + bool aDoFlush, bool aForceCompletion, double *aStdDev); + + uint32_t GetCurrentEvent() { return mCurrentEvent; } + + typedef std::map > DTMap; + typedef std::map > PathMap; + typedef std::map > SourceSurfaceMap; + typedef std::map > GradientStopsMap; + typedef std::map > ScaledFontMap; + typedef std::map > FilterNodeMap; + + DTMap mDrawTargets; + PathMap mPaths; + SourceSurfaceMap mSourceSurfaces; + GradientStopsMap mGradientStops; + ScaledFontMap mScaledFonts; + FilterNodeMap mFilterNodes; + std::vector mRecordedEvents; + hash_set mDisabledEvents; +signals: + void EventDisablingUpdated(int32_t aID); +private: + friend class PlaybackTranslator; + + bool IsClipPush(uint32_t aID, int32_t aRefID = -1); + bool IsClipPop(uint32_t aID, int32_t aRefID = -1); + bool FindCorrespondingClipID(uint32_t aID, uint32_t *aOtherID); + + void PlayToEvent(uint32_t aID); + void PlaybackEvent(mozilla::gfx::RecordedEvent *aEvent); + + bool CanDisableEvent(mozilla::gfx::RecordedEvent *aEvent); + + void ForceCompletion(); + + uint32_t mCurrentEvent; + mozilla::RefPtr mBaseDT; +}; + +#endif // PLAYBACKMANAGER_H diff --git a/libazure/player2d/player2d.pro b/libazure/player2d/player2d.pro new file mode 100644 index 0000000..175944d --- /dev/null +++ b/libazure/player2d/player2d.pro @@ -0,0 +1,117 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2012-08-06T16:20:06 +# +#------------------------------------------------- + +QT += core gui widgets + +TARGET = player2d +TEMPLATE = app +QMAKE_CXXFLAGS += -std=c++11 +CONFIG += c++11 + +SOURCES += main.cpp\ + mainwindow.cpp \ + drawtargetwidget.cpp \ + playbackmanager.cpp \ + displaymanager.cpp \ + drawtargetview.cpp \ + TreeItems.cpp \ + surfaceview.cpp \ + sourcesurfaceview.cpp \ + gradientstopsview.cpp \ + redundancyanalysis.cpp \ + calltiminganalysis.cpp + +HEADERS += mainwindow.h \ + drawtargetwidget.h \ + playbackmanager.h \ + TreeItems.h \ + displaymanager.h \ + drawtargetview.h \ + surfaceview.h \ + sourcesurfaceview.h \ + gradientstopsview.h \ + redundancyanalysis.h \ + timer.h \ + calltiminganalysis.h + +FORMS += mainwindow.ui \ + drawtargetview.ui \ + sourcesurfaceview.ui \ + gradientstopsview.ui \ + redundancyanalysis.ui \ + calltiminganalysis.ui + +!isEmpty(MOZ2D_CAIRO) { + DEFINES += USE_CAIRO +} +!isEmpty(MOZ2D_SKIA) { + DEFINES += USE_SKIA +} +!isEmpty(MOZ2D_NVPR) { + DEFINES += USE_NVPR +} +!isEmpty(MOZ2D_DEBUG) { + CONFIG += debug +} + +CONFIG(release, debug|release) { + CONFIG_PREFIX = "Release" +} else { + CONFIG_PREFIX = "Debug" +} + +win32 { + !isEmpty(MOZ2D_CAIRO) { + isEmpty(MOZ2D_SKIA) { + error("Can only build with both Skia and Cairo or neither on windows.") + } + DIR_SUFFIX = " (With Skia)" + + LIBS += -L"$$PWD/../../skia/out/$$CONFIG_PREFIX" -L"$$PWD/../../cairo/src/$$CONFIG_PREFIX" + LIBS += -lskia_core -lskia_images -lskia_effects -lskia_utils -lskia_ports -lskia_opts -lskia_skgpu -lskia_opts_ssse3 -lskia_sfnt -lusp10 -lopengl32 -lcairo-static + } + + LIBS += -L"$$PWD/../$$CONFIG_PREFIX$$DIR_SUFFIX/" -lgfx2d + +} else:symbian: LIBS += -lgfx2d +else:unix { + isEmpty(MOZ2D_PATH) { + MOZ2D_PATH = "$$PWD/.." + } + + CONFIG(release, debug|release) { + LIBS += -L$$MOZ2D_PATH/release -lmoz2d $$(MOZ2D_PLAYER2D_LIBS) + } else { + LIBS += -L$$MOZ2D_PATH/debug -lmoz2d $$(MOZ2D_PLAYER2D_LIBS) + } + + !macx: GROUP_START = -Wl,--start-group + !macx: GROUP_END = -Wl,--end-group + !isEmpty(MOZ2D_SKIA) { + LIBS += -L$$MOZ2D_SKIA/out/$$CONFIG_PREFIX/ $$GROUP_START -lskia_images -lskia_effects -lskia_sfnt -lskia_utils -lskia_core -lskia_skgpu -lskia_opts -lskia_opts_ssse3 -lskia_ports -lfreetype -lfontconfig -lGL $$GROUP_END + } + !isEmpty(MOZ2D_NVPR) { + LIBS += -ldl -lX11 + } +} + +INCLUDEPATH += $$PWD/../ +DEPENDPATH += $$PWD/../ + +static: QTPLUGIN += qico +static: DEFINES += QT_STATIC + +win32:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/../release/gfx2d.lib +else:win32:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/../debug/gfx2d.lib + +unix:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/../release/libmoz2d.a +else:unix:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/../debug/libmoz2d.a + +win32: LIBS += -ld3d10_1 -ld3d11 +win32: DEFINES += INITGUID USE_D2D1_1 + +RESOURCES += \ + resources.qrc diff --git a/libazure/player2d/redundancyanalysis.cpp b/libazure/player2d/redundancyanalysis.cpp new file mode 100644 index 0000000..5304bcd --- /dev/null +++ b/libazure/player2d/redundancyanalysis.cpp @@ -0,0 +1,155 @@ +#include "redundancyanalysis.h" +#include "ui_redundancyanalysis.h" + +#include "RecordedEvent.h" +#include + +#include "timer.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +RedundancyAnalysis::RedundancyAnalysis(PlaybackManager *aPBManager, QWidget *parent) : + QMainWindow(parent), + mPBManager(aPBManager), + ui(new Ui::RedundancyAnalysis) +{ + ui->setupUi(this); +} + +RedundancyAnalysis::~RedundancyAnalysis() +{ + delete ui; +} + +void RedundancyAnalysis::on_lineEdit_textChanged(const QString &aNewStart) +{ + ui->dtList->clear(); + bool ok; + uint32_t start = aNewStart.toInt(&ok); + + if (!ok) { + return; + } + + mPBManager->PlaybackToEvent(start); + + PlaybackManager::DTMap::iterator iter = mPBManager->mDrawTargets.begin(); + + for (;mPBManager->mDrawTargets.end() != iter; iter++) { + QVariant var((qulonglong)iter->first); + ui->dtList->addItem(QString::fromStdString(StringFromPtr(iter->first)), var); + } +} + +static bool +CompareSurfaces(DataSourceSurface *aSurfA, DataSourceSurface *aSurfB) +{ + for (int y = 0; y < aSurfA->GetSize().height; y++) { + if (memcmp(aSurfA->GetData() + y * aSurfA->Stride(), aSurfB->GetData() + y * aSurfB->Stride(), aSurfA->GetSize().width * 4) != 0) { + return false; + } + } + return true; +} + +void RedundancyAnalysis::on_pushButton_clicked() +{ + bool ok; + uint32_t start = ui->lineEdit->text().toInt(&ok); + + if (!ok) { + QMessageBox::critical(this, "Error", "Invalid starting event"); + return; + } + + uint32_t end = ui->lineEdit_2->text().toInt(&ok); + if (!ok) { + QMessageBox::critical(this, "Error", "Invalid end event"); + return; + } + + if (end <= start) { + QMessageBox::critical(this, "Error", "End event must be after start event"); + return; + } + + ReferencePtr dtPtr = (void*)(ui->dtList->itemData(ui->dtList->currentIndex()).toUInt()); + + mPBManager->PlaybackToEvent(start); + RefPtr dt = mPBManager->LookupDrawTarget(dtPtr); + QString str = "Beginning Analysis of DT 0x"; + str.append(QString::fromStdString(StringFromPtr(dtPtr))); + ui->plainTextEdit->appendPlainText(str); + + mPBManager->PlaybackToEvent(end); + + RefPtr endDT = mPBManager->LookupDrawTarget(dtPtr); + if (dt != endDT) { + ui->plainTextEdit->appendPlainText("Analysis failed"); + return; + } + +#ifdef WIN32 + LARGE_INTEGER startStamp, endStamp, freq; +#endif + + RefPtr surf = dt->Snapshot(); + RefPtr refDataSurf = surf->GetDataSurface(); + ReferencePtr data = refDataSurf->GetData(); + + uint32_t redundantEvents = 0; + ui->progressBar->setEnabled(true); + ui->progressBar->setMaximum(end - start); + ui->progressBar->setValue(0); + for (uint32_t i = start; i < end; i++) { + mPBManager->PlaybackToEvent(start); + ui->progressBar->setValue(i); + QApplication::processEvents(); + mPBManager->DisableEvent(i); + mPBManager->PlaybackToEvent(end); + RefPtr newDT = mPBManager->LookupDrawTarget(dtPtr); + RefPtr srcSurf = newDT->Snapshot(); + RefPtr cmpSurf = srcSurf->GetDataSurface(); + if (!CompareSurfaces(cmpSurf, refDataSurf)) { + mPBManager->EnableEvent(i); + continue; + } + redundantEvents++; + } + + ui->plainTextEdit->appendPlainText("Analysis finished."); + + str = "Analyzed events: " + QString::number(end - start); + ui->plainTextEdit->appendPlainText(str); + str = "Redundant events: " + QString::number(redundantEvents); + ui->plainTextEdit->appendPlainText(str); + + HighPrecisionMeasurement timer; + + mPBManager->PlaybackToEvent(start); + dt = mPBManager->LookupDrawTarget(dtPtr); + dt->Flush(); + + timer.Start(); + mPBManager->PlaybackToEvent(end); + dt->Flush(); + + double timeSecond = timer.Measure(); + + mPBManager->EnableAllEvents(); + mPBManager->PlaybackToEvent(start); + dt = mPBManager->LookupDrawTarget(dtPtr); + dt->Flush(); + + timer.Start(); + mPBManager->PlaybackToEvent(end); + dt->Flush(); + + double timeFirst = timer.Measure(); + + str = "Old timing: " + QString::number(timeFirst, 'g', 3) + " ms"; + ui->plainTextEdit->appendPlainText(str); + str = "New timing: " + QString::number(timeSecond, 'g', 3) + " ms"; + ui->plainTextEdit->appendPlainText(str); +} diff --git a/libazure/player2d/redundancyanalysis.h b/libazure/player2d/redundancyanalysis.h new file mode 100644 index 0000000..6fd41d1 --- /dev/null +++ b/libazure/player2d/redundancyanalysis.h @@ -0,0 +1,30 @@ +#ifndef REDUNDANCYANALYSIS_H +#define REDUNDANCYANALYSIS_H + +#include + +#include "playbackmanager.h" + +namespace Ui { + class RedundancyAnalysis; +} + +class RedundancyAnalysis : public QMainWindow +{ + Q_OBJECT + +public: + explicit RedundancyAnalysis(PlaybackManager *aPBManager, QWidget *parent = 0); + ~RedundancyAnalysis(); + +private slots: + void on_lineEdit_textChanged(const QString &arg1); + + void on_pushButton_clicked(); + +private: + PlaybackManager *mPBManager; + Ui::RedundancyAnalysis *ui; +}; + +#endif // REDUNDANCYANALYSIS_H diff --git a/libazure/player2d/redundancyanalysis.ui b/libazure/player2d/redundancyanalysis.ui new file mode 100644 index 0000000..8bcc43f --- /dev/null +++ b/libazure/player2d/redundancyanalysis.ui @@ -0,0 +1,77 @@ + + + RedundancyAnalysis + + + + 0 + 0 + 481 + 263 + + + + Redundancy Analysis + + + + + + + false + + + 0 + + + + + + + 0 + + + + + + + + + + Start Call + + + + + + + End Call + + + + + + + Analyze + + + + + + + + + + + + + DrawTarget + + + + + + + + + diff --git a/libazure/player2d/resources.qrc b/libazure/player2d/resources.qrc new file mode 100644 index 0000000..19c4d42 --- /dev/null +++ b/libazure/player2d/resources.qrc @@ -0,0 +1,11 @@ + + + icons/zoom_best_fit.ico + icons/zoom_in.ico + icons/zoom_out.ico + icons/zoom_original.ico + icons/vis_clip.ico + icons/back.ico + icons/forward.ico + + diff --git a/libazure/player2d/sourcesurfaceview.cpp b/libazure/player2d/sourcesurfaceview.cpp new file mode 100644 index 0000000..3665cce --- /dev/null +++ b/libazure/player2d/sourcesurfaceview.cpp @@ -0,0 +1,52 @@ +#include "sourcesurfaceview.h" +#include "ui_sourcesurfaceview.h" +#include "2D.h" +#include "RecordedEvent.h" +#include "mainwindow.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +SourceSurfaceView::SourceSurfaceView(ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, QWidget *parent) : + SurfaceView(parent), + ui(new Ui::SourceSurfaceView), + mRefPtr(aRefPtr), + mTranslator(aTranslator) +{ + ui->setupUi(this); + ui->dtWidget->SwitchToBackend(int(MainWindow::mMainBackend)); + + connect(ui->dtWidget, SIGNAL(RefillDT()), SLOT(UpdateView())); + connect(this, SIGNAL(SwitchingBackend(uint32_t)), ui->dtWidget, SLOT(SwitchToBackend(uint32_t))); +} + +SourceSurfaceView::~SourceSurfaceView() +{ + delete ui; +} + +TemporaryRef +SourceSurfaceView::GetSourceSurface() +{ + RefPtr surf = mTranslator->LookupSourceSurface(mRefPtr); + return surf; +} + +DrawTargetWidget* +SourceSurfaceView::GetDestDTWidget() const +{ + return ui->dtWidget; +} + +QScrollBar* +SourceSurfaceView::GetHorizontalScrollBar() const +{ + return ui->horizontalScrollBar; +} + +QScrollBar* +SourceSurfaceView::GetVerticalScrollBar() const +{ + return ui->verticalScrollBar; +} diff --git a/libazure/player2d/sourcesurfaceview.h b/libazure/player2d/sourcesurfaceview.h new file mode 100644 index 0000000..f7d5ab9 --- /dev/null +++ b/libazure/player2d/sourcesurfaceview.h @@ -0,0 +1,36 @@ +#ifndef SOURCESURFACEVIEW_H +#define SOURCESURFACEVIEW_H + +#include "surfaceview.h" + +namespace Ui { +class SourceSurfaceView; +} + +namespace mozilla { +namespace gfx { +class Translator; +} +} + +class SourceSurfaceView : public SurfaceView +{ + Q_OBJECT + +public: + explicit SourceSurfaceView(mozilla::gfx::ReferencePtr aRefPtr, mozilla::gfx::Translator *aTranslator, + QWidget *parent = 0); + ~SourceSurfaceView(); + + virtual mozilla::TemporaryRef GetSourceSurface(); + virtual DrawTargetWidget *GetDestDTWidget() const; + virtual QScrollBar *GetHorizontalScrollBar() const; + virtual QScrollBar *GetVerticalScrollBar() const; +private: + Ui::SourceSurfaceView *ui; + + mozilla::gfx::ReferencePtr mRefPtr; + mozilla::gfx::Translator *mTranslator; +}; + +#endif // SOURCESURFACEVIEW_H diff --git a/libazure/player2d/sourcesurfaceview.ui b/libazure/player2d/sourcesurfaceview.ui new file mode 100644 index 0000000..9c7cb76 --- /dev/null +++ b/libazure/player2d/sourcesurfaceview.ui @@ -0,0 +1,171 @@ + + + SourceSurfaceView + + + + 0 + 0 + 512 + 399 + + + + Form + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + + + + 0 + 0 + + + + toolBar + + + + + + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + 0 + + + 0 + + + 0 + + + Qt::Vertical + + + + + + + + :/icons/icons/zoom_best_fit.ico:/icons/icons/zoom_best_fit.ico + + + Fit To Window + + + Resize this DrawTarget to fit in the window + + + + + + :/icons/icons/zoom_in.ico:/icons/icons/zoom_in.ico + + + Zoom In + + + Zoom In + + + + + + :/icons/icons/zoom_out.ico:/icons/icons/zoom_out.ico + + + Zoom Out + + + Zoom Out + + + + + + :/icons/icons/zoom_original.ico:/icons/icons/zoom_original.ico + + + Original Size + + + Original Size + + + + + + DrawTargetWidget + QWidget +
drawtargetwidget.h
+ 1 +
+
+ + + + + + verticalScrollBar + valueChanged(int) + DrawTargetView + UpdateView() + + + 503 + 202 + + + 255 + 199 + + + + + horizontalScrollBar + valueChanged(int) + DrawTargetView + UpdateView() + + + 247 + 390 + + + 255 + 199 + + + + + + UpdateView() + on_actionFit_To_Window_triggered() + +
diff --git a/libazure/player2d/surfaceview.cpp b/libazure/player2d/surfaceview.cpp new file mode 100644 index 0000000..aed6ebe --- /dev/null +++ b/libazure/player2d/surfaceview.cpp @@ -0,0 +1,129 @@ +#include "surfaceview.h" +#include "2D.h" +#include + +#include "drawtargetwidget.h" +#include "RecordedEvent.h" +#include + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +const float kZoomSizes[] = { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f }; + +SurfaceView::SurfaceView(QWidget *parent) : + QWidget(parent), + mZoomFactor(1.0f) +{ +} + +void +SurfaceView::UpdateView() +{ + DrawTarget *dt = GetDestDTWidget()->GetDT(); + + RefPtr srcSurf = GetSourceSurface(); + + dt->FillRect(Rect(0, 0, 100000, 100000), ColorPattern(Color(0.5f, 0.5f, 0.5f, 1.0f))); + + if (!srcSurf) { + dt->Flush(); + GetDestDTWidget()->refresh(); + return; + } + + srcSurf = srcSurf->GetDataSurface(); + + IntSize dtSize = dt->GetSize(); + IntSize dstSurfSize = srcSurf->GetSize(); + IntSize dstSize = srcSurf->GetSize(); + dstSize.width = int(float(dstSize.width * mZoomFactor)); + dstSize.height = int(float(dstSize.height * mZoomFactor)); + + QScrollBar *horizontalScrollBar = GetHorizontalScrollBar(); + QScrollBar *verticalScrollBar = GetVerticalScrollBar(); + horizontalScrollBar->setPageStep(dtSize.width); + verticalScrollBar->setPageStep(dtSize.height); + horizontalScrollBar->setMaximum(max(dstSize.width - dtSize.width, 0)); + verticalScrollBar->setMaximum(max(dstSize.height - dtSize.height, 0)); + int xtranslate = horizontalScrollBar->value(); + int ytranslate = verticalScrollBar->value(); + Matrix mat; + mat.Translate(-xtranslate, -ytranslate); + dt->SetTransform(mat); + + RefPtr tmpdt = dt->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::B8G8R8X8); + tmpdt->FillRect(Rect(0, 0, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); + tmpdt->FillRect(Rect(10, 10, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f))); + tmpdt->FillRect(Rect(10, 0, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); + tmpdt->FillRect(Rect(0, 10, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f))); + RefPtr src = tmpdt->Snapshot(); + tmpdt = NULL; + + Rect surfRect(0, 0, dstSurfSize.width, dstSurfSize.height); + Rect dstRect(0, 0, dstSize.width, dstSize.height); + dt->FillRect(dstRect, SurfacePattern(src, ExtendMode::REPEAT)); + + if (srcSurf->GetFormat() != SurfaceFormat::A8) { + dt->DrawSurface(srcSurf, dstRect, surfRect, DrawSurfaceOptions(mZoomFactor > 1.5f ? Filter::POINT : Filter::LINEAR)); + } else { + dt->PushClipRect(dstRect); + dt->Mask(ColorPattern(Color(0, 0, 0, 1)), SurfacePattern(srcSurf, ExtendMode::CLAMP)); + dt->PopClip(); + } + + dt->Flush(); + + GetDestDTWidget()->refresh(); +} + +void SurfaceView::on_actionOriginal_Size_triggered() +{ + mZoomFactor = 1.0f; + UpdateView(); +} + +void SurfaceView::on_actionFit_To_Window_triggered() +{ + RefPtr srcSurf = GetSourceSurface(); + + if (!srcSurf) { + mZoomFactor = 1.0f; + return; + } + + IntSize srcSize = srcSurf->GetSize(); + IntSize dstSize = GetDestDTWidget()->GetDT()->GetSize(); + + mZoomFactor = min(float(dstSize.width) / srcSize.width, float(dstSize.height) / srcSize.height); + UpdateView(); +} + +void SurfaceView::on_actionZoom_In_triggered() +{ + for (int i = 0; i < sizeof(kZoomSizes) / sizeof(float); i++) { + if (kZoomSizes[i] > mZoomFactor) { + mZoomFactor = kZoomSizes[i]; + UpdateView(); + return; + } + } + + mZoomFactor = 16.0f; + UpdateView(); +} + +void SurfaceView::on_actionZoom_Out_triggered() +{ + for (int i = (sizeof(kZoomSizes) / sizeof(float) - 1); i >= 0; i--) { + if (kZoomSizes[i] < mZoomFactor) { + mZoomFactor = kZoomSizes[i]; + UpdateView(); + return; + } + } + + mZoomFactor = 0.125f; + UpdateView(); +} diff --git a/libazure/player2d/surfaceview.h b/libazure/player2d/surfaceview.h new file mode 100644 index 0000000..e527c55 --- /dev/null +++ b/libazure/player2d/surfaceview.h @@ -0,0 +1,42 @@ +#ifndef SURFACEVIEW_H +#define SURFACEVIEW_H + +#include +#include "2D.h" + +#include "RecordedEvent.h" + +class DrawTargetWidget; +class QScrollBar; + +class SurfaceView : public QWidget +{ + Q_OBJECT + +public: + explicit SurfaceView(QWidget *parent = 0); + +protected: + virtual mozilla::TemporaryRef GetSourceSurface() = 0; + virtual DrawTargetWidget *GetDestDTWidget() const = 0; + virtual QScrollBar *GetHorizontalScrollBar() const = 0; + virtual QScrollBar *GetVerticalScrollBar() const = 0; + +public slots: + void UpdateView(); + +signals: + void SwitchingBackend(uint32_t aType); + +protected slots: + void on_actionZoom_In_triggered(); + void on_actionOriginal_Size_triggered(); + void on_actionFit_To_Window_triggered(); + void on_actionZoom_Out_triggered(); + +private: + float mZoomFactor; +}; + + +#endif // SURFACEVIEW_H diff --git a/libazure/player2d/timer.h b/libazure/player2d/timer.h new file mode 100644 index 0000000..0654ef6 --- /dev/null +++ b/libazure/player2d/timer.h @@ -0,0 +1,42 @@ + +#ifdef _MSC_VER +#include +#else +#include +#include +#endif + +class HighPrecisionMeasurement +{ +public: + void Start() { +#ifdef WIN32 + ::QueryPerformanceCounter(&mStart); +#else + gettimeofday(&mStart, NULL); +#endif + } + + double Measure() { +#ifdef WIN32 + LARGE_INTEGER end, freq; + ::QueryPerformanceCounter(&end); + ::QueryPerformanceFrequency(&freq); + return (double(end.QuadPart) - double(mStart.QuadPart)) / double(freq.QuadPart) * 1000.00; +#else + struct timeval end; + gettimeofday(&end, NULL); + + long seconds = end.tv_sec - mStart.tv_sec; + long useconds = end.tv_usec - mStart.tv_usec; + long mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5; + return mtime; +#endif + } +private: +#ifdef WIN32 + LARGE_INTEGER mStart; +#else + struct timeval mStart; +#endif +}; diff --git a/libazure/recordbench/Main.cpp b/libazure/recordbench/Main.cpp new file mode 100644 index 0000000..482736a --- /dev/null +++ b/libazure/recordbench/Main.cpp @@ -0,0 +1,299 @@ +// recordbench.cpp : Defines the entry point for the console application. +// + +#include +#ifdef WIN32 +#include +#endif +#if USE_NVPR +#include "nvpr/GL.h" +#endif +#include "2D.h" +#include "RecordedEvent.h" +#include "RawTranslator.h" +#include "perftest/TestBase.h" + +#include +#include + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +BackendType sTestedBackends[] = +{ +#ifdef WIN32 + BackendType::DIRECT2D, +#endif +#ifdef USE_NVPR + BackendType::NVPR, +#endif +#ifdef USE_SKIA + BackendType::SKIA, +#endif +#ifdef USE_CAIRO + BackendType::CAIRO, +#endif +}; + +string +GetBackendName(BackendType aType) +{ + switch(aType) { + case BackendType::DIRECT2D: + return "Direct2D"; + case BackendType::SKIA: + return "Skia"; + case BackendType::CAIRO: + return "Cairo"; + case BackendType::NVPR: + return "NVpr"; + default: + return "Unknown"; + } +} + +void +FinishDrawing(DrawTarget* aDT) +{ +#ifdef WIN32 + if (aDT->GetBackendType() == BackendType::DIRECT2D) { + aDT->Flush(); + + RefPtr query; + D3D10_QUERY_DESC desc; + desc.Query = D3D10_QUERY_EVENT; + desc.MiscFlags = 0; + Factory::GetDirect3D10Device()->CreateQuery(&desc, byRef(query)); + query->End(); + while (query->GetData(nullptr, 0, 0) == S_FALSE) {} + return; + } +#endif +#if USE_NVPR + if (aDT->GetBackendType() == BackendType::NVPR) { + using nvpr::gl; + gl->MakeCurrent(); + gl->Finish(); + return; + } +#endif +} + +struct RetainedDrawTargetData { + RetainedDrawTargetData(int aCreationEvent) + : mCreationEvent(aCreationEvent) + , mEndClipDepth(0) + {} + int mCreationEvent; + int mEndClipDepth; +}; + +static int sN = 10; +static bool sRetainDrawTargets; +static bool sRetainPaths; +static bool sRetainSourceSurfaces; +static bool sRetainGradientStops; + +int +main(int argc, char *argv[], char *envp[]) +{ + if (argc < 2) { + printf("No recording specified."); + return 1; + } + + for (int i = 1; i < argc - 1; i++) { + if (sscanf(argv[i], "--n=%i", &sN)) { + continue; + } + if (!strcmp(argv[i], "--retain-draw-targets")) { + sRetainDrawTargets = true; + continue; + } + if (!strcmp(argv[i], "--retain-paths")) { + sRetainPaths = true; + continue; + } + if (!strcmp(argv[i], "--retain-source-surfaces")) { + sRetainSourceSurfaces = true; + continue; + } + if (!strcmp(argv[i], "--retain-gradient-stops")) { + sRetainGradientStops = true; + continue; + } + } + + struct EventWithID { + RecordedEvent* recordedEvent; + uint32_t eventID; + }; + + vector drawingEvents; + vector retainedObjectCreations; + map > retainedDrawTargets; + + ifstream inputFile; + + inputFile.open(argv[argc - 1], istream::in | istream::binary); + + inputFile.seekg(0, ios::end); + int length = inputFile.tellg(); + inputFile.seekg(0, ios::beg); + + uint32_t magicInt; + ReadElement(inputFile, magicInt); + if (magicInt != 0xc001feed) { + printf("File is not a valid recording"); + return 1; + } + + uint16_t majorRevision; + uint16_t minorRevision; + ReadElement(inputFile, majorRevision); + ReadElement(inputFile, minorRevision); + + if (majorRevision != kMajorRevision) { + printf("Recording was made with a different major revision"); + return 1; + } + + if (minorRevision > kMinorRevision) { + printf("Recording was made with a later minor revision"); + return 1; + } + + uint32_t eventIndex = 0; + while (inputFile.tellg() < length) { + int32_t type; + ReadElement(inputFile, type); + + EventWithID newEvent; + newEvent.recordedEvent = RecordedEvent::LoadEventFromStream(inputFile, (RecordedEvent::EventType)type); + newEvent.eventID = eventIndex++; + + RecordedEvent::EventType eventType = newEvent.recordedEvent->GetType(); + + if ((sRetainDrawTargets && eventType == RecordedEvent::DRAWTARGETCREATION) || + (sRetainPaths && eventType == RecordedEvent::PATHCREATION) || + (sRetainSourceSurfaces && eventType == RecordedEvent::SOURCESURFACECREATION) || + (sRetainGradientStops && eventType == RecordedEvent::GRADIENTSTOPSCREATION) || + (eventType == RecordedEvent::SCALEDFONTCREATION)) { + + retainedObjectCreations.push_back(newEvent); + + if (eventType == RecordedEvent::DRAWTARGETCREATION) { + ReferencePtr drawTargetId = newEvent.recordedEvent->GetObjectRef(); + RetainedDrawTargetData data(newEvent.eventID); + retainedDrawTargets[drawTargetId].push_back(data); + } + + continue; + } + + if ((sRetainDrawTargets && eventType == RecordedEvent::DRAWTARGETDESTRUCTION) || + (sRetainPaths && eventType == RecordedEvent::PATHDESTRUCTION) || + (sRetainSourceSurfaces && eventType == RecordedEvent::SOURCESURFACEDESTRUCTION) || + (sRetainGradientStops && eventType == RecordedEvent::GRADIENTSTOPSDESTRUCTION) || + (eventType == RecordedEvent::SCALEDFONTDESTRUCTION)) { + // Retained objects never get destroyed. + continue; + } + + if (sRetainDrawTargets && (eventType == RecordedEvent::PUSHCLIP || + eventType == RecordedEvent::PUSHCLIPRECT)) { + ReferencePtr drawTargetId = newEvent.recordedEvent->GetObjectRef(); + retainedDrawTargets[drawTargetId].back().mEndClipDepth++; + } + + if (sRetainDrawTargets && eventType == RecordedEvent::POPCLIP) { + ReferencePtr drawTargetId = newEvent.recordedEvent->GetObjectRef(); + retainedDrawTargets[drawTargetId].back().mEndClipDepth--; + } + + if (sRetainSourceSurfaces && eventType == RecordedEvent::SNAPSHOT) { + retainedObjectCreations.push_back(newEvent); + } + + drawingEvents.push_back(newEvent); + } + +#ifdef WIN32 + RefPtr device; + ::D3D10CreateDevice1(nullptr, + D3D10_DRIVER_TYPE_HARDWARE, + nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + D3D10_FEATURE_LEVEL_10_0, + D3D10_1_SDK_VERSION, + byRef(device)); + + Factory::SetDirect3D10Device(device); +#endif + + for (int i = 0; i < sizeof(sTestedBackends) / sizeof(BackendType); i++) { + RefPtr dt = Factory::CreateDrawTarget(sTestedBackends[i], IntSize(1, 1), SurfaceFormat::B8G8R8A8); + + RawTranslator* translator = + RawTranslator::Create(dt, sRetainDrawTargets, sRetainPaths, + sRetainSourceSurfaces, sRetainGradientStops); + + for (int c = 0; c < retainedObjectCreations.size(); c++) { + translator->SetEventNumber(retainedObjectCreations[c].eventID); + retainedObjectCreations[c].recordedEvent->PlayEvent(translator); + } + + vector data(sN + 1); + double average = 0; + + for (int k = 0; k < (sN + 1); k++) { + HighPrecisionMeasurement measurement; + measurement.Start(); + + for (int c = 0; c < drawingEvents.size(); c++) { + translator->SetEventNumber(drawingEvents[c].eventID); + drawingEvents[c].recordedEvent->PlayEvent(translator); + } + + // Reset retained draw targets. + for (const auto& drawTargetList : retainedDrawTargets) { + for (const auto& drawTargetData : drawTargetList.second) { + translator->SetEventNumber(drawTargetData.mCreationEvent); + DrawTarget* drawTarget = translator->LookupDrawTarget(drawTargetList.first); + for (int i = 0; i < drawTargetData.mEndClipDepth; i++) { + drawTarget->PopClip(); + } + drawTarget->SetTransform(Matrix()); + drawTarget->ClearRect(Rect(Point(), Size(drawTarget->GetSize()))); + } + } + + if (k == 0 || k == sN) { + // TODO: This skews the sqDiffSum. + FinishDrawing(dt); + } + + data[k] = measurement.Measure(); + + if (k > 0) { + average += data[k]; + } + } + average /= sN; + + double sqDiffSum = 0; + for (int c = 1; c < sN + 1; c++) { + sqDiffSum += pow(data[c] - average, 2); + } + + sqDiffSum /= sN; + + printf("Rendering time (%s): %f +/- %f ms\n", GetBackendName(sTestedBackends[i]).c_str(), average, sqrt(sqDiffSum)); + + delete translator; + } + + return 0; +} diff --git a/libazure/recordbench/RawTranslator.cpp b/libazure/recordbench/RawTranslator.cpp new file mode 100644 index 0000000..0ef5ca4 --- /dev/null +++ b/libazure/recordbench/RawTranslator.cpp @@ -0,0 +1,204 @@ +#include "RawTranslator.h" +#include "Filters.h" +#include +#include + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +enum RetainBehavior { RETAIN, NO_RETAIN }; + +template +class RawTranslatorImpl : public RawTranslator +{ +public: + RawTranslatorImpl(DrawTarget *aBaseDT) + : RawTranslator(aBaseDT) + {} + +private: + template inline T + *LookupObject(map > &aMap, ReferencePtr aRefPtr) + { + typedef typename std::map > MapType; + typename MapType::iterator iter = aMap.find(aRefPtr); + return (iter != aMap.end()) ? iter->second : NULL; + } + + template inline void + AddObject(map > &aMap, ReferencePtr aRefPtr, T *aObject) + { + aMap[aRefPtr] = aObject; + } + + template inline void + RemoveObject(map > &aMap, ReferencePtr aRefPtr) + { + aMap.erase(aRefPtr); + } + + template struct RetainedObject { + uint32_t startEvent; + RefPtr object; + }; + + template inline RefPtr + &LookupObject(map > > &aMap, ReferencePtr aRefPtr) + { + typedef typename std::map > > MapType; + typename MapType::iterator iter = aMap.find(aRefPtr); + if (iter == aMap.end()) { + printf("Attempted to look up a nonexistent object. Aborting.\n"); + exit(-1); + } + + vector > &retainedObjects = iter->second; + if (retainedObjects.front().startEvent > mEventNumber) { + printf("Attempted to look up a nonexistent object. Aborting.\n"); + exit(-1); + } + + size_t left = 0, right = retainedObjects.size(); + while (left + 1 != right) { + size_t mid = (left + right) / 2; + if (retainedObjects[mid].startEvent <= mEventNumber) { + left = mid; + } else { + right = mid; + } + } + + return retainedObjects[left].object; + } + + template inline void + AddObject(map > > &aMap, ReferencePtr aRefPtr, T *aObject) + { + RetainedObject retainedObject = {mEventNumber, aObject}; + vector > &retainedObjects = aMap[aRefPtr]; + if (!retainedObjects.empty() && + retainedObjects.back().startEvent >= retainedObject.startEvent) { + // Snapshots still get added every frame. + RefPtr &object = LookupObject(aMap, aRefPtr); + object = aObject; + return; + } + retainedObjects.push_back(retainedObject); + } + + template inline void + RemoveObject(map > > &aMap, ReferencePtr aRefPtr) + { + RefPtr &object = LookupObject(aMap, aRefPtr); + object = nullptr; + } + + // Translator + virtual DrawTarget *LookupDrawTarget(ReferencePtr aRefPtr) { return LookupObject(mDrawTargets, aRefPtr); } + virtual Path *LookupPath(ReferencePtr aRefPtr) { return LookupObject(mPaths, aRefPtr); } + virtual SourceSurface *LookupSourceSurface(ReferencePtr aRefPtr) { return LookupObject(mSourceSurfaces, aRefPtr); } + virtual FilterNode *LookupFilterNode(ReferencePtr aRefPtr) { return LookupObject(mFilterNodes, aRefPtr); } + virtual GradientStops *LookupGradientStops(ReferencePtr aRefPtr) { return LookupObject(mGradientStops, aRefPtr); } + virtual ScaledFont *LookupScaledFont(ReferencePtr aRefPtr) { return LookupObject(mScaledFonts, aRefPtr); } + virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) { AddObject(mDrawTargets, aRefPtr, aDT); } + virtual void AddPath(ReferencePtr aRefPtr, Path *aPath) { AddObject(mPaths, aRefPtr, aPath); } + virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aSurface) { AddObject(mSourceSurfaces, aRefPtr, aSurface); } + virtual void AddFilterNode(ReferencePtr aRefPtr, FilterNode *aFilter) { AddObject(mFilterNodes, aRefPtr, aFilter); } + virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aStops) { AddObject(mGradientStops, aRefPtr, aStops); } + virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) { AddObject(mScaledFonts, aRefPtr, aScaledFont); } + virtual void RemoveDrawTarget(ReferencePtr aRefPtr) { RemoveObject(mDrawTargets, aRefPtr); } + virtual void RemovePath(ReferencePtr aRefPtr) { RemoveObject(mPaths, aRefPtr); } + virtual void RemoveSourceSurface(ReferencePtr aRefPtr) { RemoveObject(mSourceSurfaces, aRefPtr); } + virtual void RemoveFilterNode(ReferencePtr aRefPtr) { RemoveObject(mFilterNodes, aRefPtr); } + virtual void RemoveGradientStops(ReferencePtr aRefPtr) { RemoveObject(mGradientStops, aRefPtr); } + virtual void RemoveScaledFont(ReferencePtr aRefPtr) { RemoveObject(mScaledFonts, aRefPtr); } + +private: + template struct MapType { + typedef map > Type; + }; + template struct MapType { + typedef map > > Type; + }; + typename MapType::Type mDrawTargets; + typename MapType::Type mPaths; + typename MapType::Type mSourceSurfaces; + typename MapType::Type mFilterNodes; + typename MapType::Type mGradientStops; + typename MapType::Type mScaledFonts; +}; + +RawTranslator +*RawTranslator::Create(DrawTarget *aBaseDT, bool aRetainDrawTargets, bool aRetainPaths, + bool aRetainSourceSurfaces, bool aRetainGradientStops) +{ + if (!aRetainDrawTargets && !aRetainPaths && !aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && !aRetainPaths && !aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && !aRetainPaths && aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && !aRetainPaths && aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && aRetainPaths && !aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && aRetainPaths && !aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && aRetainPaths && aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (!aRetainDrawTargets && aRetainPaths && aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && !aRetainPaths && !aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && !aRetainPaths && !aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && !aRetainPaths && aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && !aRetainPaths && aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && aRetainPaths && !aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && aRetainPaths && !aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && aRetainPaths && aRetainSourceSurfaces && !aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + if (aRetainDrawTargets && aRetainPaths && aRetainSourceSurfaces && aRetainGradientStops) { + return new RawTranslatorImpl(aBaseDT); + } + return NULL; +} + +FontType +RawTranslator::GetDesiredFontType() +{ + switch (mBaseDT->GetBackendType()) { + case BackendType::DIRECT2D: + return FontType::DWRITE; + case BackendType::CAIRO: + return FontType::CAIRO; + case BackendType::SKIA: + return FontType::SKIA; + case BackendType::NVPR: + return FontType::NVPR; + default: + MOZ_ASSERT(false); + return FontType::DWRITE; + } +} diff --git a/libazure/recordbench/RawTranslator.h b/libazure/recordbench/RawTranslator.h new file mode 100644 index 0000000..bb80c55 --- /dev/null +++ b/libazure/recordbench/RawTranslator.h @@ -0,0 +1,22 @@ + +#include "2D.h" +#include "RecordedEvent.h" + +class RawTranslator : public mozilla::gfx::Translator +{ +public: + static RawTranslator + *Create(mozilla::gfx::DrawTarget *aBaseDT, bool aRetainDrawTargets, + bool aRetainPaths, bool aRetainSourceSurfaces, bool aRetainGradientStops); + + void SetEventNumber(uint32_t aEventNumber) { mEventNumber = aEventNumber; } + virtual mozilla::gfx::DrawTarget *GetReferenceDrawTarget() { return mBaseDT; } + virtual mozilla::gfx::FontType GetDesiredFontType(); + +protected: + RawTranslator(mozilla::gfx::DrawTarget *aBaseDT) + : mBaseDT(aBaseDT) + {} + uint32_t mEventNumber; + mozilla::RefPtr mBaseDT; +}; diff --git a/libazure/recordbench/recordbench.vcxproj b/libazure/recordbench/recordbench.vcxproj new file mode 100644 index 0000000..e89afe3 --- /dev/null +++ b/libazure/recordbench/recordbench.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug (With Skia) + Win32 + + + Debug + Win32 + + + Release (With Skia) + Win32 + + + Release + Win32 + + + + {10760766-5991-426D-A2D3-C0A0789A3BB6} + Win32Proj + recordbench + + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + $(SolutionDir)\..\cairo\src\Debug;$(SolutionDir)\..\skia\out\Debug;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + false + + + false + $(SolutionDir)\..\cairo\src\Release;$(SolutionDir)\..\skia\out\Release;$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + + + + Level3 + Disabled + USE_NVPR;WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions); + ../ + + + Console + true + ../$(Configuration)/gfx2d.lib;opengl32.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + USE_NVPR;USE_SKIA;USE_CAIRO;USE_D2D1_1;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../ + + + Console + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + Level3 + + + MaxSpeed + true + true + USE_NVPR;WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions); + ../ + + + Console + true + true + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + USE_NVPR;USE_SKIA;USE_CAIRO;USE_D2D1_1;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../ + + + Console + true + true + true + ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libazure/src/gfx/2d/DrawTargetCG.cpp b/libazure/src/gfx/2d/DrawTargetCG.cpp deleted file mode 100644 index 37fe4e3..0000000 --- a/libazure/src/gfx/2d/DrawTargetCG.cpp +++ /dev/null @@ -1,1141 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "DrawTargetCG.h" -#include "SourceSurfaceCG.h" -#include "Rect.h" -#include "ScaledFontMac.h" -#include "Tools.h" -#include -#include "QuartzSupport.h" - -//CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode); - -// A private API that Cairo has been using for a long time -CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform); - -namespace mozilla { -namespace gfx { - -static CGRect RectToCGRect(Rect r) -{ - return CGRectMake(r.x, r.y, r.width, r.height); -} - -static CGRect IntRectToCGRect(IntRect r) -{ - return CGRectMake(r.x, r.y, r.width, r.height); -} - -CGBlendMode ToBlendMode(CompositionOp op) -{ - CGBlendMode mode; - switch (op) { - case OP_OVER: - mode = kCGBlendModeNormal; - break; - case OP_ADD: - mode = kCGBlendModePlusLighter; - break; - case OP_ATOP: - mode = kCGBlendModeSourceAtop; - break; - case OP_OUT: - mode = kCGBlendModeSourceOut; - break; - case OP_IN: - mode = kCGBlendModeSourceIn; - break; - case OP_SOURCE: - mode = kCGBlendModeCopy; - break; - case OP_DEST_IN: - mode = kCGBlendModeDestinationIn; - break; - case OP_DEST_OUT: - mode = kCGBlendModeDestinationOut; - break; - case OP_DEST_OVER: - mode = kCGBlendModeDestinationOver; - break; - case OP_DEST_ATOP: - mode = kCGBlendModeDestinationAtop; - break; - case OP_XOR: - mode = kCGBlendModeXOR; - break; - case OP_MULTIPLY: - mode = kCGBlendModeMultiply; - break; - case OP_SCREEN: - mode = kCGBlendModeScreen; - break; - case OP_OVERLAY: - mode = kCGBlendModeOverlay; - break; - case OP_DARKEN: - mode = kCGBlendModeDarken; - break; - case OP_LIGHTEN: - mode = kCGBlendModeLighten; - break; - case OP_COLOR_DODGE: - mode = kCGBlendModeColorDodge; - break; - case OP_COLOR_BURN: - mode = kCGBlendModeColorBurn; - break; - case OP_HARD_LIGHT: - mode = kCGBlendModeHardLight; - break; - case OP_SOFT_LIGHT: - mode = kCGBlendModeSoftLight; - break; - case OP_DIFFERENCE: - mode = kCGBlendModeDifference; - break; - case OP_EXCLUSION: - mode = kCGBlendModeExclusion; - break; - case OP_HUE: - mode = kCGBlendModeHue; - break; - case OP_SATURATION: - mode = kCGBlendModeSaturation; - break; - case OP_COLOR: - mode = kCGBlendModeColor; - break; - case OP_LUMINOSITY: - mode = kCGBlendModeLuminosity; - break; - /* - case OP_CLEAR: - mode = kCGBlendModeClear; - break;*/ - default: - mode = kCGBlendModeNormal; - } - return mode; -} - - - -DrawTargetCG::DrawTargetCG() : mCg(nullptr), mSnapshot(nullptr) -{ -} - -DrawTargetCG::~DrawTargetCG() -{ - MarkChanged(); - - // We need to conditionally release these because Init can fail without initializing these. - if (mColorSpace) - CGColorSpaceRelease(mColorSpace); - if (mCg) - CGContextRelease(mCg); - free(mData); -} - -BackendType -DrawTargetCG::GetType() const -{ - // It may be worth spliting Bitmap and IOSurface DrawTarget - // into seperate classes. - if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) { - return BACKEND_COREGRAPHICS_ACCELERATED; - } else { - return BACKEND_COREGRAPHICS; - } -} - -TemporaryRef -DrawTargetCG::Snapshot() -{ - if (!mSnapshot) { - if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) { - return new SourceSurfaceCGIOSurfaceContext(this); - } else { - mSnapshot = new SourceSurfaceCGBitmapContext(this); - } - } - - return mSnapshot; -} - -TemporaryRef -DrawTargetCG::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const -{ - // XXX: in thebes we use CGLayers to do this kind of thing. It probably makes sense - // to add that in somehow, but at a higher level - RefPtr newTarget = new DrawTargetCG(); - if (newTarget->Init(GetType(), aSize, aFormat)) { - return newTarget; - } else { - return nullptr; - } -} - -TemporaryRef -DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) const -{ - RefPtr newSurf = new SourceSurfaceCG(); - - if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { - return nullptr; - } - - return newSurf; -} - -static CGImageRef -GetImageFromSourceSurface(SourceSurface *aSurface) -{ - if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE) - return static_cast(aSurface)->GetImage(); - else if (aSurface->GetType() == SURFACE_COREGRAPHICS_CGCONTEXT) - return static_cast(aSurface)->GetImage(); - else if (aSurface->GetType() == SURFACE_DATA) - return static_cast(aSurface)->GetImage(); - abort(); -} - -TemporaryRef -DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const -{ - return nullptr; -} - -class UnboundnessFixer -{ - CGRect mClipBounds; - CGLayerRef mLayer; - CGContextRef mCg; - public: - UnboundnessFixer() : mCg(nullptr) {} - - CGContextRef Check(CGContextRef baseCg, CompositionOp blend) - { - if (!IsOperatorBoundByMask(blend)) { - mClipBounds = CGContextGetClipBoundingBox(baseCg); - // TransparencyLayers aren't blended using the blend mode so - // we are forced to use CGLayers - - //XXX: The size here is in default user space units, of the layer relative to the graphics context. - // is the clip bounds still correct if, for example, we have a scale applied to the context? - mLayer = CGLayerCreateWithContext(baseCg, mClipBounds.size, nullptr); - //XXX: if the size is 0x0 we get a nullptr CGContext back from GetContext - mCg = CGLayerGetContext(mLayer); - // CGContext's default to have the origin at the bottom left - // so flip it to the top left and adjust for the origin - // of the layer - CGContextTranslateCTM(mCg, -mClipBounds.origin.x, mClipBounds.origin.y + mClipBounds.size.height); - CGContextScaleCTM(mCg, 1, -1); - - return mCg; - } else { - return baseCg; - } - } - - void Fix(CGContextRef baseCg) - { - if (mCg) { - CGContextTranslateCTM(baseCg, 0, mClipBounds.size.height); - CGContextScaleCTM(baseCg, 1, -1); - mClipBounds.origin.y *= -1; - CGContextDrawLayerAtPoint(baseCg, mClipBounds.origin, mLayer); - CGContextRelease(mCg); - } - } -}; - -void -DrawTargetCG::DrawSurface(SourceSurface *aSurface, - const Rect &aDest, - const Rect &aSource, - const DrawSurfaceOptions &aSurfOptions, - const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGImageRef image; - CGImageRef subimage = nullptr; - CGContextSaveGState(mCg); - - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(cg, aDrawOptions.mAlpha); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - image = GetImageFromSourceSurface(aSurface); - /* we have two options here: - * - create a subimage -- this is slower - * - fancy things with clip and different dest rects */ - { - subimage = CGImageCreateWithImageInRect(image, RectToCGRect(aSource)); - image = subimage; - } - - CGContextScaleCTM(cg, 1, -1); - - CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + aDest.height), - aDest.width, aDest.height); - - //XXX: we should implement this for patterns too - if (aSurfOptions.mFilter == FILTER_POINT) - CGContextSetInterpolationQuality(cg, kCGInterpolationNone); - - CGContextDrawImage(cg, flippedRect, image); - - fixer.Fix(mCg); - - CGContextRestoreGState(mCg); - - CGImageRelease(subimage); -} - -static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor) -{ - CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a}; - return CGColorCreate(aColorSpace, components); -} - -class GradientStopsCG : public GradientStops -{ - public: - //XXX: The skia backend uses a vector and passes in aNumStops. It should do better - GradientStopsCG(GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode) - { - //XXX: do the stops need to be in any particular order? - // what should we do about the color space here? we certainly shouldn't be - // recreating it all the time - std::vector colors; - std::vector offsets; - colors.reserve(aNumStops*4); - offsets.reserve(aNumStops); - - for (uint32_t i = 0; i < aNumStops; i++) { - colors.push_back(aStops[i].color.r); - colors.push_back(aStops[i].color.g); - colors.push_back(aStops[i].color.b); - colors.push_back(aStops[i].color.a); - - offsets.push_back(aStops[i].offset); - } - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - mGradient = CGGradientCreateWithColorComponents(colorSpace, - &colors.front(), - &offsets.front(), - aNumStops); - CGColorSpaceRelease(colorSpace); - } - virtual ~GradientStopsCG() { - CGGradientRelease(mGradient); - } - // Will always report BACKEND_COREGRAPHICS, but it is compatible - // with BACKEND_COREGRAPHICS_ACCELERATED - BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; } - CGGradientRef mGradient; -}; - -TemporaryRef -DrawTargetCG::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode) const -{ - return new GradientStopsCG(aStops, aNumStops, aExtendMode); -} - -static void -DrawGradient(CGContextRef cg, const Pattern &aPattern) -{ - if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) { - const LinearGradientPattern& pat = static_cast(aPattern); - GradientStopsCG *stops = static_cast(pat.mStops.get()); - // XXX: we should take the m out of the properties of LinearGradientPatterns - CGPoint startPoint = { pat.mBegin.x, pat.mBegin.y }; - CGPoint endPoint = { pat.mEnd.x, pat.mEnd.y }; - - // Canvas spec states that we should avoid drawing degenerate gradients (XXX: should this be in common code?) - //if (startPoint.x == endPoint.x && startPoint.y == endPoint.y) - // return; - - CGContextDrawLinearGradient(cg, stops->mGradient, startPoint, endPoint, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) { - const RadialGradientPattern& pat = static_cast(aPattern); - GradientStopsCG *stops = static_cast(pat.mStops.get()); - - // XXX: we should take the m out of the properties of RadialGradientPatterns - CGPoint startCenter = { pat.mCenter1.x, pat.mCenter1.y }; - CGFloat startRadius = pat.mRadius1; - CGPoint endCenter = { pat.mCenter2.x, pat.mCenter2.y }; - CGFloat endRadius = pat.mRadius2; - - //XXX: are there degenerate radial gradients that we should avoid drawing? - CGContextDrawRadialGradient(cg, stops->mGradient, startCenter, startRadius, endCenter, endRadius, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - } else { - assert(0); - } - -} - -static void -drawPattern(void *info, CGContextRef context) -{ - CGImageRef image = static_cast(info); - CGRect rect = {{0, 0}, - {static_cast(CGImageGetWidth(image)), - static_cast(CGImageGetHeight(image))}}; - CGContextDrawImage(context, rect, image); -} - -static void -releaseInfo(void *info) -{ - CGImageRef image = static_cast(info); - CGImageRelease(image); -} - -CGPatternCallbacks patternCallbacks = { - 0, - drawPattern, - releaseInfo -}; - -static bool -isGradient(const Pattern &aPattern) -{ - return aPattern.GetType() == PATTERN_LINEAR_GRADIENT || aPattern.GetType() == PATTERN_RADIAL_GRADIENT; -} - -/* CoreGraphics patterns ignore the userspace transform so - * we need to multiply it in */ -static CGPatternRef -CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace) -{ - const SurfacePattern& pat = static_cast(aPattern); - // XXX: is .get correct here? - CGImageRef image = GetImageFromSourceSurface(pat.mSurface.get()); - CGFloat xStep, yStep; - switch (pat.mExtendMode) { - case EXTEND_CLAMP: - // The 1 << 22 comes from Webkit see Pattern::createPlatformPattern() in PatternCG.cpp for more info - xStep = static_cast(1 << 22); - yStep = static_cast(1 << 22); - break; - case EXTEND_REFLECT: - assert(0); - case EXTEND_REPEAT: - xStep = static_cast(CGImageGetWidth(image)); - yStep = static_cast(CGImageGetHeight(image)); - // webkit uses wkCGPatternCreateWithImageAndTransform a wrapper around CGPatternCreateWithImage2 - // this is done to avoid pixel-cracking along pattern boundaries - // (see https://bugs.webkit.org/show_bug.cgi?id=53055) - // typedef enum { - // wkPatternTilingNoDistortion, - // wkPatternTilingConstantSpacingMinimalDistortion, - // wkPatternTilingConstantSpacing - // } wkPatternTiling; - // extern CGPatternRef (*wkCGPatternCreateWithImageAndTransform)(CGImageRef, CGAffineTransform, int); - } - - //XXX: We should be using CGContextDrawTiledImage when we can. Even though it - // creates a pattern, it seems to go down a faster path than using a delegate - // like we do below - CGRect bounds = { - {0, 0,}, - {static_cast(CGImageGetWidth(image)), static_cast(CGImageGetHeight(image))} - }; - CGAffineTransform transform = - CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformMakeScale(1, - -1), - GfxMatrixToCGAffineTransform(pat.mMatrix)), - aUserSpace); - transform = CGAffineTransformTranslate(transform, 0, -static_cast(CGImageGetHeight(image))); - return CGPatternCreate(CGImageRetain(image), bounds, transform, xStep, yStep, kCGPatternTilingConstantSpacing, - true, &patternCallbacks); -} - -static void -SetFillFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern) -{ - assert(!isGradient(aPattern)); - if (aPattern.GetType() == PATTERN_COLOR) { - - const Color& color = static_cast(aPattern).mColor; - //XXX: we should cache colors - CGColorRef cgcolor = ColorToCGColor(aColorSpace, color); - CGContextSetFillColorWithColor(cg, cgcolor); - CGColorRelease(cgcolor); - } else if (aPattern.GetType() == PATTERN_SURFACE) { - - CGColorSpaceRef patternSpace; - patternSpace = CGColorSpaceCreatePattern (nullptr); - CGContextSetFillColorSpace(cg, patternSpace); - CGColorSpaceRelease(patternSpace); - - CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg)); - CGFloat alpha = 1.; - CGContextSetFillPattern(cg, pattern, &alpha); - CGPatternRelease(pattern); - } -} - -static void -SetStrokeFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern) -{ - assert(!isGradient(aPattern)); - if (aPattern.GetType() == PATTERN_COLOR) { - const Color& color = static_cast(aPattern).mColor; - //XXX: we should cache colors - CGColorRef cgcolor = ColorToCGColor(aColorSpace, color); - CGContextSetStrokeColorWithColor(cg, cgcolor); - CGColorRelease(cgcolor); - } else if (aPattern.GetType() == PATTERN_SURFACE) { - CGColorSpaceRef patternSpace; - patternSpace = CGColorSpaceCreatePattern (nullptr); - CGContextSetStrokeColorSpace(cg, patternSpace); - CGColorSpaceRelease(patternSpace); - - CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg)); - CGFloat alpha = 1.; - CGContextSetStrokePattern(cg, pattern, &alpha); - CGPatternRelease(pattern); - } - -} - - -void -DrawTargetCG::FillRect(const Rect &aRect, - const Pattern &aPattern, - const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(mCg, aDrawOptions.mAlpha); - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - if (isGradient(aPattern)) { - CGContextClipToRect(cg, RectToCGRect(aRect)); - DrawGradient(cg, aPattern); - } else { - SetFillFromPattern(cg, mColorSpace, aPattern); - CGContextFillRect(cg, RectToCGRect(aRect)); - } - - fixer.Fix(mCg); - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(mCg, aDrawOptions.mAlpha); - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - CGContextBeginPath(cg); - CGContextMoveToPoint(cg, p1.x, p1.y); - CGContextAddLineToPoint(cg, p2.x, p2.y); - - SetStrokeOptions(cg, aStrokeOptions); - - if (isGradient(aPattern)) { - CGContextReplacePathWithStrokedPath(cg); - //XXX: should we use EO clip here? - CGContextClip(cg); - DrawGradient(cg, aPattern); - } else { - SetStrokeFromPattern(cg, mColorSpace, aPattern); - CGContextStrokePath(cg); - } - - fixer.Fix(mCg); - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::StrokeRect(const Rect &aRect, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions, - const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(mCg, aDrawOptions.mAlpha); - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - // we don't need to set all of the stroke state because - // it doesn't apply when stroking rects - switch (aStrokeOptions.mLineJoin) - { - case JOIN_BEVEL: - CGContextSetLineJoin(cg, kCGLineJoinBevel); - break; - case JOIN_ROUND: - CGContextSetLineJoin(cg, kCGLineJoinRound); - break; - case JOIN_MITER: - case JOIN_MITER_OR_BEVEL: - CGContextSetLineJoin(cg, kCGLineJoinMiter); - break; - } - CGContextSetLineWidth(cg, aStrokeOptions.mLineWidth); - - if (isGradient(aPattern)) { - // There's no CGContextClipStrokeRect so we do it by hand - CGContextBeginPath(cg); - CGContextAddRect(cg, RectToCGRect(aRect)); - CGContextReplacePathWithStrokedPath(cg); - //XXX: should we use EO clip here? - CGContextClip(cg); - DrawGradient(cg, aPattern); - } else { - SetStrokeFromPattern(cg, mColorSpace, aPattern); - CGContextStrokeRect(cg, RectToCGRect(aRect)); - } - - fixer.Fix(mCg); - CGContextRestoreGState(mCg); -} - - -void -DrawTargetCG::ClearRect(const Rect &aRect) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); - - CGContextClearRect(mCg, RectToCGRect(aRect)); - - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::Stroke(const Path *aPath, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(mCg, aDrawOptions.mAlpha); - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - - CGContextBeginPath(cg); - - assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS); - const PathCG *cgPath = static_cast(aPath); - CGContextAddPath(cg, cgPath->GetPath()); - - SetStrokeOptions(cg, aStrokeOptions); - - if (isGradient(aPattern)) { - CGContextReplacePathWithStrokedPath(cg); - //XXX: should we use EO clip here? - CGContextClip(cg); - DrawGradient(cg, aPattern); - } else { - CGContextBeginPath(cg); - // XXX: we could put fill mode into the path fill rule if we wanted - const PathCG *cgPath = static_cast(aPath); - CGContextAddPath(cg, cgPath->GetPath()); - - SetStrokeFromPattern(cg, mColorSpace, aPattern); - CGContextStrokePath(cg); - } - - fixer.Fix(mCg); - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS); - - CGContextSaveGState(mCg); - - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(cg, aDrawOptions.mAlpha); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - CGContextBeginPath(cg); - // XXX: we could put fill mode into the path fill rule if we wanted - const PathCG *cgPath = static_cast(aPath); - - if (isGradient(aPattern)) { - // setup a clip to draw the gradient through - if (CGPathIsEmpty(cgPath->GetPath())) { - // Adding an empty path will cause us not to clip - // so clip everything explicitly - CGContextClipToRect(mCg, CGRectZero); - } else { - CGContextAddPath(cg, cgPath->GetPath()); - if (cgPath->GetFillRule() == FILL_EVEN_ODD) - CGContextEOClip(mCg); - else - CGContextClip(mCg); - } - - DrawGradient(cg, aPattern); - } else { - CGContextAddPath(cg, cgPath->GetPath()); - - SetFillFromPattern(cg, mColorSpace, aPattern); - - if (cgPath->GetFillRule() == FILL_EVEN_ODD) - CGContextEOFillPath(cg); - else - CGContextFillPath(cg); - } - - fixer.Fix(mCg); - CGContextRestoreGState(mCg); -} - - -void -DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aDrawOptions, - const GlyphRenderingOptions*) -{ - MarkChanged(); - - assert(aBuffer.mNumGlyphs); - CGContextSaveGState(mCg); - - CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp)); - UnboundnessFixer fixer; - CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp); - CGContextSetAlpha(cg, aDrawOptions.mAlpha); - - CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform)); - - ScaledFontMac* macFont = static_cast(aFont); - - //XXX: we should use a stack vector here when we have a class like that - std::vector glyphs; - std::vector positions; - glyphs.resize(aBuffer.mNumGlyphs); - positions.resize(aBuffer.mNumGlyphs); - - // Handle the flip - CGAffineTransform matrix = CGAffineTransformMakeScale(1, -1); - CGContextConcatCTM(cg, matrix); - // CGContextSetTextMatrix works differently with kCGTextClip && kCGTextFill - // It seems that it transforms the positions with TextFill and not with TextClip - // Therefore we'll avoid it. See also: - // http://cgit.freedesktop.org/cairo/commit/?id=9c0d761bfcdd28d52c83d74f46dd3c709ae0fa69 - - for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { - glyphs[i] = aBuffer.mGlyphs[i].mIndex; - // XXX: CGPointMake might not be inlined - positions[i] = CGPointMake(aBuffer.mGlyphs[i].mPosition.x, - -aBuffer.mGlyphs[i].mPosition.y); - } - - //XXX: CGContextShowGlyphsAtPositions is 10.5+ for older versions use CGContextShowGlyphsWithAdvances - if (isGradient(aPattern)) { - CGContextSetTextDrawingMode(cg, kCGTextClip); - if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) { - ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(), - &positions.front(), - aBuffer.mNumGlyphs, cg); - } else { - CGContextSetFont(cg, macFont->mFont); - CGContextSetFontSize(cg, macFont->mSize); - CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), - aBuffer.mNumGlyphs); - } - DrawGradient(cg, aPattern); - } else { - //XXX: with CoreGraphics we can stroke text directly instead of going - // through GetPath. It would be nice to add support for using that - CGContextSetTextDrawingMode(cg, kCGTextFill); - SetFillFromPattern(cg, mColorSpace, aPattern); - if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) { - ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(), - &positions.front(), - aBuffer.mNumGlyphs, cg); - } else { - CGContextSetFont(cg, macFont->mFont); - CGContextSetFontSize(cg, macFont->mSize); - CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), - aBuffer.mNumGlyphs); - } - } - - fixer.Fix(mCg); - CGContextRestoreGState(cg); -} - -extern "C" { -void -CGContextResetClip(CGContextRef); -}; - -void -DrawTargetCG::CopySurface(SourceSurface *aSurface, - const IntRect& aSourceRect, - const IntPoint &aDestination) -{ - MarkChanged(); - - CGImageRef image; - CGImageRef subimage = nullptr; - if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE) { - image = GetImageFromSourceSurface(aSurface); - /* we have two options here: - * - create a subimage -- this is slower - * - fancy things with clip and different dest rects */ - { - subimage = CGImageCreateWithImageInRect(image, IntRectToCGRect(aSourceRect)); - image = subimage; - } - // XXX: it might be more efficient for us to do the copy directly if we have access to the bits - - CGContextSaveGState(mCg); - - // CopySurface ignores the clip, so we need to use private API to temporarily reset it - CGContextResetClip(mCg); - CGContextSetBlendMode(mCg, kCGBlendModeCopy); - - CGContextScaleCTM(mCg, 1, -1); - - CGRect flippedRect = CGRectMake(aDestination.x, -(aDestination.y + aSourceRect.height), - aSourceRect.width, aSourceRect.height); - - CGContextDrawImage(mCg, flippedRect, image); - - CGContextRestoreGState(mCg); - - CGImageRelease(subimage); - } -} - -void -DrawTargetCG::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator) -{ - MarkChanged(); - - CGImageRef image; - image = GetImageFromSourceSurface(aSurface); - - IntSize size = aSurface->GetSize(); - CGContextSaveGState(mCg); - //XXX do we need to do the fixup here? - CGContextSetBlendMode(mCg, ToBlendMode(aOperator)); - - CGContextScaleCTM(mCg, 1, -1); - - CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + size.height), - size.width, size.height); - - CGColorRef color = ColorToCGColor(mColorSpace, aColor); - CGSize offset = {aOffset.x, -aOffset.y}; - // CoreGraphics needs twice sigma as it's amount of blur - CGContextSetShadowWithColor(mCg, offset, 2*aSigma, color); - CGColorRelease(color); - - CGContextDrawImage(mCg, flippedRect, image); - - CGContextRestoreGState(mCg); - -} - -bool -DrawTargetCG::Init(BackendType aType, - unsigned char* aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) -{ - // XXX: we should come up with some consistent semantics for dealing - // with zero area drawtargets - if (aSize.width <= 0 || aSize.height <= 0 || - // 32767 is the maximum size supported by cairo - // we clamp to that to make it easier to interoperate - aSize.width > 32767 || aSize.height > 32767) { - mColorSpace = nullptr; - mCg = nullptr; - mData = nullptr; - return false; - } - - //XXX: handle SurfaceFormat - - //XXX: we'd be better off reusing the Colorspace across draw targets - mColorSpace = CGColorSpaceCreateDeviceRGB(); - - if (aData == nullptr && aType != BACKEND_COREGRAPHICS_ACCELERATED) { - // XXX: Currently, Init implicitly clears, that can often be a waste of time - mData = calloc(aSize.height * aStride, 1); - aData = static_cast(mData); - } else { - // mData == nullptr means DrawTargetCG doesn't own the image data and will not - // delete it in the destructor - mData = nullptr; - } - - mSize = aSize; - - if (aType == BACKEND_COREGRAPHICS_ACCELERATED) { - RefPtr ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height); - mCg = ioSurface->CreateIOSurfaceContext(); - // If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null - // and we will fallback to software below - mData = nullptr; - } - - if (!mCg || aType == BACKEND_COREGRAPHICS) { - int bitsPerComponent = 8; - - CGBitmapInfo bitinfo; - bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; - - // XXX: what should we do if this fails? - mCg = CGBitmapContextCreate (aData, - mSize.width, - mSize.height, - bitsPerComponent, - aStride, - mColorSpace, - bitinfo); - } - - assert(mCg); - // CGContext's default to have the origin at the bottom left - // so flip it to the top left - CGContextTranslateCTM(mCg, 0, mSize.height); - CGContextScaleCTM(mCg, 1, -1); - // See Bug 722164 for performance details - // Medium or higher quality lead to expensive interpolation - // for canvas we want to use low quality interpolation - // to have competitive performance with other canvas - // implementation. - // XXX: Create input parameter to control interpolation and - // use the default for content. - CGContextSetInterpolationQuality(mCg, kCGInterpolationLow); - - // XXX: set correct format - mFormat = FORMAT_B8G8R8A8; - - if (aType == BACKEND_COREGRAPHICS_ACCELERATED) { - // The bitmap backend uses callac to clear, we can't do that without - // reading back the surface. This should trigger something equivilent - // to glClear. - ClearRect(Rect(0, 0, mSize.width, mSize.height)); - } - - return true; -} - -void -DrawTargetCG::Flush() -{ - CGContextFlush(mCg); -} - -bool -DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize) -{ - // XXX: we should come up with some consistent semantics for dealing - // with zero area drawtargets - if (aSize.width == 0 || aSize.height == 0) { - mColorSpace = nullptr; - mCg = nullptr; - mData = nullptr; - return false; - } - - //XXX: handle SurfaceFormat - - //XXX: we'd be better off reusing the Colorspace across draw targets - mColorSpace = CGColorSpaceCreateDeviceRGB(); - - mSize = aSize; - - mCg = cgContext; - - mData = nullptr; - - assert(mCg); - // CGContext's default to have the origin at the bottom left - // so flip it to the top left - CGContextTranslateCTM(mCg, 0, mSize.height); - CGContextScaleCTM(mCg, 1, -1); - - //XXX: set correct format - mFormat = FORMAT_B8G8R8A8; - - return true; -} - -bool -DrawTargetCG::Init(BackendType aType, const IntSize &aSize, SurfaceFormat &aFormat) -{ - int stride = aSize.width*4; - - // Calling Init with aData == nullptr will allocate. - return Init(aType, nullptr, aSize, stride, aFormat); -} - -TemporaryRef -DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const -{ - RefPtr pb = new PathBuilderCG(aFillRule); - return pb; -} - -void* -DrawTargetCG::GetNativeSurface(NativeSurfaceType aType) -{ - if ((aType == NATIVE_SURFACE_CGCONTEXT && GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) || - (aType == NATIVE_SURFACE_CGCONTEXT_ACCELERATED && GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE)) { - return mCg; - } else { - return nullptr; - } -} - -void -DrawTargetCG::Mask(const Pattern &aSource, - const Pattern &aMask, - const DrawOptions &aDrawOptions) -{ - MarkChanged(); - - CGContextSaveGState(mCg); - - if (isGradient(aMask)) { - assert(0); - } else { - if (aMask.GetType() == PATTERN_COLOR) { - DrawOptions drawOptions(aDrawOptions); - const Color& color = static_cast(aMask).mColor; - drawOptions.mAlpha *= color.a; - assert(0); - // XXX: we need to get a rect that when transformed covers the entire surface - //Rect - //FillRect(rect, aSource, drawOptions); - } else if (aMask.GetType() == PATTERN_SURFACE) { - const SurfacePattern& pat = static_cast(aMask); - CGImageRef mask = GetImageFromSourceSurface(pat.mSurface.get()); - Rect rect(0,0, CGImageGetWidth(mask), CGImageGetHeight(mask)); - // XXX: probably we need to do some flipping of the image or something - CGContextClipToMask(mCg, RectToCGRect(rect), mask); - FillRect(rect, aSource, aDrawOptions); - } - } - - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::PushClipRect(const Rect &aRect) -{ - CGContextSaveGState(mCg); - - /* We go through a bit of trouble to temporarilly set the transform - * while we add the path */ - CGAffineTransform previousTransform = CGContextGetCTM(mCg); - CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); - CGContextClipToRect(mCg, RectToCGRect(aRect)); - CGContextSetCTM(mCg, previousTransform); -} - - -void -DrawTargetCG::PushClip(const Path *aPath) -{ - CGContextSaveGState(mCg); - - CGContextBeginPath(mCg); - assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS); - - const PathCG *cgPath = static_cast(aPath); - - // Weirdly, CoreGraphics clips empty paths as all shown - // but emtpy rects as all clipped. We detect this situation and - // workaround it appropriately - if (CGPathIsEmpty(cgPath->GetPath())) { - // XXX: should we return here? - CGContextClipToRect(mCg, CGRectZero); - } - - - /* We go through a bit of trouble to temporarilly set the transform - * while we add the path. XXX: this could be improved if we keep - * the CTM as resident state on the DrawTarget. */ - CGContextSaveGState(mCg); - CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform)); - CGContextAddPath(mCg, cgPath->GetPath()); - CGContextRestoreGState(mCg); - - if (cgPath->GetFillRule() == FILL_EVEN_ODD) - CGContextEOClip(mCg); - else - CGContextClip(mCg); -} - -void -DrawTargetCG::PopClip() -{ - CGContextRestoreGState(mCg); -} - -void -DrawTargetCG::MarkChanged() -{ - if (mSnapshot) { - if (mSnapshot->refCount() > 1) { - // We only need to worry about snapshots that someone else knows about - mSnapshot->DrawTargetWillChange(); - } - mSnapshot = nullptr; - } -} - - - -} -} diff --git a/libazure/src/gfx/2d/DrawTargetCairo.cpp b/libazure/src/gfx/2d/DrawTargetCairo.cpp deleted file mode 100644 index fd3c502..0000000 --- a/libazure/src/gfx/2d/DrawTargetCairo.cpp +++ /dev/null @@ -1,951 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DrawTargetCairo.h" - -#include "SourceSurfaceCairo.h" -#include "PathCairo.h" -#include "HelpersCairo.h" -#include "ScaledFontBase.h" - -#include "cairo.h" -#include "cairo-tee.h" -#include - -#include "Blur.h" -#include "Logging.h" -#include "Tools.h" - -#ifdef CAIRO_HAS_QUARTZ_SURFACE -#include "cairo-quartz.h" -#include -#endif - -#ifdef CAIRO_HAS_XLIB_SURFACE -#include "cairo-xlib.h" -#endif - -#include - -namespace mozilla { -namespace gfx { - -namespace { - -// An RAII class to prepare to draw a context and optional path. Saves and -// restores the context on construction/destruction. -class AutoPrepareForDrawing -{ -public: - AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx) - : mCtx(ctx) - { - dt->PrepareForDrawing(ctx); - cairo_save(mCtx); - MOZ_ASSERT(cairo_status(mCtx) || dt->GetTransform() == GetTransform()); - } - - AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx, const Path* path) - : mCtx(ctx) - { - dt->PrepareForDrawing(ctx, path); - cairo_save(mCtx); - MOZ_ASSERT(cairo_status(mCtx) || dt->GetTransform() == GetTransform()); - } - - ~AutoPrepareForDrawing() { cairo_restore(mCtx); } - -private: -#ifdef DEBUG - Matrix GetTransform() - { - cairo_matrix_t mat; - cairo_get_matrix(mCtx, &mat); - return Matrix(mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0); - } -#endif - - cairo_t* mCtx; -}; - -} // end anonymous namespace - -static bool -GetCairoSurfaceSize(cairo_surface_t* surface, IntSize& size) -{ - switch (cairo_surface_get_type(surface)) - { - case CAIRO_SURFACE_TYPE_IMAGE: - { - size.width = cairo_image_surface_get_width(surface); - size.height = cairo_image_surface_get_height(surface); - return true; - } - -#ifdef CAIRO_HAS_XLIB_SURFACE - case CAIRO_SURFACE_TYPE_XLIB: - { - size.width = cairo_xlib_surface_get_width(surface); - size.height = cairo_xlib_surface_get_height(surface); - return true; - } -#endif - -#ifdef CAIRO_HAS_QUARTZ_SURFACE - case CAIRO_SURFACE_TYPE_QUARTZ: - { - CGContextRef cgc = cairo_quartz_surface_get_cg_context(surface); - - // It's valid to call these CGBitmapContext functions on non-bitmap - // contexts; they'll just return 0 in that case. - size.width = CGBitmapContextGetWidth(cgc); - size.height = CGBitmapContextGetWidth(cgc); - return true; - } -#endif - - default: - return false; - } -} - -static bool -PatternIsCompatible(const Pattern& aPattern) -{ - switch (aPattern.GetType()) - { - case PATTERN_LINEAR_GRADIENT: - { - const LinearGradientPattern& pattern = static_cast(aPattern); - return pattern.mStops->GetBackendType() == BACKEND_CAIRO; - } - case PATTERN_RADIAL_GRADIENT: - { - const RadialGradientPattern& pattern = static_cast(aPattern); - return pattern.mStops->GetBackendType() == BACKEND_CAIRO; - } - default: - return true; - } -} - -static cairo_user_data_key_t surfaceDataKey; - -void -ReleaseData(void* aData) -{ - static_cast(aData)->Release(); -} - -/** - * Returns cairo surface for the given SourceSurface. - * If possible, it will use the cairo_surface associated with aSurface, - * otherwise, it will create a new cairo_surface. - * In either case, the caller must call cairo_surface_destroy on the - * result when it is done with it. - */ -cairo_surface_t* -GetCairoSurfaceForSourceSurface(SourceSurface *aSurface) -{ - if (aSurface->GetType() == SURFACE_CAIRO) { - cairo_surface_t* surf = static_cast(aSurface)->GetSurface(); - cairo_surface_reference(surf); - return surf; - } - - if (aSurface->GetType() == SURFACE_CAIRO_IMAGE) { - cairo_surface_t* surf = - static_cast(aSurface)->GetSurface(); - cairo_surface_reference(surf); - return surf; - } - - RefPtr data = aSurface->GetDataSurface(); - if (!data) { - return nullptr; - } - - cairo_surface_t* surf = - cairo_image_surface_create_for_data(data->GetData(), - GfxFormatToCairoFormat(data->GetFormat()), - data->GetSize().width, - data->GetSize().height, - data->Stride()); - - // In certain scenarios, requesting larger than 8k image fails. Bug 803568 - // covers the details of how to run into it, but the full detailed - // investigation hasn't been done to determine the underlying cause. We - // will just handle the failure to allocate the surface to avoid a crash. - if (cairo_surface_status(surf)) { - return nullptr; - } - - cairo_surface_set_user_data(surf, - &surfaceDataKey, - data.forget().drop(), - ReleaseData); - return surf; -} - -// Never returns nullptr. As such, you must always pass in Cairo-compatible -// patterns, most notably gradients with a GradientStopCairo. -// The pattern returned must have cairo_pattern_destroy() called on it by the -// caller. -// As the cairo_pattern_t returned may depend on the Pattern passed in, the -// lifetime of the cairo_pattern_t returned must not exceed the lifetime of the -// Pattern passed in. -static cairo_pattern_t* -GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha) -{ - cairo_pattern_t* pat; - - switch (aPattern.GetType()) - { - case PATTERN_COLOR: - { - Color color = static_cast(aPattern).mColor; - pat = cairo_pattern_create_rgba(color.r, color.g, color.b, color.a * aAlpha); - break; - } - - case PATTERN_SURFACE: - { - const SurfacePattern& pattern = static_cast(aPattern); - cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(pattern.mSurface); - - pat = cairo_pattern_create_for_surface(surf); - - // The pattern matrix is a matrix that transforms the pattern into user - // space. Cairo takes a matrix that converts from user space to pattern - // space. Cairo therefore needs the inverse. - - cairo_matrix_t mat; - GfxMatrixToCairoMatrix(pattern.mMatrix, mat); - cairo_matrix_invert(&mat); - cairo_pattern_set_matrix(pat, &mat); - - cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(pattern.mFilter)); - cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(pattern.mExtendMode)); - - cairo_surface_destroy(surf); - - break; - } - case PATTERN_LINEAR_GRADIENT: - { - const LinearGradientPattern& pattern = static_cast(aPattern); - - pat = cairo_pattern_create_linear(pattern.mBegin.x, pattern.mBegin.y, - pattern.mEnd.x, pattern.mEnd.y); - - MOZ_ASSERT(pattern.mStops->GetBackendType() == BACKEND_CAIRO); - GradientStopsCairo* cairoStops = static_cast(pattern.mStops.get()); - cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(cairoStops->GetExtendMode())); - - const std::vector& stops = cairoStops->GetStops(); - for (size_t i = 0; i < stops.size(); ++i) { - const GradientStop& stop = stops[i]; - cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r, - stop.color.g, stop.color.b, - stop.color.a); - } - - break; - } - case PATTERN_RADIAL_GRADIENT: - { - const RadialGradientPattern& pattern = static_cast(aPattern); - - pat = cairo_pattern_create_radial(pattern.mCenter1.x, pattern.mCenter1.y, pattern.mRadius1, - pattern.mCenter2.x, pattern.mCenter2.y, pattern.mRadius2); - - MOZ_ASSERT(pattern.mStops->GetBackendType() == BACKEND_CAIRO); - GradientStopsCairo* cairoStops = static_cast(pattern.mStops.get()); - cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(cairoStops->GetExtendMode())); - - const std::vector& stops = cairoStops->GetStops(); - for (size_t i = 0; i < stops.size(); ++i) { - const GradientStop& stop = stops[i]; - cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r, - stop.color.g, stop.color.b, - stop.color.a); - } - - break; - } - default: - { - // We should support all pattern types! - MOZ_ASSERT(false); - } - } - - return pat; -} - -static bool -NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions) -{ - // We pre-multiply colours' alpha by the global alpha, so we don't need to - // use an intermediate surface for them. - if (aPattern.GetType() == PATTERN_COLOR) - return false; - - if (aOptions.mAlpha == 1.0) - return false; - - return true; -} - -DrawTargetCairo::DrawTargetCairo() - : mContext(nullptr) - , mPathObserver(nullptr) -{ -} - -DrawTargetCairo::~DrawTargetCairo() -{ - MarkSnapshotIndependent(); - if (mPathObserver) { - mPathObserver->ForgetDrawTarget(); - } - cairo_destroy(mContext); - if (mSurface) { - cairo_surface_destroy(mSurface); - } -} - -IntSize -DrawTargetCairo::GetSize() -{ - return mSize; -} - -TemporaryRef -DrawTargetCairo::Snapshot() -{ - if (mSnapshot) { - return mSnapshot; - } - - IntSize size = GetSize(); - - cairo_content_t content = cairo_surface_get_content(mSurface); - mSnapshot = new SourceSurfaceCairo(mSurface, - size, - CairoContentToGfxFormat(content), - this); - return mSnapshot; -} - -void -DrawTargetCairo::Flush() -{ - cairo_surface_t* surf = cairo_get_target(mContext); - cairo_surface_flush(surf); -} - -void -DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = nullptr */) -{ - WillChange(aPath); -} - -void -DrawTargetCairo::DrawSurface(SourceSurface *aSurface, - const Rect &aDest, - const Rect &aSource, - const DrawSurfaceOptions &aSurfOptions, - const DrawOptions &aOptions) -{ - AutoPrepareForDrawing prep(this, mContext); - - float sx = aSource.Width() / aDest.Width(); - float sy = aSource.Height() / aDest.Height(); - - cairo_matrix_t src_mat; - cairo_matrix_init_translate(&src_mat, aSource.X(), aSource.Y()); - cairo_matrix_scale(&src_mat, sx, sy); - - cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface); - cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf); - cairo_surface_destroy(surf); - - cairo_pattern_set_matrix(pat, &src_mat); - cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter)); - cairo_pattern_set_extend(pat, CAIRO_EXTEND_PAD); - - cairo_translate(mContext, aDest.X(), aDest.Y()); - - if (IsOperatorBoundByMask(aOptions.mCompositionOp)) { - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); - cairo_clip(mContext); - cairo_set_source(mContext, pat); - } else { - cairo_push_group(mContext); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height()); - cairo_set_source(mContext, pat); - cairo_fill(mContext); - cairo_pop_group_to_source(mContext); - } - - cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); - - cairo_paint_with_alpha(mContext, aOptions.mAlpha); - - cairo_pattern_destroy(pat); -} - -void -DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface, - const Point &aDest, - const Color &aColor, - const Point &aOffset, - Float aSigma, - CompositionOp aOperator) -{ - if (aSurface->GetType() != SURFACE_CAIRO) { - return; - } - - Float width = Float(aSurface->GetSize().width); - Float height = Float(aSurface->GetSize().height); - - SourceSurfaceCairo* source = static_cast(aSurface); - cairo_surface_t* sourcesurf = source->GetSurface(); - cairo_surface_t* blursurf; - cairo_surface_t* surf; - - // We only use the A8 surface for blurred shadows. Unblurred shadows can just - // use the RGBA surface directly. - if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) { - blursurf = cairo_tee_surface_index(sourcesurf, 0); - surf = cairo_tee_surface_index(sourcesurf, 1); - - MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE); - Rect extents(0, 0, width, height); - AlphaBoxBlur blur(cairo_image_surface_get_data(blursurf), - extents, - cairo_image_surface_get_stride(blursurf), - aSigma); - blur.Blur(); - } else { - blursurf = sourcesurf; - surf = sourcesurf; - } - - WillChange(); - ClearSurfaceForUnboundedSource(aOperator); - - cairo_save(mContext); - cairo_set_operator(mContext, GfxOpToCairoOp(aOperator)); - cairo_identity_matrix(mContext); - cairo_translate(mContext, aDest.x, aDest.y); - - if (IsOperatorBoundByMask(aOperator)){ - cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); - cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); - - // Now that the shadow has been drawn, we can draw the surface on top. - cairo_set_source_surface(mContext, surf, 0, 0); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, width, height); - cairo_fill(mContext); - } else { - cairo_push_group(mContext); - cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a); - cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y); - - // Now that the shadow has been drawn, we can draw the surface on top. - cairo_set_source_surface(mContext, surf, 0, 0); - cairo_new_path(mContext); - cairo_rectangle(mContext, 0, 0, width, height); - cairo_fill(mContext); - cairo_pop_group_to_source(mContext); - cairo_paint(mContext); - } - - cairo_restore(mContext); -} - -void -DrawTargetCairo::DrawPattern(const Pattern& aPattern, - const StrokeOptions& aStrokeOptions, - const DrawOptions& aOptions, - DrawPatternType aDrawType) -{ - if (!PatternIsCompatible(aPattern)) { - return; - } - - cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha); - cairo_set_source(mContext, pat); - - if (NeedIntermediateSurface(aPattern, aOptions) || - !IsOperatorBoundByMask(aOptions.mCompositionOp)) { - cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA); - - ClearSurfaceForUnboundedSource(aOptions.mCompositionOp); - - // Don't want operators to be applied twice - cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); - - if (aDrawType == DRAW_STROKE) { - SetCairoStrokeOptions(mContext, aStrokeOptions); - cairo_stroke_preserve(mContext); - } else { - cairo_fill_preserve(mContext); - } - - cairo_pop_group_to_source(mContext); - - // Now draw the content using the desired operator - cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); - cairo_paint_with_alpha(mContext, aOptions.mAlpha); - } else { - ClearSurfaceForUnboundedSource(aOptions.mCompositionOp); - cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); - - if (aDrawType == DRAW_STROKE) { - SetCairoStrokeOptions(mContext, aStrokeOptions); - cairo_stroke_preserve(mContext); - } else { - cairo_fill_preserve(mContext); - } - } - - cairo_pattern_destroy(pat); -} - -void -DrawTargetCairo::FillRect(const Rect &aRect, - const Pattern &aPattern, - const DrawOptions &aOptions) -{ - AutoPrepareForDrawing prep(this, mContext); - - cairo_new_path(mContext); - cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height()); - - DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL); -} - -void -DrawTargetCairo::CopySurface(SourceSurface *aSurface, - const IntRect &aSource, - const IntPoint &aDest) -{ - AutoPrepareForDrawing prep(this, mContext); - - if (!aSurface || aSurface->GetType() != SURFACE_CAIRO) { - gfxWarning() << "Unsupported surface type specified"; - return; - } - - cairo_surface_t* surf = static_cast(aSurface)->GetSurface(); - - cairo_identity_matrix(mContext); - - cairo_set_source_surface(mContext, surf, aDest.x - aSource.x, aDest.y - aSource.y); - cairo_set_operator(mContext, CAIRO_OPERATOR_SOURCE); - - cairo_reset_clip(mContext); - cairo_new_path(mContext); - cairo_rectangle(mContext, aDest.x, aDest.y, aSource.width, aSource.height); - cairo_fill(mContext); -} - -void -DrawTargetCairo::ClearRect(const Rect& aRect) -{ - AutoPrepareForDrawing prep(this, mContext); - - cairo_new_path(mContext); - cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); - cairo_rectangle(mContext, aRect.X(), aRect.Y(), - aRect.Width(), aRect.Height()); - cairo_fill(mContext); -} - -void -DrawTargetCairo::StrokeRect(const Rect &aRect, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, - const DrawOptions &aOptions /* = DrawOptions() */) -{ - AutoPrepareForDrawing prep(this, mContext); - - cairo_new_path(mContext); - cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height()); - - DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); -} - -void -DrawTargetCairo::StrokeLine(const Point &aStart, - const Point &aEnd, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, - const DrawOptions &aOptions /* = DrawOptions() */) -{ - AutoPrepareForDrawing prep(this, mContext); - - cairo_new_path(mContext); - cairo_move_to(mContext, aStart.x, aStart.y); - cairo_line_to(mContext, aEnd.x, aEnd.y); - - DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); -} - -void -DrawTargetCairo::Stroke(const Path *aPath, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions /* = StrokeOptions() */, - const DrawOptions &aOptions /* = DrawOptions() */) -{ - AutoPrepareForDrawing prep(this, mContext, aPath); - - if (aPath->GetBackendType() != BACKEND_CAIRO) - return; - - PathCairo* path = const_cast(static_cast(aPath)); - path->CopyPathTo(mContext, this); - - DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE); -} - -void -DrawTargetCairo::Fill(const Path *aPath, - const Pattern &aPattern, - const DrawOptions &aOptions /* = DrawOptions() */) -{ - AutoPrepareForDrawing prep(this, mContext, aPath); - - if (aPath->GetBackendType() != BACKEND_CAIRO) - return; - - PathCairo* path = const_cast(static_cast(aPath)); - path->CopyPathTo(mContext, this); - - DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL); -} - -void -DrawTargetCairo::FillGlyphs(ScaledFont *aFont, - const GlyphBuffer &aBuffer, - const Pattern &aPattern, - const DrawOptions &aOptions, - const GlyphRenderingOptions*) -{ - AutoPrepareForDrawing prep(this, mContext); - - ScaledFontBase* scaledFont = static_cast(aFont); - cairo_set_scaled_font(mContext, scaledFont->GetCairoScaledFont()); - - cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha); - cairo_set_source(mContext, pat); - cairo_pattern_destroy(pat); - - // Convert our GlyphBuffer into an array of Cairo glyphs. - std::vector glyphs(aBuffer.mNumGlyphs); - for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { - glyphs[i].index = aBuffer.mGlyphs[i].mIndex; - glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; - glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; - } - - cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs); -} - -void -DrawTargetCairo::Mask(const Pattern &aSource, - const Pattern &aMask, - const DrawOptions &aOptions /* = DrawOptions() */) -{ - AutoPrepareForDrawing prep(this, mContext); - - cairo_pattern_t* source = GfxPatternToCairoPattern(aSource, aOptions.mAlpha); - cairo_set_source(mContext, source); - - cairo_pattern_t* mask = GfxPatternToCairoPattern(aMask, aOptions.mAlpha); - cairo_mask(mContext, mask); - - cairo_pattern_destroy(mask); - cairo_pattern_destroy(source); -} - -void -DrawTargetCairo::PushClip(const Path *aPath) -{ - if (aPath->GetBackendType() != BACKEND_CAIRO) { - return; - } - - WillChange(aPath); - cairo_save(mContext); - - PathCairo* path = const_cast(static_cast(aPath)); - path->CopyPathTo(mContext, this); - cairo_clip_preserve(mContext); -} - -void -DrawTargetCairo::PushClipRect(const Rect& aRect) -{ - WillChange(); - cairo_save(mContext); - - cairo_new_path(mContext); - cairo_rectangle(mContext, aRect.X(), aRect.Y(), aRect.Width(), aRect.Height()); - cairo_clip_preserve(mContext); -} - -void -DrawTargetCairo::PopClip() -{ - // save/restore does not affect the path, so no need to call WillChange() - cairo_restore(mContext); -} - -TemporaryRef -DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) const -{ - RefPtr builder = new PathBuilderCairo(mContext, - const_cast(this), - aFillRule); - - return builder; -} - -void -DrawTargetCairo::ClearSurfaceForUnboundedSource(const CompositionOp &aOperator) -{ - if (aOperator != OP_SOURCE) - return; - cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); - // It doesn't really matter what the source is here, since Paint - // isn't bounded by the source and the mask covers the entire clip - // region. - cairo_paint(mContext); -} - - -TemporaryRef -DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, - ExtendMode aExtendMode) const -{ - RefPtr stops = new GradientStopsCairo(aStops, aNumStops, - aExtendMode); - return stops; -} - -/** - * Copies pixel data from aData into aSurface; aData must have the dimensions - * given in aSize, with a stride of aStride bytes and aPixelWidth bytes per pixel - */ -static void -CopyDataToCairoSurface(cairo_surface_t* aSurface, - unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - int32_t aPixelWidth) -{ - unsigned char* surfData = cairo_image_surface_get_data(aSurface); - // In certain scenarios, requesting larger than 8k image fails. Bug 803568 - // covers the details of how to run into it, but the full detailed - // investigation hasn't been done to determine the underlying cause. We - // will just handle the failure to allocate the surface to avoid a crash. - if (!surfData) { - return; - } - for (int32_t y = 0; y < aSize.height; ++y) { - memcpy(surfData + y * aSize.width * aPixelWidth, - aData + y * aStride, - aSize.width * aPixelWidth); - } - cairo_surface_mark_dirty(aSurface); -} - -TemporaryRef -DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) const -{ - cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), - aSize.width, - aSize.height); - // In certain scenarios, requesting larger than 8k image fails. Bug 803568 - // covers the details of how to run into it, but the full detailed - // investigation hasn't been done to determine the underlying cause. We - // will just handle the failure to allocate the surface to avoid a crash. - if (cairo_surface_status(surf)) { - return nullptr; - } - - CopyDataToCairoSurface(surf, aData, aSize, aStride, BytesPerPixel(aFormat)); - - RefPtr source_surf = new SourceSurfaceCairo(surf, aSize, aFormat); - cairo_surface_destroy(surf); - - return source_surf; -} - -TemporaryRef -DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const -{ - return aSurface; -} - -TemporaryRef -DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const -{ - if (aSurface.mType == NATIVE_SURFACE_CAIRO_SURFACE) { - IntSize size; - cairo_surface_t* surf = static_cast(aSurface.mSurface); - if (GetCairoSurfaceSize(surf, size)) { - RefPtr source = - new SourceSurfaceCairo(surf, size, aSurface.mFormat); - return source; - } - } - - return nullptr; -} - -TemporaryRef -DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const -{ - cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext), - GfxFormatToCairoContent(aFormat), - aSize.width, aSize.height); - - if (!cairo_surface_status(similar)) { - RefPtr target = new DrawTargetCairo(); - target->InitAlreadyReferenced(similar, aSize); - return target; - } - - return nullptr; -} - -bool -DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize) -{ - mContext = cairo_create(aSurface); - mSurface = aSurface; - mSize = aSize; - mFormat = CairoContentToGfxFormat(cairo_surface_get_content(aSurface)); - - return true; -} - -TemporaryRef -DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat, - float aSigma) const -{ - cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext), - GfxFormatToCairoContent(aFormat), - aSize.width, aSize.height); - - if (cairo_surface_status(similar)) { - return nullptr; - } - - // If we don't have a blur then we can use the RGBA mask and keep all the - // operations in graphics memory. - if (aSigma == 0.0F) { - RefPtr target = new DrawTargetCairo(); - target->InitAlreadyReferenced(similar, aSize); - return target; - } - - cairo_surface_t* blursurf = cairo_image_surface_create(CAIRO_FORMAT_A8, - aSize.width, - aSize.height); - - if (cairo_surface_status(blursurf)) { - return nullptr; - } - - cairo_surface_t* tee = cairo_tee_surface_create(blursurf); - cairo_surface_destroy(blursurf); - if (cairo_surface_status(tee)) { - cairo_surface_destroy(similar); - return nullptr; - } - - cairo_tee_surface_add(tee, similar); - cairo_surface_destroy(similar); - - RefPtr target = new DrawTargetCairo(); - target->InitAlreadyReferenced(tee, aSize); - return target; -} - -bool -DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize) -{ - cairo_surface_reference(aSurface); - return InitAlreadyReferenced(aSurface, aSize); -} - -void * -DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType) -{ - if (aType == NATIVE_SURFACE_CAIRO_SURFACE) { - return cairo_get_target(mContext); - } - - return nullptr; -} - -void -DrawTargetCairo::MarkSnapshotIndependent() -{ - if (mSnapshot) { - if (mSnapshot->refCount() > 1) { - // We only need to worry about snapshots that someone else knows about - mSnapshot->DrawTargetWillChange(); - } - mSnapshot = nullptr; - } -} - -void -DrawTargetCairo::WillChange(const Path* aPath /* = nullptr */) -{ - MarkSnapshotIndependent(); - - if (mPathObserver && - (!aPath || !mPathObserver->ContainsPath(aPath))) { - mPathObserver->PathWillChange(); - mPathObserver = nullptr; - } -} - -void -DrawTargetCairo::SetPathObserver(CairoPathContext* aPathObserver) -{ - if (mPathObserver && mPathObserver != aPathObserver) { - mPathObserver->PathWillChange(); - } - mPathObserver = aPathObserver; -} - -void -DrawTargetCairo::SetTransform(const Matrix& aTransform) -{ - mTransform = aTransform; - - cairo_matrix_t mat; - GfxMatrixToCairoMatrix(mTransform, mat); - cairo_set_matrix(mContext, &mat); -} - -} -} diff --git a/libazure/src/gfx/2d/DrawTargetSkia.cpp b/libazure/src/gfx/2d/DrawTargetSkia.cpp deleted file mode 100644 index 1a81a33..0000000 --- a/libazure/src/gfx/2d/DrawTargetSkia.cpp +++ /dev/null @@ -1,745 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DrawTargetSkia.h" -#include "SourceSurfaceSkia.h" -#include "ScaledFontBase.h" -#include "SkDevice.h" - -#ifdef USE_SKIA_GPU -#include "SkGpuDevice.h" -#endif - -#include "SkTypeface.h" -#include "SkGradientShader.h" -#include "SkBlurDrawLooper.h" -#include "SkBlurMaskFilter.h" -#include "SkColorFilter.h" -#include "SkLayerRasterizer.h" -#include "SkLayerDrawLooper.h" -#include "SkDashPathEffect.h" -#include "Logging.h" -#include "HelpersSkia.h" -#include "Tools.h" -#include - -#ifdef ANDROID -# define USE_SOFT_CLIPPING false -#else -# define USE_SOFT_CLIPPING true -#endif - -namespace mozilla { -namespace gfx { - -class GradientStopsSkia : public GradientStops -{ -public: - GradientStopsSkia(const std::vector& aStops, uint32_t aNumStops, ExtendMode aExtendMode) - : mCount(aNumStops) - , mExtendMode(aExtendMode) - { - if (mCount == 0) { - return; - } - - // Skia gradients always require a stop at 0.0 and 1.0, insert these if - // we don't have them. - uint32_t shift = 0; - if (aStops[0].offset != 0) { - mCount++; - shift = 1; - } - if (aStops[aNumStops-1].offset != 1) { - mCount++; - } - mColors.resize(mCount); - mPositions.resize(mCount); - if (aStops[0].offset != 0) { - mColors[0] = ColorToSkColor(aStops[0].color, 1.0); - mPositions[0] = 0; - } - for (uint32_t i = 0; i < aNumStops; i++) { - mColors[i + shift] = ColorToSkColor(aStops[i].color, 1.0); - mPositions[i + shift] = SkFloatToScalar(aStops[i].offset); - } - if (aStops[aNumStops-1].offset != 1) { - mColors[mCount-1] = ColorToSkColor(aStops[aNumStops-1].color, 1.0); - mPositions[mCount-1] = SK_Scalar1; - } - } - - BackendType GetBackendType() const { return BACKEND_SKIA; } - - std::vector mColors; - std::vector mPositions; - int mCount; - ExtendMode mExtendMode; -}; - -DrawTargetSkia::DrawTargetSkia() -{ -} - -DrawTargetSkia::~DrawTargetSkia() -{ - if (mSnapshots.size()) { - for (std::vector::iterator iter = mSnapshots.begin(); - iter != mSnapshots.end(); iter++) { - (*iter)->DrawTargetDestroyed(); - } - // All snapshots will now have copied data. - mSnapshots.clear(); - } -} - -TemporaryRef -DrawTargetSkia::Snapshot() -{ - RefPtr source = new SourceSurfaceSkia(); - if (!source->InitWithBitmap(mBitmap, mFormat, this)) { - return nullptr; - } - AppendSnapshot(source); - return source; -} - -void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0) -{ - switch (aPattern.GetType()) { - case PATTERN_COLOR: { - Color color = static_cast(aPattern).mColor; - aPaint.setColor(ColorToSkColor(color, aAlpha)); - break; - } - case PATTERN_LINEAR_GRADIENT: { - const LinearGradientPattern& pat = static_cast(aPattern); - GradientStopsSkia *stops = static_cast(pat.mStops.get()); - SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); - - if (stops->mCount >= 2) { - SkPoint points[2]; - points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y)); - points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y)); - - SkShader* shader = SkGradientShader::CreateLinear(points, - &stops->mColors.front(), - &stops->mPositions.front(), - stops->mCount, - mode); - - if (shader) { - SkMatrix mat; - GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); - } - - } else { - aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); - } - break; - } - case PATTERN_RADIAL_GRADIENT: { - const RadialGradientPattern& pat = static_cast(aPattern); - GradientStopsSkia *stops = static_cast(pat.mStops.get()); - SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); - - if (stops->mCount >= 2) { - SkPoint points[2]; - points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y)); - points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y)); - - SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0], - SkFloatToScalar(pat.mRadius1), - points[1], - SkFloatToScalar(pat.mRadius2), - &stops->mColors.front(), - &stops->mPositions.front(), - stops->mCount, - mode); - if (shader) { - SkMatrix mat; - GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); - } - - } else { - aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); - } - break; - } - case PATTERN_SURFACE: { - const SurfacePattern& pat = static_cast(aPattern); - const SkBitmap& bitmap = static_cast(pat.mSurface.get())->GetBitmap(); - - SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode); - SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode); - SkMatrix mat; - GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); - if (pat.mFilter == FILTER_POINT) { - aPaint.setFilterBitmap(false); - } - break; - } - } -} - -struct AutoPaintSetup { - AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern) - : mNeedsRestore(false), mAlpha(1.0) - { - Init(aCanvas, aOptions); - SetPaintPattern(mPaint, aPattern, mAlpha); - } - - AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions) - : mNeedsRestore(false), mAlpha(1.0) - { - Init(aCanvas, aOptions); - } - - ~AutoPaintSetup() - { - if (mNeedsRestore) { - mCanvas->restore(); - } - } - - void Init(SkCanvas *aCanvas, const DrawOptions& aOptions) - { - mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); - mCanvas = aCanvas; - - //TODO: Can we set greyscale somehow? - if (aOptions.mAntialiasMode != AA_NONE) { - mPaint.setAntiAlias(true); - } else { - mPaint.setAntiAlias(false); - } - - MOZ_ASSERT(aOptions.mSnapping == SNAP_NONE, "Pixel snapping not supported yet!"); - - // TODO: We could skip the temporary for operator_source and just - // clear the clip rect. The other operators would be harder - // but could be worth it to skip pushing a group. - if (!IsOperatorBoundByMask(aOptions.mCompositionOp)) { - mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - SkPaint temp; - temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); - temp.setAlpha(U8CPU(aOptions.mAlpha*255)); - //TODO: Get a rect here - mCanvas->saveLayer(nullptr, &temp); - mNeedsRestore = true; - } else { - mPaint.setAlpha(U8CPU(aOptions.mAlpha*255.0)); - mAlpha = aOptions.mAlpha; - } - mPaint.setFilterBitmap(true); - } - - // TODO: Maybe add an operator overload to access this easier? - SkPaint mPaint; - bool mNeedsRestore; - SkCanvas* mCanvas; - Float mAlpha; -}; - -void -DrawTargetSkia::Flush() -{ - mCanvas->flush(); -} - -void -DrawTargetSkia::DrawSurface(SourceSurface *aSurface, - const Rect &aDest, - const Rect &aSource, - const DrawSurfaceOptions &aSurfOptions, - const DrawOptions &aOptions) -{ - if (aSurface->GetType() != SURFACE_SKIA) { - return; - } - - if (aSource.IsEmpty()) { - return; - } - - MarkChanged(); - - SkRect destRect = RectToSkRect(aDest); - SkRect sourceRect = RectToSkRect(aSource); - - SkMatrix matrix; - matrix.setRectToRect(sourceRect, destRect, SkMatrix::kFill_ScaleToFit); - - const SkBitmap& bitmap = static_cast(aSurface)->GetBitmap(); - - AutoPaintSetup paint(mCanvas.get(), aOptions); - SkShader *shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - shader->setLocalMatrix(matrix); - SkSafeUnref(paint.mPaint.setShader(shader)); - if (aSurfOptions.mFilter != FILTER_LINEAR) { - paint.mPaint.setFilterBitmap(false); - } - mCanvas->drawRect(destRect, paint.mPaint); -} - -void -DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface, - const Point &aDest, - const Color &aColor, - const Point &aOffset, - Float aSigma, - CompositionOp aOperator) -{ - MarkChanged(); - mCanvas->save(SkCanvas::kMatrix_SaveFlag); - mCanvas->resetMatrix(); - - uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag | - SkBlurMaskFilter::kIgnoreTransform_BlurFlag; - const SkBitmap& bitmap = static_cast(aSurface)->GetBitmap(); - SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - SkMatrix matrix; - matrix.reset(); - matrix.setTranslateX(SkFloatToScalar(aDest.x)); - matrix.setTranslateY(SkFloatToScalar(aDest.y)); - shader->setLocalMatrix(matrix); - SkLayerDrawLooper* dl = new SkLayerDrawLooper; - SkLayerDrawLooper::LayerInfo info; - info.fPaintBits |= SkLayerDrawLooper::kShader_Bit; - SkPaint *layerPaint = dl->addLayer(info); - layerPaint->setShader(shader); - - info.fPaintBits = 0; - info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; - info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; - info.fColorMode = SkXfermode::kDst_Mode; - info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); - info.fPostTranslate = true; - - SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags); - SkColor color = ColorToSkColor(aColor, 1); - SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode); - - - layerPaint = dl->addLayer(info); - SkSafeUnref(layerPaint->setMaskFilter(mf)); - SkSafeUnref(layerPaint->setColorFilter(cf)); - layerPaint->setColor(color); - - // TODO: This is using the rasterizer to calculate an alpha mask - // on both the shadow and normal layers. We should fix this - // properly so it only happens for the shadow layer - SkLayerRasterizer *raster = new SkLayerRasterizer(); - SkPaint maskPaint; - SkSafeUnref(maskPaint.setShader(shader)); - raster->addLayer(maskPaint, 0, 0); - - SkPaint paint; - paint.setAntiAlias(true); - SkSafeUnref(paint.setRasterizer(raster)); - paint.setXfermodeMode(GfxOpToSkiaOp(aOperator)); - SkSafeUnref(paint.setLooper(dl)); - - SkRect rect = RectToSkRect(Rect(Float(aDest.x), Float(aDest.y), - Float(bitmap.width()), Float(bitmap.height()))); - mCanvas->drawRect(rect, paint); - mCanvas->restore(); -} - -void -DrawTargetSkia::FillRect(const Rect &aRect, - const Pattern &aPattern, - const DrawOptions &aOptions) -{ - MarkChanged(); - SkRect rect = RectToSkRect(aRect); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - - mCanvas->drawRect(rect, paint.mPaint); -} - -void -DrawTargetSkia::Stroke(const Path *aPath, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions, - const DrawOptions &aOptions) -{ - MarkChanged(); - MOZ_ASSERT(aPath, "Null path"); - if (aPath->GetBackendType() != BACKEND_SKIA) { - return; - } - - const PathSkia *skiaPath = static_cast(aPath); - - - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { - return; - } - - mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); -} - -void -DrawTargetSkia::StrokeRect(const Rect &aRect, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions, - const DrawOptions &aOptions) -{ - MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { - return; - } - - mCanvas->drawRect(RectToSkRect(aRect), paint.mPaint); -} - -void -DrawTargetSkia::StrokeLine(const Point &aStart, - const Point &aEnd, - const Pattern &aPattern, - const StrokeOptions &aStrokeOptions, - const DrawOptions &aOptions) -{ - MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { - return; - } - - mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y), - SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y), - paint.mPaint); -} - -void -DrawTargetSkia::Fill(const Path *aPath, - const Pattern &aPattern, - const DrawOptions &aOptions) -{ - MarkChanged(); - if (aPath->GetBackendType() != BACKEND_SKIA) { - return; - } - - const PathSkia *skiaPath = static_cast(aPath); - - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - - mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); -} - -void -DrawTargetSkia::FillGlyphs(ScaledFont *aFont, - const GlyphBuffer &aBuffer, - const Pattern &aPattern, - const DrawOptions &aOptions, - const GlyphRenderingOptions*) -{ - if (aFont->GetType() != FONT_MAC && - aFont->GetType() != FONT_SKIA && - aFont->GetType() != FONT_GDI) { - return; - } - - MarkChanged(); - - ScaledFontBase* skiaFont = static_cast(aFont); - - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - paint.mPaint.setTypeface(skiaFont->GetSkTypeface()); - paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize)); - paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - paint.mPaint.setSubpixelText(true); - - std::vector indices; - std::vector offsets; - indices.resize(aBuffer.mNumGlyphs); - offsets.resize(aBuffer.mNumGlyphs); - - for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { - indices[i] = aBuffer.mGlyphs[i].mIndex; - offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x); - offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y); - } - - mCanvas->drawPosText(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), paint.mPaint); -} - -void -DrawTargetSkia::Mask(const Pattern &aSource, - const Pattern &aMask, - const DrawOptions &aOptions) -{ - MarkChanged(); - AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); - - SkPaint maskPaint; - SetPaintPattern(maskPaint, aMask); - - SkLayerRasterizer *raster = new SkLayerRasterizer(); - raster->addLayer(maskPaint); - SkSafeUnref(paint.mPaint.setRasterizer(raster)); - - // Skia only uses the mask rasterizer when we are drawing a path/rect. - // Take our destination bounds and convert them into user space to use - // as the path to draw. - SkPath path; - path.addRect(SkRect::MakeWH(SkScalar(mSize.width), SkScalar(mSize.height))); - - Matrix temp = mTransform; - temp.Invert(); - SkMatrix mat; - GfxMatrixToSkiaMatrix(temp, mat); - path.transform(mat); - - mCanvas->drawPath(path, paint.mPaint); -} - -TemporaryRef -DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) const -{ - RefPtr newSurf = new SourceSurfaceSkia(); - - if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { - gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize; - return nullptr; - } - - return newSurf; -} - -TemporaryRef -DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const -{ - RefPtr target = new DrawTargetSkia(); - if (!target->Init(aSize, aFormat)) { - return nullptr; - } - return target; -} - -TemporaryRef -DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const -{ - return nullptr; -} - -TemporaryRef -DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const -{ - return nullptr; -} - -void -DrawTargetSkia::CopySurface(SourceSurface *aSurface, - const IntRect& aSourceRect, - const IntPoint &aDestination) -{ - //TODO: We could just use writePixels() here if the sourceRect is the entire source - - if (aSurface->GetType() != SURFACE_SKIA) { - return; - } - - MarkChanged(); - - const SkBitmap& bitmap = static_cast(aSurface)->GetBitmap(); - - mCanvas->save(); - mCanvas->resetMatrix(); - SkRect dest = IntRectToSkRect(IntRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height)); - SkIRect source = IntRectToSkIRect(aSourceRect); - mCanvas->clipRect(dest, SkRegion::kReplace_Op); - SkPaint paint; - - if (mBitmap.config() == SkBitmap::kRGB_565_Config && - mCanvas->getDevice()->config() == SkBitmap::kRGB_565_Config) { - // Set the xfermode to SOURCE_OVER to workaround - // http://code.google.com/p/skia/issues/detail?id=628 - // RGB565 is opaque so they're equivalent anyway - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - } else { - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - } - - mCanvas->drawBitmapRect(bitmap, &source, dest, &paint); - mCanvas->restore(); -} - -bool -DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) -{ - mBitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height); - if (!mBitmap.allocPixels()) { - return false; - } - mBitmap.eraseARGB(0, 0, 0, 0); - SkAutoTUnref device(new SkDevice(mBitmap)); - SkAutoTUnref canvas(new SkCanvas(device.get())); - mSize = aSize; - - mDevice = device.get(); - mCanvas = canvas.get(); - mFormat = aFormat; - return true; -} - -#ifdef USE_SKIA_GPU -void -DrawTargetSkia::InitWithFBO(unsigned int aFBOID, GrContext* aGrContext, const IntSize &aSize, SurfaceFormat aFormat) -{ - GrBackendRenderTargetDesc targetDescriptor; - - targetDescriptor.fWidth = aSize.width; - targetDescriptor.fHeight = aSize.height; - targetDescriptor.fConfig = GfxFormatToGrConfig(aFormat); - targetDescriptor.fSampleCnt = 0; - targetDescriptor.fRenderTargetHandle = aFBOID; - - SkAutoTUnref target(aGrContext->wrapBackendRenderTarget(targetDescriptor)); - - SkAutoTUnref device(new SkGpuDevice(aGrContext, target.get())); - SkAutoTUnref canvas(new SkCanvas(device.get())); - mSize = aSize; - - mDevice = device.get(); - mCanvas = canvas.get(); - mFormat = aFormat; -} -#endif - -void -DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) -{ - if (aFormat == FORMAT_B8G8R8X8) { - // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX - ConvertBGRXToBGRA(aData, aSize, aStride); - mBitmap.setIsOpaque(true); - } - - mBitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride); - mBitmap.setPixels(aData); - - SkAutoTUnref device(new SkDevice(mBitmap)); - SkAutoTUnref canvas(new SkCanvas(device.get())); - mSize = aSize; - - mDevice = device.get(); - mCanvas = canvas.get(); - mFormat = aFormat; -} - -void -DrawTargetSkia::SetTransform(const Matrix& aTransform) -{ - SkMatrix mat; - GfxMatrixToSkiaMatrix(aTransform, mat); - mCanvas->setMatrix(mat); - mTransform = aTransform; -} - -TemporaryRef -DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const -{ - RefPtr pb = new PathBuilderSkia(aFillRule); - return pb; -} - -void -DrawTargetSkia::ClearRect(const Rect &aRect) -{ - MarkChanged(); - SkPaint paint; - mCanvas->save(); - mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); - paint.setColor(SkColorSetARGB(0, 0, 0, 0)); - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - mCanvas->drawPaint(paint); - mCanvas->restore(); -} - -void -DrawTargetSkia::PushClip(const Path *aPath) -{ - if (aPath->GetBackendType() != BACKEND_SKIA) { - return; - } - - const PathSkia *skiaPath = static_cast(aPath); - mCanvas->save(SkCanvas::kClip_SaveFlag); - mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); -} - -void -DrawTargetSkia::PushClipRect(const Rect& aRect) -{ - SkRect rect = RectToSkRect(aRect); - - mCanvas->save(SkCanvas::kClip_SaveFlag); - mCanvas->clipRect(rect, SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); -} - -void -DrawTargetSkia::PopClip() -{ - mCanvas->restore(); -} - -TemporaryRef -DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const -{ - std::vector stops; - stops.resize(aNumStops); - for (uint32_t i = 0; i < aNumStops; i++) { - stops[i] = aStops[i]; - } - std::stable_sort(stops.begin(), stops.end()); - - return new GradientStopsSkia(stops, aNumStops, aExtendMode); -} - -void -DrawTargetSkia::AppendSnapshot(SourceSurfaceSkia* aSnapshot) -{ - mSnapshots.push_back(aSnapshot); -} - -void -DrawTargetSkia::RemoveSnapshot(SourceSurfaceSkia* aSnapshot) -{ - std::vector::iterator iter = std::find(mSnapshots.begin(), mSnapshots.end(), aSnapshot); - if (iter != mSnapshots.end()) { - mSnapshots.erase(iter); - } -} - -void -DrawTargetSkia::MarkChanged() -{ - if (mSnapshots.size()) { - for (std::vector::iterator iter = mSnapshots.begin(); - iter != mSnapshots.end(); iter++) { - (*iter)->DrawTargetWillChange(); - } - // All snapshots will now have copied data. - mSnapshots.clear(); - } -} - -} -} diff --git a/libazure/src/gfx/2d/HelpersD2D.h b/libazure/src/gfx/2d/HelpersD2D.h deleted file mode 100644 index 1e84336..0000000 --- a/libazure/src/gfx/2d/HelpersD2D.h +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_HELPERSD2D_H_ -#define MOZILLA_GFX_HELPERSD2D_H_ - -#include "moz-d2d1-1.h" - -#include -#include "2D.h" - -#include "ScaledFontDWrite.h" - -namespace mozilla { -namespace gfx { - -static inline D2D1_POINT_2F D2DPoint(const Point &aPoint) -{ - return D2D1::Point2F(aPoint.x, aPoint.y); -} - -static inline D2D1_SIZE_U D2DIntSize(const IntSize &aSize) -{ - return D2D1::SizeU(aSize.width, aSize.height); -} - -static inline D2D1_RECT_F D2DRect(const Rect &aRect) -{ - return D2D1::RectF(aRect.x, aRect.y, aRect.XMost(), aRect.YMost()); -} - -static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode) -{ - D2D1_EXTEND_MODE extend; - switch (aExtendMode) { - case EXTEND_REPEAT: - extend = D2D1_EXTEND_MODE_WRAP; - break; - case EXTEND_REFLECT: - extend = D2D1_EXTEND_MODE_MIRROR; - break; - default: - extend = D2D1_EXTEND_MODE_CLAMP; - } - - return extend; -} - -static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter) -{ - switch (aFilter) { - case FILTER_POINT: - return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; - default: - return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR; - } -} - -static inline D2D1_ANTIALIAS_MODE D2DAAMode(AntialiasMode aMode) -{ - switch (aMode) { - case AA_NONE: - return D2D1_ANTIALIAS_MODE_ALIASED; - default: - return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; - } -} - -static inline D2D1_MATRIX_3X2_F D2DMatrix(const Matrix &aTransform) -{ - return D2D1::Matrix3x2F(aTransform._11, aTransform._12, - aTransform._21, aTransform._22, - aTransform._31, aTransform._32); -} - -static inline D2D1_COLOR_F D2DColor(const Color &aColor) -{ - return D2D1::ColorF(aColor.r, aColor.g, aColor.b, aColor.a); -} - -static inline IntSize ToIntSize(const D2D1_SIZE_U &aSize) -{ - return IntSize(aSize.width, aSize.height); -} - -static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat) -{ - switch(aFormat.format) { - case DXGI_FORMAT_A8_UNORM: - return FORMAT_A8; - case DXGI_FORMAT_B8G8R8A8_UNORM: - if (aFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE) { - return FORMAT_B8G8R8X8; - } else { - return FORMAT_B8G8R8A8; - } - default: - return FORMAT_B8G8R8A8; - } -} - -static inline Rect ToRect(const D2D1_RECT_F &aRect) -{ - return Rect(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top); -} - -static inline DXGI_FORMAT DXGIFormat(SurfaceFormat aFormat) -{ - switch (aFormat) { - case FORMAT_B8G8R8A8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case FORMAT_B8G8R8X8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case FORMAT_A8: - return DXGI_FORMAT_A8_UNORM; - default: - return DXGI_FORMAT_UNKNOWN; - } -} - -static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) -{ - switch (aFormat) { - case FORMAT_B8G8R8X8: - return D2D1_ALPHA_MODE_IGNORE; - default: - return D2D1_ALPHA_MODE_PREMULTIPLIED; - } -} - -static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat) -{ - return D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat)); -} - -static inline bool IsPatternSupportedByD2D(const Pattern &aPattern) -{ - if (aPattern.GetType() != PATTERN_RADIAL_GRADIENT) { - return true; - } - - const RadialGradientPattern *pat = - static_cast(&aPattern); - - if (pat->mRadius1 != 0) { - return false; - } - - Point diff = pat->mCenter2 - pat->mCenter1; - - if (sqrt(diff.x * diff.x + diff.y * diff.y) >= pat->mRadius2) { - // Inner point lies outside the circle. - return false; - } - - return true; -} - -/** - * This structure is used to pass rectangles to our shader constant. We can use - * this for passing rectangular areas to SetVertexShaderConstant. In the format - * of a 4 component float(x,y,width,height). Our vertex shader can then use - * this to construct rectangular positions from the 0,0-1,1 quad that we source - * it with. - */ -struct ShaderConstantRectD3D10 -{ - float mX, mY, mWidth, mHeight; - ShaderConstantRectD3D10(float aX, float aY, float aWidth, float aHeight) - : mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight) - { } - - // For easy passing to SetVertexShaderConstantF. - operator float* () { return &mX; } -}; - -static inline DWRITE_MATRIX -DWriteMatrixFromMatrix(Matrix &aMatrix) -{ - DWRITE_MATRIX mat; - mat.m11 = aMatrix._11; - mat.m12 = aMatrix._12; - mat.m21 = aMatrix._21; - mat.m22 = aMatrix._22; - mat.dx = aMatrix._31; - mat.dy = aMatrix._32; - return mat; -} - -class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN -{ - static const unsigned kNumAutoGlyphs = 256; - -public: - AutoDWriteGlyphRun() { - glyphCount = 0; - } - - ~AutoDWriteGlyphRun() { - if (glyphCount > kNumAutoGlyphs) { - delete[] glyphIndices; - delete[] glyphAdvances; - delete[] glyphOffsets; - } - } - - void allocate(unsigned aNumGlyphs) { - glyphCount = aNumGlyphs; - if (aNumGlyphs <= kNumAutoGlyphs) { - glyphIndices = &mAutoIndices[0]; - glyphAdvances = &mAutoAdvances[0]; - glyphOffsets = &mAutoOffsets[0]; - } else { - glyphIndices = new UINT16[aNumGlyphs]; - glyphAdvances = new FLOAT[aNumGlyphs]; - glyphOffsets = new DWRITE_GLYPH_OFFSET[aNumGlyphs]; - } - } - -private: - DWRITE_GLYPH_OFFSET mAutoOffsets[kNumAutoGlyphs]; - FLOAT mAutoAdvances[kNumAutoGlyphs]; - UINT16 mAutoIndices[kNumAutoGlyphs]; -}; - -static inline void -DWriteGlyphRunFromGlyphs(const GlyphBuffer &aGlyphs, ScaledFontDWrite *aFont, AutoDWriteGlyphRun *run) -{ - run->allocate(aGlyphs.mNumGlyphs); - - FLOAT *advances = const_cast(run->glyphAdvances); - UINT16 *indices = const_cast(run->glyphIndices); - DWRITE_GLYPH_OFFSET *offsets = const_cast(run->glyphOffsets); - - memset(advances, 0, sizeof(FLOAT) * aGlyphs.mNumGlyphs); - for (unsigned int i = 0; i < aGlyphs.mNumGlyphs; i++) { - indices[i] = aGlyphs.mGlyphs[i].mIndex; - offsets[i].advanceOffset = aGlyphs.mGlyphs[i].mPosition.x; - offsets[i].ascenderOffset = -aGlyphs.mGlyphs[i].mPosition.y; - } - - run->bidiLevel = 0; - run->fontFace = aFont->mFontFace; - run->fontEmSize = aFont->GetSize(); - run->glyphCount = aGlyphs.mNumGlyphs; - run->isSideways = FALSE; -} - -} -} - -#endif /* MOZILLA_GFX_HELPERSD2D_H_ */ diff --git a/libazure/src/gfx/2d/HelpersSkia.h b/libazure/src/gfx/2d/HelpersSkia.h deleted file mode 100644 index 1d8c2d9..0000000 --- a/libazure/src/gfx/2d/HelpersSkia.h +++ /dev/null @@ -1,269 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_HELPERSSKIA_H_ -#define MOZILLA_GFX_HELPERSSKIA_H_ - -#include "2D.h" -#include "SkCanvas.h" -#include "SkDashPathEffect.h" -#include "SkShader.h" -#ifdef USE_SKIA_GPU -#include "GrTypes.h" -#endif -#include "mozilla/Assertions.h" -#include - -namespace mozilla { -namespace gfx { - -static inline SkBitmap::Config -GfxFormatToSkiaConfig(SurfaceFormat format) -{ - switch (format) - { - case FORMAT_B8G8R8A8: - return SkBitmap::kARGB_8888_Config; - case FORMAT_B8G8R8X8: - // We probably need to do something here. - return SkBitmap::kARGB_8888_Config; - case FORMAT_R5G6B5: - return SkBitmap::kRGB_565_Config; - case FORMAT_A8: - return SkBitmap::kA8_Config; - - } - - return SkBitmap::kARGB_8888_Config; -} - -#ifdef USE_SKIA_GPU -static inline GrPixelConfig -GfxFormatToGrConfig(SurfaceFormat format) -{ - switch (format) - { - case FORMAT_B8G8R8A8: - return kBGRA_8888_GrPixelConfig; - case FORMAT_B8G8R8X8: - // We probably need to do something here. - return kBGRA_8888_GrPixelConfig; - case FORMAT_R5G6B5: - return kRGB_565_GrPixelConfig; - case FORMAT_A8: - return kAlpha_8_GrPixelConfig; - default: - return kRGBA_8888_GrPixelConfig; - } - -} -#endif -static inline void -GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval) -{ - retval.setAll(SkFloatToScalar(mat._11), SkFloatToScalar(mat._21), SkFloatToScalar(mat._31), - SkFloatToScalar(mat._12), SkFloatToScalar(mat._22), SkFloatToScalar(mat._32), - 0, 0, SK_Scalar1); -} - -static inline SkPaint::Cap -CapStyleToSkiaCap(CapStyle aCap) -{ - switch (aCap) - { - case CAP_BUTT: - return SkPaint::kButt_Cap; - case CAP_ROUND: - return SkPaint::kRound_Cap; - case CAP_SQUARE: - return SkPaint::kSquare_Cap; - } - return SkPaint::kDefault_Cap; -} - -static inline SkPaint::Join -JoinStyleToSkiaJoin(JoinStyle aJoin) -{ - switch (aJoin) - { - case JOIN_BEVEL: - return SkPaint::kBevel_Join; - case JOIN_ROUND: - return SkPaint::kRound_Join; - case JOIN_MITER: - case JOIN_MITER_OR_BEVEL: - return SkPaint::kMiter_Join; - } - return SkPaint::kDefault_Join; -} - -static inline bool -StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions) -{ - // Skia renders 0 width strokes with a width of 1 (and in black), - // so we should just skip the draw call entirely. - if (!aOptions.mLineWidth) { - return false; - } - aPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth)); - aPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit)); - aPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap)); - aPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin)); - - if (aOptions.mDashLength > 0) { - // Skia only supports dash arrays that are multiples of 2. - uint32_t dashCount; - - if (aOptions.mDashLength % 2 == 0) { - dashCount = aOptions.mDashLength; - } else { - dashCount = aOptions.mDashLength * 2; - } - - std::vector pattern; - pattern.resize(dashCount); - - for (uint32_t i = 0; i < dashCount; i++) { - pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i % aOptions.mDashLength]); - } - - SkDashPathEffect* dash = new SkDashPathEffect(&pattern.front(), - dashCount, - SkFloatToScalar(aOptions.mDashOffset)); - SkSafeUnref(aPaint.setPathEffect(dash)); - } - - aPaint.setStyle(SkPaint::kStroke_Style); - return true; -} - -static inline void -ConvertBGRXToBGRA(unsigned char* aData, const IntSize &aSize, int32_t aStride) -{ - uint32_t* pixel = reinterpret_cast(aData); - - for (int row = 0; row < aSize.height; ++row) { - for (int column = 0; column < aSize.width; ++column) { - pixel[column] |= 0xFF000000; - } - pixel += (aStride/4); - } -} - -static inline SkXfermode::Mode -GfxOpToSkiaOp(CompositionOp op) -{ - switch (op) - { - case OP_OVER: - return SkXfermode::kSrcOver_Mode; - case OP_ADD: - return SkXfermode::kPlus_Mode; - case OP_ATOP: - return SkXfermode::kSrcATop_Mode; - case OP_OUT: - return SkXfermode::kSrcOut_Mode; - case OP_IN: - return SkXfermode::kSrcIn_Mode; - case OP_SOURCE: - return SkXfermode::kSrc_Mode; - case OP_DEST_IN: - return SkXfermode::kDstIn_Mode; - case OP_DEST_OUT: - return SkXfermode::kDstOut_Mode; - case OP_DEST_OVER: - return SkXfermode::kDstOver_Mode; - case OP_DEST_ATOP: - return SkXfermode::kDstATop_Mode; - case OP_XOR: - return SkXfermode::kXor_Mode; - case OP_MULTIPLY: - return SkXfermode::kMultiply_Mode; - case OP_SCREEN: - return SkXfermode::kScreen_Mode; - case OP_OVERLAY: - return SkXfermode::kOverlay_Mode; - case OP_DARKEN: - return SkXfermode::kDarken_Mode; - case OP_LIGHTEN: - return SkXfermode::kLighten_Mode; - case OP_COLOR_DODGE: - return SkXfermode::kColorDodge_Mode; - case OP_COLOR_BURN: - return SkXfermode::kColorBurn_Mode; - case OP_HARD_LIGHT: - return SkXfermode::kHardLight_Mode; - case OP_SOFT_LIGHT: - return SkXfermode::kSoftLight_Mode; - case OP_DIFFERENCE: - return SkXfermode::kDifference_Mode; - case OP_EXCLUSION: - return SkXfermode::kExclusion_Mode; - case OP_HUE: - return SkXfermode::kHue_Mode; - case OP_SATURATION: - return SkXfermode::kSaturation_Mode; - case OP_COLOR: - return SkXfermode::kColor_Mode; - case OP_LUMINOSITY: - return SkXfermode::kLuminosity_Mode; - default: - return SkXfermode::kSrcOver_Mode; - } -} - -static inline SkColor ColorToSkColor(const Color &color, Float aAlpha) -{ - //XXX: do a better job converting to int - return SkColorSetARGB(U8CPU(color.a*aAlpha*255.0), U8CPU(color.r*255.0), - U8CPU(color.g*255.0), U8CPU(color.b*255.0)); -} - -static inline SkRect -RectToSkRect(const Rect& aRect) -{ - return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y), - SkFloatToScalar(aRect.width), SkFloatToScalar(aRect.height)); -} - -static inline SkRect -IntRectToSkRect(const IntRect& aRect) -{ - return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y), - SkIntToScalar(aRect.width), SkIntToScalar(aRect.height)); -} - -static inline SkIRect -RectToSkIRect(const Rect& aRect) -{ - return SkIRect::MakeXYWH(int32_t(aRect.x), int32_t(aRect.y), - int32_t(aRect.width), int32_t(aRect.height)); -} - -static inline SkIRect -IntRectToSkIRect(const IntRect& aRect) -{ - return SkIRect::MakeXYWH(aRect.x, aRect.y, aRect.width, aRect.height); -} - -static inline SkShader::TileMode -ExtendModeToTileMode(ExtendMode aMode) -{ - switch (aMode) - { - case EXTEND_CLAMP: - return SkShader::kClamp_TileMode; - case EXTEND_REPEAT: - return SkShader::kRepeat_TileMode; - case EXTEND_REFLECT: - return SkShader::kMirror_TileMode; - } - return SkShader::kClamp_TileMode; -} - -} -} - -#endif /* MOZILLA_GFX_HELPERSSKIA_H_ */ diff --git a/libazure/src/gfx/2d/Logging.h b/libazure/src/gfx/2d/Logging.h deleted file mode 100644 index 4911293..0000000 --- a/libazure/src/gfx/2d/Logging.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_LOGGING_H_ -#define MOZILLA_GFX_LOGGING_H_ - -#include -#include -#include - -#include "Point.h" -#include "Matrix.h" - -#ifdef WIN32 -#include -#endif - -#ifdef PR_LOGGING -#include - -extern PRLogModuleInfo *GetGFX2DLog(); -#endif - -namespace mozilla { -namespace gfx { - -const int LOG_DEBUG = 1; -const int LOG_WARNING = 2; - -#ifdef PR_LOGGING - -inline PRLogModuleLevel PRLogLevelForLevel(int aLevel) { - switch (aLevel) { - case LOG_DEBUG: - return PR_LOG_DEBUG; - case LOG_WARNING: - return PR_LOG_WARNING; - } - return PR_LOG_DEBUG; -} - -#endif - -extern int sGfxLogLevel; - -static inline void OutputMessage(const std::string &aString, int aLevel) { -#if defined(WIN32) && !defined(PR_LOGGING) - if (aLevel >= sGfxLogLevel) { - ::OutputDebugStringA(aString.c_str()); - } -#elif defined(PR_LOGGING) - if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) { - PR_LogPrint(aString.c_str()); - } -#else - if (aLevel >= sGfxLogLevel) { - printf("%s", aString.c_str()); - } -#endif -} - -class NoLog -{ -public: - NoLog() {} - ~NoLog() {} - - template - NoLog &operator <<(const T &aLogText) { return *this; } -}; - -template -class Log -{ -public: - Log() {} - ~Log() { mMessage << '\n'; WriteLog(mMessage.str()); } - - Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; } - Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; } - Log &operator <<(const Size &aSize) - { mMessage << "(" << aSize.width << "x" << aSize.height << ")"; return *this; } - Log &operator <<(const IntSize &aSize) - { mMessage << "(" << aSize.width << "x" << aSize.height << ")"; return *this; } - Log &operator<<(const Matrix& aMatrix) - { mMessage << "[ " << aMatrix._11 << " " << aMatrix._12 << " ; " << aMatrix._21 << " " << aMatrix._22 << " ; " << aMatrix._31 << " " << aMatrix._32 << " ]"; return *this; } - - -private: - - void WriteLog(const std::string &aString) { - OutputMessage(aString, L); - } - - std::stringstream mMessage; -}; - -typedef Log DebugLog; -typedef Log WarningLog; - -#ifdef GFX_LOG_DEBUG -#define gfxDebug DebugLog -#else -#define gfxDebug if (1) ; else NoLog -#endif -#ifdef GFX_LOG_WARNING -#define gfxWarning WarningLog -#else -#define gfxWarning if (1) ; else NoLog -#endif - -} -} - -#endif /* MOZILLA_GFX_LOGGING_H_ */ diff --git a/libazure/src/gfx/2d/Matrix.cpp b/libazure/src/gfx/2d/Matrix.cpp deleted file mode 100644 index 80e2d3d..0000000 --- a/libazure/src/gfx/2d/Matrix.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Matrix.h" -#include "Tools.h" -#include - -namespace mozilla { -namespace gfx { - -Matrix -Matrix::Rotation(Float aAngle) -{ - Matrix newMatrix; - - Float s = sin(aAngle); - Float c = cos(aAngle); - - newMatrix._11 = c; - newMatrix._12 = s; - newMatrix._21 = -s; - newMatrix._22 = c; - - return newMatrix; -} - -Rect -Matrix::TransformBounds(const Rect &aRect) const -{ - int i; - Point quad[4]; - Float min_x, max_x; - Float min_y, max_y; - - quad[0] = *this * aRect.TopLeft(); - quad[1] = *this * aRect.TopRight(); - quad[2] = *this * aRect.BottomLeft(); - quad[3] = *this * aRect.BottomRight(); - - min_x = max_x = quad[0].x; - min_y = max_y = quad[0].y; - - for (i = 1; i < 4; i++) { - if (quad[i].x < min_x) - min_x = quad[i].x; - if (quad[i].x > max_x) - max_x = quad[i].x; - - if (quad[i].y < min_y) - min_y = quad[i].y; - if (quad[i].y > max_y) - max_y = quad[i].y; - } - - return Rect(min_x, min_y, max_x - min_x, max_y - min_y); -} - -void -Matrix::NudgeToIntegers() -{ - NudgeToInteger(&_11); - NudgeToInteger(&_12); - NudgeToInteger(&_21); - NudgeToInteger(&_22); - NudgeToInteger(&_31); - NudgeToInteger(&_32); -} - -} -} diff --git a/libazure/src/gfx/2d/PathCairo.cpp b/libazure/src/gfx/2d/PathCairo.cpp deleted file mode 100644 index c2c370b..0000000 --- a/libazure/src/gfx/2d/PathCairo.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "PathCairo.h" -#include -#include "DrawTargetCairo.h" -#include "Logging.h" -#include "PathHelpers.h" -#include "HelpersCairo.h" - -namespace mozilla { -namespace gfx { - -CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget) - : mContext(aCtx) - , mDrawTarget(aDrawTarget) -{ - cairo_reference(mContext); - - // A new path in the DrawTarget's context. - aDrawTarget->SetPathObserver(this); - cairo_new_path(mContext); -} - -CairoPathContext::CairoPathContext(CairoPathContext& aPathContext) - : mContext(aPathContext.mContext) - , mDrawTarget(nullptr) -{ - cairo_reference(mContext); - DuplicateContextAndPath(); -} - -CairoPathContext::~CairoPathContext() -{ - if (mDrawTarget) { - DrawTargetCairo* drawTarget = mDrawTarget; - ForgetDrawTarget(); - - // We need to set mDrawTarget to nullptr before we tell DrawTarget otherwise - // we will think we need to make a defensive copy of the path. - drawTarget->SetPathObserver(nullptr); - } - cairo_destroy(mContext); -} - -void -CairoPathContext::DuplicateContextAndPath() -{ - // Duplicate the path. - cairo_path_t* path = cairo_copy_path(mContext); - - // Duplicate the context. - cairo_surface_t* surf = cairo_get_target(mContext); - cairo_matrix_t matrix; - cairo_get_matrix(mContext, &matrix); - cairo_destroy(mContext); - - mContext = cairo_create(surf); - - // Set the matrix to match the source context so that the path is copied in - // device space. After this point it doesn't matter what the transform is - // set to because it's always swapped out before use. - cairo_set_matrix(mContext, &matrix); - - // Add the path, and throw away our duplicate. - cairo_append_path(mContext, path); - cairo_path_destroy(path); -} - -void -CairoPathContext::ForgetDrawTarget() -{ - // We don't need to set the path observer back to nullptr in this case - // because ForgetDrawTarget() is trigged when the target has been - // grabbed by another path observer. - mDrawTarget = nullptr; -} - -void -CairoPathContext::PathWillChange() -{ - // Once we've copied out the context's path, there's no use to holding on to - // the draw target. Thus, there's nothing for us to do if we're independent - // of the draw target, since we'll have already copied out the context's - // path. - if (mDrawTarget) { - // The context we point to is going to change from under us. To continue - // using this path, we need to copy it to a new context. - DuplicateContextAndPath(); - ForgetDrawTarget(); - } -} - -void -CairoPathContext::CopyPathTo(cairo_t* aToContext, Matrix& aTransform) -{ - if (aToContext != mContext) { - CairoTempMatrix tempMatrix(mContext, aTransform); - cairo_path_t* path = cairo_copy_path(mContext); - cairo_new_path(aToContext); - cairo_append_path(aToContext, path); - cairo_path_destroy(path); - } -} - -bool -CairoPathContext::ContainsPath(const Path* aPath) -{ - if (aPath->GetBackendType() != BACKEND_CAIRO) { - return false; - } - - const PathCairo* path = static_cast(aPath); - RefPtr ctx = const_cast(path)->GetPathContext(); - return ctx == this; -} - -PathBuilderCairo::PathBuilderCairo(CairoPathContext* aPathContext, - FillRule aFillRule, - const Matrix& aTransform /* = Matrix() */) - : mPathContext(aPathContext) - , mTransform(aTransform) - , mFillRule(aFillRule) -{} - -PathBuilderCairo::PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule) - : mPathContext(new CairoPathContext(aCtx, aDrawTarget)) - , mTransform(aDrawTarget->GetTransform()) - , mFillRule(aFillRule) -{} - -void -PathBuilderCairo::MoveTo(const Point &aPoint) -{ - PrepareForWrite(); - CairoTempMatrix tempMatrix(*mPathContext, mTransform); - cairo_move_to(*mPathContext, aPoint.x, aPoint.y); -} - -void -PathBuilderCairo::LineTo(const Point &aPoint) -{ - PrepareForWrite(); - CairoTempMatrix tempMatrix(*mPathContext, mTransform); - cairo_line_to(*mPathContext, aPoint.x, aPoint.y); -} - -void -PathBuilderCairo::BezierTo(const Point &aCP1, - const Point &aCP2, - const Point &aCP3) -{ - PrepareForWrite(); - CairoTempMatrix tempMatrix(*mPathContext, mTransform); - cairo_curve_to(*mPathContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y); -} - -void -PathBuilderCairo::QuadraticBezierTo(const Point &aCP1, - const Point &aCP2) -{ - PrepareForWrite(); - CairoTempMatrix tempMatrix(*mPathContext, mTransform); - - // We need to elevate the degree of this quadratic Bézier to cubic, so we're - // going to add an intermediate control point, and recompute control point 1. - // The first and last control points remain the same. - // This formula can be found on http://fontforge.sourceforge.net/bezier.html - Point CP0 = CurrentPoint(); - Point CP1 = (CP0 + aCP1 * 2.0) / 3.0; - Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0; - Point CP3 = aCP2; - - cairo_curve_to(*mPathContext, CP1.x, CP1.y, CP2.x, CP2.y, CP3.x, CP3.y); -} - -void -PathBuilderCairo::Close() -{ - PrepareForWrite(); - cairo_close_path(*mPathContext); -} - -void -PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle, - float aEndAngle, bool aAntiClockwise) -{ - ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise); -} - -Point -PathBuilderCairo::CurrentPoint() const -{ - CairoTempMatrix tempMatrix(*mPathContext, mTransform); - double x, y; - cairo_get_current_point(*mPathContext, &x, &y); - return Point((Float)x, (Float)y); -} - -TemporaryRef -PathBuilderCairo::Finish() -{ - return new PathCairo(mPathContext, mTransform, mFillRule); -} - -TemporaryRef -PathBuilderCairo::GetPathContext() -{ - return mPathContext; -} - -void -PathBuilderCairo::PrepareForWrite() -{ - // Only PathBuilder and PathCairo maintain references to CairoPathContext. - // DrawTarget does not. If we're sharing a reference to the context then we - // need to create a copy that we can modify. This provides copy on write - // behaviour. - if (mPathContext->refCount() != 1) { - mPathContext = new CairoPathContext(*mPathContext); - } -} - -PathCairo::PathCairo(CairoPathContext* aPathContext, Matrix& aTransform, - FillRule aFillRule) - : mPathContext(aPathContext) - , mTransform(aTransform) - , mFillRule(aFillRule) -{} - -TemporaryRef -PathCairo::CopyToBuilder(FillRule aFillRule) const -{ - return new PathBuilderCairo(mPathContext, aFillRule, mTransform); -} - -TemporaryRef -PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const -{ - // We are given the transform we would apply from device space to user space. - // However in cairo our path is in device space so we view the transform as - // being the other way round. We therefore need to apply the inverse transform - // to our current cairo transform. - Matrix inverse = aTransform; - inverse.Invert(); - - return new PathBuilderCairo(mPathContext, aFillRule, mTransform * inverse); -} - -bool -PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const -{ - CairoTempMatrix(*mPathContext, mTransform); - - Matrix inverse = aTransform; - inverse.Invert(); - Point transformed = inverse * aPoint; - - // Needs the correct fill rule set. - cairo_set_fill_rule(*mPathContext, GfxFillRuleToCairoFillRule(mFillRule)); - return cairo_in_fill(*mPathContext, transformed.x, transformed.y); -} - -bool -PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, - const Point &aPoint, - const Matrix &aTransform) const -{ - CairoTempMatrix(*mPathContext, mTransform); - - Matrix inverse = aTransform; - inverse.Invert(); - Point transformed = inverse * aPoint; - - SetCairoStrokeOptions(*mPathContext, aStrokeOptions); - return cairo_in_stroke(*mPathContext, transformed.x, transformed.y); -} - -Rect -PathCairo::GetBounds(const Matrix &aTransform) const -{ - CairoTempMatrix(*mPathContext, mTransform); - - double x1, y1, x2, y2; - - cairo_path_extents(*mPathContext, &x1, &y1, &x2, &y2); - Rect bounds(Float(x1), Float(y1), Float(x2 - x1), Float(y2 - y1)); - return aTransform.TransformBounds(bounds); -} - -Rect -PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions, - const Matrix &aTransform) const -{ - CairoTempMatrix(*mPathContext, mTransform); - - double x1, y1, x2, y2; - - SetCairoStrokeOptions(*mPathContext, aStrokeOptions); - - cairo_stroke_extents(*mPathContext, &x1, &y1, &x2, &y2); - Rect bounds((Float)x1, (Float)y1, (Float)(x2 - x1), (Float)(y2 - y1)); - return aTransform.TransformBounds(bounds); -} - -TemporaryRef -PathCairo::GetPathContext() -{ - return mPathContext; -} - -void -PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget) -{ - mPathContext->CopyPathTo(aContext, mTransform); - cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule)); -} - -} -} diff --git a/libazure/src/gfx/2d/PathCairo.h b/libazure/src/gfx/2d/PathCairo.h deleted file mode 100644 index 50cb366..0000000 --- a/libazure/src/gfx/2d/PathCairo.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_PATH_CAIRO_H_ -#define MOZILLA_GFX_PATH_CAIRO_H_ - -#include "2D.h" -#include "cairo.h" - -namespace mozilla { -namespace gfx { - -class DrawTargetCairo; - -// A reference to a cairo context that can maintain and set a path. -// -// This class exists to make it possible for us to not construct paths manually -// using cairo_path_t, which in the common case is a speed and memory -// optimization (as the cairo_t maintains the path for us, and we don't have to -// use cairo_append_path). Instead, we can share a cairo_t with a DrawTarget, -// and have it inform us when we need to make a copy of the path. -// -// Exactly one Path* object represents the current path on a given DrawTarget's -// context. That Path* object registers its CairoPathContext with the -// DrawTarget it's associated with. If that DrawTarget is going to change its -// path, it has to tell the CairoPathContext beforehand so the path can be -// saved off. -// The path ownership is transferred to every new instance of CairoPathContext -// in the constructor. We inform the draw target of the new context object, -// which causes us to save off a copy of the path, as we're not going to be -// informed upon changes any more. -// Any transformation on aCtx is not applied to this path, though a path can be -// transformed separately from its context by passing a matrix to the -// constructor. -class CairoPathContext : public RefCounted -{ -public: - // Construct a new empty CairoPathContext that uses the given draw target and - // its cairo context. Using the existing context may save having to copy the - // path later. - CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget); - - // Copy the path. - CairoPathContext(CairoPathContext& aPathContext); - - ~CairoPathContext(); - - // Copy the path on mContext to be the path on aToContext, if they aren't the - // same. At this point we set the fill rule for the destination context as - // there is little point in doing this earlier. - void CopyPathTo(cairo_t* aToContext, Matrix& aTransform); - - // This method must be called by the draw target before it changes the path - // currently on the cairo context. - void PathWillChange(); - - // This method must be called as the draw target is dying. In this case, we - // forget our reference to the draw target, and become the only reference to - // our context. - void ForgetDrawTarget(); - - // Create a duplicate context, and copy this path to that context. - void DuplicateContextAndPath(); - - // Returns true if this CairoPathContext represents path. - bool ContainsPath(const Path* path); - - cairo_t* GetContext() const { return mContext; } - DrawTargetCairo* GetDrawTarget() const { return mDrawTarget; } - operator cairo_t* () const { return mContext; } - -private: // data - cairo_t* mContext; - // Not a RefPtr to avoid cycles. - DrawTargetCairo* mDrawTarget; -}; - -class PathBuilderCairo : public PathBuilder -{ -public: - // Creates a new empty path. It also implicitly takes ownership of aCtx by - // calling aDrawTarget->SetPathObserver(). Therefore, if the draw target has a - // path observer, this constructor will cause it to copy out its path. - PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule); - - // Creates a path builder out of an existing CairoPathContext with a new fill - // rule and transform. - PathBuilderCairo(CairoPathContext* aContext, FillRule aFillRule, const Matrix& aTransform = Matrix()); - - virtual void MoveTo(const Point &aPoint); - virtual void LineTo(const Point &aPoint); - virtual void BezierTo(const Point &aCP1, - const Point &aCP2, - const Point &aCP3); - virtual void QuadraticBezierTo(const Point &aCP1, - const Point &aCP2); - virtual void Close(); - virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, - float aEndAngle, bool aAntiClockwise = false); - virtual Point CurrentPoint() const; - virtual TemporaryRef Finish(); - - TemporaryRef GetPathContext(); - -private: // data - void PrepareForWrite(); - - RefPtr mPathContext; - Matrix mTransform; - FillRule mFillRule; -}; - -class PathCairo : public Path -{ -public: - PathCairo(CairoPathContext* aPathContex, Matrix& aTransform, FillRule aFillRule); - - virtual BackendType GetBackendType() const { return BACKEND_CAIRO; } - - virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; - virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, - FillRule aFillRule = FILL_WINDING) const; - - virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; - - virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions, - const Point &aPoint, - const Matrix &aTransform) const; - - virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const; - - virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions, - const Matrix &aTransform = Matrix()) const; - - virtual FillRule GetFillRule() const { return mFillRule; } - - TemporaryRef GetPathContext(); - - // Set this path to be the current path for aContext (if it's not already - // aContext's path). You must pass the draw target associated with the - // context as aDrawTarget. - void CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget); - -private: - RefPtr mPathContext; - Matrix mTransform; - FillRule mFillRule; -}; - -} -} - -#endif /* MOZILLA_GFX_PATH_CAIRO_H_ */ diff --git a/libazure/src/gfx/2d/PathHelpers.h b/libazure/src/gfx/2d/PathHelpers.h deleted file mode 100644 index 9cecae8..0000000 --- a/libazure/src/gfx/2d/PathHelpers.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_PATHHELPERS_H_ -#define MOZILLA_GFX_PATHHELPERS_H_ - -#include "2D.h" -#include "mozilla/Constants.h" - -namespace mozilla { -namespace gfx { - -template -void ArcToBezier(T* aSink, const Point &aOrigin, float aRadius, float aStartAngle, - float aEndAngle, bool aAntiClockwise) -{ - Point startPoint(aOrigin.x + cos(aStartAngle) * aRadius, - aOrigin.y + sin(aStartAngle) * aRadius); - - aSink->LineTo(startPoint); - - // Clockwise we always sweep from the smaller to the larger angle, ccw - // it's vice versa. - if (!aAntiClockwise && (aEndAngle < aStartAngle)) { - Float correction = Float(ceil((aStartAngle - aEndAngle) / (2.0f * M_PI))); - aEndAngle += float(correction * 2.0f * M_PI); - } else if (aAntiClockwise && (aStartAngle < aEndAngle)) { - Float correction = (Float)ceil((aEndAngle - aStartAngle) / (2.0f * M_PI)); - aStartAngle += float(correction * 2.0f * M_PI); - } - - // Sweeping more than 2 * pi is a full circle. - if (!aAntiClockwise && (aEndAngle - aStartAngle > 2 * M_PI)) { - aEndAngle = float(aStartAngle + 2.0f * M_PI); - } else if (aAntiClockwise && (aStartAngle - aEndAngle > 2.0f * M_PI)) { - aEndAngle = float(aStartAngle - 2.0f * M_PI); - } - - // Calculate the total arc we're going to sweep. - Float arcSweepLeft = fabs(aEndAngle - aStartAngle); - - Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f; - - Float currentStartAngle = aStartAngle; - - while (arcSweepLeft > 0) { - // We guarantee here the current point is the start point of the next - // curve segment. - Float currentEndAngle; - - if (arcSweepLeft > M_PI / 2.0f) { - currentEndAngle = Float(currentStartAngle + M_PI / 2.0f * sweepDirection); - } else { - currentEndAngle = currentStartAngle + arcSweepLeft * sweepDirection; - } - - Point currentStartPoint(aOrigin.x + cos(currentStartAngle) * aRadius, - aOrigin.y + sin(currentStartAngle) * aRadius); - Point currentEndPoint(aOrigin.x + cos(currentEndAngle) * aRadius, - aOrigin.y + sin(currentEndAngle) * aRadius); - - // Calculate kappa constant for partial curve. The sign of angle in the - // tangent will actually ensure this is negative for a counter clockwise - // sweep, so changing signs later isn't needed. - Float kappa = (4.0f / 3.0f) * tan((currentEndAngle - currentStartAngle) / 4.0f) * aRadius; - - Point tangentStart(-sin(currentStartAngle), cos(currentStartAngle)); - Point cp1 = currentStartPoint; - cp1 += tangentStart * kappa; - - Point revTangentEnd(sin(currentEndAngle), -cos(currentEndAngle)); - Point cp2 = currentEndPoint; - cp2 += revTangentEnd * kappa; - - aSink->BezierTo(cp1, cp2, currentEndPoint); - - arcSweepLeft -= Float(M_PI / 2.0f); - currentStartAngle = currentEndAngle; - } -} - -} -} - -#endif /* MOZILLA_GFX_PATHHELPERS_H_ */ diff --git a/libazure/src/gfx/2d/Rect.cpp b/libazure/src/gfx/2d/Rect.cpp deleted file mode 100644 index 9b50b19..0000000 --- a/libazure/src/gfx/2d/Rect.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Rect.h" -#include "Tools.h" - -namespace mozilla { -namespace gfx { - -void Rect::NudgeToIntegers() -{ - NudgeToInteger(&x); - NudgeToInteger(&y); - NudgeToInteger(&width); - NudgeToInteger(&height); -} - -} -} diff --git a/libazure/src/gfx/2d/ScaledFontBase.cpp b/libazure/src/gfx/2d/ScaledFontBase.cpp deleted file mode 100644 index a946d31..0000000 --- a/libazure/src/gfx/2d/ScaledFontBase.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ScaledFontBase.h" - -#ifdef USE_SKIA -#include "PathSkia.h" -#include "SkPaint.h" -#include "SkPath.h" -#endif - -#ifdef USE_CAIRO -#include "PathCairo.h" -#endif - -#include -#include - -using namespace std; - -namespace mozilla { -namespace gfx { - -ScaledFontBase::~ScaledFontBase() -{ -#ifdef USE_SKIA - SkSafeUnref(mTypeface); -#endif -#ifdef USE_CAIRO - cairo_scaled_font_destroy(mScaledFont); -#endif -} - -ScaledFontBase::ScaledFontBase(Float aSize) - : mSize(aSize) -{ -#ifdef USE_SKIA - mTypeface = nullptr; -#endif -#ifdef USE_CAIRO - mScaledFont = nullptr; -#endif -} - -TemporaryRef -ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) -{ -#ifdef USE_SKIA - if (aTarget->GetType() == BACKEND_SKIA) { - SkPaint paint; - paint.setTypeface(GetSkTypeface()); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - paint.setTextSize(SkFloatToScalar(mSize)); - - std::vector indices; - std::vector offsets; - indices.resize(aBuffer.mNumGlyphs); - offsets.resize(aBuffer.mNumGlyphs); - - for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { - indices[i] = aBuffer.mGlyphs[i].mIndex; - offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x); - offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y); - } - - SkPath path; - paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path); - return new PathSkia(path, FILL_WINDING); - } -#endif -#ifdef USE_CAIRO - if (aTarget->GetType() == BACKEND_CAIRO) { - MOZ_ASSERT(mScaledFont); - - RefPtr builder_iface = aTarget->CreatePathBuilder(); - PathBuilderCairo* builder = static_cast(builder_iface.get()); - - // Manually build the path for the PathBuilder. - RefPtr context = builder->GetPathContext(); - - cairo_set_scaled_font(*context, mScaledFont); - - // Convert our GlyphBuffer into an array of Cairo glyphs. - std::vector glyphs(aBuffer.mNumGlyphs); - for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) { - glyphs[i].index = aBuffer.mGlyphs[i].mIndex; - glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x; - glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; - } - - cairo_glyph_path(*context, &glyphs[0], aBuffer.mNumGlyphs); - - return builder->Finish(); - } -#endif - return nullptr; -} - -void -ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder) -{ - // XXX - implement me - MOZ_ASSERT(false); - return; -} - -#ifdef USE_CAIRO -void -ScaledFontBase::SetCairoScaledFont(cairo_scaled_font_t* font) -{ - MOZ_ASSERT(!mScaledFont); - - mScaledFont = font; - cairo_scaled_font_reference(mScaledFont); -} -#endif - -} -} diff --git a/libazure/src/gfx/2d/ShadersD2D.h b/libazure/src/gfx/2d/ShadersD2D.h deleted file mode 100644 index 8d589d6..0000000 --- a/libazure/src/gfx/2d/ShadersD2D.h +++ /dev/null @@ -1,15985 +0,0 @@ -#if 0 -// -// FX Version: fx_4_0 -// Child effect (requires effect pool): false -// -// 4 local buffer(s) -// -cbuffer $Globals -{ - uint blendop; // Offset: 0, size: 4 -} - -cbuffer cb0 -{ - float4 QuadDesc; // Offset: 0, size: 16 - float4 TexCoords; // Offset: 16, size: 16 - float4 MaskTexCoords; // Offset: 32, size: 16 - float4 TextColor; // Offset: 48, size: 16 -} - -cbuffer cb1 -{ - float4 BlurOffsetsH[3]; // Offset: 0, size: 48 - float4 BlurOffsetsV[3]; // Offset: 48, size: 48 - float4 BlurWeights[3]; // Offset: 96, size: 48 - float4 ShadowColor; // Offset: 144, size: 16 -} - -cbuffer cb2 -{ - float3x3 DeviceSpaceToUserSpace; // Offset: 0, size: 44 - float2 dimensions; // Offset: 48, size: 8 - float3 diff; // Offset: 64, size: 12 - float2 center1; // Offset: 80, size: 8 - float A; // Offset: 88, size: 4 - float radius1; // Offset: 92, size: 4 - float sq_radius1; // Offset: 96, size: 4 -} - -// -// 13 local object(s) -// -Texture2D tex; -Texture2D bcktex; -Texture2D mask; -SamplerState sSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = tex; - AddressU = uint(CLAMP /* 3 */); - AddressV = uint(CLAMP /* 3 */); -}; -SamplerState sBckSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = bcktex; - AddressU = uint(CLAMP /* 3 */); - AddressV = uint(CLAMP /* 3 */); -}; -SamplerState sWrapSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = tex; - AddressU = uint(WRAP /* 1 */); - AddressV = uint(WRAP /* 1 */); -}; -SamplerState sMirrorSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = tex; - AddressU = uint(MIRROR /* 2 */); - AddressV = uint(MIRROR /* 2 */); -}; -SamplerState sMaskSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = mask; - AddressU = uint(CLAMP /* 3 */); - AddressV = uint(CLAMP /* 3 */); -}; -SamplerState sShadowSampler -{ - Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); - Texture = tex; - AddressU = uint(BORDER /* 4 */); - AddressV = uint(BORDER /* 4 */); - BorderColor = float4(0, 0, 0, 0); -}; -RasterizerState TextureRast -{ - ScissorEnable = bool(TRUE /* 1 */); - CullMode = uint(NONE /* 1 */); -}; -BlendState ShadowBlendH -{ - BlendEnable[0] = bool(FALSE /* 0 */); - RenderTargetWriteMask[0] = byte(0x0f); -}; -BlendState ShadowBlendV -{ - BlendEnable[0] = bool(TRUE /* 1 */); - SrcBlend[0] = uint(ONE /* 2 */); - DestBlend[0] = uint(INV_SRC_ALPHA /* 6 */); - BlendOp[0] = uint(ADD /* 1 */); - SrcBlendAlpha[0] = uint(ONE /* 2 */); - DestBlendAlpha[0] = uint(INV_SRC_ALPHA /* 6 */); - BlendOpAlpha[0] = uint(ADD /* 1 */); - RenderTargetWriteMask[0] = byte(0x0f); -}; -BlendState bTextBlend -{ - AlphaToCoverageEnable = bool(FALSE /* 0 */); - BlendEnable[0] = bool(TRUE /* 1 */); - SrcBlend[0] = uint(SRC1_COLOR /* 16 */); - DestBlend[0] = uint(INV_SRC1_COLOR /* 17 */); - BlendOp[0] = uint(ADD /* 1 */); - SrcBlendAlpha[0] = uint(SRC1_ALPHA /* 18 */); - DestBlendAlpha[0] = uint(INV_SRC1_ALPHA /* 19 */); - BlendOpAlpha[0] = uint(ADD /* 1 */); - RenderTargetWriteMask[0] = byte(0x0f); -}; - -// -// 8 technique(s) -// -technique10 SampleTexture -{ - pass P0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // tex texture float4 2d 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // - // - // Level9 shader bytecode: - // - ps_2_x - dcl t0 - dcl_2d s0 - texld r0, t0, s0 - mov oC0, r0 - - // approximately 2 instruction slots used (1 texture, 1 arithmetic) - ps_4_0 - dcl_sampler s0, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - sample o0.xyzw, v1.xyxx, t0.xyzw, s0 - ret - // Approximately 2 instruction slots used - - }; - } - -} - -technique10 SampleTextureForSeparableBlending_1 -{ - pass P0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer $Globals - // { - // - // uint blendop; // Offset: 0 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sBckSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // bcktex texture float4 2d 1 1 - // $Globals cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 0 1 (UINT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c1, -1, -2, -3, -4 - def c2, 1, 0, 0.5, -2 - def c3, -5, 0, 0, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mov r0.w, c0.x - add r0.x, r0.w, c3.x - mul r0.x, r0.x, r0.x - texld r1, t0, s0 - texld r2, t0, s1 - rcp r0.y, r2.w - mul r3.xyz, r0.y, r2 - mul r4.xyz, r3, r3 - cmp r4.xyz, -r4, c2.y, c2.x - mad r5, r2.xyzx, -r0.y, c2.zzzx - mad r0.yz, r2, -r0.y, c2.x - rcp r3.w, r1.w - mul r2.xyz, r1, r3.w - rcp r4.w, r2.x - mad r4.w, r5.w, -r4.w, c2.x - max r5.w, r4.w, c2.y - cmp r6.x, -r2.x, r4.x, r5.w - rcp r5.w, r2.y - mad r5.w, r0.y, -r5.w, c2.x - max r6.w, r5.w, c2.y - cmp r6.y, -r2.y, r4.y, r6.w - rcp r5.w, r2.z - mad r5.w, r0.z, -r5.w, c2.x - max r6.w, r5.w, c2.y - cmp r6.z, -r2.z, r4.z, r6.w - max r4.xyz, r2, r3 - cmp r0.xyz, -r0.x, r4, r6 - add r4, r0.w, c1 - mul r4, r4, r4 - min r6.xyz, r3, r2 - cmp r0.xyz, -r4.w, r6, r0 - mad r6.xyz, r3, -c2.w, -c2.x - add r6.xyz, -r6, c2.x - mad r7.xyz, r1, -r3.w, c2.x - mad r8.xyz, r1, r3.w, r3 - mad r8.xyz, r2, -r3, r8 - mad r6.xyz, r7, -r6, c2.x - add r7.xyz, r3, r3 - mul r3.xyz, r3, r2 - mul r7.xyz, r2, r7 - cmp r5.xyz, r5, r7, r6 - cmp r0.xyz, -r4.z, r5, r0 - cmp r0.xyz, -r4.y, r8, r0 - cmp r0.xyz, -r4.x, r3, r0 - lrp r3.xyz, r2.w, r0, r2 - mul r3.w, r2.w, r2.w - cmp r3.w, -r3.w, c2.x, c2.y - mul r0.xyz, r1.w, r3 - mul r0.w, r1.w, r1.w - cmp r0.w, -r0.w, c2.x, c2.y - add r0.w, r3.w, r0.w - cmp r1.xyz, -r0.w, r0, r1 - mov oC0, r1 - - // approximately 53 instruction slots used (2 texture, 51 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[1], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_temps 7 - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - sample r1.xyzw, v1.xyxx, t1.xyzw, s1 - eq r2.x, r0.w, l(0.000000) - eq r2.y, r1.w, l(0.000000) - or r2.x, r2.y, r2.x - if_nz r2.x - mov o0.xyzw, r0.xyzw - ret - endif - div r0.xyz, r0.xyzx, r0.wwww - div r1.xyz, r1.xyzx, r1.wwww - ieq r2.x, cb0[0].x, l(1) - if_nz r2.x - mul r2.xyz, r0.xyzx, r1.xyzx - else - ieq r2.w, cb0[0].x, l(2) - if_nz r2.w - add r3.xyz, r0.xyzx, r1.xyzx - mad r2.xyz, -r0.xyzx, r1.xyzx, r3.xyzx - else - ieq r2.w, cb0[0].x, l(3) - if_nz r2.w - ge r3.xyz, l(0.500000, 0.500000, 0.500000, 0.000000), r1.xyzx - add r4.xyz, r1.xyzx, r1.xyzx - mul r4.xyz, r0.xyzx, r4.xyzx - mad r5.xyz, r1.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000) - add r6.xyz, -r0.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - add r5.xyz, -r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - mad r5.xyz, -r6.xyzx, r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - movc r2.xyz, r3.xyzx, r4.xyzx, r5.xyzx - else - ieq r2.w, cb0[0].x, l(4) - if_nz r2.w - min r2.xyz, r0.xyzx, r1.xyzx - else - ieq r2.w, cb0[0].x, l(5) - max r3.xyz, r0.xyzx, r1.xyzx - lt r4.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzx - add r5.xyz, -r1.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - div r5.xyz, r5.xyzx, r0.xyzx - min r5.xyz, r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - add r5.xyz, -r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - ne r1.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r1.xyzx - and r1.xyz, r1.xyzx, l(0x3f800000, 0x3f800000, 0x3f800000, 0) - movc r1.xyz, r4.xyzx, r5.xyzx, r1.xyzx - movc r2.xyz, r2.wwww, r3.xyzx, r1.xyzx - endif - endif - endif - endif - add r1.x, -r1.w, l(1.000000) - mul r1.yzw, r1.wwww, r2.xxyz - mad r0.xyz, r1.xxxx, r0.xyzx, r1.yzwy - mul o0.xyz, r0.wwww, r0.xyzx - mov o0.w, r0.w - ret - // Approximately 56 instruction slots used - - }; - } - -} - -technique10 SampleTextureForSeparableBlending_2 -{ - pass P0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer $Globals - // { - // - // uint blendop; // Offset: 0 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sBckSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // bcktex texture float4 2d 1 1 - // $Globals cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 0 1 (UINT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c1, -7, -8, -9, -10 - def c2, 1, 0, 0.25, 0.5 - def c3, 2, -1, 16, -12 - def c4, 4, 2, 1, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mov r0.w, c0.x - add r0, r0.w, c1 - mul r0, r0, r0 - texld r1, t0, s0 - texld r2, t0, s1 - rcp r3.w, r2.w - mad r3.xy, r2.yzzw, -r3.w, c2.z - mul r4.xyz, r2, r3.w - mad r5.xyz, r4, c3.z, c3.w - mad r5.xyz, r5, r4, c4.x - mul r5.xyz, r4, r5 - rsq r4.w, r4.y - rcp r4.w, r4.w - cmp r4.w, r3.x, r5.y, r4.w - mad r4.w, r2.y, -r3.w, r4.w - rcp r3.x, r1.w - mul r6.xyz, r1, r3.x - mad r7.xyz, r6, c3.x, c3.y - mad r4.w, r7.y, r4.w, r4.y - mad r8.xyz, r1, -r3.x, c2.w - mad r9, r2.xyzx, -r3.w, c2.xxxz - mad r10.xyz, r6, -c4.y, c4.z - mul r10.xyz, r4, r10 - mad r10.xyz, r10, -r9, r4 - cmp r11.y, r8.y, r10.y, r4.w - rsq r4.w, r4.z - rcp r4.w, r4.w - cmp r4.w, r3.y, r5.z, r4.w - mad r4.w, r2.z, -r3.w, r4.w - mad r4.w, r7.z, r4.w, r4.z - cmp r11.z, r8.z, r10.z, r4.w - rsq r4.w, r4.x - rcp r4.w, r4.w - cmp r4.w, r9.w, r5.x, r4.w - mad r4.w, r2.x, -r3.w, r4.w - mad r4.w, r7.x, r4.w, r4.x - add r2.xyz, -r7, c2.x - mad r2.xyz, r9, -r2, c2.x - cmp r11.x, r8.x, r10.x, r4.w - mad r3.yzw, r1.xxyz, r3.x, -r4.xxyz - mad r5.xyz, r1, r3.x, r4 - abs r3.xyz, r3.yzww - mul r7.xyz, r4, r6 - mad r5.xyz, r7, -c3.x, r5 - cmp r3.xyz, -r0.w, r3, r5 - cmp r3.xyz, -r0.z, r11, r3 - add r5.xyz, r6, r6 - mul r5.xyz, r4, r5 - mul r4.xyz, r4, r4 - cmp r4.xyz, -r4, c2.y, c2.x - cmp r2.xyz, r8, r5, r2 - cmp r0.yzw, -r0.y, r2.xxyz, r3.xxyz - rcp r4.w, r6.x - mad r4.w, r9.x, -r4.w, c2.x - max r6.w, r4.w, c2.y - cmp r2.x, -r6.x, r4.x, r6.w - rcp r6.w, r6.y - mad r6.w, r9.y, -r6.w, c2.x - max r3.x, r6.w, c2.y - cmp r2.y, -r6.y, r4.y, r3.x - rcp r6.w, r6.z - mad r6.w, r9.z, -r6.w, c2.x - max r3.x, r6.w, c2.y - cmp r2.z, -r6.z, r4.z, r3.x - cmp r0.xyz, -r0.x, r2, r0.yzww - lrp r3.xyz, r2.w, r0, r6 - mul r3.w, r2.w, r2.w - cmp r3.w, -r3.w, c2.x, c2.y - mul r0.xyz, r1.w, r3 - mul r0.w, r1.w, r1.w - cmp r0.w, -r0.w, c2.x, c2.y - add r0.w, r3.w, r0.w - cmp r1.xyz, -r0.w, r0, r1 - mov oC0, r1 - - // approximately 74 instruction slots used (2 texture, 72 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[1], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_temps 7 - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - sample r1.xyzw, v1.xyxx, t1.xyzw, s1 - eq r2.x, r0.w, l(0.000000) - eq r2.y, r1.w, l(0.000000) - or r2.x, r2.y, r2.x - if_nz r2.x - mov o0.xyzw, r0.xyzw - ret - endif - div r0.xyz, r0.xyzx, r0.wwww - div r1.xyz, r1.xyzx, r1.wwww - ieq r2.x, cb0[0].x, l(7) - if_nz r2.x - lt r2.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzx - add r3.xyz, -r1.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - div r3.xyz, r3.xyzx, r0.xyzx - min r3.xyz, r3.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - add r3.xyz, -r3.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - ne r4.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r1.xyzx - and r4.xyz, r4.xyzx, l(0x3f800000, 0x3f800000, 0x3f800000, 0) - movc r2.xyz, r2.xyzx, r3.xyzx, r4.xyzx - else - ieq r2.w, cb0[0].x, l(8) - if_nz r2.w - ge r3.xyz, l(0.500000, 0.500000, 0.500000, 0.000000), r0.xyzx - add r4.xyz, r0.xyzx, r0.xyzx - mul r4.xyz, r1.xyzx, r4.xyzx - mad r5.xyz, r0.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000) - add r6.xyz, -r1.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - add r5.xyz, -r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - mad r5.xyz, -r6.xyzx, r5.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - movc r2.xyz, r3.xyzx, r4.xyzx, r5.xyzx - else - ieq r2.w, cb0[0].x, l(9) - if_nz r2.w - ge r3.xyz, l(0.250000, 0.250000, 0.250000, 0.000000), r1.xyzx - mad r4.xyz, r1.xyzx, l(16.000000, 16.000000, 16.000000, 0.000000), l(-12.000000, -12.000000, -12.000000, 0.000000) - mad r4.xyz, r4.xyzx, r1.xyzx, l(4.000000, 4.000000, 4.000000, 0.000000) - mul r4.xyz, r1.xyzx, r4.xyzx - sqrt r5.xyz, r1.xyzx - movc r3.xyz, r3.xyzx, r4.xyzx, r5.xyzx - ge r4.xyz, l(0.500000, 0.500000, 0.500000, 0.000000), r0.xyzx - mad r5.xyz, -r0.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(1.000000, 1.000000, 1.000000, 0.000000) - mul r5.xyz, r1.xyzx, r5.xyzx - add r6.xyz, -r1.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) - mad r5.xyz, -r5.xyzx, r6.xyzx, r1.xyzx - mad r6.xyz, r0.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000) - add r3.xyz, -r1.xyzx, r3.xyzx - mad r3.xyz, r6.xyzx, r3.xyzx, r1.xyzx - movc r2.xyz, r4.xyzx, r5.xyzx, r3.xyzx - else - ieq r2.w, cb0[0].x, l(10) - add r3.xyz, r0.xyzx, -r1.xyzx - add r4.xyz, r0.xyzx, r1.xyzx - mul r1.xyz, r0.xyzx, r1.xyzx - mad r1.xyz, -r1.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), r4.xyzx - movc r2.xyz, r2.wwww, |r3.xyzx|, r1.xyzx - endif - endif - endif - add r1.x, -r1.w, l(1.000000) - mul r1.yzw, r1.wwww, r2.xxyz - mad r0.xyz, r1.xxxx, r0.xyzx, r1.yzwy - mul o0.xyz, r0.wwww, r0.xyzx - mov o0.w, r0.w - ret - // Approximately 66 instruction slots used - - }; - } - -} - -technique10 SampleTextureForNonSeparableBlending -{ - pass P0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer $Globals - // { - // - // uint blendop; // Offset: 0 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sBckSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // bcktex texture float4 2d 1 1 - // $Globals cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 0 1 (UINT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c1, -12, -13, -14, 0 - def c2, 1, 0, 0, 0 - def c3, 0.300000012, 0.589999974, 0.109999999, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mov r0.y, c2.y - mov r1.y, c2.y - mov r2.z, c2.y - texld r3, t0, s1 - texld r4, t0, s0 - rcp r0.w, r4.w - mul r5.xyz, r0.w, r4 - mad r6.xy, r4.yxzw, r0.w, -r5.zyzw - cmp r7.xy, r6.x, r5.yzzw, r5.zyzw - max r1.w, r5.x, r7.x - min r2.w, r7.y, r5.x - add r7.w, r1.w, -r2.w - mov r8.w, r7.w - rcp r1.w, r3.w - mul r9.xyz, r1.w, r3 - mad r10.xy, r3.x, r1.w, -r9.zyzw - rcp r2.w, r10.y - mul r2.w, r2.w, r8.w - mad r11, r3.zyyz, r1.w, -r9.xxzy - mul r8.y, r2.w, r11.w - mov r10.zw, r11 - cmp r1.xz, -r10.y, r10.yyww, r8.wyyw - rcp r2.w, r10.x - mul r2.w, r2.w, r8.w - mul r8.x, r2.w, r10.z - cmp r2.xy, -r10.x, r10.xzzw, r8.wxzw - cmp r1.xyz, r10.w, r1, r2 - rcp r5.w, r10.w - mul r5.w, r5.w, r8.w - mul r8.z, r5.w, r10.y - cmp r0.xz, -r11.w, r10.yyww, r8.zyww - cmp r0.xyz, r11.x, r0, r1 - mov r1.x, c2.y - mov r2.x, c2.y - mov r8.z, c2.y - rcp r2.w, r10.z - mul r2.w, r2.w, r8.w - mul r7.x, r2.w, r10.x - cmp r8.xy, -r11.z, r10.xzzw, r7.xwzw - rcp r2.w, r11.y - mul r2.w, r2.w, r8.w - mul r7.y, r2.w, r11.x - cmp r2.yz, -r11.y, r11.xyxw, r7.xwyw - cmp r2.xyz, r11.x, r2, r8 - rcp r2.w, r11.x - mul r2.w, r2.w, r8.w - mul r7.z, r2.w, r11.y - cmp r1.yz, -r11.x, r11.xyxw, r7.xzww - cmp r1.xyz, r10.w, r1, r2 - cmp r0.xyz, r11.y, r1, r0 - cmp r1.xy, r10.z, r9.yzzw, r9.zyzw - dp3 r5.w, r0, c3 - dp3 r1.z, r9, c3 - add r5.w, -r5.w, r1.z - add r0.xyz, r0, r5.w - add r5.w, -r0.y, r0.x - cmp r2.xy, r5.w, r0.yxzw, r0 - min r5.w, r0.z, r2.x - max r7.x, r2.y, r0.z - dp3 r2.x, r0, c3 - add r2.y, -r5.w, r2.x - rcp r2.y, r2.y - add r7.yzw, r0.xxyz, -r2.x - mul r7.yzw, r2.x, r7 - mad r2.yzw, r7, r2.y, r2.x - cmp r0.xyz, r5.w, r0, r2.yzww - add r2.yzw, -r2.x, r0.xxyz - add r5.w, -r2.x, c2.x - mul r2.yzw, r2, r5.w - add r5.w, -r2.x, r7.x - add r7.x, -r7.x, c2.x - rcp r5.w, r5.w - mad r2.xyz, r2.yzww, r5.w, r2.x - cmp r0.xyz, r7.x, r0, r2 - dp3 r5.w, r5, c3 - add r2.x, r1.z, -r5.w - add r5.w, -r1.z, r5.w - mad r2.yzw, r3.xxyz, r1.w, r5.w - mad r3.xyz, r4, r0.w, r2.x - mad r7, r4.zyzx, r0.w, -r5.xxyz - add r0.w, -r3.y, r3.x - cmp r8.xy, r0.w, r3.yxzw, r3 - min r0.w, r3.z, r8.x - max r1.w, r8.y, r3.z - dp3 r5.w, r3, c3 - add r2.x, -r0.w, r5.w - rcp r2.x, r2.x - add r8.xyz, r3, -r5.w - mul r8.xyz, r5.w, r8 - mad r8.xyz, r8, r2.x, r5.w - cmp r3.xyz, r0.w, r3, r8 - add r8.xyz, -r5.w, r3 - add r0.w, -r5.w, c2.x - mul r8.xyz, r0.w, r8 - add r0.w, r1.w, -r5.w - add r1.w, -r1.w, c2.x - rcp r0.w, r0.w - mad r8.xyz, r8, r0.w, r5.w - cmp r3.xyz, r1.w, r3, r8 - add r0.w, -r2.z, r2.y - cmp r8.xy, r0.w, r2.zyzw, r2.yzzw - min r0.w, r2.w, r8.x - max r1.w, r8.y, r2.w - dp3 r5.w, r2.yzww, c3 - add r2.x, -r0.w, r5.w - rcp r2.x, r2.x - add r8.xyz, r2.yzww, -r5.w - mul r8.xyz, r5.w, r8 - mad r8.xyz, r8, r2.x, r5.w - cmp r2.xyz, r0.w, r2.yzww, r8 - add r8.xyz, -r5.w, r2 - add r0.w, -r5.w, c2.x - mul r8.xyz, r0.w, r8 - add r0.w, r1.w, -r5.w - add r1.w, -r1.w, c2.x - rcp r0.w, r0.w - mad r8.xyz, r8, r0.w, r5.w - cmp r2.xyz, r1.w, r2, r8 - mov r0.w, c0.x - add r8.xyz, r0.w, c1 - mul r8.xyz, r8, r8 - cmp r2.xyz, -r8.z, r3, r2 - cmp r0.xyz, -r8.y, r0, r2 - mov r2.y, c2.y - mov r3.y, c2.y - mov r10.z, c2.y - max r0.w, r9.x, r1.x - min r2.w, r1.y, r9.x - add r9.w, r0.w, -r2.w - mov r11.w, r9.w - rcp r0.w, r7.w - mul r0.w, r0.w, r11.w - mul r11.x, r0.w, r6.x - mov r6.zw, r7.xywz - cmp r10.xy, -r7.w, r6.zxzw, r11.wxzw - rcp r0.w, r6.y - mul r0.w, r0.w, r11.w - mul r11.y, r0.w, r7.z - cmp r3.xz, -r6.y, r6.yyww, r11.wyyw - cmp r1.xyw, r7.z, r3.xyzz, r10.xyzz - rcp r0.w, r7.z - mul r0.w, r0.w, r11.w - mul r11.z, r0.w, r6.y - cmp r2.xz, -r7.z, r6.yyww, r11.zyww - cmp r1.xyw, r7.x, r2.xyzz, r1 - mov r2.x, c2.y - mov r3.z, c2.y - rcp r0.w, r6.x - mul r0.w, r0.w, r11.w - mul r9.x, r0.w, r7.w - cmp r3.xy, -r6.x, r6.zxzw, r9.xwzw - rcp r0.w, r7.y - mul r0.w, r0.w, r11.w - mul r9.y, r0.w, r7.x - cmp r2.yz, -r7.y, r7.xyxw, r9.xwyw - cmp r2.xyz, r7.x, r2, r3 - mov r3.x, c2.y - rcp r0.w, r7.x - mul r0.w, r0.w, r11.w - mul r9.z, r0.w, r7.y - cmp r3.yz, -r7.x, r7.xyxw, r9.xzww - cmp r2.xyz, r7.z, r3, r2 - cmp r1.xyw, r7.y, r2.xyzz, r1 - dp3 r0.w, r1.xyww, c3 - add r0.w, -r0.w, r1.z - add r1.xyz, r0.w, r1.xyww - add r0.w, -r1.y, r1.x - cmp r2.xy, r0.w, r1.yxzw, r1 - min r0.w, r1.z, r2.x - max r5.w, r2.y, r1.z - dp3 r1.w, r1, c3 - add r2.xyz, -r1.w, r1 - mul r2.xyz, r1.w, r2 - add r2.w, -r0.w, r1.w - rcp r2.w, r2.w - mad r2.xyz, r2, r2.w, r1.w - cmp r1.xyz, r0.w, r1, r2 - add r2.xyz, -r1.w, r1 - add r0.w, -r1.w, c2.x - mul r2.xyz, r0.w, r2 - add r0.w, -r1.w, r5.w - add r2.w, -r5.w, c2.x - rcp r0.w, r0.w - mad r2.xyz, r2, r0.w, r1.w - cmp r1.xyz, r2.w, r1, r2 - cmp r0.xyz, -r8.x, r1, r0 - lrp r1.xyz, r3.w, r0, r5 - mul r1.w, r3.w, r3.w - cmp r1.w, -r1.w, c2.x, c2.y - mul r0.xyz, r4.w, r1 - mul r0.w, r4.w, r4.w - cmp r0.w, -r0.w, c2.x, c2.y - add r0.w, r1.w, r0.w - cmp r4.xyz, -r0.w, r0, r4 - mov oC0, r4 - - // approximately 195 instruction slots used (2 texture, 193 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[1], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_temps 9 - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - sample r1.xyzw, v1.xyxx, t1.xyzw, s1 - eq r2.x, r0.w, l(0.000000) - eq r2.y, r1.w, l(0.000000) - or r2.x, r2.y, r2.x - if_nz r2.x - mov o0.xyzw, r0.xyzw - ret - endif - div r0.xyz, r0.xyzx, r0.wwww - div r1.xyz, r1.xyzx, r1.wwww - ieq r2.x, cb0[0].x, l(12) - if_nz r2.x - max r2.x, r1.z, r1.y - max r2.x, r1.x, r2.x - min r2.y, r1.z, r1.y - min r2.y, r1.x, r2.y - add r2.w, -r2.y, r2.x - ge r3.x, r0.y, r0.x - if_nz r3.x - add r3.xyzw, -r0.xxzz, r0.yzxy - lt r4.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r3.yxwy - div r5.xyz, r2.wwww, r3.yxwy - mul r2.xyz, r3.xyzx, r5.xyzx - movc r5.yz, r4.xxxx, r2.xxwx, r3.xxyx - ge r4.xw, r0.zzzz, r0.yyyx - movc r6.yz, r4.yyyy, r2.wwyw, r3.xxyx - movc r3.xy, r4.zzzz, r2.zwzz, r3.zwzz - mov r6.x, l(0) - mov r3.z, l(0) - movc r3.xyz, r4.wwww, r6.xyzx, r3.xyzx - mov r5.x, l(0) - movc r3.xyz, r4.xxxx, r5.xyzx, r3.xyzx - else - add r4.xyzw, -r0.yyzz, r0.xzyx - lt r5.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r4.yxwy - div r6.xyz, r2.wwww, r4.yxwy - mul r2.xyz, r4.xyzx, r6.xyzx - movc r6.xz, r5.xxxx, r2.xxwx, r4.xxyx - ge r5.xw, r0.zzzz, r0.xxxy - movc r7.xz, r5.yyyy, r2.wwyw, r4.xxyx - movc r2.xy, r5.zzzz, r2.wzww, r4.wzww - mov r7.y, l(0) - mov r2.z, l(0) - movc r2.xyz, r5.wwww, r7.xyzx, r2.xyzx - mov r6.y, l(0) - movc r3.xyz, r5.xxxx, r6.xyzx, r2.xyzx - endif - dp3 r2.x, r1.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - dp3 r2.y, r3.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - add r2.x, -r2.y, r2.x - add r2.xyz, r2.xxxx, r3.xyzx - dp3 r2.w, r2.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - min r3.x, r2.y, r2.x - min r3.x, r2.z, r3.x - max r3.y, r2.y, r2.x - max r3.y, r2.z, r3.y - lt r3.z, r3.x, l(0.000000) - add r4.xyz, -r2.wwww, r2.xyzx - mul r4.xyz, r2.wwww, r4.xyzx - add r3.x, r2.w, -r3.x - div r4.xyz, r4.xyzx, r3.xxxx - add r4.xyz, r2.wwww, r4.xyzx - movc r2.xyz, r3.zzzz, r4.xyzx, r2.xyzx - lt r3.x, l(1.000000), r3.y - add r4.xyz, -r2.wwww, r2.xyzx - add r3.z, -r2.w, l(1.000000) - mul r4.xyz, r3.zzzz, r4.xyzx - add r3.y, -r2.w, r3.y - div r3.yzw, r4.xxyz, r3.yyyy - add r3.yzw, r2.wwww, r3.yyzw - movc r2.xyz, r3.xxxx, r3.yzwy, r2.xyzx - else - ieq r2.w, cb0[0].x, l(13) - if_nz r2.w - max r2.w, r0.z, r0.y - max r2.w, r0.x, r2.w - min r3.x, r0.z, r0.y - min r3.x, r0.x, r3.x - add r3.w, r2.w, -r3.x - ge r2.w, r1.y, r1.x - if_nz r2.w - add r4.xyzw, -r1.xxzz, r1.yzxy - lt r5.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r4.yxwy - div r6.xyz, r3.wwww, r4.yxwy - mul r3.xyz, r4.xyzx, r6.xyzx - movc r6.yz, r5.xxxx, r3.xxwx, r4.xxyx - ge r5.xw, r1.zzzz, r1.yyyx - movc r7.yz, r5.yyyy, r3.wwyw, r4.xxyx - movc r4.xy, r5.zzzz, r3.zwzz, r4.zwzz - mov r7.x, l(0) - mov r4.z, l(0) - movc r4.xyz, r5.wwww, r7.xyzx, r4.xyzx - mov r6.x, l(0) - movc r4.xyz, r5.xxxx, r6.xyzx, r4.xyzx - else - add r5.xyzw, -r1.yyzz, r1.xzyx - lt r6.xyz, l(0.000000, 0.000000, 0.000000, 0.000000), r5.yxwy - div r7.xyz, r3.wwww, r5.yxwy - mul r3.xyz, r5.xyzx, r7.xyzx - movc r7.xz, r6.xxxx, r3.xxwx, r5.xxyx - ge r6.xw, r1.zzzz, r1.xxxy - movc r8.xz, r6.yyyy, r3.wwyw, r5.xxyx - movc r3.xy, r6.zzzz, r3.wzww, r5.wzww - mov r8.y, l(0) - mov r3.z, l(0) - movc r3.xyz, r6.wwww, r8.xyzx, r3.xyzx - mov r7.y, l(0) - movc r4.xyz, r6.xxxx, r7.xyzx, r3.xyzx - endif - dp3 r2.w, r1.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - dp3 r3.x, r4.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - add r2.w, r2.w, -r3.x - add r3.xyz, r2.wwww, r4.xyzx - dp3 r2.w, r3.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - min r3.w, r3.y, r3.x - min r3.w, r3.z, r3.w - max r4.x, r3.y, r3.x - max r4.x, r3.z, r4.x - lt r4.y, r3.w, l(0.000000) - add r5.xyz, -r2.wwww, r3.xyzx - mul r5.xyz, r2.wwww, r5.xyzx - add r3.w, r2.w, -r3.w - div r5.xyz, r5.xyzx, r3.wwww - add r5.xyz, r2.wwww, r5.xyzx - movc r3.xyz, r4.yyyy, r5.xyzx, r3.xyzx - lt r3.w, l(1.000000), r4.x - add r4.yzw, -r2.wwww, r3.xxyz - add r5.x, -r2.w, l(1.000000) - mul r4.yzw, r4.yyzw, r5.xxxx - add r4.x, -r2.w, r4.x - div r4.xyz, r4.yzwy, r4.xxxx - add r4.xyz, r2.wwww, r4.xyzx - movc r2.xyz, r3.wwww, r4.xyzx, r3.xyzx - else - ieq r2.w, cb0[0].x, l(14) - if_nz r2.w - dp3 r2.w, r1.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - dp3 r3.x, r0.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - add r2.w, r2.w, -r3.x - add r3.xyz, r0.xyzx, r2.wwww - dp3 r2.w, r3.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - min r3.w, r3.y, r3.x - min r3.w, r3.z, r3.w - max r4.x, r3.y, r3.x - max r4.x, r3.z, r4.x - lt r4.y, r3.w, l(0.000000) - add r5.xyz, -r2.wwww, r3.xyzx - mul r5.xyz, r2.wwww, r5.xyzx - add r3.w, r2.w, -r3.w - div r5.xyz, r5.xyzx, r3.wwww - add r5.xyz, r2.wwww, r5.xyzx - movc r3.xyz, r4.yyyy, r5.xyzx, r3.xyzx - lt r3.w, l(1.000000), r4.x - add r4.yzw, -r2.wwww, r3.xxyz - add r5.x, -r2.w, l(1.000000) - mul r4.yzw, r4.yyzw, r5.xxxx - add r4.x, -r2.w, r4.x - div r4.xyz, r4.yzwy, r4.xxxx - add r4.xyz, r2.wwww, r4.xyzx - movc r2.xyz, r3.wwww, r4.xyzx, r3.xyzx - else - dp3 r2.w, r0.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - dp3 r3.x, r1.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - add r2.w, r2.w, -r3.x - add r1.xyz, r1.xyzx, r2.wwww - dp3 r2.w, r1.xyzx, l(0.300000, 0.590000, 0.110000, 0.000000) - min r3.x, r1.y, r1.x - min r3.x, r1.z, r3.x - max r3.y, r1.y, r1.x - max r3.y, r1.z, r3.y - lt r3.z, r3.x, l(0.000000) - add r4.xyz, r1.xyzx, -r2.wwww - mul r4.xyz, r2.wwww, r4.xyzx - add r3.x, r2.w, -r3.x - div r4.xyz, r4.xyzx, r3.xxxx - add r4.xyz, r2.wwww, r4.xyzx - movc r1.xyz, r3.zzzz, r4.xyzx, r1.xyzx - lt r3.x, l(1.000000), r3.y - add r4.xyz, -r2.wwww, r1.xyzx - add r3.z, -r2.w, l(1.000000) - mul r4.xyz, r3.zzzz, r4.xyzx - add r3.y, -r2.w, r3.y - div r3.yzw, r4.xxyz, r3.yyyy - add r3.yzw, r2.wwww, r3.yyzw - movc r2.xyz, r3.xxxx, r3.yzwy, r1.xyzx - endif - endif - endif - add r1.x, -r1.w, l(1.000000) - mul r1.yzw, r1.wwww, r2.xxyz - mad r0.xyz, r1.xxxx, r0.xyzx, r1.yzwy - mul o0.xyz, r0.wwww, r0.xyzx - mov o0.w, r0.w - ret - // Approximately 195 instruction slots used - - }; - } - -} - -technique10 SampleRadialGradient -{ - pass APos - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 3 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c3, 0.5, 0, 0, 0 - def c4, 1, -1, 0, -0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -c2.x - mul r0.w, r0.w, c1.z - mov r0.z, c1.w - dp3 r0.x, r0, c0 - mad r0.y, r0.x, r0.x, -r0.w - abs r0.z, r0.y - rsq r0.z, r0.z - rcp r1.x, r0.z - mov r1.yz, -r1.x - add r0.xzw, r0.x, r1.xyyz - rcp r1.x, c1.z - mul r0.xzw, r0, r1.x - mov r1.w, c1.w - mad r1.xyz, r0.xzww, c0.z, r1.w - cmp r2.x, r1.x, r0.x, r0.w - cmp r0.xzw, r1.xyyz, c4.xyxy, c4.zyzw - mov r2.y, c3.x - texld r1, t0, s1 - texld r2, r2, s0 - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - add r0.w, r0.w, r0.x - cmp r0.x, r0.w, r0.x, r0.z - cmp r1, -r0.x, c4.z, r1 - cmp r0, r0.y, r1, c4.z - mov oC0, r0 - - // approximately 28 instruction slots used (2 texture, 26 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[7], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 3 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - add r0.x, r0.x, -cb0[6].x - mul r0.x, r0.x, cb0[5].z - mad r0.x, r0.z, r0.z, -r0.x - lt r0.y, r0.x, l(0.000000) - sqrt r1.x, |r0.x| - mov r1.y, -r1.x - add r0.xz, r0.zzzz, r1.xxyx - div r0.xz, r0.xxzx, cb0[5].zzzz - mul r1.xy, r0.xzxx, cb0[4].zzzz - ge r1.xy, r1.xyxx, -cb0[5].wwww - and r1.xy, r1.xyxx, l(0x3f800000, 0x3f800000, 0, 0) - add r0.x, -r0.z, r0.x - mad r2.x, r1.x, r0.x, r0.z - mov r2.y, l(0.500000) - sample r2.xyzw, r2.xyxx, t0.xyzw, s0 - if_nz r0.y - mov o0.xyzw, l(0,0,0,0) - ret - endif - max r0.x, r1.y, r1.x - ge r0.x, l(0.000000), r0.x - if_nz r0.x - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r2.xyz, r2.wwww, r2.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r2.xyzw - ret - // Approximately 33 instruction slots used - - }; - } - - pass A0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 2 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c2, 0.5, 0, 0, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mul r0.w, c1.w, c1.w - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -r0.w - mul r0.w, r0.w, c2.x - mov r0.z, c1.w - dp3 r0.x, r0, c0 - rcp r0.x, r0.x - mul r0.x, r0.x, r0.w - mov r0.y, c2.x - texld r1, t0, s1 - texld r2, r0, s0 - mov r0.w, c1.w - mad r0.x, r0.x, -c0.z, -r0.w - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - cmp r0, r0.x, c2.y, r1 - mov oC0, r0 - - // approximately 18 instruction slots used (2 texture, 16 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[6], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 2 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - mad r0.x, -cb0[5].w, cb0[5].w, r0.x - mul r0.x, r0.x, l(0.500000) - div r0.x, r0.x, r0.z - mul r0.z, r0.x, cb0[4].z - ge r0.z, -cb0[5].w, r0.z - mov r0.y, l(0.500000) - sample r1.xyzw, r0.xyxx, t0.xyzw, s0 - if_nz r0.z - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r1.xyz, r1.wwww, r1.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r1.xyzw - ret - // Approximately 19 instruction slots used - - }; - } - - pass APosWrap - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sWrapSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 3 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c3, 0.5, 0, 0, 0 - def c4, 1, -1, 0, -0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -c2.x - mul r0.w, r0.w, c1.z - mov r0.z, c1.w - dp3 r0.x, r0, c0 - mad r0.y, r0.x, r0.x, -r0.w - abs r0.z, r0.y - rsq r0.z, r0.z - rcp r1.x, r0.z - mov r1.yz, -r1.x - add r0.xzw, r0.x, r1.xyyz - rcp r1.x, c1.z - mul r0.xzw, r0, r1.x - mov r1.w, c1.w - mad r1.xyz, r0.xzww, c0.z, r1.w - cmp r2.x, r1.x, r0.x, r0.w - cmp r0.xzw, r1.xyyz, c4.xyxy, c4.zyzw - mov r2.y, c3.x - texld r1, t0, s1 - texld r2, r2, s0 - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - add r0.w, r0.w, r0.x - cmp r0.x, r0.w, r0.x, r0.z - cmp r1, -r0.x, c4.z, r1 - cmp r0, r0.y, r1, c4.z - mov oC0, r0 - - // approximately 28 instruction slots used (2 texture, 26 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[7], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 3 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - add r0.x, r0.x, -cb0[6].x - mul r0.x, r0.x, cb0[5].z - mad r0.x, r0.z, r0.z, -r0.x - lt r0.y, r0.x, l(0.000000) - sqrt r1.x, |r0.x| - mov r1.y, -r1.x - add r0.xz, r0.zzzz, r1.xxyx - div r0.xz, r0.xxzx, cb0[5].zzzz - mul r1.xy, r0.xzxx, cb0[4].zzzz - ge r1.xy, r1.xyxx, -cb0[5].wwww - and r1.xy, r1.xyxx, l(0x3f800000, 0x3f800000, 0, 0) - add r0.x, -r0.z, r0.x - mad r2.x, r1.x, r0.x, r0.z - mov r2.y, l(0.500000) - sample r2.xyzw, r2.xyxx, t0.xyzw, s0 - if_nz r0.y - mov o0.xyzw, l(0,0,0,0) - ret - endif - max r0.x, r1.y, r1.x - ge r0.x, l(0.000000), r0.x - if_nz r0.x - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r2.xyz, r2.wwww, r2.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r2.xyzw - ret - // Approximately 33 instruction slots used - - }; - } - - pass A0Wrap - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sWrapSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 2 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c2, 0.5, 0, 0, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mul r0.w, c1.w, c1.w - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -r0.w - mul r0.w, r0.w, c2.x - mov r0.z, c1.w - dp3 r0.x, r0, c0 - rcp r0.x, r0.x - mul r0.x, r0.x, r0.w - mov r0.y, c2.x - texld r1, t0, s1 - texld r2, r0, s0 - mov r0.w, c1.w - mad r0.x, r0.x, -c0.z, -r0.w - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - cmp r0, r0.x, c2.y, r1 - mov oC0, r0 - - // approximately 18 instruction slots used (2 texture, 16 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[6], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 2 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - mad r0.x, -cb0[5].w, cb0[5].w, r0.x - mul r0.x, r0.x, l(0.500000) - div r0.x, r0.x, r0.z - mul r0.z, r0.x, cb0[4].z - ge r0.z, -cb0[5].w, r0.z - mov r0.y, l(0.500000) - sample r1.xyzw, r0.xyxx, t0.xyzw, s0 - if_nz r0.z - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r1.xyz, r1.wwww, r1.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r1.xyzw - ret - // Approximately 19 instruction slots used - - }; - } - - pass APosMirror - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sMirrorSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 3 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c3, 0.5, 0, 0, 0 - def c4, 1, -1, 0, -0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -c2.x - mul r0.w, r0.w, c1.z - mov r0.z, c1.w - dp3 r0.x, r0, c0 - mad r0.y, r0.x, r0.x, -r0.w - abs r0.z, r0.y - rsq r0.z, r0.z - rcp r1.x, r0.z - mov r1.yz, -r1.x - add r0.xzw, r0.x, r1.xyyz - rcp r1.x, c1.z - mul r0.xzw, r0, r1.x - mov r1.w, c1.w - mad r1.xyz, r0.xzww, c0.z, r1.w - cmp r2.x, r1.x, r0.x, r0.w - cmp r0.xzw, r1.xyyz, c4.xyxy, c4.zyzw - mov r2.y, c3.x - texld r1, t0, s1 - texld r2, r2, s0 - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - add r0.w, r0.w, r0.x - cmp r0.x, r0.w, r0.x, r0.z - cmp r1, -r0.x, c4.z, r1 - cmp r0, r0.y, r1, c4.z - mov oC0, r0 - - // approximately 28 instruction slots used (2 texture, 26 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[7], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 3 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - add r0.x, r0.x, -cb0[6].x - mul r0.x, r0.x, cb0[5].z - mad r0.x, r0.z, r0.z, -r0.x - lt r0.y, r0.x, l(0.000000) - sqrt r1.x, |r0.x| - mov r1.y, -r1.x - add r0.xz, r0.zzzz, r1.xxyx - div r0.xz, r0.xxzx, cb0[5].zzzz - mul r1.xy, r0.xzxx, cb0[4].zzzz - ge r1.xy, r1.xyxx, -cb0[5].wwww - and r1.xy, r1.xyxx, l(0x3f800000, 0x3f800000, 0, 0) - add r0.x, -r0.z, r0.x - mad r2.x, r1.x, r0.x, r0.z - mov r2.y, l(0.500000) - sample r2.xyzw, r2.xyxx, t0.xyzw, s0 - if_nz r0.y - mov o0.xyzw, l(0,0,0,0) - ret - endif - max r0.x, r1.y, r1.x - ge r0.x, l(0.000000), r0.x - if_nz r0.x - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r2.xyz, r2.wwww, r2.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r2.xyzw - ret - // Approximately 33 instruction slots used - - }; - } - - pass A0Mirror - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 - // float2 dimensions; // Offset: 48 Size: 8 - // float3 diff; // Offset: 64 Size: 12 [unused] - // float2 center1; // Offset: 80 Size: 8 [unused] - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 [unused] - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // cb2 cbuffer NA NA 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 1 ( FLT, FLT, FLT, FLT) - // c2 cb0 2 1 ( FLT, FLT, FLT, FLT) - // c3 cb1 0 2 ( FLT, FLT, FLT, FLT) - // c5 cb1 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c6, 1, 0.5, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad r0.xy, v0, c1.zwzw, c1 - add r0.z, r0.x, c6.x - mul r0.z, r0.z, c5.x - mul r1.x, r0.z, c6.y - add r0.z, -r0.y, c6.x - add oPos.xy, r0, c0 - mul r0.x, r0.z, c5.y - mul r1.y, r0.x, c6.y - mov r1.z, c6.x - dp3 oT0.w, r1, c3 - dp3 oT0.z, r1, c4 - mov oPos.zw, c6.xyzx - - // approximately 13 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_constantbuffer cb1[4], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - dcl_temps 2 - mov o0.zw, l(0,0,0,1.000000) - mad r0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.xy, r0.xyxx - add r0.x, r0.x, l(1.000000) - add r0.y, -r0.y, l(1.000000) - mul r0.xy, r0.xyxx, cb1[3].xyxx - mul r1.xy, r0.xyxx, l(0.500000, 0.500000, 0.000000, 0.000000) - mov r1.z, l(1.000000) - dp3 o1.z, r1.xyzx, cb1[0].xyzx - dp3 o1.w, r1.xyzx, cb1[1].xyzx - mad o1.xy, v0.xyxx, cb0[2].zwzz, cb0[2].xyxx - ret - // Approximately 12 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb2 - // { - // - // float3x3 DeviceSpaceToUserSpace; // Offset: 0 Size: 44 [unused] - // float2 dimensions; // Offset: 48 Size: 8 [unused] - // float3 diff; // Offset: 64 Size: 12 - // float2 center1; // Offset: 80 Size: 8 - // float A; // Offset: 88 Size: 4 [unused] - // float radius1; // Offset: 92 Size: 4 - // float sq_radius1; // Offset: 96 Size: 4 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sMirrorSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb2 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 4 2 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c2, 0.5, 0, 0, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mul r0.w, c1.w, c1.w - add r0.xy, t0.wzzw, -c1 - dp2add r0.w, r0, r0, -r0.w - mul r0.w, r0.w, c2.x - mov r0.z, c1.w - dp3 r0.x, r0, c0 - rcp r0.x, r0.x - mul r0.x, r0.x, r0.w - mov r0.y, c2.x - texld r1, t0, s1 - texld r2, r0, s0 - mov r0.w, c1.w - mad r0.x, r0.x, -c0.z, -r0.w - mul r2.xyz, r2.w, r2 - mul r1, r1.w, r2 - cmp r0, r0.x, c2.y, r1 - mov oC0, r0 - - // approximately 18 instruction slots used (2 texture, 16 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[6], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 2 - add r0.xy, v1.zwzz, -cb0[5].xyxx - mov r0.z, cb0[5].w - dp3 r0.z, r0.xyzx, cb0[4].xyzx - dp2 r0.x, r0.xyxx, r0.xyxx - mad r0.x, -cb0[5].w, cb0[5].w, r0.x - mul r0.x, r0.x, l(0.500000) - div r0.x, r0.x, r0.z - mul r0.z, r0.x, cb0[4].z - ge r0.z, -cb0[5].w, r0.z - mov r0.y, l(0.500000) - sample r1.xyzw, r0.xyxx, t0.xyzw, s0 - if_nz r0.z - mov o0.xyzw, l(0,0,0,0) - ret - endif - mul r1.xyz, r1.wwww, r1.xyzx - sample r0.xyzw, v1.xyxx, t1.xyzw, s1 - mul o0.xyzw, r0.wwww, r1.xyzw - ret - // Approximately 19 instruction slots used - - }; - } - -} - -technique10 SampleMaskedTexture -{ - pass P0 - { - RasterizerState = TextureRast; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - dcl t0 - dcl_2d s0 - dcl_2d s1 - mov r0.xy, t0.wzzw - texld r1, t0, s0 - texld r0, r0, s1 - mul r0, r0.w, r1 - mov oC0, r0 - - // approximately 5 instruction slots used (2 texture, 3 arithmetic) - ps_4_0 - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 2 - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - sample r1.xyzw, v1.zwzz, t1.xyzw, s1 - mul o0.xyzw, r0.xyzw, r1.wwww - ret - // Approximately 4 instruction slots used - - }; - } - -} - -technique10 SampleTextureWithShadow -{ - pass P0 - { - RasterizerState = TextureRast; - AB_BlendFactor = float4(1, 1, 1, 1); - AB_SampleMask = uint(0xffffffff); - BlendState = ShadowBlendH; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb1 - // { - // - // float4 BlurOffsetsH[3]; // Offset: 0 Size: 48 - // float4 BlurOffsetsV[3]; // Offset: 48 Size: 48 [unused] - // float4 BlurWeights[3]; // Offset: 96 Size: 48 - // float4 ShadowColor; // Offset: 144 Size: 16 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sShadowSampler sampler NA NA 0 1 - // tex texture float4 2d 0 1 - // cb1 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 0 3 ( FLT, FLT, FLT, FLT) - // c3 cb0 6 4 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // - // - // Level9 shader bytecode: - // - ps_2_x - dcl t0 - dcl_2d s0 - add r0.x, t0.x, c0.y - mov r0.y, t0.y - add r1.x, t0.x, c0.x - mov r1.y, t0.y - texld r0, r0, s0 - texld r1, r1, s0 - mul r0.x, r0.w, c3.y - mad r0.x, c3.x, r1.w, r0.x - add r1.x, t0.x, c0.z - mov r1.y, t0.y - add r2.x, t0.x, c0.w - mov r2.y, t0.y - texld r1, r1, s0 - texld r2, r2, s0 - mad r0.x, c3.z, r1.w, r0.x - mad r0.x, c3.w, r2.w, r0.x - add r1.x, t0.x, c1.x - mov r1.y, t0.y - add r2.x, t0.x, c1.y - mov r2.y, t0.y - texld r1, r1, s0 - texld r2, r2, s0 - mad r0.x, c4.x, r1.w, r0.x - mad r0.x, c4.y, r2.w, r0.x - add r1.x, t0.x, c1.z - mov r1.y, t0.y - add r2.x, t0.x, c1.w - mov r2.y, t0.y - texld r1, r1, s0 - texld r2, r2, s0 - mad r0.x, c4.z, r1.w, r0.x - mad r0.x, c4.w, r2.w, r0.x - add r1.x, t0.x, c2.x - mov r1.y, t0.y - texld r1, r1, s0 - mad r0.x, c5.x, r1.w, r0.x - mul r0, r0.x, c6 - mov oC0, r0 - - // approximately 38 instruction slots used (9 texture, 29 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[10], immediateIndexed - dcl_sampler s0, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_temps 4 - add r0.xyzw, v1.xxxx, cb0[0].zxwy - mov r1.xz, r0.yywy - mov r1.yw, v1.yyyy - sample r2.xyzw, r1.zwzz, t0.xyzw, s0 - sample r1.xyzw, r1.xyxx, t0.xyzw, s0 - mul r1.x, r2.w, cb0[6].y - mad r1.x, cb0[6].x, r1.w, r1.x - mov r0.yw, v1.yyyy - sample r2.xyzw, r0.xyxx, t0.xyzw, s0 - sample r0.xyzw, r0.zwzz, t0.xyzw, s0 - mad r0.x, cb0[6].z, r2.w, r1.x - mad r0.x, cb0[6].w, r0.w, r0.x - add r1.xyzw, v1.xxxx, cb0[1].zxwy - mov r2.xz, r1.yywy - mov r2.yw, v1.yyyy - sample r3.xyzw, r2.xyxx, t0.xyzw, s0 - sample r2.xyzw, r2.zwzz, t0.xyzw, s0 - mad r0.x, cb0[7].x, r3.w, r0.x - mad r0.x, cb0[7].y, r2.w, r0.x - mov r1.yw, v1.yyyy - sample r2.xyzw, r1.xyxx, t0.xyzw, s0 - sample r1.xyzw, r1.zwzz, t0.xyzw, s0 - mad r0.x, cb0[7].z, r2.w, r0.x - mad r0.x, cb0[7].w, r1.w, r0.x - add r1.x, v1.x, cb0[2].x - mov r1.y, v1.y - sample r1.xyzw, r1.xyxx, t0.xyzw, s0 - mad r0.x, cb0[8].x, r1.w, r0.x - mul o0.xyzw, r0.xxxx, cb0[9].xyzw - ret - // Approximately 30 instruction slots used - - }; - } - - pass P1 - { - RasterizerState = TextureRast; - AB_BlendFactor = float4(1, 1, 1, 1); - AB_SampleMask = uint(0xffffffff); - BlendState = ShadowBlendV; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb1 - // { - // - // float4 BlurOffsetsH[3]; // Offset: 0 Size: 48 [unused] - // float4 BlurOffsetsV[3]; // Offset: 48 Size: 48 - // float4 BlurWeights[3]; // Offset: 96 Size: 48 - // float4 ShadowColor; // Offset: 144 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sShadowSampler sampler NA NA 0 1 - // tex texture float4 2d 0 1 - // cb1 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 3 6 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // - // - // Level9 shader bytecode: - // - ps_2_x - dcl t0 - dcl_2d s0 - add r0.y, t0.y, c0.y - mov r0.x, t0.x - add r1.y, t0.y, c0.x - mov r1.x, t0.x - texld r0, r0, s0 - texld r1, r1, s0 - mul r0, r0, c3.y - mad r0, c3.x, r1, r0 - add r1.y, t0.y, c0.z - mov r1.x, t0.x - add r2.y, t0.y, c0.w - mov r2.x, t0.x - texld r1, r1, s0 - texld r2, r2, s0 - mad r0, c3.z, r1, r0 - mad r0, c3.w, r2, r0 - add r1.y, t0.y, c1.x - mov r1.x, t0.x - add r2.y, t0.y, c1.y - mov r2.x, t0.x - texld r1, r1, s0 - texld r2, r2, s0 - mad r0, c4.x, r1, r0 - mad r0, c4.y, r2, r0 - add r1.y, t0.y, c1.z - mov r1.x, t0.x - add r2.y, t0.y, c1.w - mov r2.x, t0.x - texld r1, r1, s0 - texld r2, r2, s0 - mad r0, c4.z, r1, r0 - mad r0, c4.w, r2, r0 - add r1.y, t0.y, c2.x - mov r1.x, t0.x - texld r1, r1, s0 - mad r0, c5.x, r1, r0 - mov oC0, r0 - - // approximately 37 instruction slots used (9 texture, 28 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[9], immediateIndexed - dcl_sampler s0, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_temps 4 - mov r0.xz, v1.xxxx - add r1.xyzw, v1.yyyy, cb0[3].xzyw - mov r0.yw, r1.xxxz - sample r2.xyzw, r0.zwzz, t0.xyzw, s0 - sample r0.xyzw, r0.xyxx, t0.xyzw, s0 - mul r2.xyzw, r2.xyzw, cb0[6].yyyy - mad r0.xyzw, cb0[6].xxxx, r0.xyzw, r2.xyzw - mov r1.xz, v1.xxxx - sample r2.xyzw, r1.xyxx, t0.xyzw, s0 - sample r1.xyzw, r1.zwzz, t0.xyzw, s0 - mad r0.xyzw, cb0[6].zzzz, r2.xyzw, r0.xyzw - mad r0.xyzw, cb0[6].wwww, r1.xyzw, r0.xyzw - mov r1.xz, v1.xxxx - add r2.xyzw, v1.yyyy, cb0[4].xzyw - mov r1.yw, r2.xxxz - sample r3.xyzw, r1.xyxx, t0.xyzw, s0 - sample r1.xyzw, r1.zwzz, t0.xyzw, s0 - mad r0.xyzw, cb0[7].xxxx, r3.xyzw, r0.xyzw - mad r0.xyzw, cb0[7].yyyy, r1.xyzw, r0.xyzw - mov r2.xz, v1.xxxx - sample r1.xyzw, r2.xyxx, t0.xyzw, s0 - sample r2.xyzw, r2.zwzz, t0.xyzw, s0 - mad r0.xyzw, cb0[7].zzzz, r1.xyzw, r0.xyzw - mad r0.xyzw, cb0[7].wwww, r2.xyzw, r0.xyzw - add r1.y, v1.y, cb0[5].x - mov r1.x, v1.x - sample r1.xyzw, r1.xyxx, t0.xyzw, s0 - mad o0.xyzw, cb0[8].xxxx, r1.xyzw, r0.xyzw - ret - // Approximately 29 instruction slots used - - }; - } - - pass P2 - { - RasterizerState = TextureRast; - AB_BlendFactor = float4(1, 1, 1, 1); - AB_SampleMask = uint(0xffffffff); - BlendState = ShadowBlendV; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb1 - // { - // - // float4 BlurOffsetsH[3]; // Offset: 0 Size: 48 [unused] - // float4 BlurOffsetsV[3]; // Offset: 48 Size: 48 - // float4 BlurWeights[3]; // Offset: 96 Size: 48 - // float4 ShadowColor; // Offset: 144 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sMaskSampler sampler NA NA 0 1 - // sShadowSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb1 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 3 6 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t1 - // s1 s1 t0 - // - // - // Level9 shader bytecode: - // - ps_2_x - dcl t0 - dcl_2d s0 - dcl_2d s1 - add r0.y, t0.y, c0.y - mov r0.x, t0.x - add r1.y, t0.y, c0.x - mov r1.x, t0.x - texld r0, r0, s1 - texld r1, r1, s1 - mul r0, r0, c3.y - mad r0, c3.x, r1, r0 - add r1.y, t0.y, c0.z - mov r1.x, t0.x - add r2.y, t0.y, c0.w - mov r2.x, t0.x - texld r1, r1, s1 - texld r2, r2, s1 - mad r0, c3.z, r1, r0 - mad r0, c3.w, r2, r0 - add r1.y, t0.y, c1.x - mov r1.x, t0.x - add r2.y, t0.y, c1.y - mov r2.x, t0.x - texld r1, r1, s1 - texld r2, r2, s1 - mad r0, c4.x, r1, r0 - mad r0, c4.y, r2, r0 - add r1.y, t0.y, c1.z - mov r1.x, t0.x - add r2.y, t0.y, c1.w - mov r2.x, t0.x - texld r1, r1, s1 - texld r2, r2, s1 - mad r0, c4.z, r1, r0 - mad r0, c4.w, r2, r0 - add r1.y, t0.y, c2.x - mov r1.x, t0.x - mov r2.xy, t0.wzzw - texld r1, r1, s1 - texld r2, r2, s0 - mad r0, c5.x, r1, r0 - mul r0, r2.w, r0 - mov oC0, r0 - - // approximately 40 instruction slots used (10 texture, 30 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[9], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_temps 4 - mov r0.xz, v1.xxxx - add r1.xyzw, v1.yyyy, cb0[3].xzyw - mov r0.yw, r1.xxxz - sample r2.xyzw, r0.zwzz, t0.xyzw, s1 - sample r0.xyzw, r0.xyxx, t0.xyzw, s1 - mul r2.xyzw, r2.xyzw, cb0[6].yyyy - mad r0.xyzw, cb0[6].xxxx, r0.xyzw, r2.xyzw - mov r1.xz, v1.xxxx - sample r2.xyzw, r1.xyxx, t0.xyzw, s1 - sample r1.xyzw, r1.zwzz, t0.xyzw, s1 - mad r0.xyzw, cb0[6].zzzz, r2.xyzw, r0.xyzw - mad r0.xyzw, cb0[6].wwww, r1.xyzw, r0.xyzw - mov r1.xz, v1.xxxx - add r2.xyzw, v1.yyyy, cb0[4].xzyw - mov r1.yw, r2.xxxz - sample r3.xyzw, r1.xyxx, t0.xyzw, s1 - sample r1.xyzw, r1.zwzz, t0.xyzw, s1 - mad r0.xyzw, cb0[7].xxxx, r3.xyzw, r0.xyzw - mad r0.xyzw, cb0[7].yyyy, r1.xyzw, r0.xyzw - mov r2.xz, v1.xxxx - sample r1.xyzw, r2.xyxx, t0.xyzw, s1 - sample r2.xyzw, r2.zwzz, t0.xyzw, s1 - mad r0.xyzw, cb0[7].zzzz, r1.xyzw, r0.xyzw - mad r0.xyzw, cb0[7].wwww, r2.xyzw, r0.xyzw - add r1.y, v1.y, cb0[5].x - mov r1.x, v1.x - sample r1.xyzw, r1.xyxx, t0.xyzw, s1 - mad r0.xyzw, cb0[8].xxxx, r1.xyzw, r0.xyzw - sample r1.xyzw, v1.zwzz, t1.xyzw, s0 - mul o0.xyzw, r0.xyzw, r1.wwww - ret - // Approximately 31 instruction slots used - - }; - } - -} - -technique10 SampleTextTexture -{ - pass Unmasked - { - RasterizerState = TextureRast; - AB_BlendFactor = float4(0, 0, 0, 0); - AB_SampleMask = uint(0xffffffff); - BlendState = bTextBlend; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 [unused] - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 [unused] - // float4 TextColor; // Offset: 48 Size: 16 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // tex texture float4 2d 0 1 - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // SV_Target 1 xyzw 1 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c1, 1, 0, 0, 0 - dcl t0 - dcl_2d s0 - mov r0.xyz, c0 - mad r0, r0.xyzx, c1.xxxy, c1.yyyx - mov oC0, r0 - texld r0, t0, s0 - mul r0, r0.zyxy, c0.w - mov oC1, r0 - - // approximately 6 instruction slots used (1 texture, 5 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[4], immediateIndexed - dcl_sampler s0, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_input_ps linear v1.xy - dcl_output o0.xyzw - dcl_output o1.xyzw - dcl_temps 1 - mov o0.xyz, cb0[3].xyzx - mov o0.w, l(1.000000) - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - mul o1.xyzw, r0.zyxy, cb0[3].wwww - ret - // Approximately 5 instruction slots used - - }; - } - - pass Masked - { - RasterizerState = TextureRast; - AB_BlendFactor = float4(0, 0, 0, 0); - AB_SampleMask = uint(0xffffffff); - BlendState = bTextBlend; - VertexShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 - // float4 TexCoords; // Offset: 16 Size: 16 - // float4 MaskTexCoords; // Offset: 32 Size: 16 - // float4 TextColor; // Offset: 48 Size: 16 [unused] - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // POSITION 0 xyz 0 NONE float xy - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float xyzw - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c1 cb0 0 3 ( FLT, FLT, FLT, FLT) - // - // - // Runtime generated constant mappings: - // - // Target Reg Constant Description - // ---------- -------------------------------------------------- - // c0 Vertex Shader position offset - // - // - // Level9 shader bytecode: - // - vs_2_x - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mad oT0.xy, v0, c2.zwzw, c2 - mad oT0.zw, v0.xyyx, c3.xywz, c3.xyyx - mad r0.xy, v0, c1.zwzw, c1 - add oPos.xy, r0, c0 - mov oPos.zw, c4.xyxy - - // approximately 5 instruction slots used - vs_4_0 - dcl_constantbuffer cb0[3], immediateIndexed - dcl_input v0.xy - dcl_output_siv o0.xyzw, position - dcl_output o1.xy - dcl_output o1.zw - mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx - mov o0.zw, l(0,0,0,1.000000) - mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx - mad o1.zw, v0.xxxy, cb0[2].zzzw, cb0[2].xxxy - ret - // Approximately 5 instruction slots used - - }; - GeometryShader = NULL; - PixelShader = asm { - // - // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 - // - // - // Buffer Definitions: - // - // cbuffer cb0 - // { - // - // float4 QuadDesc; // Offset: 0 Size: 16 [unused] - // float4 TexCoords; // Offset: 16 Size: 16 [unused] - // float4 MaskTexCoords; // Offset: 32 Size: 16 [unused] - // float4 TextColor; // Offset: 48 Size: 16 - // - // } - // - // - // Resource Bindings: - // - // Name Type Format Dim Slot Elements - // ------------------------------ ---------- ------- ----------- ---- -------- - // sSampler sampler NA NA 0 1 - // sMaskSampler sampler NA NA 1 1 - // tex texture float4 2d 0 1 - // mask texture float4 2d 1 1 - // cb0 cbuffer NA NA 0 1 - // - // - // - // Input signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Position 0 xyzw 0 POS float - // TEXCOORD 0 xy 1 NONE float xy - // TEXCOORD 1 zw 1 NONE float zw - // - // - // Output signature: - // - // Name Index Mask Register SysValue Format Used - // -------------------- ----- ------ -------- -------- ------ ------ - // SV_Target 0 xyzw 0 TARGET float xyzw - // SV_Target 1 xyzw 1 TARGET float xyzw - // - // - // Constant buffer to DX9 shader constant mappings: - // - // Target Reg Buffer Start Reg # of Regs Data Conversion - // ---------- ------- --------- --------- ---------------------- - // c0 cb0 3 1 ( FLT, FLT, FLT, FLT) - // - // - // Sampler/Resource to DX9 shader sampler mappings: - // - // Target Sampler Source Sampler Source Resource - // -------------- --------------- ---------------- - // s0 s0 t0 - // s1 s1 t1 - // - // - // Level9 shader bytecode: - // - ps_2_x - def c1, 1, 0, 0, 0 - dcl t0 - dcl_2d s0 - dcl_2d s1 - mov r0.xyz, c0 - mad r0, r0.xyzx, c1.xxxy, c1.yyyx - mov oC0, r0 - mov r0.xy, t0.wzzw - texld r1, t0, s0 - texld r0, r0, s1 - mul r1, r1.zyxy, c0.w - mul r0, r0.w, r1 - mov oC1, r0 - - // approximately 9 instruction slots used (2 texture, 7 arithmetic) - ps_4_0 - dcl_constantbuffer cb0[4], immediateIndexed - dcl_sampler s0, mode_default - dcl_sampler s1, mode_default - dcl_resource_texture2d (float,float,float,float) t0 - dcl_resource_texture2d (float,float,float,float) t1 - dcl_input_ps linear v1.xy - dcl_input_ps linear v1.zw - dcl_output o0.xyzw - dcl_output o1.xyzw - dcl_temps 2 - mov o0.xyz, cb0[3].xyzx - mov o0.w, l(1.000000) - sample r0.xyzw, v1.xyxx, t0.xyzw, s0 - mul r0.xyzw, r0.zyxy, cb0[3].wwww - sample r1.xyzw, v1.zwzz, t1.xyzw, s1 - mul o1.xyzw, r0.xyzw, r1.wwww - ret - // Approximately 7 instruction slots used - - }; - } - -} - -#endif - -const BYTE d2deffect[] = -{ - 68, 88, 66, 67, 46, 111, - 78, 187, 43, 249, 12, 10, - 72, 253, 154, 62, 41, 62, - 180, 131, 1, 0, 0, 0, - 114, 19, 1, 0, 1, 0, - 0, 0, 36, 0, 0, 0, - 70, 88, 49, 48, 70, 19, - 1, 0, 1, 16, 255, 254, - 4, 0, 0, 0, 16, 0, - 0, 0, 13, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 8, 0, 0, 0, 190, 6, - 1, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 32, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 36, 71, - 108, 111, 98, 97, 108, 115, - 0, 117, 105, 110, 116, 0, - 13, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 16, 0, - 0, 0, 4, 0, 0, 0, - 25, 9, 0, 0, 98, 108, - 101, 110, 100, 111, 112, 0, - 99, 98, 48, 0, 102, 108, - 111, 97, 116, 52, 0, 58, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 16, - 0, 0, 0, 16, 0, 0, - 0, 16, 0, 0, 0, 10, - 33, 0, 0, 81, 117, 97, - 100, 68, 101, 115, 99, 0, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 77, 97, - 115, 107, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 84, 101, 120, 116, 67, 111, - 108, 111, 114, 0, 99, 98, - 49, 0, 58, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 48, 0, - 0, 0, 10, 33, 0, 0, - 66, 108, 117, 114, 79, 102, - 102, 115, 101, 116, 115, 72, - 0, 66, 108, 117, 114, 79, - 102, 102, 115, 101, 116, 115, - 86, 0, 66, 108, 117, 114, - 87, 101, 105, 103, 104, 116, - 115, 0, 83, 104, 97, 100, - 111, 119, 67, 111, 108, 111, - 114, 0, 99, 98, 50, 0, - 102, 108, 111, 97, 116, 51, - 120, 51, 0, 222, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 44, 0, 0, - 0, 48, 0, 0, 0, 36, - 0, 0, 0, 11, 91, 0, - 0, 68, 101, 118, 105, 99, - 101, 83, 112, 97, 99, 101, - 84, 111, 85, 115, 101, 114, - 83, 112, 97, 99, 101, 0, - 102, 108, 111, 97, 116, 50, - 0, 26, 1, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 8, 0, 0, 0, 16, - 0, 0, 0, 8, 0, 0, - 0, 10, 17, 0, 0, 100, - 105, 109, 101, 110, 115, 105, - 111, 110, 115, 0, 102, 108, - 111, 97, 116, 51, 0, 72, - 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 12, - 0, 0, 0, 16, 0, 0, - 0, 12, 0, 0, 0, 10, - 25, 0, 0, 100, 105, 102, - 102, 0, 99, 101, 110, 116, - 101, 114, 49, 0, 102, 108, - 111, 97, 116, 0, 120, 1, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 16, 0, 0, 0, - 4, 0, 0, 0, 9, 9, - 0, 0, 65, 0, 114, 97, - 100, 105, 117, 115, 49, 0, - 115, 113, 95, 114, 97, 100, - 105, 117, 115, 49, 0, 84, - 101, 120, 116, 117, 114, 101, - 50, 68, 0, 175, 1, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 12, 0, 0, - 0, 116, 101, 120, 0, 98, - 99, 107, 116, 101, 120, 0, - 109, 97, 115, 107, 0, 83, - 97, 109, 112, 108, 101, 114, - 83, 116, 97, 116, 101, 0, - 229, 1, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 21, 0, 0, 0, 115, 83, - 97, 109, 112, 108, 101, 114, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 21, 0, 0, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 3, 0, 0, - 0, 115, 66, 99, 107, 83, - 97, 109, 112, 108, 101, 114, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 21, 0, 0, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 3, 0, 0, - 0, 115, 87, 114, 97, 112, - 83, 97, 109, 112, 108, 101, - 114, 0, 1, 0, 0, 0, - 2, 0, 0, 0, 21, 0, - 0, 0, 1, 0, 0, 0, - 2, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, - 2, 0, 0, 0, 1, 0, - 0, 0, 115, 77, 105, 114, - 114, 111, 114, 83, 97, 109, - 112, 108, 101, 114, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 21, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 2, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 2, 0, 0, 0, 115, - 77, 97, 115, 107, 83, 97, - 109, 112, 108, 101, 114, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 21, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 3, 0, 0, 0, - 115, 83, 104, 97, 100, 111, - 119, 83, 97, 109, 112, 108, - 101, 114, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 21, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 4, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 4, - 0, 0, 0, 4, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 82, 97, 115, - 116, 101, 114, 105, 122, 101, - 114, 83, 116, 97, 116, 101, - 0, 87, 3, 0, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 84, - 101, 120, 116, 117, 114, 101, - 82, 97, 115, 116, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 1, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 1, 0, 0, 0, 66, - 108, 101, 110, 100, 83, 116, - 97, 116, 101, 0, 167, 3, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 83, 104, 97, 100, - 111, 119, 66, 108, 101, 110, - 100, 72, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 15, - 0, 0, 0, 83, 104, 97, - 100, 111, 119, 66, 108, 101, - 110, 100, 86, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 2, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 6, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 2, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 6, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 15, 0, 0, 0, 98, 84, - 101, 120, 116, 66, 108, 101, - 110, 100, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 16, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 17, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 18, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 19, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 15, - 0, 0, 0, 83, 97, 109, - 112, 108, 101, 84, 101, 120, - 116, 117, 114, 101, 0, 80, - 48, 0, 68, 4, 0, 0, - 68, 88, 66, 67, 43, 219, - 5, 122, 32, 21, 232, 165, - 63, 89, 201, 32, 133, 13, - 217, 23, 1, 0, 0, 0, - 68, 4, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 248, 0, 0, 0, 244, 1, - 0, 0, 112, 2, 0, 0, - 160, 3, 0, 0, 212, 3, - 0, 0, 65, 111, 110, 57, - 184, 0, 0, 0, 184, 0, - 0, 0, 0, 2, 254, 255, - 132, 0, 0, 0, 52, 0, - 0, 0, 1, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 48, 0, 0, 0, 36, 0, - 1, 0, 48, 0, 0, 0, - 0, 0, 3, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 254, 255, - 81, 0, 0, 5, 4, 0, - 15, 160, 0, 0, 0, 0, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 5, 0, - 0, 128, 0, 0, 15, 144, - 4, 0, 0, 4, 0, 0, - 3, 224, 0, 0, 228, 144, - 2, 0, 238, 160, 2, 0, - 228, 160, 4, 0, 0, 4, - 0, 0, 12, 224, 0, 0, - 20, 144, 3, 0, 180, 160, - 3, 0, 20, 160, 4, 0, - 0, 4, 0, 0, 3, 128, - 0, 0, 228, 144, 1, 0, - 238, 160, 1, 0, 228, 160, - 2, 0, 0, 3, 0, 0, - 3, 192, 0, 0, 228, 128, - 0, 0, 228, 160, 1, 0, - 0, 2, 0, 0, 12, 192, - 4, 0, 68, 160, 255, 255, - 0, 0, 83, 72, 68, 82, - 244, 0, 0, 0, 64, 0, - 1, 0, 61, 0, 0, 0, - 89, 0, 0, 4, 70, 142, - 32, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 95, 0, - 0, 3, 50, 16, 16, 0, - 0, 0, 0, 0, 103, 0, - 0, 4, 242, 32, 16, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 50, 32, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 194, 32, 16, 0, 1, 0, - 0, 0, 50, 0, 0, 11, - 50, 32, 16, 0, 0, 0, - 0, 0, 70, 16, 16, 0, - 0, 0, 0, 0, 230, 138, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 70, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, - 0, 8, 194, 32, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 128, 63, - 50, 0, 0, 11, 50, 32, - 16, 0, 1, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 50, 0, 0, 11, - 194, 32, 16, 0, 1, 0, - 0, 0, 6, 20, 16, 0, - 0, 0, 0, 0, 166, 142, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 6, 132, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 62, 0, - 0, 1, 83, 84, 65, 84, - 116, 0, 0, 0, 5, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 40, 1, - 0, 0, 1, 0, 0, 0, - 64, 0, 0, 0, 1, 0, - 0, 0, 28, 0, 0, 0, - 0, 4, 254, 255, 0, 129, - 0, 0, 246, 0, 0, 0, - 60, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 99, 98, 48, 0, - 60, 0, 0, 0, 4, 0, - 0, 0, 88, 0, 0, 0, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 184, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 196, 0, - 0, 0, 0, 0, 0, 0, - 212, 0, 0, 0, 16, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 196, 0, - 0, 0, 0, 0, 0, 0, - 222, 0, 0, 0, 32, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 196, 0, - 0, 0, 0, 0, 0, 0, - 236, 0, 0, 0, 48, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 196, 0, - 0, 0, 0, 0, 0, 0, - 81, 117, 97, 100, 68, 101, - 115, 99, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 77, 97, 115, 107, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 84, 101, - 120, 116, 67, 111, 108, 111, - 114, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 57, 46, 50, 57, 46, - 57, 53, 50, 46, 51, 49, - 49, 49, 0, 171, 73, 83, - 71, 78, 44, 0, 0, 0, - 1, 0, 0, 0, 8, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 7, 3, - 0, 0, 80, 79, 83, 73, - 84, 73, 79, 78, 0, 171, - 171, 171, 79, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 12, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 3, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 232, 4, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 212, 2, 0, 0, - 68, 88, 66, 67, 49, 216, - 1, 9, 139, 250, 199, 147, - 128, 100, 93, 201, 53, 248, - 147, 65, 1, 0, 0, 0, - 212, 2, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 164, 0, 0, 0, 16, 1, - 0, 0, 140, 1, 0, 0, - 48, 2, 0, 0, 160, 2, - 0, 0, 65, 111, 110, 57, - 100, 0, 0, 0, 100, 0, - 0, 0, 0, 2, 255, 255, - 60, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 40, 0, - 0, 0, 40, 0, 0, 0, - 40, 0, 1, 0, 36, 0, - 0, 0, 40, 0, 0, 0, - 0, 0, 1, 2, 255, 255, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 15, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 176, - 0, 8, 228, 160, 1, 0, - 0, 2, 0, 8, 15, 128, - 0, 0, 228, 128, 255, 255, - 0, 0, 83, 72, 68, 82, - 100, 0, 0, 0, 64, 0, - 0, 0, 25, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 98, 16, - 0, 3, 50, 16, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 242, 32, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 32, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 62, 0, - 0, 1, 83, 84, 65, 84, - 116, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 156, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 28, 0, 0, 0, - 0, 4, 255, 255, 0, 129, - 0, 0, 105, 0, 0, 0, - 92, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 101, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 115, 83, - 97, 109, 112, 108, 101, 114, - 0, 116, 101, 120, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 57, 46, 57, 53, 50, - 46, 51, 49, 49, 49, 0, - 171, 171, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 3, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 97, 114, 103, 101, - 116, 0, 171, 171, 68, 9, - 0, 0, 0, 0, 0, 0, - 83, 97, 109, 112, 108, 101, - 84, 101, 120, 116, 117, 114, - 101, 70, 111, 114, 83, 101, - 112, 97, 114, 97, 98, 108, - 101, 66, 108, 101, 110, 100, - 105, 110, 103, 95, 49, 0, - 68, 4, 0, 0, 68, 88, - 66, 67, 43, 219, 5, 122, - 32, 21, 232, 165, 63, 89, - 201, 32, 133, 13, 217, 23, - 1, 0, 0, 0, 68, 4, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 248, 0, - 0, 0, 244, 1, 0, 0, - 112, 2, 0, 0, 160, 3, - 0, 0, 212, 3, 0, 0, - 65, 111, 110, 57, 184, 0, - 0, 0, 184, 0, 0, 0, - 0, 2, 254, 255, 132, 0, - 0, 0, 52, 0, 0, 0, - 1, 0, 36, 0, 0, 0, - 48, 0, 0, 0, 48, 0, - 0, 0, 36, 0, 1, 0, - 48, 0, 0, 0, 0, 0, - 3, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 254, 255, 81, 0, - 0, 5, 4, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 4, 0, - 0, 4, 0, 0, 3, 224, - 0, 0, 228, 144, 2, 0, - 238, 160, 2, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 12, 224, 0, 0, 20, 144, - 3, 0, 180, 160, 3, 0, - 20, 160, 4, 0, 0, 4, - 0, 0, 3, 128, 0, 0, - 228, 144, 1, 0, 238, 160, - 1, 0, 228, 160, 2, 0, - 0, 3, 0, 0, 3, 192, - 0, 0, 228, 128, 0, 0, - 228, 160, 1, 0, 0, 2, - 0, 0, 12, 192, 4, 0, - 68, 160, 255, 255, 0, 0, - 83, 72, 68, 82, 244, 0, - 0, 0, 64, 0, 1, 0, - 61, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 95, 0, 0, 3, - 50, 16, 16, 0, 0, 0, - 0, 0, 103, 0, 0, 4, - 242, 32, 16, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 50, 32, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 194, 32, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 50, 32, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 8, - 194, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 50, 0, - 0, 11, 50, 32, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 194, 32, - 16, 0, 1, 0, 0, 0, - 6, 20, 16, 0, 0, 0, - 0, 0, 166, 142, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 6, 132, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 40, 1, 0, 0, - 1, 0, 0, 0, 64, 0, - 0, 0, 1, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 254, 255, 0, 129, 0, 0, - 246, 0, 0, 0, 60, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 99, 98, 48, 0, 60, 0, - 0, 0, 4, 0, 0, 0, - 88, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 212, 0, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 222, 0, - 0, 0, 32, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 236, 0, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 81, 117, - 97, 100, 68, 101, 115, 99, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 77, 97, 115, 107, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 84, 101, 120, 116, - 67, 111, 108, 111, 114, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 171, 73, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 7, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 171, 171, 171, - 79, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 12, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 3, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 72, 12, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 68, 13, 0, 0, 68, 88, - 66, 67, 180, 179, 174, 166, - 206, 181, 80, 74, 110, 159, - 145, 158, 201, 171, 12, 93, - 1, 0, 0, 0, 68, 13, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 128, 4, - 0, 0, 184, 10, 0, 0, - 52, 11, 0, 0, 160, 12, - 0, 0, 16, 13, 0, 0, - 65, 111, 110, 57, 64, 4, - 0, 0, 64, 4, 0, 0, - 0, 2, 255, 255, 8, 4, - 0, 0, 56, 0, 0, 0, - 1, 0, 44, 0, 0, 0, - 56, 0, 0, 0, 56, 0, - 2, 0, 36, 0, 0, 0, - 56, 0, 0, 0, 0, 0, - 1, 1, 1, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 1, 2, - 255, 255, 81, 0, 0, 5, - 1, 0, 15, 160, 0, 0, - 128, 191, 0, 0, 0, 192, - 0, 0, 64, 192, 0, 0, - 128, 192, 81, 0, 0, 5, - 2, 0, 15, 160, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 63, 0, 0, - 0, 192, 81, 0, 0, 5, - 3, 0, 15, 160, 0, 0, - 160, 192, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 1, 0, 0, 2, - 0, 0, 8, 128, 0, 0, - 0, 160, 2, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 255, 128, 3, 0, 0, 160, - 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 0, 128, - 0, 0, 0, 128, 66, 0, - 0, 3, 1, 0, 15, 128, - 0, 0, 228, 176, 0, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 0, 0, - 228, 176, 1, 8, 228, 160, - 6, 0, 0, 2, 0, 0, - 2, 128, 2, 0, 255, 128, - 5, 0, 0, 3, 3, 0, - 7, 128, 0, 0, 85, 128, - 2, 0, 228, 128, 5, 0, - 0, 3, 4, 0, 7, 128, - 3, 0, 228, 128, 3, 0, - 228, 128, 88, 0, 0, 4, - 4, 0, 7, 128, 4, 0, - 228, 129, 2, 0, 85, 160, - 2, 0, 0, 160, 4, 0, - 0, 4, 5, 0, 15, 128, - 2, 0, 36, 128, 0, 0, - 85, 129, 2, 0, 42, 160, - 4, 0, 0, 4, 0, 0, - 6, 128, 2, 0, 228, 128, - 0, 0, 85, 129, 2, 0, - 0, 160, 6, 0, 0, 2, - 3, 0, 8, 128, 1, 0, - 255, 128, 5, 0, 0, 3, - 2, 0, 7, 128, 1, 0, - 228, 128, 3, 0, 255, 128, - 6, 0, 0, 2, 4, 0, - 8, 128, 2, 0, 0, 128, - 4, 0, 0, 4, 4, 0, - 8, 128, 5, 0, 255, 128, - 4, 0, 255, 129, 2, 0, - 0, 160, 11, 0, 0, 3, - 5, 0, 8, 128, 4, 0, - 255, 128, 2, 0, 85, 160, - 88, 0, 0, 4, 6, 0, - 1, 128, 2, 0, 0, 129, - 4, 0, 0, 128, 5, 0, - 255, 128, 6, 0, 0, 2, - 5, 0, 8, 128, 2, 0, - 85, 128, 4, 0, 0, 4, - 5, 0, 8, 128, 0, 0, - 85, 128, 5, 0, 255, 129, - 2, 0, 0, 160, 11, 0, - 0, 3, 6, 0, 8, 128, - 5, 0, 255, 128, 2, 0, - 85, 160, 88, 0, 0, 4, - 6, 0, 2, 128, 2, 0, - 85, 129, 4, 0, 85, 128, - 6, 0, 255, 128, 6, 0, - 0, 2, 5, 0, 8, 128, - 2, 0, 170, 128, 4, 0, - 0, 4, 5, 0, 8, 128, - 0, 0, 170, 128, 5, 0, - 255, 129, 2, 0, 0, 160, - 11, 0, 0, 3, 6, 0, - 8, 128, 5, 0, 255, 128, - 2, 0, 85, 160, 88, 0, - 0, 4, 6, 0, 4, 128, - 2, 0, 170, 129, 4, 0, - 170, 128, 6, 0, 255, 128, - 11, 0, 0, 3, 4, 0, - 7, 128, 2, 0, 228, 128, - 3, 0, 228, 128, 88, 0, - 0, 4, 0, 0, 7, 128, - 0, 0, 0, 129, 4, 0, - 228, 128, 6, 0, 228, 128, - 2, 0, 0, 3, 4, 0, - 15, 128, 0, 0, 255, 128, - 1, 0, 228, 160, 5, 0, - 0, 3, 4, 0, 15, 128, - 4, 0, 228, 128, 4, 0, - 228, 128, 10, 0, 0, 3, - 6, 0, 7, 128, 3, 0, - 228, 128, 2, 0, 228, 128, - 88, 0, 0, 4, 0, 0, - 7, 128, 4, 0, 255, 129, - 6, 0, 228, 128, 0, 0, - 228, 128, 4, 0, 0, 4, - 6, 0, 7, 128, 3, 0, - 228, 128, 2, 0, 255, 161, - 2, 0, 0, 161, 2, 0, - 0, 3, 6, 0, 7, 128, - 6, 0, 228, 129, 2, 0, - 0, 160, 4, 0, 0, 4, - 7, 0, 7, 128, 1, 0, - 228, 128, 3, 0, 255, 129, - 2, 0, 0, 160, 4, 0, - 0, 4, 8, 0, 7, 128, - 1, 0, 228, 128, 3, 0, - 255, 128, 3, 0, 228, 128, - 4, 0, 0, 4, 8, 0, - 7, 128, 2, 0, 228, 128, - 3, 0, 228, 129, 8, 0, - 228, 128, 4, 0, 0, 4, - 6, 0, 7, 128, 7, 0, - 228, 128, 6, 0, 228, 129, - 2, 0, 0, 160, 2, 0, - 0, 3, 7, 0, 7, 128, - 3, 0, 228, 128, 3, 0, - 228, 128, 5, 0, 0, 3, - 3, 0, 7, 128, 3, 0, - 228, 128, 2, 0, 228, 128, - 5, 0, 0, 3, 7, 0, - 7, 128, 2, 0, 228, 128, - 7, 0, 228, 128, 88, 0, - 0, 4, 5, 0, 7, 128, - 5, 0, 228, 128, 7, 0, - 228, 128, 6, 0, 228, 128, - 88, 0, 0, 4, 0, 0, - 7, 128, 4, 0, 170, 129, - 5, 0, 228, 128, 0, 0, - 228, 128, 88, 0, 0, 4, - 0, 0, 7, 128, 4, 0, - 85, 129, 8, 0, 228, 128, - 0, 0, 228, 128, 88, 0, - 0, 4, 0, 0, 7, 128, - 4, 0, 0, 129, 3, 0, - 228, 128, 0, 0, 228, 128, - 18, 0, 0, 4, 3, 0, - 7, 128, 2, 0, 255, 128, - 0, 0, 228, 128, 2, 0, - 228, 128, 5, 0, 0, 3, - 3, 0, 8, 128, 2, 0, - 255, 128, 2, 0, 255, 128, - 88, 0, 0, 4, 3, 0, - 8, 128, 3, 0, 255, 129, - 2, 0, 0, 160, 2, 0, - 85, 160, 5, 0, 0, 3, - 0, 0, 7, 128, 1, 0, - 255, 128, 3, 0, 228, 128, - 5, 0, 0, 3, 0, 0, - 8, 128, 1, 0, 255, 128, - 1, 0, 255, 128, 88, 0, - 0, 4, 0, 0, 8, 128, - 0, 0, 255, 129, 2, 0, - 0, 160, 2, 0, 85, 160, - 2, 0, 0, 3, 0, 0, - 8, 128, 3, 0, 255, 128, - 0, 0, 255, 128, 88, 0, - 0, 4, 1, 0, 7, 128, - 0, 0, 255, 129, 0, 0, - 228, 128, 1, 0, 228, 128, - 1, 0, 0, 2, 0, 8, - 15, 128, 1, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 48, 6, 0, 0, - 64, 0, 0, 0, 140, 1, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 1, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 104, 0, 0, 2, - 7, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 1, 0, - 0, 0, 0, 96, 16, 0, - 1, 0, 0, 0, 24, 0, - 0, 7, 18, 0, 16, 0, - 2, 0, 0, 0, 58, 0, - 16, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 0, 24, 0, 0, 7, - 34, 0, 16, 0, 2, 0, - 0, 0, 58, 0, 16, 0, - 1, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 0, 0, - 60, 0, 0, 7, 18, 0, - 16, 0, 2, 0, 0, 0, - 26, 0, 16, 0, 2, 0, - 0, 0, 10, 0, 16, 0, - 2, 0, 0, 0, 31, 0, - 4, 3, 10, 0, 16, 0, - 2, 0, 0, 0, 54, 0, - 0, 5, 242, 32, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 62, 0, 0, 1, 21, 0, - 0, 1, 14, 0, 0, 7, - 114, 0, 16, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 0, 0, 0, 0, - 14, 0, 0, 7, 114, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 246, 15, 16, 0, - 1, 0, 0, 0, 32, 0, - 0, 8, 18, 0, 16, 0, - 2, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 1, 0, 0, 0, - 31, 0, 4, 3, 10, 0, - 16, 0, 2, 0, 0, 0, - 56, 0, 0, 7, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 18, 0, - 0, 1, 32, 0, 0, 8, - 130, 0, 16, 0, 2, 0, - 0, 0, 10, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 2, 0, 0, 0, 31, 0, - 4, 3, 58, 0, 16, 0, - 2, 0, 0, 0, 0, 0, - 0, 7, 114, 0, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 50, 0, 0, 10, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 18, 0, 0, 1, 32, 0, - 0, 8, 130, 0, 16, 0, - 2, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 3, 0, 0, 0, - 31, 0, 4, 3, 58, 0, - 16, 0, 2, 0, 0, 0, - 29, 0, 0, 10, 114, 0, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 63, 0, 0, 0, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 0, 0, - 0, 7, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 50, 0, 0, 15, 114, 0, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 64, 0, 0, - 0, 64, 0, 0, 0, 64, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 191, - 0, 0, 128, 191, 0, 0, - 128, 191, 0, 0, 0, 0, - 0, 0, 0, 11, 114, 0, - 16, 0, 6, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 11, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 5, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 0, 0, 50, 0, - 0, 13, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 128, 65, 0, 0, 0, - 6, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 55, 0, 0, 9, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 5, 0, - 0, 0, 18, 0, 0, 1, - 32, 0, 0, 8, 130, 0, - 16, 0, 2, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 4, 0, - 0, 0, 31, 0, 4, 3, - 58, 0, 16, 0, 2, 0, - 0, 0, 51, 0, 0, 7, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 18, 0, 0, 1, 32, 0, - 0, 8, 130, 0, 16, 0, - 2, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 5, 0, 0, 0, - 52, 0, 0, 7, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 49, 0, - 0, 10, 114, 0, 16, 0, - 4, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 11, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 0, 0, 14, 0, - 0, 7, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 51, 0, 0, 10, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 5, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 11, 114, 0, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 57, 0, 0, 10, - 114, 0, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 1, 0, 0, 10, 114, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 55, 0, - 0, 9, 114, 0, 16, 0, - 2, 0, 0, 0, 246, 15, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 21, 0, - 0, 1, 21, 0, 0, 1, - 21, 0, 0, 1, 21, 0, - 0, 1, 0, 0, 0, 8, - 18, 0, 16, 0, 1, 0, - 0, 0, 58, 0, 16, 128, - 65, 0, 0, 0, 1, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 56, 0, - 0, 7, 226, 0, 16, 0, - 1, 0, 0, 0, 246, 15, - 16, 0, 1, 0, 0, 0, - 6, 9, 16, 0, 2, 0, - 0, 0, 50, 0, 0, 9, - 114, 0, 16, 0, 0, 0, - 0, 0, 6, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 150, 7, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 114, 32, 16, 0, 0, 0, - 0, 0, 246, 15, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 130, 32, - 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 0, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 56, 0, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 21, 0, 0, 0, 5, 0, - 0, 0, 2, 0, 0, 0, - 6, 0, 0, 0, 5, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 18, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 100, 1, 0, 0, - 1, 0, 0, 0, 232, 0, - 0, 0, 5, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 255, 255, 0, 129, 0, 0, - 48, 1, 0, 0, 188, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 197, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 209, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 213, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 1, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 220, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 115, 83, 97, 109, - 112, 108, 101, 114, 0, 115, - 66, 99, 107, 83, 97, 109, - 112, 108, 101, 114, 0, 116, - 101, 120, 0, 98, 99, 107, - 116, 101, 120, 0, 36, 71, - 108, 111, 98, 97, 108, 115, - 0, 171, 171, 171, 220, 0, - 0, 0, 1, 0, 0, 0, - 0, 1, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 24, 1, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 32, 1, 0, 0, - 0, 0, 0, 0, 98, 108, - 101, 110, 100, 111, 112, 0, - 0, 0, 19, 0, 1, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 171, - 171, 171, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 3, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 97, 114, 103, 101, - 116, 0, 171, 171, 164, 16, - 0, 0, 0, 0, 0, 0, - 83, 97, 109, 112, 108, 101, - 84, 101, 120, 116, 117, 114, - 101, 70, 111, 114, 83, 101, - 112, 97, 114, 97, 98, 108, - 101, 66, 108, 101, 110, 100, - 105, 110, 103, 95, 50, 0, - 68, 4, 0, 0, 68, 88, - 66, 67, 43, 219, 5, 122, - 32, 21, 232, 165, 63, 89, - 201, 32, 133, 13, 217, 23, - 1, 0, 0, 0, 68, 4, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 248, 0, - 0, 0, 244, 1, 0, 0, - 112, 2, 0, 0, 160, 3, - 0, 0, 212, 3, 0, 0, - 65, 111, 110, 57, 184, 0, - 0, 0, 184, 0, 0, 0, - 0, 2, 254, 255, 132, 0, - 0, 0, 52, 0, 0, 0, - 1, 0, 36, 0, 0, 0, - 48, 0, 0, 0, 48, 0, - 0, 0, 36, 0, 1, 0, - 48, 0, 0, 0, 0, 0, - 3, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 254, 255, 81, 0, - 0, 5, 4, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 4, 0, - 0, 4, 0, 0, 3, 224, - 0, 0, 228, 144, 2, 0, - 238, 160, 2, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 12, 224, 0, 0, 20, 144, - 3, 0, 180, 160, 3, 0, - 20, 160, 4, 0, 0, 4, - 0, 0, 3, 128, 0, 0, - 228, 144, 1, 0, 238, 160, - 1, 0, 228, 160, 2, 0, - 0, 3, 0, 0, 3, 192, - 0, 0, 228, 128, 0, 0, - 228, 160, 1, 0, 0, 2, - 0, 0, 12, 192, 4, 0, - 68, 160, 255, 255, 0, 0, - 83, 72, 68, 82, 244, 0, - 0, 0, 64, 0, 1, 0, - 61, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 95, 0, 0, 3, - 50, 16, 16, 0, 0, 0, - 0, 0, 103, 0, 0, 4, - 242, 32, 16, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 50, 32, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 194, 32, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 50, 32, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 8, - 194, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 50, 0, - 0, 11, 50, 32, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 194, 32, - 16, 0, 1, 0, 0, 0, - 6, 20, 16, 0, 0, 0, - 0, 0, 166, 142, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 6, 132, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 40, 1, 0, 0, - 1, 0, 0, 0, 64, 0, - 0, 0, 1, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 254, 255, 0, 129, 0, 0, - 246, 0, 0, 0, 60, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 99, 98, 48, 0, 60, 0, - 0, 0, 4, 0, 0, 0, - 88, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 212, 0, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 222, 0, - 0, 0, 32, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 236, 0, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 81, 117, - 97, 100, 68, 101, 115, 99, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 77, 97, 115, 107, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 84, 101, 120, 116, - 67, 111, 108, 111, 114, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 171, 73, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 7, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 171, 171, 171, - 79, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 12, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 3, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 24, 30, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 248, 16, 0, 0, 68, 88, - 66, 67, 151, 251, 133, 70, - 33, 144, 133, 159, 10, 71, - 213, 0, 66, 117, 44, 234, - 1, 0, 0, 0, 248, 16, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 12, 6, - 0, 0, 108, 14, 0, 0, - 232, 14, 0, 0, 84, 16, - 0, 0, 196, 16, 0, 0, - 65, 111, 110, 57, 204, 5, - 0, 0, 204, 5, 0, 0, - 0, 2, 255, 255, 148, 5, - 0, 0, 56, 0, 0, 0, - 1, 0, 44, 0, 0, 0, - 56, 0, 0, 0, 56, 0, - 2, 0, 36, 0, 0, 0, - 56, 0, 0, 0, 0, 0, - 1, 1, 1, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 1, 2, - 255, 255, 81, 0, 0, 5, - 1, 0, 15, 160, 0, 0, - 224, 192, 0, 0, 0, 193, - 0, 0, 16, 193, 0, 0, - 32, 193, 81, 0, 0, 5, - 2, 0, 15, 160, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 128, 62, 0, 0, - 0, 63, 81, 0, 0, 5, - 3, 0, 15, 160, 0, 0, - 0, 64, 0, 0, 128, 191, - 0, 0, 128, 65, 0, 0, - 64, 193, 81, 0, 0, 5, - 4, 0, 15, 160, 0, 0, - 128, 64, 0, 0, 0, 64, - 0, 0, 128, 63, 0, 0, - 0, 0, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 1, 0, 0, 2, - 0, 0, 8, 128, 0, 0, - 0, 160, 2, 0, 0, 3, - 0, 0, 15, 128, 0, 0, - 255, 128, 1, 0, 228, 160, - 5, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 128, - 0, 0, 228, 128, 66, 0, - 0, 3, 1, 0, 15, 128, - 0, 0, 228, 176, 0, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 0, 0, - 228, 176, 1, 8, 228, 160, - 6, 0, 0, 2, 3, 0, - 8, 128, 2, 0, 255, 128, - 4, 0, 0, 4, 3, 0, - 3, 128, 2, 0, 233, 128, - 3, 0, 255, 129, 2, 0, - 170, 160, 5, 0, 0, 3, - 4, 0, 7, 128, 2, 0, - 228, 128, 3, 0, 255, 128, - 4, 0, 0, 4, 5, 0, - 7, 128, 4, 0, 228, 128, - 3, 0, 170, 160, 3, 0, - 255, 160, 4, 0, 0, 4, - 5, 0, 7, 128, 5, 0, - 228, 128, 4, 0, 228, 128, - 4, 0, 0, 160, 5, 0, - 0, 3, 5, 0, 7, 128, - 4, 0, 228, 128, 5, 0, - 228, 128, 7, 0, 0, 2, - 4, 0, 8, 128, 4, 0, - 85, 128, 6, 0, 0, 2, - 4, 0, 8, 128, 4, 0, - 255, 128, 88, 0, 0, 4, - 4, 0, 8, 128, 3, 0, - 0, 128, 5, 0, 85, 128, - 4, 0, 255, 128, 4, 0, - 0, 4, 4, 0, 8, 128, - 2, 0, 85, 128, 3, 0, - 255, 129, 4, 0, 255, 128, - 6, 0, 0, 2, 3, 0, - 1, 128, 1, 0, 255, 128, - 5, 0, 0, 3, 6, 0, - 7, 128, 1, 0, 228, 128, - 3, 0, 0, 128, 4, 0, - 0, 4, 7, 0, 7, 128, - 6, 0, 228, 128, 3, 0, - 0, 160, 3, 0, 85, 160, - 4, 0, 0, 4, 4, 0, - 8, 128, 7, 0, 85, 128, - 4, 0, 255, 128, 4, 0, - 85, 128, 4, 0, 0, 4, - 8, 0, 7, 128, 1, 0, - 228, 128, 3, 0, 0, 129, - 2, 0, 255, 160, 4, 0, - 0, 4, 9, 0, 15, 128, - 2, 0, 36, 128, 3, 0, - 255, 129, 2, 0, 128, 160, - 4, 0, 0, 4, 10, 0, - 7, 128, 6, 0, 228, 128, - 4, 0, 85, 161, 4, 0, - 170, 160, 5, 0, 0, 3, - 10, 0, 7, 128, 4, 0, - 228, 128, 10, 0, 228, 128, - 4, 0, 0, 4, 10, 0, - 7, 128, 10, 0, 228, 128, - 9, 0, 228, 129, 4, 0, - 228, 128, 88, 0, 0, 4, - 11, 0, 2, 128, 8, 0, - 85, 128, 10, 0, 85, 128, - 4, 0, 255, 128, 7, 0, - 0, 2, 4, 0, 8, 128, - 4, 0, 170, 128, 6, 0, - 0, 2, 4, 0, 8, 128, - 4, 0, 255, 128, 88, 0, - 0, 4, 4, 0, 8, 128, - 3, 0, 85, 128, 5, 0, - 170, 128, 4, 0, 255, 128, - 4, 0, 0, 4, 4, 0, - 8, 128, 2, 0, 170, 128, - 3, 0, 255, 129, 4, 0, - 255, 128, 4, 0, 0, 4, - 4, 0, 8, 128, 7, 0, - 170, 128, 4, 0, 255, 128, - 4, 0, 170, 128, 88, 0, - 0, 4, 11, 0, 4, 128, - 8, 0, 170, 128, 10, 0, - 170, 128, 4, 0, 255, 128, - 7, 0, 0, 2, 4, 0, - 8, 128, 4, 0, 0, 128, - 6, 0, 0, 2, 4, 0, - 8, 128, 4, 0, 255, 128, - 88, 0, 0, 4, 4, 0, - 8, 128, 9, 0, 255, 128, - 5, 0, 0, 128, 4, 0, - 255, 128, 4, 0, 0, 4, - 4, 0, 8, 128, 2, 0, - 0, 128, 3, 0, 255, 129, - 4, 0, 255, 128, 4, 0, - 0, 4, 4, 0, 8, 128, - 7, 0, 0, 128, 4, 0, - 255, 128, 4, 0, 0, 128, - 2, 0, 0, 3, 2, 0, - 7, 128, 7, 0, 228, 129, - 2, 0, 0, 160, 4, 0, - 0, 4, 2, 0, 7, 128, - 9, 0, 228, 128, 2, 0, - 228, 129, 2, 0, 0, 160, - 88, 0, 0, 4, 11, 0, - 1, 128, 8, 0, 0, 128, - 10, 0, 0, 128, 4, 0, - 255, 128, 4, 0, 0, 4, - 3, 0, 14, 128, 1, 0, - 144, 128, 3, 0, 0, 128, - 4, 0, 144, 129, 4, 0, - 0, 4, 5, 0, 7, 128, - 1, 0, 228, 128, 3, 0, - 0, 128, 4, 0, 228, 128, - 35, 0, 0, 2, 3, 0, - 7, 128, 3, 0, 249, 128, - 5, 0, 0, 3, 7, 0, - 7, 128, 4, 0, 228, 128, - 6, 0, 228, 128, 4, 0, - 0, 4, 5, 0, 7, 128, - 7, 0, 228, 128, 3, 0, - 0, 161, 5, 0, 228, 128, - 88, 0, 0, 4, 3, 0, - 7, 128, 0, 0, 255, 129, - 3, 0, 228, 128, 5, 0, - 228, 128, 88, 0, 0, 4, - 3, 0, 7, 128, 0, 0, - 170, 129, 11, 0, 228, 128, - 3, 0, 228, 128, 2, 0, - 0, 3, 5, 0, 7, 128, - 6, 0, 228, 128, 6, 0, - 228, 128, 5, 0, 0, 3, - 5, 0, 7, 128, 4, 0, - 228, 128, 5, 0, 228, 128, - 5, 0, 0, 3, 4, 0, - 7, 128, 4, 0, 228, 128, - 4, 0, 228, 128, 88, 0, - 0, 4, 4, 0, 7, 128, - 4, 0, 228, 129, 2, 0, - 85, 160, 2, 0, 0, 160, - 88, 0, 0, 4, 2, 0, - 7, 128, 8, 0, 228, 128, - 5, 0, 228, 128, 2, 0, - 228, 128, 88, 0, 0, 4, - 0, 0, 14, 128, 0, 0, - 85, 129, 2, 0, 144, 128, - 3, 0, 144, 128, 6, 0, - 0, 2, 4, 0, 8, 128, - 6, 0, 0, 128, 4, 0, - 0, 4, 4, 0, 8, 128, - 9, 0, 0, 128, 4, 0, - 255, 129, 2, 0, 0, 160, - 11, 0, 0, 3, 6, 0, - 8, 128, 4, 0, 255, 128, - 2, 0, 85, 160, 88, 0, - 0, 4, 2, 0, 1, 128, - 6, 0, 0, 129, 4, 0, - 0, 128, 6, 0, 255, 128, - 6, 0, 0, 2, 6, 0, - 8, 128, 6, 0, 85, 128, - 4, 0, 0, 4, 6, 0, - 8, 128, 9, 0, 85, 128, - 6, 0, 255, 129, 2, 0, - 0, 160, 11, 0, 0, 3, - 3, 0, 1, 128, 6, 0, - 255, 128, 2, 0, 85, 160, - 88, 0, 0, 4, 2, 0, - 2, 128, 6, 0, 85, 129, - 4, 0, 85, 128, 3, 0, - 0, 128, 6, 0, 0, 2, - 6, 0, 8, 128, 6, 0, - 170, 128, 4, 0, 0, 4, - 6, 0, 8, 128, 9, 0, - 170, 128, 6, 0, 255, 129, - 2, 0, 0, 160, 11, 0, - 0, 3, 3, 0, 1, 128, - 6, 0, 255, 128, 2, 0, - 85, 160, 88, 0, 0, 4, - 2, 0, 4, 128, 6, 0, - 170, 129, 4, 0, 170, 128, - 3, 0, 0, 128, 88, 0, - 0, 4, 0, 0, 7, 128, - 0, 0, 0, 129, 2, 0, - 228, 128, 0, 0, 249, 128, - 18, 0, 0, 4, 3, 0, - 7, 128, 2, 0, 255, 128, - 0, 0, 228, 128, 6, 0, - 228, 128, 5, 0, 0, 3, - 3, 0, 8, 128, 2, 0, - 255, 128, 2, 0, 255, 128, - 88, 0, 0, 4, 3, 0, - 8, 128, 3, 0, 255, 129, - 2, 0, 0, 160, 2, 0, - 85, 160, 5, 0, 0, 3, - 0, 0, 7, 128, 1, 0, - 255, 128, 3, 0, 228, 128, - 5, 0, 0, 3, 0, 0, - 8, 128, 1, 0, 255, 128, - 1, 0, 255, 128, 88, 0, - 0, 4, 0, 0, 8, 128, - 0, 0, 255, 129, 2, 0, - 0, 160, 2, 0, 85, 160, - 2, 0, 0, 3, 0, 0, - 8, 128, 3, 0, 255, 128, - 0, 0, 255, 128, 88, 0, - 0, 4, 1, 0, 7, 128, - 0, 0, 255, 129, 0, 0, - 228, 128, 1, 0, 228, 128, - 1, 0, 0, 2, 0, 8, - 15, 128, 1, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 88, 8, 0, 0, - 64, 0, 0, 0, 22, 2, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 1, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 104, 0, 0, 2, - 7, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 1, 0, - 0, 0, 0, 96, 16, 0, - 1, 0, 0, 0, 24, 0, - 0, 7, 18, 0, 16, 0, - 2, 0, 0, 0, 58, 0, - 16, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 0, 24, 0, 0, 7, - 34, 0, 16, 0, 2, 0, - 0, 0, 58, 0, 16, 0, - 1, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 0, 0, - 60, 0, 0, 7, 18, 0, - 16, 0, 2, 0, 0, 0, - 26, 0, 16, 0, 2, 0, - 0, 0, 10, 0, 16, 0, - 2, 0, 0, 0, 31, 0, - 4, 3, 10, 0, 16, 0, - 2, 0, 0, 0, 54, 0, - 0, 5, 242, 32, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 62, 0, 0, 1, 21, 0, - 0, 1, 14, 0, 0, 7, - 114, 0, 16, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 0, 0, 0, 0, - 14, 0, 0, 7, 114, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 246, 15, 16, 0, - 1, 0, 0, 0, 32, 0, - 0, 8, 18, 0, 16, 0, - 2, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 7, 0, 0, 0, - 31, 0, 4, 3, 10, 0, - 16, 0, 2, 0, 0, 0, - 49, 0, 0, 10, 114, 0, - 16, 0, 2, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 11, 114, 0, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 128, 65, 0, 0, 0, - 1, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 0, 0, - 14, 0, 0, 7, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 51, 0, - 0, 10, 114, 0, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 11, - 114, 0, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 3, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 0, 0, 57, 0, - 0, 10, 114, 0, 16, 0, - 4, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 1, 0, 0, 10, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 0, 0, - 55, 0, 0, 9, 114, 0, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 18, 0, 0, 1, 32, 0, - 0, 8, 130, 0, 16, 0, - 2, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 8, 0, 0, 0, - 31, 0, 4, 3, 58, 0, - 16, 0, 2, 0, 0, 0, - 29, 0, 0, 10, 114, 0, - 16, 0, 3, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 63, 0, 0, 0, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 7, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 7, - 114, 0, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 50, 0, 0, 15, 114, 0, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 64, 0, 0, - 0, 64, 0, 0, 0, 64, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 191, - 0, 0, 128, 191, 0, 0, - 128, 191, 0, 0, 0, 0, - 0, 0, 0, 11, 114, 0, - 16, 0, 6, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 1, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 0, 0, 0, 11, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 5, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 0, 0, 50, 0, - 0, 13, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 128, 65, 0, 0, 0, - 6, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 55, 0, 0, 9, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 3, 0, 0, 0, 70, 2, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 5, 0, - 0, 0, 18, 0, 0, 1, - 32, 0, 0, 8, 130, 0, - 16, 0, 2, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 9, 0, - 0, 0, 31, 0, 4, 3, - 58, 0, 16, 0, 2, 0, - 0, 0, 29, 0, 0, 10, - 114, 0, 16, 0, 3, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 62, 0, 0, - 128, 62, 0, 0, 128, 62, - 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 15, 114, 0, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 65, 0, 0, - 128, 65, 0, 0, 128, 65, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 64, 193, - 0, 0, 64, 193, 0, 0, - 64, 193, 0, 0, 0, 0, - 50, 0, 0, 12, 114, 0, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 4, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 64, - 0, 0, 128, 64, 0, 0, - 128, 64, 0, 0, 0, 0, - 56, 0, 0, 7, 114, 0, - 16, 0, 4, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 75, 0, - 0, 5, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 55, 0, 0, 9, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 29, 0, 0, 10, 114, 0, - 16, 0, 4, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 63, 0, 0, 0, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 16, 114, 0, 16, 0, - 5, 0, 0, 0, 70, 2, - 16, 128, 65, 0, 0, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 64, - 0, 0, 0, 64, 0, 0, - 0, 64, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 56, 0, 0, 7, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 0, 0, 0, 11, 114, 0, - 16, 0, 6, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 1, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 0, 0, - 0, 0, 50, 0, 0, 10, - 114, 0, 16, 0, 5, 0, - 0, 0, 70, 2, 16, 128, - 65, 0, 0, 0, 5, 0, - 0, 0, 70, 2, 16, 0, - 6, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 15, 114, 0, - 16, 0, 6, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 64, 0, 0, - 0, 64, 0, 0, 0, 64, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 128, 191, - 0, 0, 128, 191, 0, 0, - 128, 191, 0, 0, 0, 0, - 0, 0, 0, 8, 114, 0, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 50, 0, 0, 9, - 114, 0, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 6, 0, 0, 0, 70, 2, - 16, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 55, 0, 0, 9, - 114, 0, 16, 0, 2, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 5, 0, 0, 0, - 70, 2, 16, 0, 3, 0, - 0, 0, 18, 0, 0, 1, - 32, 0, 0, 8, 130, 0, - 16, 0, 2, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 8, - 114, 0, 16, 0, 3, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 128, 65, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 7, 114, 0, 16, 0, - 4, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 114, 0, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 13, 114, 0, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 128, 65, 0, - 0, 0, 1, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 64, 0, 0, 0, 64, - 0, 0, 0, 64, 0, 0, - 0, 0, 70, 2, 16, 0, - 4, 0, 0, 0, 55, 0, - 0, 10, 114, 0, 16, 0, - 2, 0, 0, 0, 246, 15, - 16, 0, 2, 0, 0, 0, - 70, 2, 16, 128, 129, 0, - 0, 0, 3, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 21, 0, 0, 1, - 21, 0, 0, 1, 21, 0, - 0, 1, 0, 0, 0, 8, - 18, 0, 16, 0, 1, 0, - 0, 0, 58, 0, 16, 128, - 65, 0, 0, 0, 1, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 56, 0, - 0, 7, 226, 0, 16, 0, - 1, 0, 0, 0, 246, 15, - 16, 0, 1, 0, 0, 0, - 6, 9, 16, 0, 2, 0, - 0, 0, 50, 0, 0, 9, - 114, 0, 16, 0, 0, 0, - 0, 0, 6, 0, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 150, 7, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 114, 32, 16, 0, 0, 0, - 0, 0, 246, 15, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 130, 32, - 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 0, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 66, 0, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 27, 0, 0, 0, 4, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 14, 0, 0, 0, 5, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 100, 1, 0, 0, - 1, 0, 0, 0, 232, 0, - 0, 0, 5, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 255, 255, 0, 129, 0, 0, - 48, 1, 0, 0, 188, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 197, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 209, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 213, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 1, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 220, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 115, 83, 97, 109, - 112, 108, 101, 114, 0, 115, - 66, 99, 107, 83, 97, 109, - 112, 108, 101, 114, 0, 116, - 101, 120, 0, 98, 99, 107, - 116, 101, 120, 0, 36, 71, - 108, 111, 98, 97, 108, 115, - 0, 171, 171, 171, 220, 0, - 0, 0, 1, 0, 0, 0, - 0, 1, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 24, 1, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 32, 1, 0, 0, - 0, 0, 0, 0, 98, 108, - 101, 110, 100, 111, 112, 0, - 0, 0, 19, 0, 1, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 171, - 171, 171, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 3, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 97, 114, 103, 101, - 116, 0, 171, 171, 116, 34, - 0, 0, 0, 0, 0, 0, - 83, 97, 109, 112, 108, 101, - 84, 101, 120, 116, 117, 114, - 101, 70, 111, 114, 78, 111, - 110, 83, 101, 112, 97, 114, - 97, 98, 108, 101, 66, 108, - 101, 110, 100, 105, 110, 103, - 0, 68, 4, 0, 0, 68, - 88, 66, 67, 43, 219, 5, - 122, 32, 21, 232, 165, 63, - 89, 201, 32, 133, 13, 217, - 23, 1, 0, 0, 0, 68, - 4, 0, 0, 6, 0, 0, - 0, 56, 0, 0, 0, 248, - 0, 0, 0, 244, 1, 0, - 0, 112, 2, 0, 0, 160, - 3, 0, 0, 212, 3, 0, - 0, 65, 111, 110, 57, 184, - 0, 0, 0, 184, 0, 0, - 0, 0, 2, 254, 255, 132, - 0, 0, 0, 52, 0, 0, - 0, 1, 0, 36, 0, 0, - 0, 48, 0, 0, 0, 48, - 0, 0, 0, 36, 0, 1, - 0, 48, 0, 0, 0, 0, - 0, 3, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 2, 254, 255, 81, - 0, 0, 5, 4, 0, 15, - 160, 0, 0, 0, 0, 0, - 0, 128, 63, 0, 0, 0, - 0, 0, 0, 0, 0, 31, - 0, 0, 2, 5, 0, 0, - 128, 0, 0, 15, 144, 4, - 0, 0, 4, 0, 0, 3, - 224, 0, 0, 228, 144, 2, - 0, 238, 160, 2, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 12, 224, 0, 0, 20, - 144, 3, 0, 180, 160, 3, - 0, 20, 160, 4, 0, 0, - 4, 0, 0, 3, 128, 0, - 0, 228, 144, 1, 0, 238, - 160, 1, 0, 228, 160, 2, - 0, 0, 3, 0, 0, 3, - 192, 0, 0, 228, 128, 0, - 0, 228, 160, 1, 0, 0, - 2, 0, 0, 12, 192, 4, - 0, 68, 160, 255, 255, 0, - 0, 83, 72, 68, 82, 244, - 0, 0, 0, 64, 0, 1, - 0, 61, 0, 0, 0, 89, - 0, 0, 4, 70, 142, 32, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 95, 0, 0, - 3, 50, 16, 16, 0, 0, - 0, 0, 0, 103, 0, 0, - 4, 242, 32, 16, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 101, 0, 0, 3, 50, - 32, 16, 0, 1, 0, 0, - 0, 101, 0, 0, 3, 194, - 32, 16, 0, 1, 0, 0, - 0, 50, 0, 0, 11, 50, - 32, 16, 0, 0, 0, 0, - 0, 70, 16, 16, 0, 0, - 0, 0, 0, 230, 138, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 70, 128, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 8, 194, 32, 16, 0, 0, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 128, 63, 50, - 0, 0, 11, 50, 32, 16, - 0, 1, 0, 0, 0, 70, - 16, 16, 0, 0, 0, 0, - 0, 230, 138, 32, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 70, 128, 32, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 50, 0, 0, 11, 194, - 32, 16, 0, 1, 0, 0, - 0, 6, 20, 16, 0, 0, - 0, 0, 0, 166, 142, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 6, 132, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, - 0, 0, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, - 68, 69, 70, 40, 1, 0, - 0, 1, 0, 0, 0, 64, - 0, 0, 0, 1, 0, 0, - 0, 28, 0, 0, 0, 0, - 4, 254, 255, 0, 129, 0, - 0, 246, 0, 0, 0, 60, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 99, 98, 48, 0, 60, - 0, 0, 0, 4, 0, 0, - 0, 88, 0, 0, 0, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 184, - 0, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 196, 0, 0, - 0, 0, 0, 0, 0, 212, - 0, 0, 0, 16, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 196, 0, 0, - 0, 0, 0, 0, 0, 222, - 0, 0, 0, 32, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 196, 0, 0, - 0, 0, 0, 0, 0, 236, - 0, 0, 0, 48, 0, 0, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 196, 0, 0, - 0, 0, 0, 0, 0, 81, - 117, 97, 100, 68, 101, 115, - 99, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 84, 101, 120, - 67, 111, 111, 114, 100, 115, - 0, 77, 97, 115, 107, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 84, 101, 120, - 116, 67, 111, 108, 111, 114, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 57, 46, 50, 57, 46, 57, - 53, 50, 46, 51, 49, 49, - 49, 0, 171, 73, 83, 71, - 78, 44, 0, 0, 0, 1, - 0, 0, 0, 8, 0, 0, - 0, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 7, 3, 0, - 0, 80, 79, 83, 73, 84, - 73, 79, 78, 0, 171, 171, - 171, 79, 83, 71, 78, 104, - 0, 0, 0, 3, 0, 0, - 0, 8, 0, 0, 0, 80, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 15, 0, 0, 0, 92, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 1, 0, 0, - 0, 3, 12, 0, 0, 92, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 1, 0, 0, - 0, 12, 3, 0, 0, 83, - 86, 95, 80, 111, 115, 105, - 116, 105, 111, 110, 0, 84, - 69, 88, 67, 79, 79, 82, - 68, 0, 171, 171, 171, 157, - 51, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 240, 37, 0, 0, 68, - 88, 66, 67, 120, 213, 101, - 102, 121, 111, 165, 92, 183, - 170, 216, 154, 223, 204, 25, - 239, 1, 0, 0, 0, 240, - 37, 0, 0, 6, 0, 0, - 0, 56, 0, 0, 0, 96, - 13, 0, 0, 100, 35, 0, - 0, 224, 35, 0, 0, 76, - 37, 0, 0, 188, 37, 0, - 0, 65, 111, 110, 57, 32, - 13, 0, 0, 32, 13, 0, - 0, 0, 2, 255, 255, 232, - 12, 0, 0, 56, 0, 0, - 0, 1, 0, 44, 0, 0, - 0, 56, 0, 0, 0, 56, - 0, 2, 0, 36, 0, 0, - 0, 56, 0, 0, 0, 0, - 0, 1, 1, 1, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 1, - 2, 255, 255, 81, 0, 0, - 5, 1, 0, 15, 160, 0, - 0, 64, 193, 0, 0, 80, - 193, 0, 0, 96, 193, 0, - 0, 0, 0, 81, 0, 0, - 5, 2, 0, 15, 160, 0, - 0, 128, 63, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 81, 0, 0, - 5, 3, 0, 15, 160, 154, - 153, 153, 62, 61, 10, 23, - 63, 174, 71, 225, 61, 0, - 0, 0, 0, 31, 0, 0, - 2, 0, 0, 0, 128, 0, - 0, 15, 176, 31, 0, 0, - 2, 0, 0, 0, 144, 0, - 8, 15, 160, 31, 0, 0, - 2, 0, 0, 0, 144, 1, - 8, 15, 160, 1, 0, 0, - 2, 0, 0, 2, 128, 2, - 0, 85, 160, 1, 0, 0, - 2, 1, 0, 2, 128, 2, - 0, 85, 160, 1, 0, 0, - 2, 2, 0, 4, 128, 2, - 0, 85, 160, 66, 0, 0, - 3, 3, 0, 15, 128, 0, - 0, 228, 176, 1, 8, 228, - 160, 66, 0, 0, 3, 4, - 0, 15, 128, 0, 0, 228, - 176, 0, 8, 228, 160, 6, - 0, 0, 2, 0, 0, 8, - 128, 4, 0, 255, 128, 5, - 0, 0, 3, 5, 0, 7, - 128, 0, 0, 255, 128, 4, - 0, 228, 128, 4, 0, 0, - 4, 6, 0, 3, 128, 4, - 0, 225, 128, 0, 0, 255, - 128, 5, 0, 230, 129, 88, - 0, 0, 4, 7, 0, 3, - 128, 6, 0, 0, 128, 5, - 0, 233, 128, 5, 0, 230, - 128, 11, 0, 0, 3, 1, - 0, 8, 128, 5, 0, 0, - 128, 7, 0, 0, 128, 10, - 0, 0, 3, 2, 0, 8, - 128, 7, 0, 85, 128, 5, - 0, 0, 128, 2, 0, 0, - 3, 7, 0, 8, 128, 1, - 0, 255, 128, 2, 0, 255, - 129, 1, 0, 0, 2, 8, - 0, 8, 128, 7, 0, 255, - 128, 6, 0, 0, 2, 1, - 0, 8, 128, 3, 0, 255, - 128, 5, 0, 0, 3, 9, - 0, 7, 128, 1, 0, 255, - 128, 3, 0, 228, 128, 4, - 0, 0, 4, 10, 0, 3, - 128, 3, 0, 0, 128, 1, - 0, 255, 128, 9, 0, 230, - 129, 6, 0, 0, 2, 2, - 0, 8, 128, 10, 0, 85, - 128, 5, 0, 0, 3, 2, - 0, 8, 128, 2, 0, 255, - 128, 8, 0, 255, 128, 4, - 0, 0, 4, 11, 0, 15, - 128, 3, 0, 150, 128, 1, - 0, 255, 128, 9, 0, 96, - 129, 5, 0, 0, 3, 8, - 0, 2, 128, 2, 0, 255, - 128, 11, 0, 255, 128, 1, - 0, 0, 2, 10, 0, 12, - 128, 11, 0, 228, 128, 88, - 0, 0, 4, 1, 0, 5, - 128, 10, 0, 85, 129, 10, - 0, 245, 128, 8, 0, 215, - 128, 6, 0, 0, 2, 2, - 0, 8, 128, 10, 0, 0, - 128, 5, 0, 0, 3, 2, - 0, 8, 128, 2, 0, 255, - 128, 8, 0, 255, 128, 5, - 0, 0, 3, 8, 0, 1, - 128, 2, 0, 255, 128, 10, - 0, 170, 128, 88, 0, 0, - 4, 2, 0, 3, 128, 10, - 0, 0, 129, 10, 0, 232, - 128, 8, 0, 227, 128, 88, - 0, 0, 4, 1, 0, 7, - 128, 10, 0, 255, 128, 1, - 0, 228, 128, 2, 0, 228, - 128, 6, 0, 0, 2, 5, - 0, 8, 128, 10, 0, 255, - 128, 5, 0, 0, 3, 5, - 0, 8, 128, 5, 0, 255, - 128, 8, 0, 255, 128, 5, - 0, 0, 3, 8, 0, 4, - 128, 5, 0, 255, 128, 10, - 0, 85, 128, 88, 0, 0, - 4, 0, 0, 5, 128, 11, - 0, 255, 129, 10, 0, 245, - 128, 8, 0, 246, 128, 88, - 0, 0, 4, 0, 0, 7, - 128, 11, 0, 0, 128, 0, - 0, 228, 128, 1, 0, 228, - 128, 1, 0, 0, 2, 1, - 0, 1, 128, 2, 0, 85, - 160, 1, 0, 0, 2, 2, - 0, 1, 128, 2, 0, 85, - 160, 1, 0, 0, 2, 8, - 0, 4, 128, 2, 0, 85, - 160, 6, 0, 0, 2, 2, - 0, 8, 128, 10, 0, 170, - 128, 5, 0, 0, 3, 2, - 0, 8, 128, 2, 0, 255, - 128, 8, 0, 255, 128, 5, - 0, 0, 3, 7, 0, 1, - 128, 2, 0, 255, 128, 10, - 0, 0, 128, 88, 0, 0, - 4, 8, 0, 3, 128, 11, - 0, 170, 129, 10, 0, 232, - 128, 7, 0, 236, 128, 6, - 0, 0, 2, 2, 0, 8, - 128, 11, 0, 85, 128, 5, - 0, 0, 3, 2, 0, 8, - 128, 2, 0, 255, 128, 8, - 0, 255, 128, 5, 0, 0, - 3, 7, 0, 2, 128, 2, - 0, 255, 128, 11, 0, 0, - 128, 88, 0, 0, 4, 2, - 0, 6, 128, 11, 0, 85, - 129, 11, 0, 196, 128, 7, - 0, 220, 128, 88, 0, 0, - 4, 2, 0, 7, 128, 11, - 0, 0, 128, 2, 0, 228, - 128, 8, 0, 228, 128, 6, - 0, 0, 2, 2, 0, 8, - 128, 11, 0, 0, 128, 5, - 0, 0, 3, 2, 0, 8, - 128, 2, 0, 255, 128, 8, - 0, 255, 128, 5, 0, 0, - 3, 7, 0, 4, 128, 2, - 0, 255, 128, 11, 0, 85, - 128, 88, 0, 0, 4, 1, - 0, 6, 128, 11, 0, 0, - 129, 11, 0, 196, 128, 7, - 0, 248, 128, 88, 0, 0, - 4, 1, 0, 7, 128, 10, - 0, 255, 128, 1, 0, 228, - 128, 2, 0, 228, 128, 88, - 0, 0, 4, 0, 0, 7, - 128, 11, 0, 85, 128, 1, - 0, 228, 128, 0, 0, 228, - 128, 88, 0, 0, 4, 1, - 0, 3, 128, 10, 0, 170, - 128, 9, 0, 233, 128, 9, - 0, 230, 128, 8, 0, 0, - 3, 5, 0, 8, 128, 0, - 0, 228, 128, 3, 0, 228, - 160, 8, 0, 0, 3, 1, - 0, 4, 128, 9, 0, 228, - 128, 3, 0, 228, 160, 2, - 0, 0, 3, 5, 0, 8, - 128, 5, 0, 255, 129, 1, - 0, 170, 128, 2, 0, 0, - 3, 0, 0, 7, 128, 0, - 0, 228, 128, 5, 0, 255, - 128, 2, 0, 0, 3, 5, - 0, 8, 128, 0, 0, 85, - 129, 0, 0, 0, 128, 88, - 0, 0, 4, 2, 0, 3, - 128, 5, 0, 255, 128, 0, - 0, 225, 128, 0, 0, 228, - 128, 10, 0, 0, 3, 5, - 0, 8, 128, 0, 0, 170, - 128, 2, 0, 0, 128, 11, - 0, 0, 3, 7, 0, 1, - 128, 2, 0, 85, 128, 0, - 0, 170, 128, 8, 0, 0, - 3, 2, 0, 1, 128, 0, - 0, 228, 128, 3, 0, 228, - 160, 2, 0, 0, 3, 2, - 0, 2, 128, 5, 0, 255, - 129, 2, 0, 0, 128, 6, - 0, 0, 2, 2, 0, 2, - 128, 2, 0, 85, 128, 2, - 0, 0, 3, 7, 0, 14, - 128, 0, 0, 144, 128, 2, - 0, 0, 129, 5, 0, 0, - 3, 7, 0, 14, 128, 2, - 0, 0, 128, 7, 0, 228, - 128, 4, 0, 0, 4, 2, - 0, 14, 128, 7, 0, 228, - 128, 2, 0, 85, 128, 2, - 0, 0, 128, 88, 0, 0, - 4, 0, 0, 7, 128, 5, - 0, 255, 128, 0, 0, 228, - 128, 2, 0, 249, 128, 2, - 0, 0, 3, 2, 0, 14, - 128, 2, 0, 0, 129, 0, - 0, 144, 128, 2, 0, 0, - 3, 5, 0, 8, 128, 2, - 0, 0, 129, 2, 0, 0, - 160, 5, 0, 0, 3, 2, - 0, 14, 128, 2, 0, 228, - 128, 5, 0, 255, 128, 2, - 0, 0, 3, 5, 0, 8, - 128, 2, 0, 0, 129, 7, - 0, 0, 128, 2, 0, 0, - 3, 7, 0, 1, 128, 7, - 0, 0, 129, 2, 0, 0, - 160, 6, 0, 0, 2, 5, - 0, 8, 128, 5, 0, 255, - 128, 4, 0, 0, 4, 2, - 0, 7, 128, 2, 0, 249, - 128, 5, 0, 255, 128, 2, - 0, 0, 128, 88, 0, 0, - 4, 0, 0, 7, 128, 7, - 0, 0, 128, 0, 0, 228, - 128, 2, 0, 228, 128, 8, - 0, 0, 3, 5, 0, 8, - 128, 5, 0, 228, 128, 3, - 0, 228, 160, 2, 0, 0, - 3, 2, 0, 1, 128, 1, - 0, 170, 128, 5, 0, 255, - 129, 2, 0, 0, 3, 5, - 0, 8, 128, 1, 0, 170, - 129, 5, 0, 255, 128, 4, - 0, 0, 4, 2, 0, 14, - 128, 3, 0, 144, 128, 1, - 0, 255, 128, 5, 0, 255, - 128, 4, 0, 0, 4, 3, - 0, 7, 128, 4, 0, 228, - 128, 0, 0, 255, 128, 2, - 0, 0, 128, 4, 0, 0, - 4, 7, 0, 15, 128, 4, - 0, 38, 128, 0, 0, 255, - 128, 5, 0, 144, 129, 2, - 0, 0, 3, 0, 0, 8, - 128, 3, 0, 85, 129, 3, - 0, 0, 128, 88, 0, 0, - 4, 8, 0, 3, 128, 0, - 0, 255, 128, 3, 0, 225, - 128, 3, 0, 228, 128, 10, - 0, 0, 3, 0, 0, 8, - 128, 3, 0, 170, 128, 8, - 0, 0, 128, 11, 0, 0, - 3, 1, 0, 8, 128, 8, - 0, 85, 128, 3, 0, 170, - 128, 8, 0, 0, 3, 5, - 0, 8, 128, 3, 0, 228, - 128, 3, 0, 228, 160, 2, - 0, 0, 3, 2, 0, 1, - 128, 0, 0, 255, 129, 5, - 0, 255, 128, 6, 0, 0, - 2, 2, 0, 1, 128, 2, - 0, 0, 128, 2, 0, 0, - 3, 8, 0, 7, 128, 3, - 0, 228, 128, 5, 0, 255, - 129, 5, 0, 0, 3, 8, - 0, 7, 128, 5, 0, 255, - 128, 8, 0, 228, 128, 4, - 0, 0, 4, 8, 0, 7, - 128, 8, 0, 228, 128, 2, - 0, 0, 128, 5, 0, 255, - 128, 88, 0, 0, 4, 3, - 0, 7, 128, 0, 0, 255, - 128, 3, 0, 228, 128, 8, - 0, 228, 128, 2, 0, 0, - 3, 8, 0, 7, 128, 5, - 0, 255, 129, 3, 0, 228, - 128, 2, 0, 0, 3, 0, - 0, 8, 128, 5, 0, 255, - 129, 2, 0, 0, 160, 5, - 0, 0, 3, 8, 0, 7, - 128, 0, 0, 255, 128, 8, - 0, 228, 128, 2, 0, 0, - 3, 0, 0, 8, 128, 1, - 0, 255, 128, 5, 0, 255, - 129, 2, 0, 0, 3, 1, - 0, 8, 128, 1, 0, 255, - 129, 2, 0, 0, 160, 6, - 0, 0, 2, 0, 0, 8, - 128, 0, 0, 255, 128, 4, - 0, 0, 4, 8, 0, 7, - 128, 8, 0, 228, 128, 0, - 0, 255, 128, 5, 0, 255, - 128, 88, 0, 0, 4, 3, - 0, 7, 128, 1, 0, 255, - 128, 3, 0, 228, 128, 8, - 0, 228, 128, 2, 0, 0, - 3, 0, 0, 8, 128, 2, - 0, 170, 129, 2, 0, 85, - 128, 88, 0, 0, 4, 8, - 0, 3, 128, 0, 0, 255, - 128, 2, 0, 230, 128, 2, - 0, 233, 128, 10, 0, 0, - 3, 0, 0, 8, 128, 2, - 0, 255, 128, 8, 0, 0, - 128, 11, 0, 0, 3, 1, - 0, 8, 128, 8, 0, 85, - 128, 2, 0, 255, 128, 8, - 0, 0, 3, 5, 0, 8, - 128, 2, 0, 249, 128, 3, - 0, 228, 160, 2, 0, 0, - 3, 2, 0, 1, 128, 0, - 0, 255, 129, 5, 0, 255, - 128, 6, 0, 0, 2, 2, - 0, 1, 128, 2, 0, 0, - 128, 2, 0, 0, 3, 8, - 0, 7, 128, 2, 0, 249, - 128, 5, 0, 255, 129, 5, - 0, 0, 3, 8, 0, 7, - 128, 5, 0, 255, 128, 8, - 0, 228, 128, 4, 0, 0, - 4, 8, 0, 7, 128, 8, - 0, 228, 128, 2, 0, 0, - 128, 5, 0, 255, 128, 88, - 0, 0, 4, 2, 0, 7, - 128, 0, 0, 255, 128, 2, - 0, 249, 128, 8, 0, 228, - 128, 2, 0, 0, 3, 8, - 0, 7, 128, 5, 0, 255, - 129, 2, 0, 228, 128, 2, - 0, 0, 3, 0, 0, 8, - 128, 5, 0, 255, 129, 2, - 0, 0, 160, 5, 0, 0, - 3, 8, 0, 7, 128, 0, - 0, 255, 128, 8, 0, 228, - 128, 2, 0, 0, 3, 0, - 0, 8, 128, 1, 0, 255, - 128, 5, 0, 255, 129, 2, - 0, 0, 3, 1, 0, 8, - 128, 1, 0, 255, 129, 2, - 0, 0, 160, 6, 0, 0, - 2, 0, 0, 8, 128, 0, - 0, 255, 128, 4, 0, 0, - 4, 8, 0, 7, 128, 8, - 0, 228, 128, 0, 0, 255, - 128, 5, 0, 255, 128, 88, - 0, 0, 4, 2, 0, 7, - 128, 1, 0, 255, 128, 2, - 0, 228, 128, 8, 0, 228, - 128, 1, 0, 0, 2, 0, - 0, 8, 128, 0, 0, 0, - 160, 2, 0, 0, 3, 8, - 0, 7, 128, 0, 0, 255, - 128, 1, 0, 228, 160, 5, - 0, 0, 3, 8, 0, 7, - 128, 8, 0, 228, 128, 8, - 0, 228, 128, 88, 0, 0, - 4, 2, 0, 7, 128, 8, - 0, 170, 129, 3, 0, 228, - 128, 2, 0, 228, 128, 88, - 0, 0, 4, 0, 0, 7, - 128, 8, 0, 85, 129, 0, - 0, 228, 128, 2, 0, 228, - 128, 1, 0, 0, 2, 2, - 0, 2, 128, 2, 0, 85, - 160, 1, 0, 0, 2, 3, - 0, 2, 128, 2, 0, 85, - 160, 1, 0, 0, 2, 10, - 0, 4, 128, 2, 0, 85, - 160, 11, 0, 0, 3, 0, - 0, 8, 128, 9, 0, 0, - 128, 1, 0, 0, 128, 10, - 0, 0, 3, 2, 0, 8, - 128, 1, 0, 85, 128, 9, - 0, 0, 128, 2, 0, 0, - 3, 9, 0, 8, 128, 0, - 0, 255, 128, 2, 0, 255, - 129, 1, 0, 0, 2, 11, - 0, 8, 128, 9, 0, 255, - 128, 6, 0, 0, 2, 0, - 0, 8, 128, 7, 0, 255, - 128, 5, 0, 0, 3, 0, - 0, 8, 128, 0, 0, 255, - 128, 11, 0, 255, 128, 5, - 0, 0, 3, 11, 0, 1, - 128, 0, 0, 255, 128, 6, - 0, 0, 128, 1, 0, 0, - 2, 6, 0, 12, 128, 7, - 0, 180, 128, 88, 0, 0, - 4, 10, 0, 3, 128, 7, - 0, 255, 129, 6, 0, 226, - 128, 11, 0, 227, 128, 6, - 0, 0, 2, 0, 0, 8, - 128, 6, 0, 85, 128, 5, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 11, - 0, 255, 128, 5, 0, 0, - 3, 11, 0, 2, 128, 0, - 0, 255, 128, 7, 0, 170, - 128, 88, 0, 0, 4, 3, - 0, 5, 128, 6, 0, 85, - 129, 6, 0, 245, 128, 11, - 0, 215, 128, 88, 0, 0, - 4, 1, 0, 11, 128, 7, - 0, 170, 128, 3, 0, 164, - 128, 10, 0, 164, 128, 6, - 0, 0, 2, 0, 0, 8, - 128, 7, 0, 170, 128, 5, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 11, - 0, 255, 128, 5, 0, 0, - 3, 11, 0, 4, 128, 0, - 0, 255, 128, 6, 0, 85, - 128, 88, 0, 0, 4, 2, - 0, 5, 128, 7, 0, 170, - 129, 6, 0, 245, 128, 11, - 0, 246, 128, 88, 0, 0, - 4, 1, 0, 11, 128, 7, - 0, 0, 128, 2, 0, 164, - 128, 1, 0, 228, 128, 1, - 0, 0, 2, 2, 0, 1, - 128, 2, 0, 85, 160, 1, - 0, 0, 2, 3, 0, 4, - 128, 2, 0, 85, 160, 6, - 0, 0, 2, 0, 0, 8, - 128, 6, 0, 0, 128, 5, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 11, - 0, 255, 128, 5, 0, 0, - 3, 9, 0, 1, 128, 0, - 0, 255, 128, 7, 0, 255, - 128, 88, 0, 0, 4, 3, - 0, 3, 128, 6, 0, 0, - 129, 6, 0, 226, 128, 9, - 0, 236, 128, 6, 0, 0, - 2, 0, 0, 8, 128, 7, - 0, 85, 128, 5, 0, 0, - 3, 0, 0, 8, 128, 0, - 0, 255, 128, 11, 0, 255, - 128, 5, 0, 0, 3, 9, - 0, 2, 128, 0, 0, 255, - 128, 7, 0, 0, 128, 88, - 0, 0, 4, 2, 0, 6, - 128, 7, 0, 85, 129, 7, - 0, 196, 128, 9, 0, 220, - 128, 88, 0, 0, 4, 2, - 0, 7, 128, 7, 0, 0, - 128, 2, 0, 228, 128, 3, - 0, 228, 128, 1, 0, 0, - 2, 3, 0, 1, 128, 2, - 0, 85, 160, 6, 0, 0, - 2, 0, 0, 8, 128, 7, - 0, 0, 128, 5, 0, 0, - 3, 0, 0, 8, 128, 0, - 0, 255, 128, 11, 0, 255, - 128, 5, 0, 0, 3, 9, - 0, 4, 128, 0, 0, 255, - 128, 7, 0, 85, 128, 88, - 0, 0, 4, 3, 0, 6, - 128, 7, 0, 0, 129, 7, - 0, 196, 128, 9, 0, 248, - 128, 88, 0, 0, 4, 2, - 0, 7, 128, 7, 0, 170, - 128, 3, 0, 228, 128, 2, - 0, 228, 128, 88, 0, 0, - 4, 1, 0, 11, 128, 7, - 0, 85, 128, 2, 0, 164, - 128, 1, 0, 228, 128, 8, - 0, 0, 3, 0, 0, 8, - 128, 1, 0, 244, 128, 3, - 0, 228, 160, 2, 0, 0, - 3, 0, 0, 8, 128, 0, - 0, 255, 129, 1, 0, 170, - 128, 2, 0, 0, 3, 1, - 0, 7, 128, 0, 0, 255, - 128, 1, 0, 244, 128, 2, - 0, 0, 3, 0, 0, 8, - 128, 1, 0, 85, 129, 1, - 0, 0, 128, 88, 0, 0, - 4, 2, 0, 3, 128, 0, - 0, 255, 128, 1, 0, 225, - 128, 1, 0, 228, 128, 10, - 0, 0, 3, 0, 0, 8, - 128, 1, 0, 170, 128, 2, - 0, 0, 128, 11, 0, 0, - 3, 5, 0, 8, 128, 2, - 0, 85, 128, 1, 0, 170, - 128, 8, 0, 0, 3, 1, - 0, 8, 128, 1, 0, 228, - 128, 3, 0, 228, 160, 2, - 0, 0, 3, 2, 0, 7, - 128, 1, 0, 255, 129, 1, - 0, 228, 128, 5, 0, 0, - 3, 2, 0, 7, 128, 1, - 0, 255, 128, 2, 0, 228, - 128, 2, 0, 0, 3, 2, - 0, 8, 128, 0, 0, 255, - 129, 1, 0, 255, 128, 6, - 0, 0, 2, 2, 0, 8, - 128, 2, 0, 255, 128, 4, - 0, 0, 4, 2, 0, 7, - 128, 2, 0, 228, 128, 2, - 0, 255, 128, 1, 0, 255, - 128, 88, 0, 0, 4, 1, - 0, 7, 128, 0, 0, 255, - 128, 1, 0, 228, 128, 2, - 0, 228, 128, 2, 0, 0, - 3, 2, 0, 7, 128, 1, - 0, 255, 129, 1, 0, 228, - 128, 2, 0, 0, 3, 0, - 0, 8, 128, 1, 0, 255, - 129, 2, 0, 0, 160, 5, - 0, 0, 3, 2, 0, 7, - 128, 0, 0, 255, 128, 2, - 0, 228, 128, 2, 0, 0, - 3, 0, 0, 8, 128, 1, - 0, 255, 129, 5, 0, 255, - 128, 2, 0, 0, 3, 2, - 0, 8, 128, 5, 0, 255, - 129, 2, 0, 0, 160, 6, - 0, 0, 2, 0, 0, 8, - 128, 0, 0, 255, 128, 4, - 0, 0, 4, 2, 0, 7, - 128, 2, 0, 228, 128, 0, - 0, 255, 128, 1, 0, 255, - 128, 88, 0, 0, 4, 1, - 0, 7, 128, 2, 0, 255, - 128, 1, 0, 228, 128, 2, - 0, 228, 128, 88, 0, 0, - 4, 0, 0, 7, 128, 8, - 0, 0, 129, 1, 0, 228, - 128, 0, 0, 228, 128, 18, - 0, 0, 4, 1, 0, 7, - 128, 3, 0, 255, 128, 0, - 0, 228, 128, 5, 0, 228, - 128, 5, 0, 0, 3, 1, - 0, 8, 128, 3, 0, 255, - 128, 3, 0, 255, 128, 88, - 0, 0, 4, 1, 0, 8, - 128, 1, 0, 255, 129, 2, - 0, 0, 160, 2, 0, 85, - 160, 5, 0, 0, 3, 0, - 0, 7, 128, 4, 0, 255, - 128, 1, 0, 228, 128, 5, - 0, 0, 3, 0, 0, 8, - 128, 4, 0, 255, 128, 4, - 0, 255, 128, 88, 0, 0, - 4, 0, 0, 8, 128, 0, - 0, 255, 129, 2, 0, 0, - 160, 2, 0, 85, 160, 2, - 0, 0, 3, 0, 0, 8, - 128, 1, 0, 255, 128, 0, - 0, 255, 128, 88, 0, 0, - 4, 4, 0, 7, 128, 0, - 0, 255, 129, 0, 0, 228, - 128, 4, 0, 228, 128, 1, - 0, 0, 2, 0, 8, 15, - 128, 4, 0, 228, 128, 255, - 255, 0, 0, 83, 72, 68, - 82, 252, 21, 0, 0, 64, - 0, 0, 0, 127, 5, 0, - 0, 89, 0, 0, 4, 70, - 142, 32, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 90, - 0, 0, 3, 0, 96, 16, - 0, 0, 0, 0, 0, 90, - 0, 0, 3, 0, 96, 16, - 0, 1, 0, 0, 0, 88, - 24, 0, 4, 0, 112, 16, - 0, 0, 0, 0, 0, 85, - 85, 0, 0, 88, 24, 0, - 4, 0, 112, 16, 0, 1, - 0, 0, 0, 85, 85, 0, - 0, 98, 16, 0, 3, 50, - 16, 16, 0, 1, 0, 0, - 0, 101, 0, 0, 3, 242, - 32, 16, 0, 0, 0, 0, - 0, 104, 0, 0, 2, 9, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 0, 0, 0, - 0, 0, 96, 16, 0, 0, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 1, - 0, 0, 0, 70, 16, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 1, 0, 0, - 0, 0, 96, 16, 0, 1, - 0, 0, 0, 24, 0, 0, - 7, 18, 0, 16, 0, 2, - 0, 0, 0, 58, 0, 16, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 24, 0, 0, 7, 34, - 0, 16, 0, 2, 0, 0, - 0, 58, 0, 16, 0, 1, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 60, - 0, 0, 7, 18, 0, 16, - 0, 2, 0, 0, 0, 26, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 2, - 0, 0, 0, 31, 0, 4, - 3, 10, 0, 16, 0, 2, - 0, 0, 0, 54, 0, 0, - 5, 242, 32, 16, 0, 0, - 0, 0, 0, 70, 14, 16, - 0, 0, 0, 0, 0, 62, - 0, 0, 1, 21, 0, 0, - 1, 14, 0, 0, 7, 114, - 0, 16, 0, 0, 0, 0, - 0, 70, 2, 16, 0, 0, - 0, 0, 0, 246, 15, 16, - 0, 0, 0, 0, 0, 14, - 0, 0, 7, 114, 0, 16, - 0, 1, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 246, 15, 16, 0, 1, - 0, 0, 0, 32, 0, 0, - 8, 18, 0, 16, 0, 2, - 0, 0, 0, 10, 128, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 12, 0, 0, 0, 31, - 0, 4, 3, 10, 0, 16, - 0, 2, 0, 0, 0, 52, - 0, 0, 7, 18, 0, 16, - 0, 2, 0, 0, 0, 42, - 0, 16, 0, 1, 0, 0, - 0, 26, 0, 16, 0, 1, - 0, 0, 0, 52, 0, 0, - 7, 18, 0, 16, 0, 2, - 0, 0, 0, 10, 0, 16, - 0, 1, 0, 0, 0, 10, - 0, 16, 0, 2, 0, 0, - 0, 51, 0, 0, 7, 34, - 0, 16, 0, 2, 0, 0, - 0, 42, 0, 16, 0, 1, - 0, 0, 0, 26, 0, 16, - 0, 1, 0, 0, 0, 51, - 0, 0, 7, 34, 0, 16, - 0, 2, 0, 0, 0, 10, - 0, 16, 0, 1, 0, 0, - 0, 26, 0, 16, 0, 2, - 0, 0, 0, 0, 0, 0, - 8, 130, 0, 16, 0, 2, - 0, 0, 0, 26, 0, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 10, 0, 16, - 0, 2, 0, 0, 0, 29, - 0, 0, 7, 18, 0, 16, - 0, 3, 0, 0, 0, 26, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 31, 0, 4, - 3, 10, 0, 16, 0, 3, - 0, 0, 0, 0, 0, 0, - 8, 242, 0, 16, 0, 3, - 0, 0, 0, 6, 10, 16, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 150, 4, 16, - 0, 0, 0, 0, 0, 49, - 0, 0, 10, 114, 0, 16, - 0, 4, 0, 0, 0, 2, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 22, 7, 16, 0, 3, - 0, 0, 0, 14, 0, 0, - 7, 114, 0, 16, 0, 5, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 22, - 7, 16, 0, 3, 0, 0, - 0, 56, 0, 0, 7, 114, - 0, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 3, - 0, 0, 0, 70, 2, 16, - 0, 5, 0, 0, 0, 55, - 0, 0, 9, 98, 0, 16, - 0, 5, 0, 0, 0, 6, - 0, 16, 0, 4, 0, 0, - 0, 6, 3, 16, 0, 2, - 0, 0, 0, 6, 1, 16, - 0, 3, 0, 0, 0, 29, - 0, 0, 7, 146, 0, 16, - 0, 4, 0, 0, 0, 166, - 10, 16, 0, 0, 0, 0, - 0, 86, 1, 16, 0, 0, - 0, 0, 0, 55, 0, 0, - 9, 98, 0, 16, 0, 6, - 0, 0, 0, 86, 5, 16, - 0, 4, 0, 0, 0, 246, - 13, 16, 0, 2, 0, 0, - 0, 6, 1, 16, 0, 3, - 0, 0, 0, 55, 0, 0, - 9, 50, 0, 16, 0, 3, - 0, 0, 0, 166, 10, 16, - 0, 4, 0, 0, 0, 230, - 10, 16, 0, 2, 0, 0, - 0, 230, 10, 16, 0, 3, - 0, 0, 0, 54, 0, 0, - 5, 18, 0, 16, 0, 6, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 66, 0, 16, - 0, 3, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 3, 0, 0, - 0, 246, 15, 16, 0, 4, - 0, 0, 0, 70, 2, 16, - 0, 6, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 54, 0, 0, 5, 18, - 0, 16, 0, 5, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 55, 0, 0, - 9, 114, 0, 16, 0, 3, - 0, 0, 0, 6, 0, 16, - 0, 4, 0, 0, 0, 70, - 2, 16, 0, 5, 0, 0, - 0, 70, 2, 16, 0, 3, - 0, 0, 0, 18, 0, 0, - 1, 0, 0, 0, 8, 242, - 0, 16, 0, 4, 0, 0, - 0, 86, 10, 16, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 134, 1, 16, 0, 0, - 0, 0, 0, 49, 0, 0, - 10, 114, 0, 16, 0, 5, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 22, - 7, 16, 0, 4, 0, 0, - 0, 14, 0, 0, 7, 114, - 0, 16, 0, 6, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 22, 7, 16, - 0, 4, 0, 0, 0, 56, - 0, 0, 7, 114, 0, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 70, 2, 16, 0, 6, - 0, 0, 0, 55, 0, 0, - 9, 82, 0, 16, 0, 6, - 0, 0, 0, 6, 0, 16, - 0, 5, 0, 0, 0, 6, - 3, 16, 0, 2, 0, 0, - 0, 6, 1, 16, 0, 4, - 0, 0, 0, 29, 0, 0, - 7, 146, 0, 16, 0, 5, - 0, 0, 0, 166, 10, 16, - 0, 0, 0, 0, 0, 6, - 4, 16, 0, 0, 0, 0, - 0, 55, 0, 0, 9, 82, - 0, 16, 0, 7, 0, 0, - 0, 86, 5, 16, 0, 5, - 0, 0, 0, 246, 13, 16, - 0, 2, 0, 0, 0, 6, - 1, 16, 0, 4, 0, 0, - 0, 55, 0, 0, 9, 50, - 0, 16, 0, 2, 0, 0, - 0, 166, 10, 16, 0, 5, - 0, 0, 0, 182, 15, 16, - 0, 2, 0, 0, 0, 182, - 15, 16, 0, 4, 0, 0, - 0, 54, 0, 0, 5, 34, - 0, 16, 0, 7, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 5, 66, 0, 16, 0, 2, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 55, - 0, 0, 9, 114, 0, 16, - 0, 2, 0, 0, 0, 246, - 15, 16, 0, 5, 0, 0, - 0, 70, 2, 16, 0, 7, - 0, 0, 0, 70, 2, 16, - 0, 2, 0, 0, 0, 54, - 0, 0, 5, 34, 0, 16, - 0, 6, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 3, 0, 0, - 0, 6, 0, 16, 0, 5, - 0, 0, 0, 70, 2, 16, - 0, 6, 0, 0, 0, 70, - 2, 16, 0, 2, 0, 0, - 0, 21, 0, 0, 1, 16, - 0, 0, 10, 18, 0, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 2, 64, 0, 0, 154, - 153, 153, 62, 61, 10, 23, - 63, 174, 71, 225, 61, 0, - 0, 0, 0, 16, 0, 0, - 10, 34, 0, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 3, 0, 0, 0, 2, - 64, 0, 0, 154, 153, 153, - 62, 61, 10, 23, 63, 174, - 71, 225, 61, 0, 0, 0, - 0, 0, 0, 0, 8, 18, - 0, 16, 0, 2, 0, 0, - 0, 26, 0, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 2, - 0, 0, 0, 0, 0, 0, - 7, 114, 0, 16, 0, 2, - 0, 0, 0, 6, 0, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 16, 0, 0, 10, 130, - 0, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 2, - 0, 0, 0, 2, 64, 0, - 0, 154, 153, 153, 62, 61, - 10, 23, 63, 174, 71, 225, - 61, 0, 0, 0, 0, 51, - 0, 0, 7, 18, 0, 16, - 0, 3, 0, 0, 0, 26, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 2, - 0, 0, 0, 51, 0, 0, - 7, 18, 0, 16, 0, 3, - 0, 0, 0, 42, 0, 16, - 0, 2, 0, 0, 0, 10, - 0, 16, 0, 3, 0, 0, - 0, 52, 0, 0, 7, 34, - 0, 16, 0, 3, 0, 0, - 0, 26, 0, 16, 0, 2, - 0, 0, 0, 10, 0, 16, - 0, 2, 0, 0, 0, 52, - 0, 0, 7, 34, 0, 16, - 0, 3, 0, 0, 0, 42, - 0, 16, 0, 2, 0, 0, - 0, 26, 0, 16, 0, 3, - 0, 0, 0, 49, 0, 0, - 7, 66, 0, 16, 0, 3, - 0, 0, 0, 10, 0, 16, - 0, 3, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 114, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 2, - 0, 0, 0, 56, 0, 0, - 7, 114, 0, 16, 0, 4, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 0, 0, 0, 8, 18, - 0, 16, 0, 3, 0, 0, - 0, 58, 0, 16, 0, 2, - 0, 0, 0, 10, 0, 16, - 128, 65, 0, 0, 0, 3, - 0, 0, 0, 14, 0, 0, - 7, 114, 0, 16, 0, 4, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 6, - 0, 16, 0, 3, 0, 0, - 0, 0, 0, 0, 7, 114, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 55, - 0, 0, 9, 114, 0, 16, - 0, 2, 0, 0, 0, 166, - 10, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 70, 2, 16, - 0, 2, 0, 0, 0, 49, - 0, 0, 7, 18, 0, 16, - 0, 3, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 26, 0, 16, 0, 3, - 0, 0, 0, 0, 0, 0, - 8, 114, 0, 16, 0, 4, - 0, 0, 0, 246, 15, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 2, 0, 0, 0, 0, - 0, 0, 8, 66, 0, 16, - 0, 3, 0, 0, 0, 58, - 0, 16, 128, 65, 0, 0, - 0, 2, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 56, 0, 0, 7, 114, - 0, 16, 0, 4, 0, 0, - 0, 166, 10, 16, 0, 3, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 0, - 0, 0, 8, 34, 0, 16, - 0, 3, 0, 0, 0, 58, - 0, 16, 128, 65, 0, 0, - 0, 2, 0, 0, 0, 26, - 0, 16, 0, 3, 0, 0, - 0, 14, 0, 0, 7, 226, - 0, 16, 0, 3, 0, 0, - 0, 6, 9, 16, 0, 4, - 0, 0, 0, 86, 5, 16, - 0, 3, 0, 0, 0, 0, - 0, 0, 7, 226, 0, 16, - 0, 3, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 86, 14, 16, 0, 3, - 0, 0, 0, 55, 0, 0, - 9, 114, 0, 16, 0, 2, - 0, 0, 0, 6, 0, 16, - 0, 3, 0, 0, 0, 150, - 7, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 2, - 0, 0, 0, 18, 0, 0, - 1, 32, 0, 0, 8, 130, - 0, 16, 0, 2, 0, 0, - 0, 10, 128, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 13, - 0, 0, 0, 31, 0, 4, - 3, 58, 0, 16, 0, 2, - 0, 0, 0, 52, 0, 0, - 7, 130, 0, 16, 0, 2, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 26, - 0, 16, 0, 0, 0, 0, - 0, 52, 0, 0, 7, 130, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 58, 0, 16, - 0, 2, 0, 0, 0, 51, - 0, 0, 7, 18, 0, 16, - 0, 3, 0, 0, 0, 42, - 0, 16, 0, 0, 0, 0, - 0, 26, 0, 16, 0, 0, - 0, 0, 0, 51, 0, 0, - 7, 18, 0, 16, 0, 3, - 0, 0, 0, 10, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 3, 0, 0, - 0, 0, 0, 0, 8, 130, - 0, 16, 0, 3, 0, 0, - 0, 58, 0, 16, 0, 2, - 0, 0, 0, 10, 0, 16, - 128, 65, 0, 0, 0, 3, - 0, 0, 0, 29, 0, 0, - 7, 130, 0, 16, 0, 2, - 0, 0, 0, 26, 0, 16, - 0, 1, 0, 0, 0, 10, - 0, 16, 0, 1, 0, 0, - 0, 31, 0, 4, 3, 58, - 0, 16, 0, 2, 0, 0, - 0, 0, 0, 0, 8, 242, - 0, 16, 0, 4, 0, 0, - 0, 6, 10, 16, 128, 65, - 0, 0, 0, 1, 0, 0, - 0, 150, 4, 16, 0, 1, - 0, 0, 0, 49, 0, 0, - 10, 114, 0, 16, 0, 5, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 22, - 7, 16, 0, 4, 0, 0, - 0, 14, 0, 0, 7, 114, - 0, 16, 0, 6, 0, 0, - 0, 246, 15, 16, 0, 3, - 0, 0, 0, 22, 7, 16, - 0, 4, 0, 0, 0, 56, - 0, 0, 7, 114, 0, 16, - 0, 3, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 70, 2, 16, 0, 6, - 0, 0, 0, 55, 0, 0, - 9, 98, 0, 16, 0, 6, - 0, 0, 0, 6, 0, 16, - 0, 5, 0, 0, 0, 6, - 3, 16, 0, 3, 0, 0, - 0, 6, 1, 16, 0, 4, - 0, 0, 0, 29, 0, 0, - 7, 146, 0, 16, 0, 5, - 0, 0, 0, 166, 10, 16, - 0, 1, 0, 0, 0, 86, - 1, 16, 0, 1, 0, 0, - 0, 55, 0, 0, 9, 98, - 0, 16, 0, 7, 0, 0, - 0, 86, 5, 16, 0, 5, - 0, 0, 0, 246, 13, 16, - 0, 3, 0, 0, 0, 6, - 1, 16, 0, 4, 0, 0, - 0, 55, 0, 0, 9, 50, - 0, 16, 0, 4, 0, 0, - 0, 166, 10, 16, 0, 5, - 0, 0, 0, 230, 10, 16, - 0, 3, 0, 0, 0, 230, - 10, 16, 0, 4, 0, 0, - 0, 54, 0, 0, 5, 18, - 0, 16, 0, 7, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 5, 66, 0, 16, 0, 4, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 55, - 0, 0, 9, 114, 0, 16, - 0, 4, 0, 0, 0, 246, - 15, 16, 0, 5, 0, 0, - 0, 70, 2, 16, 0, 7, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 54, - 0, 0, 5, 18, 0, 16, - 0, 6, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 4, 0, 0, - 0, 6, 0, 16, 0, 5, - 0, 0, 0, 70, 2, 16, - 0, 6, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 18, 0, 0, 1, 0, - 0, 0, 8, 242, 0, 16, - 0, 5, 0, 0, 0, 86, - 10, 16, 128, 65, 0, 0, - 0, 1, 0, 0, 0, 134, - 1, 16, 0, 1, 0, 0, - 0, 49, 0, 0, 10, 114, - 0, 16, 0, 6, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 22, 7, 16, - 0, 5, 0, 0, 0, 14, - 0, 0, 7, 114, 0, 16, - 0, 7, 0, 0, 0, 246, - 15, 16, 0, 3, 0, 0, - 0, 22, 7, 16, 0, 5, - 0, 0, 0, 56, 0, 0, - 7, 114, 0, 16, 0, 3, - 0, 0, 0, 70, 2, 16, - 0, 5, 0, 0, 0, 70, - 2, 16, 0, 7, 0, 0, - 0, 55, 0, 0, 9, 82, - 0, 16, 0, 7, 0, 0, - 0, 6, 0, 16, 0, 6, - 0, 0, 0, 6, 3, 16, - 0, 3, 0, 0, 0, 6, - 1, 16, 0, 5, 0, 0, - 0, 29, 0, 0, 7, 146, - 0, 16, 0, 6, 0, 0, - 0, 166, 10, 16, 0, 1, - 0, 0, 0, 6, 4, 16, - 0, 1, 0, 0, 0, 55, - 0, 0, 9, 82, 0, 16, - 0, 8, 0, 0, 0, 86, - 5, 16, 0, 6, 0, 0, - 0, 246, 13, 16, 0, 3, - 0, 0, 0, 6, 1, 16, - 0, 5, 0, 0, 0, 55, - 0, 0, 9, 50, 0, 16, - 0, 3, 0, 0, 0, 166, - 10, 16, 0, 6, 0, 0, - 0, 182, 15, 16, 0, 3, - 0, 0, 0, 182, 15, 16, - 0, 5, 0, 0, 0, 54, - 0, 0, 5, 34, 0, 16, - 0, 8, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 5, 66, - 0, 16, 0, 3, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 55, 0, 0, - 9, 114, 0, 16, 0, 3, - 0, 0, 0, 246, 15, 16, - 0, 6, 0, 0, 0, 70, - 2, 16, 0, 8, 0, 0, - 0, 70, 2, 16, 0, 3, - 0, 0, 0, 54, 0, 0, - 5, 34, 0, 16, 0, 7, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 55, - 0, 0, 9, 114, 0, 16, - 0, 4, 0, 0, 0, 6, - 0, 16, 0, 6, 0, 0, - 0, 70, 2, 16, 0, 7, - 0, 0, 0, 70, 2, 16, - 0, 3, 0, 0, 0, 21, - 0, 0, 1, 16, 0, 0, - 10, 130, 0, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 1, 0, 0, 0, 2, - 64, 0, 0, 154, 153, 153, - 62, 61, 10, 23, 63, 174, - 71, 225, 61, 0, 0, 0, - 0, 16, 0, 0, 10, 18, - 0, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 2, 64, 0, - 0, 154, 153, 153, 62, 61, - 10, 23, 63, 174, 71, 225, - 61, 0, 0, 0, 0, 0, - 0, 0, 8, 130, 0, 16, - 0, 2, 0, 0, 0, 58, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 128, 65, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 7, 114, - 0, 16, 0, 3, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 16, - 0, 0, 10, 130, 0, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 2, 64, 0, 0, 154, - 153, 153, 62, 61, 10, 23, - 63, 174, 71, 225, 61, 0, - 0, 0, 0, 51, 0, 0, - 7, 130, 0, 16, 0, 3, - 0, 0, 0, 26, 0, 16, - 0, 3, 0, 0, 0, 10, - 0, 16, 0, 3, 0, 0, - 0, 51, 0, 0, 7, 130, - 0, 16, 0, 3, 0, 0, - 0, 42, 0, 16, 0, 3, - 0, 0, 0, 58, 0, 16, - 0, 3, 0, 0, 0, 52, - 0, 0, 7, 18, 0, 16, - 0, 4, 0, 0, 0, 26, - 0, 16, 0, 3, 0, 0, - 0, 10, 0, 16, 0, 3, - 0, 0, 0, 52, 0, 0, - 7, 18, 0, 16, 0, 4, - 0, 0, 0, 42, 0, 16, - 0, 3, 0, 0, 0, 10, - 0, 16, 0, 4, 0, 0, - 0, 49, 0, 0, 7, 34, - 0, 16, 0, 4, 0, 0, - 0, 58, 0, 16, 0, 3, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 8, 114, 0, 16, - 0, 5, 0, 0, 0, 246, - 15, 16, 128, 65, 0, 0, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 56, 0, 0, 7, 114, - 0, 16, 0, 5, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 5, 0, 0, 0, 0, - 0, 0, 8, 130, 0, 16, - 0, 3, 0, 0, 0, 58, - 0, 16, 0, 2, 0, 0, - 0, 58, 0, 16, 128, 65, - 0, 0, 0, 3, 0, 0, - 0, 14, 0, 0, 7, 114, - 0, 16, 0, 5, 0, 0, - 0, 70, 2, 16, 0, 5, - 0, 0, 0, 246, 15, 16, - 0, 3, 0, 0, 0, 0, - 0, 0, 7, 114, 0, 16, - 0, 5, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 5, - 0, 0, 0, 55, 0, 0, - 9, 114, 0, 16, 0, 3, - 0, 0, 0, 86, 5, 16, - 0, 4, 0, 0, 0, 70, - 2, 16, 0, 5, 0, 0, - 0, 70, 2, 16, 0, 3, - 0, 0, 0, 49, 0, 0, - 7, 130, 0, 16, 0, 3, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 10, - 0, 16, 0, 4, 0, 0, - 0, 0, 0, 0, 8, 226, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 6, 9, 16, 0, 3, - 0, 0, 0, 0, 0, 0, - 8, 18, 0, 16, 0, 5, - 0, 0, 0, 58, 0, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 56, - 0, 0, 7, 226, 0, 16, - 0, 4, 0, 0, 0, 86, - 14, 16, 0, 4, 0, 0, - 0, 6, 0, 16, 0, 5, - 0, 0, 0, 0, 0, 0, - 8, 18, 0, 16, 0, 4, - 0, 0, 0, 58, 0, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 10, 0, 16, - 0, 4, 0, 0, 0, 14, - 0, 0, 7, 114, 0, 16, - 0, 4, 0, 0, 0, 150, - 7, 16, 0, 4, 0, 0, - 0, 6, 0, 16, 0, 4, - 0, 0, 0, 0, 0, 0, - 7, 114, 0, 16, 0, 4, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 2, 0, 0, - 0, 246, 15, 16, 0, 3, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 18, 0, 0, 1, 32, - 0, 0, 8, 130, 0, 16, - 0, 2, 0, 0, 0, 10, - 128, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 14, 0, 0, - 0, 31, 0, 4, 3, 58, - 0, 16, 0, 2, 0, 0, - 0, 16, 0, 0, 10, 130, - 0, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 2, 64, 0, - 0, 154, 153, 153, 62, 61, - 10, 23, 63, 174, 71, 225, - 61, 0, 0, 0, 0, 16, - 0, 0, 10, 18, 0, 16, - 0, 3, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 154, - 153, 153, 62, 61, 10, 23, - 63, 174, 71, 225, 61, 0, - 0, 0, 0, 0, 0, 0, - 8, 130, 0, 16, 0, 2, - 0, 0, 0, 58, 0, 16, - 0, 2, 0, 0, 0, 10, - 0, 16, 128, 65, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 7, 114, 0, 16, - 0, 3, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 16, 0, 0, - 10, 130, 0, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 3, 0, 0, 0, 2, - 64, 0, 0, 154, 153, 153, - 62, 61, 10, 23, 63, 174, - 71, 225, 61, 0, 0, 0, - 0, 51, 0, 0, 7, 130, - 0, 16, 0, 3, 0, 0, - 0, 26, 0, 16, 0, 3, - 0, 0, 0, 10, 0, 16, - 0, 3, 0, 0, 0, 51, - 0, 0, 7, 130, 0, 16, - 0, 3, 0, 0, 0, 42, - 0, 16, 0, 3, 0, 0, - 0, 58, 0, 16, 0, 3, - 0, 0, 0, 52, 0, 0, - 7, 18, 0, 16, 0, 4, - 0, 0, 0, 26, 0, 16, - 0, 3, 0, 0, 0, 10, - 0, 16, 0, 3, 0, 0, - 0, 52, 0, 0, 7, 18, - 0, 16, 0, 4, 0, 0, - 0, 42, 0, 16, 0, 3, - 0, 0, 0, 10, 0, 16, - 0, 4, 0, 0, 0, 49, - 0, 0, 7, 34, 0, 16, - 0, 4, 0, 0, 0, 58, - 0, 16, 0, 3, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 8, 114, 0, 16, 0, 5, - 0, 0, 0, 246, 15, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 3, 0, 0, 0, 56, - 0, 0, 7, 114, 0, 16, - 0, 5, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 5, - 0, 0, 0, 0, 0, 0, - 8, 130, 0, 16, 0, 3, - 0, 0, 0, 58, 0, 16, - 0, 2, 0, 0, 0, 58, - 0, 16, 128, 65, 0, 0, - 0, 3, 0, 0, 0, 14, - 0, 0, 7, 114, 0, 16, - 0, 5, 0, 0, 0, 70, - 2, 16, 0, 5, 0, 0, - 0, 246, 15, 16, 0, 3, - 0, 0, 0, 0, 0, 0, - 7, 114, 0, 16, 0, 5, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 5, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 3, 0, 0, - 0, 86, 5, 16, 0, 4, - 0, 0, 0, 70, 2, 16, - 0, 5, 0, 0, 0, 70, - 2, 16, 0, 3, 0, 0, - 0, 49, 0, 0, 7, 130, - 0, 16, 0, 3, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 10, 0, 16, - 0, 4, 0, 0, 0, 0, - 0, 0, 8, 226, 0, 16, - 0, 4, 0, 0, 0, 246, - 15, 16, 128, 65, 0, 0, - 0, 2, 0, 0, 0, 6, - 9, 16, 0, 3, 0, 0, - 0, 0, 0, 0, 8, 18, - 0, 16, 0, 5, 0, 0, - 0, 58, 0, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 56, 0, 0, - 7, 226, 0, 16, 0, 4, - 0, 0, 0, 86, 14, 16, - 0, 4, 0, 0, 0, 6, - 0, 16, 0, 5, 0, 0, - 0, 0, 0, 0, 8, 18, - 0, 16, 0, 4, 0, 0, - 0, 58, 0, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 4, - 0, 0, 0, 14, 0, 0, - 7, 114, 0, 16, 0, 4, - 0, 0, 0, 150, 7, 16, - 0, 4, 0, 0, 0, 6, - 0, 16, 0, 4, 0, 0, - 0, 0, 0, 0, 7, 114, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 55, - 0, 0, 9, 114, 0, 16, - 0, 2, 0, 0, 0, 246, - 15, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 70, 2, 16, - 0, 3, 0, 0, 0, 18, - 0, 0, 1, 16, 0, 0, - 10, 130, 0, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 0, 0, 0, 0, 2, - 64, 0, 0, 154, 153, 153, - 62, 61, 10, 23, 63, 174, - 71, 225, 61, 0, 0, 0, - 0, 16, 0, 0, 10, 18, - 0, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 2, 64, 0, - 0, 154, 153, 153, 62, 61, - 10, 23, 63, 174, 71, 225, - 61, 0, 0, 0, 0, 0, - 0, 0, 8, 130, 0, 16, - 0, 2, 0, 0, 0, 58, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 128, 65, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 7, 114, - 0, 16, 0, 1, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 16, - 0, 0, 10, 130, 0, 16, - 0, 2, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 2, 64, 0, 0, 154, - 153, 153, 62, 61, 10, 23, - 63, 174, 71, 225, 61, 0, - 0, 0, 0, 51, 0, 0, - 7, 18, 0, 16, 0, 3, - 0, 0, 0, 26, 0, 16, - 0, 1, 0, 0, 0, 10, - 0, 16, 0, 1, 0, 0, - 0, 51, 0, 0, 7, 18, - 0, 16, 0, 3, 0, 0, - 0, 42, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 0, 3, 0, 0, 0, 52, - 0, 0, 7, 34, 0, 16, - 0, 3, 0, 0, 0, 26, - 0, 16, 0, 1, 0, 0, - 0, 10, 0, 16, 0, 1, - 0, 0, 0, 52, 0, 0, - 7, 34, 0, 16, 0, 3, - 0, 0, 0, 42, 0, 16, - 0, 1, 0, 0, 0, 26, - 0, 16, 0, 3, 0, 0, - 0, 49, 0, 0, 7, 66, - 0, 16, 0, 3, 0, 0, - 0, 10, 0, 16, 0, 3, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 8, 114, 0, 16, - 0, 4, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 246, 15, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 56, 0, 0, 7, 114, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 4, 0, 0, 0, 0, - 0, 0, 8, 18, 0, 16, - 0, 3, 0, 0, 0, 58, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 128, 65, - 0, 0, 0, 3, 0, 0, - 0, 14, 0, 0, 7, 114, - 0, 16, 0, 4, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 6, 0, 16, - 0, 3, 0, 0, 0, 0, - 0, 0, 7, 114, 0, 16, - 0, 4, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 55, 0, 0, - 9, 114, 0, 16, 0, 1, - 0, 0, 0, 166, 10, 16, - 0, 3, 0, 0, 0, 70, - 2, 16, 0, 4, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 49, 0, 0, - 7, 18, 0, 16, 0, 3, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 26, - 0, 16, 0, 3, 0, 0, - 0, 0, 0, 0, 8, 114, - 0, 16, 0, 4, 0, 0, - 0, 246, 15, 16, 128, 65, - 0, 0, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 0, 0, 0, - 8, 66, 0, 16, 0, 3, - 0, 0, 0, 58, 0, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 56, - 0, 0, 7, 114, 0, 16, - 0, 4, 0, 0, 0, 166, - 10, 16, 0, 3, 0, 0, - 0, 70, 2, 16, 0, 4, - 0, 0, 0, 0, 0, 0, - 8, 34, 0, 16, 0, 3, - 0, 0, 0, 58, 0, 16, - 128, 65, 0, 0, 0, 2, - 0, 0, 0, 26, 0, 16, - 0, 3, 0, 0, 0, 14, - 0, 0, 7, 226, 0, 16, - 0, 3, 0, 0, 0, 6, - 9, 16, 0, 4, 0, 0, - 0, 86, 5, 16, 0, 3, - 0, 0, 0, 0, 0, 0, - 7, 226, 0, 16, 0, 3, - 0, 0, 0, 246, 15, 16, - 0, 2, 0, 0, 0, 86, - 14, 16, 0, 3, 0, 0, - 0, 55, 0, 0, 9, 114, - 0, 16, 0, 2, 0, 0, - 0, 6, 0, 16, 0, 3, - 0, 0, 0, 150, 7, 16, - 0, 3, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 21, 0, 0, 1, 21, - 0, 0, 1, 21, 0, 0, - 1, 0, 0, 0, 8, 18, - 0, 16, 0, 1, 0, 0, - 0, 58, 0, 16, 128, 65, - 0, 0, 0, 1, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 56, 0, 0, - 7, 226, 0, 16, 0, 1, - 0, 0, 0, 246, 15, 16, - 0, 1, 0, 0, 0, 6, - 9, 16, 0, 2, 0, 0, - 0, 50, 0, 0, 9, 114, - 0, 16, 0, 0, 0, 0, - 0, 6, 0, 16, 0, 1, - 0, 0, 0, 70, 2, 16, - 0, 0, 0, 0, 0, 150, - 7, 16, 0, 1, 0, 0, - 0, 56, 0, 0, 7, 114, - 32, 16, 0, 0, 0, 0, - 0, 246, 15, 16, 0, 0, - 0, 0, 0, 70, 2, 16, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 130, 32, 16, - 0, 0, 0, 0, 0, 58, - 0, 16, 0, 0, 0, 0, - 0, 62, 0, 0, 1, 83, - 84, 65, 84, 116, 0, 0, - 0, 195, 0, 0, 0, 9, - 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 127, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 7, - 0, 0, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 36, - 0, 0, 0, 28, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 68, 69, - 70, 100, 1, 0, 0, 1, - 0, 0, 0, 232, 0, 0, - 0, 5, 0, 0, 0, 28, - 0, 0, 0, 0, 4, 255, - 255, 0, 129, 0, 0, 48, - 1, 0, 0, 188, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 197, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 209, 0, 0, 0, 2, - 0, 0, 0, 5, 0, 0, - 0, 4, 0, 0, 0, 255, - 255, 255, 255, 0, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 213, 0, 0, - 0, 2, 0, 0, 0, 5, - 0, 0, 0, 4, 0, 0, - 0, 255, 255, 255, 255, 1, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 220, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 115, 83, 97, 109, 112, - 108, 101, 114, 0, 115, 66, - 99, 107, 83, 97, 109, 112, - 108, 101, 114, 0, 116, 101, - 120, 0, 98, 99, 107, 116, - 101, 120, 0, 36, 71, 108, - 111, 98, 97, 108, 115, 0, - 171, 171, 171, 220, 0, 0, - 0, 1, 0, 0, 0, 0, - 1, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 24, 1, 0, - 0, 0, 0, 0, 0, 4, - 0, 0, 0, 2, 0, 0, - 0, 32, 1, 0, 0, 0, - 0, 0, 0, 98, 108, 101, - 110, 100, 111, 112, 0, 0, - 0, 19, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 77, 105, 99, - 114, 111, 115, 111, 102, 116, - 32, 40, 82, 41, 32, 72, - 76, 83, 76, 32, 83, 104, - 97, 100, 101, 114, 32, 67, - 111, 109, 112, 105, 108, 101, - 114, 32, 57, 46, 50, 57, - 46, 57, 53, 50, 46, 51, - 49, 49, 49, 0, 171, 171, - 171, 73, 83, 71, 78, 104, - 0, 0, 0, 3, 0, 0, - 0, 8, 0, 0, 0, 80, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 15, 0, 0, 0, 92, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 1, 0, 0, - 0, 3, 3, 0, 0, 92, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 83, - 86, 95, 80, 111, 115, 105, - 116, 105, 111, 110, 0, 84, - 69, 88, 67, 79, 79, 82, - 68, 0, 171, 171, 171, 79, - 83, 71, 78, 44, 0, 0, - 0, 1, 0, 0, 0, 8, - 0, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 83, 86, 95, - 84, 97, 114, 103, 101, 116, - 0, 171, 171, 249, 55, 0, - 0, 0, 0, 0, 0, 83, - 97, 109, 112, 108, 101, 82, - 97, 100, 105, 97, 108, 71, - 114, 97, 100, 105, 101, 110, - 116, 0, 65, 80, 111, 115, - 0, 40, 7, 0, 0, 68, - 88, 66, 67, 46, 205, 200, - 104, 105, 244, 107, 100, 111, - 73, 199, 142, 36, 0, 178, - 231, 1, 0, 0, 0, 40, - 7, 0, 0, 6, 0, 0, - 0, 56, 0, 0, 0, 148, - 1, 0, 0, 104, 3, 0, - 0, 228, 3, 0, 0, 132, - 6, 0, 0, 184, 6, 0, - 0, 65, 111, 110, 57, 84, - 1, 0, 0, 84, 1, 0, - 0, 0, 2, 254, 255, 252, - 0, 0, 0, 88, 0, 0, - 0, 4, 0, 36, 0, 0, - 0, 84, 0, 0, 0, 84, - 0, 0, 0, 36, 0, 1, - 0, 84, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 2, - 0, 1, 0, 2, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 3, 0, 0, - 0, 0, 0, 1, 0, 3, - 0, 1, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 2, 254, 255, 81, - 0, 0, 5, 6, 0, 15, - 160, 0, 0, 128, 63, 0, - 0, 0, 63, 0, 0, 0, - 0, 0, 0, 0, 0, 31, - 0, 0, 2, 5, 0, 0, - 128, 0, 0, 15, 144, 4, - 0, 0, 4, 0, 0, 3, - 224, 0, 0, 228, 144, 2, - 0, 238, 160, 2, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 3, 128, 0, 0, 228, - 144, 1, 0, 238, 160, 1, - 0, 228, 160, 2, 0, 0, - 3, 0, 0, 4, 128, 0, - 0, 0, 128, 6, 0, 0, - 160, 5, 0, 0, 3, 0, - 0, 4, 128, 0, 0, 170, - 128, 5, 0, 0, 160, 5, - 0, 0, 3, 1, 0, 1, - 128, 0, 0, 170, 128, 6, - 0, 85, 160, 2, 0, 0, - 3, 0, 0, 4, 128, 0, - 0, 85, 129, 6, 0, 0, - 160, 2, 0, 0, 3, 0, - 0, 3, 192, 0, 0, 228, - 128, 0, 0, 228, 160, 5, - 0, 0, 3, 0, 0, 1, - 128, 0, 0, 170, 128, 5, - 0, 85, 160, 5, 0, 0, - 3, 1, 0, 2, 128, 0, - 0, 0, 128, 6, 0, 85, - 160, 1, 0, 0, 2, 1, - 0, 4, 128, 6, 0, 0, - 160, 8, 0, 0, 3, 0, - 0, 8, 224, 1, 0, 228, - 128, 3, 0, 228, 160, 8, - 0, 0, 3, 0, 0, 4, - 224, 1, 0, 228, 128, 4, - 0, 228, 160, 1, 0, 0, - 2, 0, 0, 12, 192, 6, - 0, 36, 160, 255, 255, 0, - 0, 83, 72, 68, 82, 204, - 1, 0, 0, 64, 0, 1, - 0, 115, 0, 0, 0, 89, - 0, 0, 4, 70, 142, 32, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 89, 0, 0, - 4, 70, 142, 32, 0, 1, - 0, 0, 0, 4, 0, 0, - 0, 95, 0, 0, 3, 50, - 16, 16, 0, 0, 0, 0, - 0, 103, 0, 0, 4, 242, - 32, 16, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 50, 32, 16, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 194, 32, 16, - 0, 1, 0, 0, 0, 104, - 0, 0, 2, 2, 0, 0, - 0, 54, 0, 0, 8, 194, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 128, 63, 50, 0, 0, - 11, 50, 0, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 0, 0, 0, 0, 230, - 138, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 70, - 128, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 50, 32, 16, - 0, 0, 0, 0, 0, 70, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 18, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 0, - 0, 0, 8, 34, 0, 16, - 0, 0, 0, 0, 0, 26, - 0, 16, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 56, 0, 0, 8, 50, - 0, 16, 0, 0, 0, 0, - 0, 70, 0, 16, 0, 0, - 0, 0, 0, 70, 128, 32, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 56, 0, 0, - 10, 50, 0, 16, 0, 1, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 2, - 64, 0, 0, 0, 0, 0, - 63, 0, 0, 0, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 5, 66, - 0, 16, 0, 1, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 16, 0, 0, - 8, 66, 32, 16, 0, 1, - 0, 0, 0, 70, 2, 16, - 0, 1, 0, 0, 0, 70, - 130, 32, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 16, - 0, 0, 8, 130, 32, 16, - 0, 1, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 70, 130, 32, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 50, 0, 0, 11, 50, - 32, 16, 0, 1, 0, 0, - 0, 70, 16, 16, 0, 0, - 0, 0, 0, 230, 138, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 70, 128, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, - 0, 0, 0, 12, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, - 68, 69, 70, 152, 2, 0, - 0, 2, 0, 0, 0, 100, - 0, 0, 0, 2, 0, 0, - 0, 28, 0, 0, 0, 0, - 4, 254, 255, 0, 129, 0, - 0, 103, 2, 0, 0, 92, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 96, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 99, 98, 48, - 0, 99, 98, 50, 0, 92, - 0, 0, 0, 4, 0, 0, - 0, 148, 0, 0, 0, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 96, - 0, 0, 0, 7, 0, 0, - 0, 52, 1, 0, 0, 112, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 244, - 0, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 16, - 1, 0, 0, 16, 0, 0, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 26, - 1, 0, 0, 32, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 40, - 1, 0, 0, 48, 0, 0, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 81, - 117, 97, 100, 68, 101, 115, - 99, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 84, 101, 120, - 67, 111, 111, 114, 100, 115, - 0, 77, 97, 115, 107, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 84, 101, 120, - 116, 67, 111, 108, 111, 114, - 0, 171, 171, 220, 1, 0, - 0, 0, 0, 0, 0, 44, - 0, 0, 0, 2, 0, 0, - 0, 244, 1, 0, 0, 0, - 0, 0, 0, 4, 2, 0, - 0, 48, 0, 0, 0, 8, - 0, 0, 0, 2, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 32, 2, 0, - 0, 64, 0, 0, 0, 12, - 0, 0, 0, 0, 0, 0, - 0, 40, 2, 0, 0, 0, - 0, 0, 0, 56, 2, 0, - 0, 80, 0, 0, 0, 8, - 0, 0, 0, 0, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 64, 2, 0, - 0, 88, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 84, 2, 0, - 0, 92, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 92, 2, 0, - 0, 96, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 68, 101, 118, - 105, 99, 101, 83, 112, 97, - 99, 101, 84, 111, 85, 115, - 101, 114, 83, 112, 97, 99, - 101, 0, 171, 3, 0, 3, - 0, 3, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 100, 105, 109, 101, 110, - 115, 105, 111, 110, 115, 0, - 171, 1, 0, 3, 0, 1, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 100, - 105, 102, 102, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 99, - 101, 110, 116, 101, 114, 49, - 0, 65, 0, 171, 171, 0, - 0, 3, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 114, 97, 100, - 105, 117, 115, 49, 0, 115, - 113, 95, 114, 97, 100, 105, - 117, 115, 49, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 73, - 83, 71, 78, 44, 0, 0, - 0, 1, 0, 0, 0, 8, - 0, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 7, - 3, 0, 0, 80, 79, 83, - 73, 84, 73, 79, 78, 0, - 171, 171, 171, 79, 83, 71, - 78, 104, 0, 0, 0, 3, - 0, 0, 0, 8, 0, 0, - 0, 80, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 3, 12, 0, - 0, 92, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 12, 3, 0, - 0, 83, 86, 95, 80, 111, - 115, 105, 116, 105, 111, 110, - 0, 84, 69, 88, 67, 79, - 79, 82, 68, 0, 171, 171, - 171, 15, 94, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 220, 9, 0, - 0, 68, 88, 66, 67, 150, - 95, 39, 142, 115, 51, 254, - 246, 202, 212, 184, 90, 65, - 64, 226, 180, 1, 0, 0, - 0, 220, 9, 0, 0, 6, - 0, 0, 0, 56, 0, 0, - 0, 128, 2, 0, 0, 88, - 6, 0, 0, 212, 6, 0, - 0, 56, 9, 0, 0, 168, - 9, 0, 0, 65, 111, 110, - 57, 64, 2, 0, 0, 64, - 2, 0, 0, 0, 2, 255, - 255, 8, 2, 0, 0, 56, - 0, 0, 0, 1, 0, 44, - 0, 0, 0, 56, 0, 0, - 0, 56, 0, 2, 0, 36, - 0, 0, 0, 56, 0, 0, - 0, 0, 0, 1, 1, 1, - 0, 0, 0, 4, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 1, 2, 255, 255, 81, - 0, 0, 5, 3, 0, 15, - 160, 0, 0, 0, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 81, - 0, 0, 5, 4, 0, 15, - 160, 0, 0, 128, 63, 0, - 0, 128, 191, 0, 0, 0, - 0, 0, 0, 0, 128, 31, - 0, 0, 2, 0, 0, 0, - 128, 0, 0, 15, 176, 31, - 0, 0, 2, 0, 0, 0, - 144, 0, 8, 15, 160, 31, - 0, 0, 2, 0, 0, 0, - 144, 1, 8, 15, 160, 2, - 0, 0, 3, 0, 0, 3, - 128, 0, 0, 235, 176, 1, - 0, 228, 161, 90, 0, 0, - 4, 0, 0, 8, 128, 0, - 0, 228, 128, 0, 0, 228, - 128, 2, 0, 0, 161, 5, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 1, - 0, 170, 160, 1, 0, 0, - 2, 0, 0, 4, 128, 1, - 0, 255, 160, 8, 0, 0, - 3, 0, 0, 1, 128, 0, - 0, 228, 128, 0, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 2, 128, 0, 0, 0, - 128, 0, 0, 0, 128, 0, - 0, 255, 129, 35, 0, 0, - 2, 0, 0, 4, 128, 0, - 0, 85, 128, 7, 0, 0, - 2, 0, 0, 4, 128, 0, - 0, 170, 128, 6, 0, 0, - 2, 1, 0, 1, 128, 0, - 0, 170, 128, 1, 0, 0, - 2, 1, 0, 6, 128, 1, - 0, 0, 129, 2, 0, 0, - 3, 0, 0, 13, 128, 0, - 0, 0, 128, 1, 0, 148, - 128, 6, 0, 0, 2, 1, - 0, 1, 128, 1, 0, 170, - 160, 5, 0, 0, 3, 0, - 0, 13, 128, 0, 0, 228, - 128, 1, 0, 0, 128, 1, - 0, 0, 2, 1, 0, 8, - 128, 1, 0, 255, 160, 4, - 0, 0, 4, 1, 0, 7, - 128, 0, 0, 248, 128, 0, - 0, 170, 160, 1, 0, 255, - 128, 88, 0, 0, 4, 2, - 0, 1, 128, 1, 0, 0, - 128, 0, 0, 0, 128, 0, - 0, 255, 128, 88, 0, 0, - 4, 0, 0, 13, 128, 1, - 0, 148, 128, 4, 0, 68, - 160, 4, 0, 230, 160, 1, - 0, 0, 2, 2, 0, 2, - 128, 3, 0, 0, 160, 66, - 0, 0, 3, 1, 0, 15, - 128, 0, 0, 228, 176, 1, - 8, 228, 160, 66, 0, 0, - 3, 2, 0, 15, 128, 2, - 0, 228, 128, 0, 8, 228, - 160, 5, 0, 0, 3, 2, - 0, 7, 128, 2, 0, 255, - 128, 2, 0, 228, 128, 5, - 0, 0, 3, 1, 0, 15, - 128, 1, 0, 255, 128, 2, - 0, 228, 128, 2, 0, 0, - 3, 0, 0, 8, 128, 0, - 0, 255, 128, 0, 0, 0, - 128, 88, 0, 0, 4, 0, - 0, 1, 128, 0, 0, 255, - 128, 0, 0, 0, 128, 0, - 0, 170, 128, 88, 0, 0, - 4, 1, 0, 15, 128, 0, - 0, 0, 129, 4, 0, 170, - 160, 1, 0, 228, 128, 88, - 0, 0, 4, 0, 0, 15, - 128, 0, 0, 85, 128, 1, - 0, 228, 128, 4, 0, 170, - 160, 1, 0, 0, 2, 0, - 8, 15, 128, 0, 0, 228, - 128, 255, 255, 0, 0, 83, - 72, 68, 82, 208, 3, 0, - 0, 64, 0, 0, 0, 244, - 0, 0, 0, 89, 0, 0, - 4, 70, 142, 32, 0, 0, - 0, 0, 0, 7, 0, 0, - 0, 90, 0, 0, 3, 0, - 96, 16, 0, 0, 0, 0, - 0, 90, 0, 0, 3, 0, - 96, 16, 0, 1, 0, 0, - 0, 88, 24, 0, 4, 0, - 112, 16, 0, 0, 0, 0, - 0, 85, 85, 0, 0, 88, - 24, 0, 4, 0, 112, 16, - 0, 1, 0, 0, 0, 85, - 85, 0, 0, 98, 16, 0, - 3, 50, 16, 16, 0, 1, - 0, 0, 0, 98, 16, 0, - 3, 194, 16, 16, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 242, 32, 16, 0, 0, - 0, 0, 0, 104, 0, 0, - 2, 3, 0, 0, 0, 0, - 0, 0, 9, 50, 0, 16, - 0, 0, 0, 0, 0, 230, - 26, 16, 0, 1, 0, 0, - 0, 70, 128, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 54, - 0, 0, 6, 66, 0, 16, - 0, 0, 0, 0, 0, 58, - 128, 32, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 16, - 0, 0, 8, 66, 0, 16, - 0, 0, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, - 0, 70, 130, 32, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 15, 0, 0, 7, 18, - 0, 16, 0, 0, 0, 0, - 0, 70, 0, 16, 0, 0, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 0, - 0, 0, 9, 18, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 10, 128, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 56, - 0, 0, 8, 18, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 42, 128, 32, 0, 0, - 0, 0, 0, 5, 0, 0, - 0, 50, 0, 0, 10, 18, - 0, 16, 0, 0, 0, 0, - 0, 42, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 49, - 0, 0, 7, 34, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 75, 0, 0, - 6, 18, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 128, 129, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 6, 34, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 128, 65, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 7, 82, 0, 16, 0, 0, - 0, 0, 0, 166, 10, 16, - 0, 0, 0, 0, 0, 6, - 1, 16, 0, 1, 0, 0, - 0, 14, 0, 0, 8, 82, - 0, 16, 0, 0, 0, 0, - 0, 6, 2, 16, 0, 0, - 0, 0, 0, 166, 138, 32, - 0, 0, 0, 0, 0, 5, - 0, 0, 0, 56, 0, 0, - 8, 50, 0, 16, 0, 1, - 0, 0, 0, 134, 0, 16, - 0, 0, 0, 0, 0, 166, - 138, 32, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 29, - 0, 0, 9, 50, 0, 16, - 0, 1, 0, 0, 0, 70, - 0, 16, 0, 1, 0, 0, - 0, 246, 143, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 1, - 0, 0, 10, 50, 0, 16, - 0, 1, 0, 0, 0, 70, - 0, 16, 0, 1, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 128, 63, 0, 0, 128, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 8, 18, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 10, 0, 16, - 0, 0, 0, 0, 0, 50, - 0, 0, 9, 18, 0, 16, - 0, 2, 0, 0, 0, 10, - 0, 16, 0, 1, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 34, 0, 16, - 0, 2, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 63, 69, 0, 0, 9, 242, - 0, 16, 0, 2, 0, 0, - 0, 70, 0, 16, 0, 2, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 31, 0, 4, 3, 26, - 0, 16, 0, 0, 0, 0, - 0, 54, 0, 0, 8, 242, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 62, 0, 0, - 1, 21, 0, 0, 1, 52, - 0, 0, 7, 18, 0, 16, - 0, 0, 0, 0, 0, 26, - 0, 16, 0, 1, 0, 0, - 0, 10, 0, 16, 0, 1, - 0, 0, 0, 29, 0, 0, - 7, 18, 0, 16, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 31, 0, 4, 3, 10, - 0, 16, 0, 0, 0, 0, - 0, 54, 0, 0, 8, 242, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 62, 0, 0, - 1, 21, 0, 0, 1, 56, - 0, 0, 7, 114, 0, 16, - 0, 2, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 2, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 1, 0, 0, - 0, 0, 96, 16, 0, 1, - 0, 0, 0, 56, 0, 0, - 7, 242, 32, 16, 0, 0, - 0, 0, 0, 246, 15, 16, - 0, 0, 0, 0, 0, 70, - 14, 16, 0, 2, 0, 0, - 0, 62, 0, 0, 1, 83, - 84, 65, 84, 116, 0, 0, - 0, 33, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 17, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 68, 69, - 70, 92, 2, 0, 0, 1, - 0, 0, 0, 224, 0, 0, - 0, 5, 0, 0, 0, 28, - 0, 0, 0, 0, 4, 255, - 255, 0, 129, 0, 0, 43, - 2, 0, 0, 188, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 197, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 210, 0, 0, 0, 2, - 0, 0, 0, 5, 0, 0, - 0, 4, 0, 0, 0, 255, - 255, 255, 255, 0, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 214, 0, 0, - 0, 2, 0, 0, 0, 5, - 0, 0, 0, 4, 0, 0, - 0, 255, 255, 255, 255, 1, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 219, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 115, 83, 97, 109, 112, - 108, 101, 114, 0, 115, 77, - 97, 115, 107, 83, 97, 109, - 112, 108, 101, 114, 0, 116, - 101, 120, 0, 109, 97, 115, - 107, 0, 99, 98, 50, 0, - 171, 219, 0, 0, 0, 7, - 0, 0, 0, 248, 0, 0, - 0, 112, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 160, 1, 0, 0, 0, - 0, 0, 0, 44, 0, 0, - 0, 0, 0, 0, 0, 184, - 1, 0, 0, 0, 0, 0, - 0, 200, 1, 0, 0, 48, - 0, 0, 0, 8, 0, 0, - 0, 0, 0, 0, 0, 212, - 1, 0, 0, 0, 0, 0, - 0, 228, 1, 0, 0, 64, - 0, 0, 0, 12, 0, 0, - 0, 2, 0, 0, 0, 236, - 1, 0, 0, 0, 0, 0, - 0, 252, 1, 0, 0, 80, - 0, 0, 0, 8, 0, 0, - 0, 2, 0, 0, 0, 212, - 1, 0, 0, 0, 0, 0, - 0, 4, 2, 0, 0, 88, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 8, - 2, 0, 0, 0, 0, 0, - 0, 24, 2, 0, 0, 92, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 8, - 2, 0, 0, 0, 0, 0, - 0, 32, 2, 0, 0, 96, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 8, - 2, 0, 0, 0, 0, 0, - 0, 68, 101, 118, 105, 99, - 101, 83, 112, 97, 99, 101, - 84, 111, 85, 115, 101, 114, - 83, 112, 97, 99, 101, 0, - 171, 3, 0, 3, 0, 3, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 100, - 105, 109, 101, 110, 115, 105, - 111, 110, 115, 0, 171, 1, - 0, 3, 0, 1, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 100, 105, 102, - 102, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 99, 101, 110, - 116, 101, 114, 49, 0, 65, - 0, 171, 171, 0, 0, 3, - 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 114, 97, 100, 105, 117, - 115, 49, 0, 115, 113, 95, - 114, 97, 100, 105, 117, 115, - 49, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 57, 46, 50, 57, 46, - 57, 53, 50, 46, 51, 49, - 49, 49, 0, 73, 83, 71, - 78, 104, 0, 0, 0, 3, - 0, 0, 0, 8, 0, 0, - 0, 80, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 3, 3, 0, - 0, 92, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 12, 12, 0, - 0, 83, 86, 95, 80, 111, - 115, 105, 116, 105, 111, 110, - 0, 84, 69, 88, 67, 79, - 79, 82, 68, 0, 171, 171, - 171, 79, 83, 71, 78, 44, - 0, 0, 0, 1, 0, 0, - 0, 8, 0, 0, 0, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 15, 0, 0, 0, 83, - 86, 95, 84, 97, 114, 103, - 101, 116, 0, 171, 171, 79, - 101, 0, 0, 0, 0, 0, - 0, 65, 48, 0, 40, 7, - 0, 0, 68, 88, 66, 67, - 46, 205, 200, 104, 105, 244, - 107, 100, 111, 73, 199, 142, - 36, 0, 178, 231, 1, 0, - 0, 0, 40, 7, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 148, 1, 0, 0, - 104, 3, 0, 0, 228, 3, - 0, 0, 132, 6, 0, 0, - 184, 6, 0, 0, 65, 111, - 110, 57, 84, 1, 0, 0, - 84, 1, 0, 0, 0, 2, - 254, 255, 252, 0, 0, 0, - 88, 0, 0, 0, 4, 0, - 36, 0, 0, 0, 84, 0, - 0, 0, 84, 0, 0, 0, - 36, 0, 1, 0, 84, 0, - 0, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 1, 0, - 2, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 3, 0, 0, 0, 0, 0, - 1, 0, 3, 0, 1, 0, - 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 2, - 254, 255, 81, 0, 0, 5, - 6, 0, 15, 160, 0, 0, - 128, 63, 0, 0, 0, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 5, 0, 0, 128, 0, 0, - 15, 144, 4, 0, 0, 4, - 0, 0, 3, 224, 0, 0, - 228, 144, 2, 0, 238, 160, - 2, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 3, 128, - 0, 0, 228, 144, 1, 0, - 238, 160, 1, 0, 228, 160, - 2, 0, 0, 3, 0, 0, - 4, 128, 0, 0, 0, 128, - 6, 0, 0, 160, 5, 0, - 0, 3, 0, 0, 4, 128, - 0, 0, 170, 128, 5, 0, - 0, 160, 5, 0, 0, 3, - 1, 0, 1, 128, 0, 0, - 170, 128, 6, 0, 85, 160, - 2, 0, 0, 3, 0, 0, - 4, 128, 0, 0, 85, 129, - 6, 0, 0, 160, 2, 0, - 0, 3, 0, 0, 3, 192, - 0, 0, 228, 128, 0, 0, - 228, 160, 5, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 170, 128, 5, 0, 85, 160, - 5, 0, 0, 3, 1, 0, - 2, 128, 0, 0, 0, 128, - 6, 0, 85, 160, 1, 0, - 0, 2, 1, 0, 4, 128, - 6, 0, 0, 160, 8, 0, - 0, 3, 0, 0, 8, 224, - 1, 0, 228, 128, 3, 0, - 228, 160, 8, 0, 0, 3, - 0, 0, 4, 224, 1, 0, - 228, 128, 4, 0, 228, 160, - 1, 0, 0, 2, 0, 0, - 12, 192, 6, 0, 36, 160, - 255, 255, 0, 0, 83, 72, - 68, 82, 204, 1, 0, 0, - 64, 0, 1, 0, 115, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 89, 0, 0, 4, 70, 142, - 32, 0, 1, 0, 0, 0, - 4, 0, 0, 0, 95, 0, - 0, 3, 50, 16, 16, 0, - 0, 0, 0, 0, 103, 0, - 0, 4, 242, 32, 16, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 50, 32, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 194, 32, 16, 0, 1, 0, - 0, 0, 104, 0, 0, 2, - 2, 0, 0, 0, 54, 0, - 0, 8, 194, 32, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 128, 63, - 50, 0, 0, 11, 50, 0, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 50, 32, 16, 0, 0, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 8, - 34, 0, 16, 0, 0, 0, - 0, 0, 26, 0, 16, 128, - 65, 0, 0, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 56, 0, - 0, 8, 50, 0, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 70, 128, 32, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 56, 0, 0, 10, 50, 0, - 16, 0, 1, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 63, 0, 0, - 0, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, - 0, 5, 66, 0, 16, 0, - 1, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 16, 0, 0, 8, 66, 32, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 70, 130, 32, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 8, - 130, 32, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 70, 130, - 32, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 50, 0, - 0, 11, 50, 32, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 12, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 152, 2, 0, 0, 2, 0, - 0, 0, 100, 0, 0, 0, - 2, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 254, 255, - 0, 129, 0, 0, 103, 2, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 96, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 99, 98, 48, 0, 99, 98, - 50, 0, 92, 0, 0, 0, - 4, 0, 0, 0, 148, 0, - 0, 0, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 96, 0, 0, 0, - 7, 0, 0, 0, 52, 1, - 0, 0, 112, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 244, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 16, 1, 0, 0, - 16, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 26, 1, 0, 0, - 32, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 40, 1, 0, 0, - 48, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 81, 117, 97, 100, - 68, 101, 115, 99, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 77, 97, - 115, 107, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 84, 101, 120, 116, 67, 111, - 108, 111, 114, 0, 171, 171, - 220, 1, 0, 0, 0, 0, - 0, 0, 44, 0, 0, 0, - 2, 0, 0, 0, 244, 1, - 0, 0, 0, 0, 0, 0, - 4, 2, 0, 0, 48, 0, - 0, 0, 8, 0, 0, 0, - 2, 0, 0, 0, 16, 2, - 0, 0, 0, 0, 0, 0, - 32, 2, 0, 0, 64, 0, - 0, 0, 12, 0, 0, 0, - 0, 0, 0, 0, 40, 2, - 0, 0, 0, 0, 0, 0, - 56, 2, 0, 0, 80, 0, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 16, 2, - 0, 0, 0, 0, 0, 0, - 64, 2, 0, 0, 88, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 68, 2, - 0, 0, 0, 0, 0, 0, - 84, 2, 0, 0, 92, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 68, 2, - 0, 0, 0, 0, 0, 0, - 92, 2, 0, 0, 96, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 68, 2, - 0, 0, 0, 0, 0, 0, - 68, 101, 118, 105, 99, 101, - 83, 112, 97, 99, 101, 84, - 111, 85, 115, 101, 114, 83, - 112, 97, 99, 101, 0, 171, - 3, 0, 3, 0, 3, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 100, 105, - 109, 101, 110, 115, 105, 111, - 110, 115, 0, 171, 1, 0, - 3, 0, 1, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 100, 105, 102, 102, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 99, 101, 110, 116, - 101, 114, 49, 0, 65, 0, - 171, 171, 0, 0, 3, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 114, 97, 100, 105, 117, 115, - 49, 0, 115, 113, 95, 114, - 97, 100, 105, 117, 115, 49, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 57, 46, 50, 57, 46, 57, - 53, 50, 46, 51, 49, 49, - 49, 0, 73, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 7, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 171, 171, 171, - 79, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 12, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 3, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 58, 111, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 188, 7, 0, 0, 68, 88, - 66, 67, 211, 81, 242, 102, - 76, 133, 243, 215, 238, 242, - 80, 72, 238, 190, 245, 27, - 1, 0, 0, 0, 188, 7, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 196, 1, - 0, 0, 56, 4, 0, 0, - 180, 4, 0, 0, 24, 7, - 0, 0, 136, 7, 0, 0, - 65, 111, 110, 57, 132, 1, - 0, 0, 132, 1, 0, 0, - 0, 2, 255, 255, 76, 1, - 0, 0, 56, 0, 0, 0, - 1, 0, 44, 0, 0, 0, - 56, 0, 0, 0, 56, 0, - 2, 0, 36, 0, 0, 0, - 56, 0, 0, 0, 0, 0, - 1, 1, 1, 0, 0, 0, - 4, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 1, 2, - 255, 255, 81, 0, 0, 5, - 2, 0, 15, 160, 0, 0, - 0, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 5, 0, 0, 3, - 0, 0, 8, 128, 1, 0, - 255, 160, 1, 0, 255, 160, - 2, 0, 0, 3, 0, 0, - 3, 128, 0, 0, 235, 176, - 1, 0, 228, 161, 90, 0, - 0, 4, 0, 0, 8, 128, - 0, 0, 228, 128, 0, 0, - 228, 128, 0, 0, 255, 129, - 5, 0, 0, 3, 0, 0, - 8, 128, 0, 0, 255, 128, - 2, 0, 0, 160, 1, 0, - 0, 2, 0, 0, 4, 128, - 1, 0, 255, 160, 8, 0, - 0, 3, 0, 0, 1, 128, - 0, 0, 228, 128, 0, 0, - 228, 160, 6, 0, 0, 2, - 0, 0, 1, 128, 0, 0, - 0, 128, 5, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 0, 128, 0, 0, 255, 128, - 1, 0, 0, 2, 0, 0, - 2, 128, 2, 0, 0, 160, - 66, 0, 0, 3, 1, 0, - 15, 128, 0, 0, 228, 176, - 1, 8, 228, 160, 66, 0, - 0, 3, 2, 0, 15, 128, - 0, 0, 228, 128, 0, 8, - 228, 160, 1, 0, 0, 2, - 0, 0, 8, 128, 1, 0, - 255, 160, 4, 0, 0, 4, - 0, 0, 1, 128, 0, 0, - 0, 128, 0, 0, 170, 161, - 0, 0, 255, 129, 5, 0, - 0, 3, 2, 0, 7, 128, - 2, 0, 255, 128, 2, 0, - 228, 128, 5, 0, 0, 3, - 1, 0, 15, 128, 1, 0, - 255, 128, 2, 0, 228, 128, - 88, 0, 0, 4, 0, 0, - 15, 128, 0, 0, 0, 128, - 2, 0, 85, 160, 1, 0, - 228, 128, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, - 228, 128, 255, 255, 0, 0, - 83, 72, 68, 82, 108, 2, - 0, 0, 64, 0, 0, 0, - 155, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 6, 0, - 0, 0, 90, 0, 0, 3, - 0, 96, 16, 0, 0, 0, - 0, 0, 90, 0, 0, 3, - 0, 96, 16, 0, 1, 0, - 0, 0, 88, 24, 0, 4, - 0, 112, 16, 0, 0, 0, - 0, 0, 85, 85, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 1, 0, 0, 0, - 85, 85, 0, 0, 98, 16, - 0, 3, 50, 16, 16, 0, - 1, 0, 0, 0, 98, 16, - 0, 3, 194, 16, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 242, 32, 16, 0, - 0, 0, 0, 0, 104, 0, - 0, 2, 2, 0, 0, 0, - 0, 0, 0, 9, 50, 0, - 16, 0, 0, 0, 0, 0, - 230, 26, 16, 0, 1, 0, - 0, 0, 70, 128, 32, 128, - 65, 0, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 54, 0, 0, 6, 66, 0, - 16, 0, 0, 0, 0, 0, - 58, 128, 32, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 16, 0, 0, 8, 66, 0, - 16, 0, 0, 0, 0, 0, - 70, 2, 16, 0, 0, 0, - 0, 0, 70, 130, 32, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 15, 0, 0, 7, - 18, 0, 16, 0, 0, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 50, 0, 0, 12, 18, 0, - 16, 0, 0, 0, 0, 0, - 58, 128, 32, 128, 65, 0, - 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 58, 128, - 32, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 56, 0, 0, 7, 18, 0, - 16, 0, 0, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 0, 63, 14, 0, - 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 42, 0, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 8, - 66, 0, 16, 0, 0, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 42, 128, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 29, 0, - 0, 9, 66, 0, 16, 0, - 0, 0, 0, 0, 58, 128, - 32, 128, 65, 0, 0, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 42, 0, 16, 0, - 0, 0, 0, 0, 54, 0, - 0, 5, 34, 0, 16, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 0, 63, - 69, 0, 0, 9, 242, 0, - 16, 0, 1, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 31, 0, 4, 3, 42, 0, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 8, 242, 32, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 62, 0, 0, 1, - 21, 0, 0, 1, 56, 0, - 0, 7, 114, 0, 16, 0, - 1, 0, 0, 0, 246, 15, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 0, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 1, 0, 0, 0, - 0, 96, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 242, 32, 16, 0, 0, 0, - 0, 0, 246, 15, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 1, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 19, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 9, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 92, 2, 0, 0, 1, 0, - 0, 0, 224, 0, 0, 0, - 5, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 255, 255, - 0, 129, 0, 0, 43, 2, - 0, 0, 188, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 197, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 210, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 1, 0, 0, 0, 12, 0, - 0, 0, 214, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 1, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 219, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 115, 83, 97, 109, 112, 108, - 101, 114, 0, 115, 77, 97, - 115, 107, 83, 97, 109, 112, - 108, 101, 114, 0, 116, 101, - 120, 0, 109, 97, 115, 107, - 0, 99, 98, 50, 0, 171, - 219, 0, 0, 0, 7, 0, - 0, 0, 248, 0, 0, 0, - 112, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 160, 1, 0, 0, 0, 0, - 0, 0, 44, 0, 0, 0, - 0, 0, 0, 0, 184, 1, - 0, 0, 0, 0, 0, 0, - 200, 1, 0, 0, 48, 0, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 212, 1, - 0, 0, 0, 0, 0, 0, - 228, 1, 0, 0, 64, 0, - 0, 0, 12, 0, 0, 0, - 2, 0, 0, 0, 236, 1, - 0, 0, 0, 0, 0, 0, - 252, 1, 0, 0, 80, 0, - 0, 0, 8, 0, 0, 0, - 2, 0, 0, 0, 212, 1, - 0, 0, 0, 0, 0, 0, - 4, 2, 0, 0, 88, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 8, 2, - 0, 0, 0, 0, 0, 0, - 24, 2, 0, 0, 92, 0, - 0, 0, 4, 0, 0, 0, - 2, 0, 0, 0, 8, 2, - 0, 0, 0, 0, 0, 0, - 32, 2, 0, 0, 96, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 8, 2, - 0, 0, 0, 0, 0, 0, - 68, 101, 118, 105, 99, 101, - 83, 112, 97, 99, 101, 84, - 111, 85, 115, 101, 114, 83, - 112, 97, 99, 101, 0, 171, - 3, 0, 3, 0, 3, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 100, 105, - 109, 101, 110, 115, 105, 111, - 110, 115, 0, 171, 1, 0, - 3, 0, 1, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 100, 105, 102, 102, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 99, 101, 110, 116, - 101, 114, 49, 0, 65, 0, - 171, 171, 0, 0, 3, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 114, 97, 100, 105, 117, 115, - 49, 0, 115, 113, 95, 114, - 97, 100, 105, 117, 115, 49, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 57, 46, 50, 57, 46, 57, - 53, 50, 46, 51, 49, 49, - 49, 0, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 3, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 12, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 97, 114, 103, 101, - 116, 0, 171, 171, 122, 118, - 0, 0, 0, 0, 0, 0, - 65, 80, 111, 115, 87, 114, - 97, 112, 0, 40, 7, 0, - 0, 68, 88, 66, 67, 46, - 205, 200, 104, 105, 244, 107, - 100, 111, 73, 199, 142, 36, - 0, 178, 231, 1, 0, 0, - 0, 40, 7, 0, 0, 6, - 0, 0, 0, 56, 0, 0, - 0, 148, 1, 0, 0, 104, - 3, 0, 0, 228, 3, 0, - 0, 132, 6, 0, 0, 184, - 6, 0, 0, 65, 111, 110, - 57, 84, 1, 0, 0, 84, - 1, 0, 0, 0, 2, 254, - 255, 252, 0, 0, 0, 88, - 0, 0, 0, 4, 0, 36, - 0, 0, 0, 84, 0, 0, - 0, 84, 0, 0, 0, 36, - 0, 1, 0, 84, 0, 0, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 2, 0, 1, 0, 2, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 3, - 0, 0, 0, 0, 0, 1, - 0, 3, 0, 1, 0, 5, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 254, - 255, 81, 0, 0, 5, 6, - 0, 15, 160, 0, 0, 128, - 63, 0, 0, 0, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 31, 0, 0, 2, 5, - 0, 0, 128, 0, 0, 15, - 144, 4, 0, 0, 4, 0, - 0, 3, 224, 0, 0, 228, - 144, 2, 0, 238, 160, 2, - 0, 228, 160, 4, 0, 0, - 4, 0, 0, 3, 128, 0, - 0, 228, 144, 1, 0, 238, - 160, 1, 0, 228, 160, 2, - 0, 0, 3, 0, 0, 4, - 128, 0, 0, 0, 128, 6, - 0, 0, 160, 5, 0, 0, - 3, 0, 0, 4, 128, 0, - 0, 170, 128, 5, 0, 0, - 160, 5, 0, 0, 3, 1, - 0, 1, 128, 0, 0, 170, - 128, 6, 0, 85, 160, 2, - 0, 0, 3, 0, 0, 4, - 128, 0, 0, 85, 129, 6, - 0, 0, 160, 2, 0, 0, - 3, 0, 0, 3, 192, 0, - 0, 228, 128, 0, 0, 228, - 160, 5, 0, 0, 3, 0, - 0, 1, 128, 0, 0, 170, - 128, 5, 0, 85, 160, 5, - 0, 0, 3, 1, 0, 2, - 128, 0, 0, 0, 128, 6, - 0, 85, 160, 1, 0, 0, - 2, 1, 0, 4, 128, 6, - 0, 0, 160, 8, 0, 0, - 3, 0, 0, 8, 224, 1, - 0, 228, 128, 3, 0, 228, - 160, 8, 0, 0, 3, 0, - 0, 4, 224, 1, 0, 228, - 128, 4, 0, 228, 160, 1, - 0, 0, 2, 0, 0, 12, - 192, 6, 0, 36, 160, 255, - 255, 0, 0, 83, 72, 68, - 82, 204, 1, 0, 0, 64, - 0, 1, 0, 115, 0, 0, - 0, 89, 0, 0, 4, 70, - 142, 32, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 89, - 0, 0, 4, 70, 142, 32, - 0, 1, 0, 0, 0, 4, - 0, 0, 0, 95, 0, 0, - 3, 50, 16, 16, 0, 0, - 0, 0, 0, 103, 0, 0, - 4, 242, 32, 16, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 101, 0, 0, 3, 50, - 32, 16, 0, 1, 0, 0, - 0, 101, 0, 0, 3, 194, - 32, 16, 0, 1, 0, 0, - 0, 104, 0, 0, 2, 2, - 0, 0, 0, 54, 0, 0, - 8, 194, 32, 16, 0, 0, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 128, 63, 50, - 0, 0, 11, 50, 0, 16, - 0, 0, 0, 0, 0, 70, - 16, 16, 0, 0, 0, 0, - 0, 230, 138, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 70, 128, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 5, 50, - 32, 16, 0, 0, 0, 0, - 0, 70, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, - 7, 18, 0, 16, 0, 0, - 0, 0, 0, 10, 0, 16, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 0, 0, 0, 8, 34, - 0, 16, 0, 0, 0, 0, - 0, 26, 0, 16, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 56, 0, 0, - 8, 50, 0, 16, 0, 0, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 70, - 128, 32, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 56, - 0, 0, 10, 50, 0, 16, - 0, 1, 0, 0, 0, 70, - 0, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 63, 0, 0, 0, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 5, 66, 0, 16, 0, 1, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 16, - 0, 0, 8, 66, 32, 16, - 0, 1, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 70, 130, 32, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 8, 130, - 32, 16, 0, 1, 0, 0, - 0, 70, 2, 16, 0, 1, - 0, 0, 0, 70, 130, 32, - 0, 1, 0, 0, 0, 1, - 0, 0, 0, 50, 0, 0, - 11, 50, 32, 16, 0, 1, - 0, 0, 0, 70, 16, 16, - 0, 0, 0, 0, 0, 230, - 138, 32, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 70, - 128, 32, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 62, - 0, 0, 1, 83, 84, 65, - 84, 116, 0, 0, 0, 12, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 4, - 0, 0, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 82, 68, 69, 70, 152, - 2, 0, 0, 2, 0, 0, - 0, 100, 0, 0, 0, 2, - 0, 0, 0, 28, 0, 0, - 0, 0, 4, 254, 255, 0, - 129, 0, 0, 103, 2, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 96, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 99, - 98, 48, 0, 99, 98, 50, - 0, 92, 0, 0, 0, 4, - 0, 0, 0, 148, 0, 0, - 0, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 96, 0, 0, 0, 7, - 0, 0, 0, 52, 1, 0, - 0, 112, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 244, 0, 0, 0, 0, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 16, 1, 0, 0, 16, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 26, 1, 0, 0, 32, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 40, 1, 0, 0, 48, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 81, 117, 97, 100, 68, - 101, 115, 99, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 77, 97, 115, - 107, 84, 101, 120, 67, 111, - 111, 114, 100, 115, 0, 84, - 101, 120, 116, 67, 111, 108, - 111, 114, 0, 171, 171, 220, - 1, 0, 0, 0, 0, 0, - 0, 44, 0, 0, 0, 2, - 0, 0, 0, 244, 1, 0, - 0, 0, 0, 0, 0, 4, - 2, 0, 0, 48, 0, 0, - 0, 8, 0, 0, 0, 2, - 0, 0, 0, 16, 2, 0, - 0, 0, 0, 0, 0, 32, - 2, 0, 0, 64, 0, 0, - 0, 12, 0, 0, 0, 0, - 0, 0, 0, 40, 2, 0, - 0, 0, 0, 0, 0, 56, - 2, 0, 0, 80, 0, 0, - 0, 8, 0, 0, 0, 0, - 0, 0, 0, 16, 2, 0, - 0, 0, 0, 0, 0, 64, - 2, 0, 0, 88, 0, 0, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 68, 2, 0, - 0, 0, 0, 0, 0, 84, - 2, 0, 0, 92, 0, 0, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 68, 2, 0, - 0, 0, 0, 0, 0, 92, - 2, 0, 0, 96, 0, 0, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 68, 2, 0, - 0, 0, 0, 0, 0, 68, - 101, 118, 105, 99, 101, 83, - 112, 97, 99, 101, 84, 111, - 85, 115, 101, 114, 83, 112, - 97, 99, 101, 0, 171, 3, - 0, 3, 0, 3, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 100, 105, 109, - 101, 110, 115, 105, 111, 110, - 115, 0, 171, 1, 0, 3, - 0, 1, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 100, 105, 102, 102, 0, - 171, 171, 171, 1, 0, 3, - 0, 1, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 99, 101, 110, 116, 101, - 114, 49, 0, 65, 0, 171, - 171, 0, 0, 3, 0, 1, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 114, - 97, 100, 105, 117, 115, 49, - 0, 115, 113, 95, 114, 97, - 100, 105, 117, 115, 49, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 73, 83, 71, 78, 44, - 0, 0, 0, 1, 0, 0, - 0, 8, 0, 0, 0, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 7, 3, 0, 0, 80, - 79, 83, 73, 84, 73, 79, - 78, 0, 171, 171, 171, 79, - 83, 71, 78, 104, 0, 0, - 0, 3, 0, 0, 0, 8, - 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 3, - 12, 0, 0, 92, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 12, - 3, 0, 0, 83, 86, 95, - 80, 111, 115, 105, 116, 105, - 111, 110, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 171, 171, 171, 75, 126, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 224, - 9, 0, 0, 68, 88, 66, - 67, 35, 204, 37, 124, 52, - 142, 69, 114, 80, 227, 92, - 126, 155, 116, 99, 185, 1, - 0, 0, 0, 224, 9, 0, - 0, 6, 0, 0, 0, 56, - 0, 0, 0, 128, 2, 0, - 0, 88, 6, 0, 0, 212, - 6, 0, 0, 60, 9, 0, - 0, 172, 9, 0, 0, 65, - 111, 110, 57, 64, 2, 0, - 0, 64, 2, 0, 0, 0, - 2, 255, 255, 8, 2, 0, - 0, 56, 0, 0, 0, 1, - 0, 44, 0, 0, 0, 56, - 0, 0, 0, 56, 0, 2, - 0, 36, 0, 0, 0, 56, - 0, 0, 0, 0, 0, 1, - 1, 1, 0, 0, 0, 4, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 255, - 255, 81, 0, 0, 5, 3, - 0, 15, 160, 0, 0, 0, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 81, 0, 0, 5, 4, - 0, 15, 160, 0, 0, 128, - 63, 0, 0, 128, 191, 0, - 0, 0, 0, 0, 0, 0, - 128, 31, 0, 0, 2, 0, - 0, 0, 128, 0, 0, 15, - 176, 31, 0, 0, 2, 0, - 0, 0, 144, 0, 8, 15, - 160, 31, 0, 0, 2, 0, - 0, 0, 144, 1, 8, 15, - 160, 2, 0, 0, 3, 0, - 0, 3, 128, 0, 0, 235, - 176, 1, 0, 228, 161, 90, - 0, 0, 4, 0, 0, 8, - 128, 0, 0, 228, 128, 0, - 0, 228, 128, 2, 0, 0, - 161, 5, 0, 0, 3, 0, - 0, 8, 128, 0, 0, 255, - 128, 1, 0, 170, 160, 1, - 0, 0, 2, 0, 0, 4, - 128, 1, 0, 255, 160, 8, - 0, 0, 3, 0, 0, 1, - 128, 0, 0, 228, 128, 0, - 0, 228, 160, 4, 0, 0, - 4, 0, 0, 2, 128, 0, - 0, 0, 128, 0, 0, 0, - 128, 0, 0, 255, 129, 35, - 0, 0, 2, 0, 0, 4, - 128, 0, 0, 85, 128, 7, - 0, 0, 2, 0, 0, 4, - 128, 0, 0, 170, 128, 6, - 0, 0, 2, 1, 0, 1, - 128, 0, 0, 170, 128, 1, - 0, 0, 2, 1, 0, 6, - 128, 1, 0, 0, 129, 2, - 0, 0, 3, 0, 0, 13, - 128, 0, 0, 0, 128, 1, - 0, 148, 128, 6, 0, 0, - 2, 1, 0, 1, 128, 1, - 0, 170, 160, 5, 0, 0, - 3, 0, 0, 13, 128, 0, - 0, 228, 128, 1, 0, 0, - 128, 1, 0, 0, 2, 1, - 0, 8, 128, 1, 0, 255, - 160, 4, 0, 0, 4, 1, - 0, 7, 128, 0, 0, 248, - 128, 0, 0, 170, 160, 1, - 0, 255, 128, 88, 0, 0, - 4, 2, 0, 1, 128, 1, - 0, 0, 128, 0, 0, 0, - 128, 0, 0, 255, 128, 88, - 0, 0, 4, 0, 0, 13, - 128, 1, 0, 148, 128, 4, - 0, 68, 160, 4, 0, 230, - 160, 1, 0, 0, 2, 2, - 0, 2, 128, 3, 0, 0, - 160, 66, 0, 0, 3, 1, - 0, 15, 128, 0, 0, 228, - 176, 1, 8, 228, 160, 66, - 0, 0, 3, 2, 0, 15, - 128, 2, 0, 228, 128, 0, - 8, 228, 160, 5, 0, 0, - 3, 2, 0, 7, 128, 2, - 0, 255, 128, 2, 0, 228, - 128, 5, 0, 0, 3, 1, - 0, 15, 128, 1, 0, 255, - 128, 2, 0, 228, 128, 2, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 0, - 0, 0, 128, 88, 0, 0, - 4, 0, 0, 1, 128, 0, - 0, 255, 128, 0, 0, 0, - 128, 0, 0, 170, 128, 88, - 0, 0, 4, 1, 0, 15, - 128, 0, 0, 0, 129, 4, - 0, 170, 160, 1, 0, 228, - 128, 88, 0, 0, 4, 0, - 0, 15, 128, 0, 0, 85, - 128, 1, 0, 228, 128, 4, - 0, 170, 160, 1, 0, 0, - 2, 0, 8, 15, 128, 0, - 0, 228, 128, 255, 255, 0, - 0, 83, 72, 68, 82, 208, - 3, 0, 0, 64, 0, 0, - 0, 244, 0, 0, 0, 89, - 0, 0, 4, 70, 142, 32, - 0, 0, 0, 0, 0, 7, - 0, 0, 0, 90, 0, 0, - 3, 0, 96, 16, 0, 0, - 0, 0, 0, 90, 0, 0, - 3, 0, 96, 16, 0, 1, - 0, 0, 0, 88, 24, 0, - 4, 0, 112, 16, 0, 0, - 0, 0, 0, 85, 85, 0, - 0, 88, 24, 0, 4, 0, - 112, 16, 0, 1, 0, 0, - 0, 85, 85, 0, 0, 98, - 16, 0, 3, 50, 16, 16, - 0, 1, 0, 0, 0, 98, - 16, 0, 3, 194, 16, 16, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 242, 32, 16, - 0, 0, 0, 0, 0, 104, - 0, 0, 2, 3, 0, 0, - 0, 0, 0, 0, 9, 50, - 0, 16, 0, 0, 0, 0, - 0, 230, 26, 16, 0, 1, - 0, 0, 0, 70, 128, 32, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 0, - 0, 54, 0, 0, 6, 66, - 0, 16, 0, 0, 0, 0, - 0, 58, 128, 32, 0, 0, - 0, 0, 0, 5, 0, 0, - 0, 16, 0, 0, 8, 66, - 0, 16, 0, 0, 0, 0, - 0, 70, 2, 16, 0, 0, - 0, 0, 0, 70, 130, 32, - 0, 0, 0, 0, 0, 4, - 0, 0, 0, 15, 0, 0, - 7, 18, 0, 16, 0, 0, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 70, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 18, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 10, 128, 32, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 6, 0, 0, - 0, 56, 0, 0, 8, 18, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 42, 128, 32, - 0, 0, 0, 0, 0, 5, - 0, 0, 0, 50, 0, 0, - 10, 18, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 42, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 49, 0, 0, 7, 34, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 75, - 0, 0, 6, 18, 0, 16, - 0, 1, 0, 0, 0, 10, - 0, 16, 128, 129, 0, 0, - 0, 0, 0, 0, 0, 54, - 0, 0, 6, 34, 0, 16, - 0, 1, 0, 0, 0, 10, - 0, 16, 128, 65, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 7, 82, 0, 16, - 0, 0, 0, 0, 0, 166, - 10, 16, 0, 0, 0, 0, - 0, 6, 1, 16, 0, 1, - 0, 0, 0, 14, 0, 0, - 8, 82, 0, 16, 0, 0, - 0, 0, 0, 6, 2, 16, - 0, 0, 0, 0, 0, 166, - 138, 32, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 56, - 0, 0, 8, 50, 0, 16, - 0, 1, 0, 0, 0, 134, - 0, 16, 0, 0, 0, 0, - 0, 166, 138, 32, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 29, 0, 0, 9, 50, - 0, 16, 0, 1, 0, 0, - 0, 70, 0, 16, 0, 1, - 0, 0, 0, 246, 143, 32, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 0, - 0, 1, 0, 0, 10, 50, - 0, 16, 0, 1, 0, 0, - 0, 70, 0, 16, 0, 1, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 128, 63, 0, - 0, 128, 63, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 8, 18, 0, 16, - 0, 0, 0, 0, 0, 42, - 0, 16, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 50, 0, 0, 9, 18, - 0, 16, 0, 2, 0, 0, - 0, 10, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 0, 0, 0, 0, 0, 42, - 0, 16, 0, 0, 0, 0, - 0, 54, 0, 0, 5, 34, - 0, 16, 0, 2, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 63, 69, 0, 0, - 9, 242, 0, 16, 0, 2, - 0, 0, 0, 70, 0, 16, - 0, 2, 0, 0, 0, 70, - 126, 16, 0, 0, 0, 0, - 0, 0, 96, 16, 0, 0, - 0, 0, 0, 31, 0, 4, - 3, 26, 0, 16, 0, 0, - 0, 0, 0, 54, 0, 0, - 8, 242, 32, 16, 0, 0, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 62, - 0, 0, 1, 21, 0, 0, - 1, 52, 0, 0, 7, 18, - 0, 16, 0, 0, 0, 0, - 0, 26, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 0, 1, 0, 0, 0, 29, - 0, 0, 7, 18, 0, 16, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 31, 0, 4, - 3, 10, 0, 16, 0, 0, - 0, 0, 0, 54, 0, 0, - 8, 242, 32, 16, 0, 0, - 0, 0, 0, 2, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 62, - 0, 0, 1, 21, 0, 0, - 1, 56, 0, 0, 7, 114, - 0, 16, 0, 2, 0, 0, - 0, 246, 15, 16, 0, 2, - 0, 0, 0, 70, 2, 16, - 0, 2, 0, 0, 0, 69, - 0, 0, 9, 242, 0, 16, - 0, 0, 0, 0, 0, 70, - 16, 16, 0, 1, 0, 0, - 0, 70, 126, 16, 0, 1, - 0, 0, 0, 0, 96, 16, - 0, 1, 0, 0, 0, 56, - 0, 0, 7, 242, 32, 16, - 0, 0, 0, 0, 0, 246, - 15, 16, 0, 0, 0, 0, - 0, 70, 14, 16, 0, 2, - 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, - 0, 0, 0, 33, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 17, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, - 68, 69, 70, 96, 2, 0, - 0, 1, 0, 0, 0, 228, - 0, 0, 0, 5, 0, 0, - 0, 28, 0, 0, 0, 0, - 4, 255, 255, 0, 129, 0, - 0, 47, 2, 0, 0, 188, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 201, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 214, 0, 0, - 0, 2, 0, 0, 0, 5, - 0, 0, 0, 4, 0, 0, - 0, 255, 255, 255, 255, 0, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 218, - 0, 0, 0, 2, 0, 0, - 0, 5, 0, 0, 0, 4, - 0, 0, 0, 255, 255, 255, - 255, 1, 0, 0, 0, 1, - 0, 0, 0, 12, 0, 0, - 0, 223, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 115, 87, 114, - 97, 112, 83, 97, 109, 112, - 108, 101, 114, 0, 115, 77, - 97, 115, 107, 83, 97, 109, - 112, 108, 101, 114, 0, 116, - 101, 120, 0, 109, 97, 115, - 107, 0, 99, 98, 50, 0, - 171, 223, 0, 0, 0, 7, - 0, 0, 0, 252, 0, 0, - 0, 112, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 164, 1, 0, 0, 0, - 0, 0, 0, 44, 0, 0, - 0, 0, 0, 0, 0, 188, - 1, 0, 0, 0, 0, 0, - 0, 204, 1, 0, 0, 48, - 0, 0, 0, 8, 0, 0, - 0, 0, 0, 0, 0, 216, - 1, 0, 0, 0, 0, 0, - 0, 232, 1, 0, 0, 64, - 0, 0, 0, 12, 0, 0, - 0, 2, 0, 0, 0, 240, - 1, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 80, - 0, 0, 0, 8, 0, 0, - 0, 2, 0, 0, 0, 216, - 1, 0, 0, 0, 0, 0, - 0, 8, 2, 0, 0, 88, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 12, - 2, 0, 0, 0, 0, 0, - 0, 28, 2, 0, 0, 92, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 12, - 2, 0, 0, 0, 0, 0, - 0, 36, 2, 0, 0, 96, - 0, 0, 0, 4, 0, 0, - 0, 2, 0, 0, 0, 12, - 2, 0, 0, 0, 0, 0, - 0, 68, 101, 118, 105, 99, - 101, 83, 112, 97, 99, 101, - 84, 111, 85, 115, 101, 114, - 83, 112, 97, 99, 101, 0, - 171, 3, 0, 3, 0, 3, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 100, - 105, 109, 101, 110, 115, 105, - 111, 110, 115, 0, 171, 1, - 0, 3, 0, 1, 0, 2, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 100, 105, 102, - 102, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 99, 101, 110, - 116, 101, 114, 49, 0, 65, - 0, 171, 171, 0, 0, 3, - 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 114, 97, 100, 105, 117, - 115, 49, 0, 115, 113, 95, - 114, 97, 100, 105, 117, 115, - 49, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 57, 46, 50, 57, 46, - 57, 53, 50, 46, 51, 49, - 49, 49, 0, 73, 83, 71, - 78, 104, 0, 0, 0, 3, - 0, 0, 0, 8, 0, 0, - 0, 80, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 3, 3, 0, - 0, 92, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 12, 12, 0, - 0, 83, 86, 95, 80, 111, - 115, 105, 116, 105, 111, 110, - 0, 84, 69, 88, 67, 79, - 79, 82, 68, 0, 171, 171, - 171, 79, 83, 71, 78, 44, - 0, 0, 0, 1, 0, 0, - 0, 8, 0, 0, 0, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 15, 0, 0, 0, 83, - 86, 95, 84, 97, 114, 103, - 101, 116, 0, 171, 171, 139, - 133, 0, 0, 0, 0, 0, - 0, 65, 48, 87, 114, 97, - 112, 0, 40, 7, 0, 0, - 68, 88, 66, 67, 46, 205, - 200, 104, 105, 244, 107, 100, - 111, 73, 199, 142, 36, 0, - 178, 231, 1, 0, 0, 0, - 40, 7, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 148, 1, 0, 0, 104, 3, - 0, 0, 228, 3, 0, 0, - 132, 6, 0, 0, 184, 6, - 0, 0, 65, 111, 110, 57, - 84, 1, 0, 0, 84, 1, - 0, 0, 0, 2, 254, 255, - 252, 0, 0, 0, 88, 0, - 0, 0, 4, 0, 36, 0, - 0, 0, 84, 0, 0, 0, - 84, 0, 0, 0, 36, 0, - 1, 0, 84, 0, 0, 0, - 0, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 1, 0, 2, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 3, 0, - 0, 0, 0, 0, 1, 0, - 3, 0, 1, 0, 5, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 254, 255, - 81, 0, 0, 5, 6, 0, - 15, 160, 0, 0, 128, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 5, 0, - 0, 128, 0, 0, 15, 144, - 4, 0, 0, 4, 0, 0, - 3, 224, 0, 0, 228, 144, - 2, 0, 238, 160, 2, 0, - 228, 160, 4, 0, 0, 4, - 0, 0, 3, 128, 0, 0, - 228, 144, 1, 0, 238, 160, - 1, 0, 228, 160, 2, 0, - 0, 3, 0, 0, 4, 128, - 0, 0, 0, 128, 6, 0, - 0, 160, 5, 0, 0, 3, - 0, 0, 4, 128, 0, 0, - 170, 128, 5, 0, 0, 160, - 5, 0, 0, 3, 1, 0, - 1, 128, 0, 0, 170, 128, - 6, 0, 85, 160, 2, 0, - 0, 3, 0, 0, 4, 128, - 0, 0, 85, 129, 6, 0, - 0, 160, 2, 0, 0, 3, - 0, 0, 3, 192, 0, 0, - 228, 128, 0, 0, 228, 160, - 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 170, 128, - 5, 0, 85, 160, 5, 0, - 0, 3, 1, 0, 2, 128, - 0, 0, 0, 128, 6, 0, - 85, 160, 1, 0, 0, 2, - 1, 0, 4, 128, 6, 0, - 0, 160, 8, 0, 0, 3, - 0, 0, 8, 224, 1, 0, - 228, 128, 3, 0, 228, 160, - 8, 0, 0, 3, 0, 0, - 4, 224, 1, 0, 228, 128, - 4, 0, 228, 160, 1, 0, - 0, 2, 0, 0, 12, 192, - 6, 0, 36, 160, 255, 255, - 0, 0, 83, 72, 68, 82, - 204, 1, 0, 0, 64, 0, - 1, 0, 115, 0, 0, 0, - 89, 0, 0, 4, 70, 142, - 32, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 1, 0, 0, 0, 4, 0, - 0, 0, 95, 0, 0, 3, - 50, 16, 16, 0, 0, 0, - 0, 0, 103, 0, 0, 4, - 242, 32, 16, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 50, 32, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 194, 32, - 16, 0, 1, 0, 0, 0, - 104, 0, 0, 2, 2, 0, - 0, 0, 54, 0, 0, 8, - 194, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 50, 0, - 0, 11, 50, 0, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 50, 32, - 16, 0, 0, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 7, - 18, 0, 16, 0, 0, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 0, 0, 0, 8, 34, 0, - 16, 0, 0, 0, 0, 0, - 26, 0, 16, 128, 65, 0, - 0, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 128, 63, 56, 0, 0, 8, - 50, 0, 16, 0, 0, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 70, 128, - 32, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 56, 0, - 0, 10, 50, 0, 16, 0, - 1, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 63, 0, 0, 0, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 66, 0, 16, 0, 1, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 16, 0, - 0, 8, 66, 32, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 70, 130, 32, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 8, 130, 32, - 16, 0, 1, 0, 0, 0, - 70, 2, 16, 0, 1, 0, - 0, 0, 70, 130, 32, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 50, 0, 0, 11, - 50, 32, 16, 0, 1, 0, - 0, 0, 70, 16, 16, 0, - 0, 0, 0, 0, 230, 138, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 70, 128, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 62, 0, - 0, 1, 83, 84, 65, 84, - 116, 0, 0, 0, 12, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 152, 2, - 0, 0, 2, 0, 0, 0, - 100, 0, 0, 0, 2, 0, - 0, 0, 28, 0, 0, 0, - 0, 4, 254, 255, 0, 129, - 0, 0, 103, 2, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 96, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 99, 98, - 48, 0, 99, 98, 50, 0, - 92, 0, 0, 0, 4, 0, - 0, 0, 148, 0, 0, 0, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 7, 0, - 0, 0, 52, 1, 0, 0, - 112, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 244, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 16, 1, 0, 0, 16, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 26, 1, 0, 0, 32, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 40, 1, 0, 0, 48, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 81, 117, 97, 100, 68, 101, - 115, 99, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 77, 97, 115, 107, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 84, 101, - 120, 116, 67, 111, 108, 111, - 114, 0, 171, 171, 220, 1, - 0, 0, 0, 0, 0, 0, - 44, 0, 0, 0, 2, 0, - 0, 0, 244, 1, 0, 0, - 0, 0, 0, 0, 4, 2, - 0, 0, 48, 0, 0, 0, - 8, 0, 0, 0, 2, 0, - 0, 0, 16, 2, 0, 0, - 0, 0, 0, 0, 32, 2, - 0, 0, 64, 0, 0, 0, - 12, 0, 0, 0, 0, 0, - 0, 0, 40, 2, 0, 0, - 0, 0, 0, 0, 56, 2, - 0, 0, 80, 0, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 16, 2, 0, 0, - 0, 0, 0, 0, 64, 2, - 0, 0, 88, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 68, 2, 0, 0, - 0, 0, 0, 0, 84, 2, - 0, 0, 92, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 68, 2, 0, 0, - 0, 0, 0, 0, 92, 2, - 0, 0, 96, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 68, 2, 0, 0, - 0, 0, 0, 0, 68, 101, - 118, 105, 99, 101, 83, 112, - 97, 99, 101, 84, 111, 85, - 115, 101, 114, 83, 112, 97, - 99, 101, 0, 171, 3, 0, - 3, 0, 3, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 100, 105, 109, 101, - 110, 115, 105, 111, 110, 115, - 0, 171, 1, 0, 3, 0, - 1, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 100, 105, 102, 102, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 99, 101, 110, 116, 101, 114, - 49, 0, 65, 0, 171, 171, - 0, 0, 3, 0, 1, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 114, 97, - 100, 105, 117, 115, 49, 0, - 115, 113, 95, 114, 97, 100, - 105, 117, 115, 49, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 57, 46, 57, 53, 50, - 46, 51, 49, 49, 49, 0, - 73, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 7, 3, 0, 0, 80, 79, - 83, 73, 84, 73, 79, 78, - 0, 171, 171, 171, 79, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 12, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 3, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 126, 143, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 192, 7, - 0, 0, 68, 88, 66, 67, - 248, 109, 152, 1, 215, 32, - 16, 141, 84, 101, 166, 194, - 131, 172, 246, 56, 1, 0, - 0, 0, 192, 7, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 196, 1, 0, 0, - 56, 4, 0, 0, 180, 4, - 0, 0, 28, 7, 0, 0, - 140, 7, 0, 0, 65, 111, - 110, 57, 132, 1, 0, 0, - 132, 1, 0, 0, 0, 2, - 255, 255, 76, 1, 0, 0, - 56, 0, 0, 0, 1, 0, - 44, 0, 0, 0, 56, 0, - 0, 0, 56, 0, 2, 0, - 36, 0, 0, 0, 56, 0, - 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 4, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 255, 255, - 81, 0, 0, 5, 2, 0, - 15, 160, 0, 0, 0, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 15, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 1, 8, 15, 160, - 5, 0, 0, 3, 0, 0, - 8, 128, 1, 0, 255, 160, - 1, 0, 255, 160, 2, 0, - 0, 3, 0, 0, 3, 128, - 0, 0, 235, 176, 1, 0, - 228, 161, 90, 0, 0, 4, - 0, 0, 8, 128, 0, 0, - 228, 128, 0, 0, 228, 128, - 0, 0, 255, 129, 5, 0, - 0, 3, 0, 0, 8, 128, - 0, 0, 255, 128, 2, 0, - 0, 160, 1, 0, 0, 2, - 0, 0, 4, 128, 1, 0, - 255, 160, 8, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 228, 128, 0, 0, 228, 160, - 6, 0, 0, 2, 0, 0, - 1, 128, 0, 0, 0, 128, - 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 0, 128, - 0, 0, 255, 128, 1, 0, - 0, 2, 0, 0, 2, 128, - 2, 0, 0, 160, 66, 0, - 0, 3, 1, 0, 15, 128, - 0, 0, 228, 176, 1, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 0, 0, - 228, 128, 0, 8, 228, 160, - 1, 0, 0, 2, 0, 0, - 8, 128, 1, 0, 255, 160, - 4, 0, 0, 4, 0, 0, - 1, 128, 0, 0, 0, 128, - 0, 0, 170, 161, 0, 0, - 255, 129, 5, 0, 0, 3, - 2, 0, 7, 128, 2, 0, - 255, 128, 2, 0, 228, 128, - 5, 0, 0, 3, 1, 0, - 15, 128, 1, 0, 255, 128, - 2, 0, 228, 128, 88, 0, - 0, 4, 0, 0, 15, 128, - 0, 0, 0, 128, 2, 0, - 85, 160, 1, 0, 228, 128, - 1, 0, 0, 2, 0, 8, - 15, 128, 0, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 108, 2, 0, 0, - 64, 0, 0, 0, 155, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 6, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 1, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 1, 0, - 0, 0, 98, 16, 0, 3, - 194, 16, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 104, 0, 0, 2, - 2, 0, 0, 0, 0, 0, - 0, 9, 50, 0, 16, 0, - 0, 0, 0, 0, 230, 26, - 16, 0, 1, 0, 0, 0, - 70, 128, 32, 128, 65, 0, - 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 54, 0, - 0, 6, 66, 0, 16, 0, - 0, 0, 0, 0, 58, 128, - 32, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 16, 0, - 0, 8, 66, 0, 16, 0, - 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, - 70, 130, 32, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 15, 0, 0, 7, 18, 0, - 16, 0, 0, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 12, 18, 0, 16, 0, - 0, 0, 0, 0, 58, 128, - 32, 128, 65, 0, 0, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 58, 128, 32, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 56, 0, - 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 63, 14, 0, 0, 7, - 18, 0, 16, 0, 0, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 42, 0, - 16, 0, 0, 0, 0, 0, - 56, 0, 0, 8, 66, 0, - 16, 0, 0, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 42, 128, 32, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 29, 0, 0, 9, - 66, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 128, - 65, 0, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 42, 0, 16, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 34, 0, 16, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 0, 63, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 31, 0, - 4, 3, 42, 0, 16, 0, - 0, 0, 0, 0, 54, 0, - 0, 8, 242, 32, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 62, 0, 0, 1, 21, 0, - 0, 1, 56, 0, 0, 7, - 114, 0, 16, 0, 1, 0, - 0, 0, 246, 15, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 1, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 56, 0, 0, 7, 242, 32, - 16, 0, 0, 0, 0, 0, - 246, 15, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 1, 0, 0, 0, 62, 0, - 0, 1, 83, 84, 65, 84, - 116, 0, 0, 0, 19, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 96, 2, - 0, 0, 1, 0, 0, 0, - 228, 0, 0, 0, 5, 0, - 0, 0, 28, 0, 0, 0, - 0, 4, 255, 255, 0, 129, - 0, 0, 47, 2, 0, 0, - 188, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 201, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 214, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 218, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 1, 0, 0, 0, - 1, 0, 0, 0, 12, 0, - 0, 0, 223, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 115, 87, - 114, 97, 112, 83, 97, 109, - 112, 108, 101, 114, 0, 115, - 77, 97, 115, 107, 83, 97, - 109, 112, 108, 101, 114, 0, - 116, 101, 120, 0, 109, 97, - 115, 107, 0, 99, 98, 50, - 0, 171, 223, 0, 0, 0, - 7, 0, 0, 0, 252, 0, - 0, 0, 112, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 164, 1, 0, 0, - 0, 0, 0, 0, 44, 0, - 0, 0, 0, 0, 0, 0, - 188, 1, 0, 0, 0, 0, - 0, 0, 204, 1, 0, 0, - 48, 0, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 216, 1, 0, 0, 0, 0, - 0, 0, 232, 1, 0, 0, - 64, 0, 0, 0, 12, 0, - 0, 0, 2, 0, 0, 0, - 240, 1, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, - 80, 0, 0, 0, 8, 0, - 0, 0, 2, 0, 0, 0, - 216, 1, 0, 0, 0, 0, - 0, 0, 8, 2, 0, 0, - 88, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 12, 2, 0, 0, 0, 0, - 0, 0, 28, 2, 0, 0, - 92, 0, 0, 0, 4, 0, - 0, 0, 2, 0, 0, 0, - 12, 2, 0, 0, 0, 0, - 0, 0, 36, 2, 0, 0, - 96, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 12, 2, 0, 0, 0, 0, - 0, 0, 68, 101, 118, 105, - 99, 101, 83, 112, 97, 99, - 101, 84, 111, 85, 115, 101, - 114, 83, 112, 97, 99, 101, - 0, 171, 3, 0, 3, 0, - 3, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 100, 105, 109, 101, 110, 115, - 105, 111, 110, 115, 0, 171, - 1, 0, 3, 0, 1, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 100, 105, - 102, 102, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 99, 101, - 110, 116, 101, 114, 49, 0, - 65, 0, 171, 171, 0, 0, - 3, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 114, 97, 100, 105, - 117, 115, 49, 0, 115, 113, - 95, 114, 97, 100, 105, 117, - 115, 49, 0, 77, 105, 99, - 114, 111, 115, 111, 102, 116, - 32, 40, 82, 41, 32, 72, - 76, 83, 76, 32, 83, 104, - 97, 100, 101, 114, 32, 67, - 111, 109, 112, 105, 108, 101, - 114, 32, 57, 46, 50, 57, - 46, 57, 53, 50, 46, 51, - 49, 49, 49, 0, 73, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 3, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 12, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 97, 114, - 103, 101, 116, 0, 171, 171, - 190, 150, 0, 0, 0, 0, - 0, 0, 65, 80, 111, 115, - 77, 105, 114, 114, 111, 114, - 0, 40, 7, 0, 0, 68, - 88, 66, 67, 46, 205, 200, - 104, 105, 244, 107, 100, 111, - 73, 199, 142, 36, 0, 178, - 231, 1, 0, 0, 0, 40, - 7, 0, 0, 6, 0, 0, - 0, 56, 0, 0, 0, 148, - 1, 0, 0, 104, 3, 0, - 0, 228, 3, 0, 0, 132, - 6, 0, 0, 184, 6, 0, - 0, 65, 111, 110, 57, 84, - 1, 0, 0, 84, 1, 0, - 0, 0, 2, 254, 255, 252, - 0, 0, 0, 88, 0, 0, - 0, 4, 0, 36, 0, 0, - 0, 84, 0, 0, 0, 84, - 0, 0, 0, 36, 0, 1, - 0, 84, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 2, - 0, 1, 0, 2, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 3, 0, 0, - 0, 0, 0, 1, 0, 3, - 0, 1, 0, 5, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 2, 254, 255, 81, - 0, 0, 5, 6, 0, 15, - 160, 0, 0, 128, 63, 0, - 0, 0, 63, 0, 0, 0, - 0, 0, 0, 0, 0, 31, - 0, 0, 2, 5, 0, 0, - 128, 0, 0, 15, 144, 4, - 0, 0, 4, 0, 0, 3, - 224, 0, 0, 228, 144, 2, - 0, 238, 160, 2, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 3, 128, 0, 0, 228, - 144, 1, 0, 238, 160, 1, - 0, 228, 160, 2, 0, 0, - 3, 0, 0, 4, 128, 0, - 0, 0, 128, 6, 0, 0, - 160, 5, 0, 0, 3, 0, - 0, 4, 128, 0, 0, 170, - 128, 5, 0, 0, 160, 5, - 0, 0, 3, 1, 0, 1, - 128, 0, 0, 170, 128, 6, - 0, 85, 160, 2, 0, 0, - 3, 0, 0, 4, 128, 0, - 0, 85, 129, 6, 0, 0, - 160, 2, 0, 0, 3, 0, - 0, 3, 192, 0, 0, 228, - 128, 0, 0, 228, 160, 5, - 0, 0, 3, 0, 0, 1, - 128, 0, 0, 170, 128, 5, - 0, 85, 160, 5, 0, 0, - 3, 1, 0, 2, 128, 0, - 0, 0, 128, 6, 0, 85, - 160, 1, 0, 0, 2, 1, - 0, 4, 128, 6, 0, 0, - 160, 8, 0, 0, 3, 0, - 0, 8, 224, 1, 0, 228, - 128, 3, 0, 228, 160, 8, - 0, 0, 3, 0, 0, 4, - 224, 1, 0, 228, 128, 4, - 0, 228, 160, 1, 0, 0, - 2, 0, 0, 12, 192, 6, - 0, 36, 160, 255, 255, 0, - 0, 83, 72, 68, 82, 204, - 1, 0, 0, 64, 0, 1, - 0, 115, 0, 0, 0, 89, - 0, 0, 4, 70, 142, 32, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 89, 0, 0, - 4, 70, 142, 32, 0, 1, - 0, 0, 0, 4, 0, 0, - 0, 95, 0, 0, 3, 50, - 16, 16, 0, 0, 0, 0, - 0, 103, 0, 0, 4, 242, - 32, 16, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 50, 32, 16, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 194, 32, 16, - 0, 1, 0, 0, 0, 104, - 0, 0, 2, 2, 0, 0, - 0, 54, 0, 0, 8, 194, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 128, 63, 50, 0, 0, - 11, 50, 0, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 0, 0, 0, 0, 230, - 138, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 70, - 128, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 50, 32, 16, - 0, 0, 0, 0, 0, 70, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 18, - 0, 16, 0, 0, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 128, 63, 0, - 0, 0, 8, 34, 0, 16, - 0, 0, 0, 0, 0, 26, - 0, 16, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 56, 0, 0, 8, 50, - 0, 16, 0, 0, 0, 0, - 0, 70, 0, 16, 0, 0, - 0, 0, 0, 70, 128, 32, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 56, 0, 0, - 10, 50, 0, 16, 0, 1, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 2, - 64, 0, 0, 0, 0, 0, - 63, 0, 0, 0, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 5, 66, - 0, 16, 0, 1, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 128, 63, 16, 0, 0, - 8, 66, 32, 16, 0, 1, - 0, 0, 0, 70, 2, 16, - 0, 1, 0, 0, 0, 70, - 130, 32, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 16, - 0, 0, 8, 130, 32, 16, - 0, 1, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, - 0, 70, 130, 32, 0, 1, - 0, 0, 0, 1, 0, 0, - 0, 50, 0, 0, 11, 50, - 32, 16, 0, 1, 0, 0, - 0, 70, 16, 16, 0, 0, - 0, 0, 0, 230, 138, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 70, 128, 32, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, - 0, 0, 0, 12, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, - 68, 69, 70, 152, 2, 0, - 0, 2, 0, 0, 0, 100, - 0, 0, 0, 2, 0, 0, - 0, 28, 0, 0, 0, 0, - 4, 254, 255, 0, 129, 0, - 0, 103, 2, 0, 0, 92, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 96, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 99, 98, 48, - 0, 99, 98, 50, 0, 92, - 0, 0, 0, 4, 0, 0, - 0, 148, 0, 0, 0, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 96, - 0, 0, 0, 7, 0, 0, - 0, 52, 1, 0, 0, 112, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 244, - 0, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 16, - 1, 0, 0, 16, 0, 0, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 26, - 1, 0, 0, 32, 0, 0, - 0, 16, 0, 0, 0, 2, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 40, - 1, 0, 0, 48, 0, 0, - 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 81, - 117, 97, 100, 68, 101, 115, - 99, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 84, 101, 120, - 67, 111, 111, 114, 100, 115, - 0, 77, 97, 115, 107, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 84, 101, 120, - 116, 67, 111, 108, 111, 114, - 0, 171, 171, 220, 1, 0, - 0, 0, 0, 0, 0, 44, - 0, 0, 0, 2, 0, 0, - 0, 244, 1, 0, 0, 0, - 0, 0, 0, 4, 2, 0, - 0, 48, 0, 0, 0, 8, - 0, 0, 0, 2, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 32, 2, 0, - 0, 64, 0, 0, 0, 12, - 0, 0, 0, 0, 0, 0, - 0, 40, 2, 0, 0, 0, - 0, 0, 0, 56, 2, 0, - 0, 80, 0, 0, 0, 8, - 0, 0, 0, 0, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 64, 2, 0, - 0, 88, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 84, 2, 0, - 0, 92, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 92, 2, 0, - 0, 96, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 68, 2, 0, 0, 0, - 0, 0, 0, 68, 101, 118, - 105, 99, 101, 83, 112, 97, - 99, 101, 84, 111, 85, 115, - 101, 114, 83, 112, 97, 99, - 101, 0, 171, 3, 0, 3, - 0, 3, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 100, 105, 109, 101, 110, - 115, 105, 111, 110, 115, 0, - 171, 1, 0, 3, 0, 1, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 100, - 105, 102, 102, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 99, - 101, 110, 116, 101, 114, 49, - 0, 65, 0, 171, 171, 0, - 0, 3, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 114, 97, 100, - 105, 117, 115, 49, 0, 115, - 113, 95, 114, 97, 100, 105, - 117, 115, 49, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 73, - 83, 71, 78, 44, 0, 0, - 0, 1, 0, 0, 0, 8, - 0, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 7, - 3, 0, 0, 80, 79, 83, - 73, 84, 73, 79, 78, 0, - 171, 171, 171, 79, 83, 71, - 78, 104, 0, 0, 0, 3, - 0, 0, 0, 8, 0, 0, - 0, 80, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 3, 12, 0, - 0, 92, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 12, 3, 0, - 0, 83, 86, 95, 80, 111, - 115, 105, 116, 105, 111, 110, - 0, 84, 69, 88, 67, 79, - 79, 82, 68, 0, 171, 171, - 171, 149, 158, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 228, 9, 0, - 0, 68, 88, 66, 67, 206, - 66, 5, 204, 201, 46, 17, - 5, 140, 32, 17, 46, 111, - 38, 42, 172, 1, 0, 0, - 0, 228, 9, 0, 0, 6, - 0, 0, 0, 56, 0, 0, - 0, 128, 2, 0, 0, 88, - 6, 0, 0, 212, 6, 0, - 0, 64, 9, 0, 0, 176, - 9, 0, 0, 65, 111, 110, - 57, 64, 2, 0, 0, 64, - 2, 0, 0, 0, 2, 255, - 255, 8, 2, 0, 0, 56, - 0, 0, 0, 1, 0, 44, - 0, 0, 0, 56, 0, 0, - 0, 56, 0, 2, 0, 36, - 0, 0, 0, 56, 0, 0, - 0, 0, 0, 1, 1, 1, - 0, 0, 0, 4, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 1, 2, 255, 255, 81, - 0, 0, 5, 3, 0, 15, - 160, 0, 0, 0, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 81, - 0, 0, 5, 4, 0, 15, - 160, 0, 0, 128, 63, 0, - 0, 128, 191, 0, 0, 0, - 0, 0, 0, 0, 128, 31, - 0, 0, 2, 0, 0, 0, - 128, 0, 0, 15, 176, 31, - 0, 0, 2, 0, 0, 0, - 144, 0, 8, 15, 160, 31, - 0, 0, 2, 0, 0, 0, - 144, 1, 8, 15, 160, 2, - 0, 0, 3, 0, 0, 3, - 128, 0, 0, 235, 176, 1, - 0, 228, 161, 90, 0, 0, - 4, 0, 0, 8, 128, 0, - 0, 228, 128, 0, 0, 228, - 128, 2, 0, 0, 161, 5, - 0, 0, 3, 0, 0, 8, - 128, 0, 0, 255, 128, 1, - 0, 170, 160, 1, 0, 0, - 2, 0, 0, 4, 128, 1, - 0, 255, 160, 8, 0, 0, - 3, 0, 0, 1, 128, 0, - 0, 228, 128, 0, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 2, 128, 0, 0, 0, - 128, 0, 0, 0, 128, 0, - 0, 255, 129, 35, 0, 0, - 2, 0, 0, 4, 128, 0, - 0, 85, 128, 7, 0, 0, - 2, 0, 0, 4, 128, 0, - 0, 170, 128, 6, 0, 0, - 2, 1, 0, 1, 128, 0, - 0, 170, 128, 1, 0, 0, - 2, 1, 0, 6, 128, 1, - 0, 0, 129, 2, 0, 0, - 3, 0, 0, 13, 128, 0, - 0, 0, 128, 1, 0, 148, - 128, 6, 0, 0, 2, 1, - 0, 1, 128, 1, 0, 170, - 160, 5, 0, 0, 3, 0, - 0, 13, 128, 0, 0, 228, - 128, 1, 0, 0, 128, 1, - 0, 0, 2, 1, 0, 8, - 128, 1, 0, 255, 160, 4, - 0, 0, 4, 1, 0, 7, - 128, 0, 0, 248, 128, 0, - 0, 170, 160, 1, 0, 255, - 128, 88, 0, 0, 4, 2, - 0, 1, 128, 1, 0, 0, - 128, 0, 0, 0, 128, 0, - 0, 255, 128, 88, 0, 0, - 4, 0, 0, 13, 128, 1, - 0, 148, 128, 4, 0, 68, - 160, 4, 0, 230, 160, 1, - 0, 0, 2, 2, 0, 2, - 128, 3, 0, 0, 160, 66, - 0, 0, 3, 1, 0, 15, - 128, 0, 0, 228, 176, 1, - 8, 228, 160, 66, 0, 0, - 3, 2, 0, 15, 128, 2, - 0, 228, 128, 0, 8, 228, - 160, 5, 0, 0, 3, 2, - 0, 7, 128, 2, 0, 255, - 128, 2, 0, 228, 128, 5, - 0, 0, 3, 1, 0, 15, - 128, 1, 0, 255, 128, 2, - 0, 228, 128, 2, 0, 0, - 3, 0, 0, 8, 128, 0, - 0, 255, 128, 0, 0, 0, - 128, 88, 0, 0, 4, 0, - 0, 1, 128, 0, 0, 255, - 128, 0, 0, 0, 128, 0, - 0, 170, 128, 88, 0, 0, - 4, 1, 0, 15, 128, 0, - 0, 0, 129, 4, 0, 170, - 160, 1, 0, 228, 128, 88, - 0, 0, 4, 0, 0, 15, - 128, 0, 0, 85, 128, 1, - 0, 228, 128, 4, 0, 170, - 160, 1, 0, 0, 2, 0, - 8, 15, 128, 0, 0, 228, - 128, 255, 255, 0, 0, 83, - 72, 68, 82, 208, 3, 0, - 0, 64, 0, 0, 0, 244, - 0, 0, 0, 89, 0, 0, - 4, 70, 142, 32, 0, 0, - 0, 0, 0, 7, 0, 0, - 0, 90, 0, 0, 3, 0, - 96, 16, 0, 0, 0, 0, - 0, 90, 0, 0, 3, 0, - 96, 16, 0, 1, 0, 0, - 0, 88, 24, 0, 4, 0, - 112, 16, 0, 0, 0, 0, - 0, 85, 85, 0, 0, 88, - 24, 0, 4, 0, 112, 16, - 0, 1, 0, 0, 0, 85, - 85, 0, 0, 98, 16, 0, - 3, 50, 16, 16, 0, 1, - 0, 0, 0, 98, 16, 0, - 3, 194, 16, 16, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 242, 32, 16, 0, 0, - 0, 0, 0, 104, 0, 0, - 2, 3, 0, 0, 0, 0, - 0, 0, 9, 50, 0, 16, - 0, 0, 0, 0, 0, 230, - 26, 16, 0, 1, 0, 0, - 0, 70, 128, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 54, - 0, 0, 6, 66, 0, 16, - 0, 0, 0, 0, 0, 58, - 128, 32, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 16, - 0, 0, 8, 66, 0, 16, - 0, 0, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, - 0, 70, 130, 32, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 15, 0, 0, 7, 18, - 0, 16, 0, 0, 0, 0, - 0, 70, 0, 16, 0, 0, - 0, 0, 0, 70, 0, 16, - 0, 0, 0, 0, 0, 0, - 0, 0, 9, 18, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 10, 128, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 56, - 0, 0, 8, 18, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 42, 128, 32, 0, 0, - 0, 0, 0, 5, 0, 0, - 0, 50, 0, 0, 10, 18, - 0, 16, 0, 0, 0, 0, - 0, 42, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 49, - 0, 0, 7, 34, 0, 16, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 0, - 0, 0, 0, 75, 0, 0, - 6, 18, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 128, 129, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, - 6, 34, 0, 16, 0, 1, - 0, 0, 0, 10, 0, 16, - 128, 65, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 7, 82, 0, 16, 0, 0, - 0, 0, 0, 166, 10, 16, - 0, 0, 0, 0, 0, 6, - 1, 16, 0, 1, 0, 0, - 0, 14, 0, 0, 8, 82, - 0, 16, 0, 0, 0, 0, - 0, 6, 2, 16, 0, 0, - 0, 0, 0, 166, 138, 32, - 0, 0, 0, 0, 0, 5, - 0, 0, 0, 56, 0, 0, - 8, 50, 0, 16, 0, 1, - 0, 0, 0, 134, 0, 16, - 0, 0, 0, 0, 0, 166, - 138, 32, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 29, - 0, 0, 9, 50, 0, 16, - 0, 1, 0, 0, 0, 70, - 0, 16, 0, 1, 0, 0, - 0, 246, 143, 32, 128, 65, - 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 1, - 0, 0, 10, 50, 0, 16, - 0, 1, 0, 0, 0, 70, - 0, 16, 0, 1, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 128, 63, 0, 0, 128, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 8, 18, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 128, 65, 0, 0, 0, 0, - 0, 0, 0, 10, 0, 16, - 0, 0, 0, 0, 0, 50, - 0, 0, 9, 18, 0, 16, - 0, 2, 0, 0, 0, 10, - 0, 16, 0, 1, 0, 0, - 0, 10, 0, 16, 0, 0, - 0, 0, 0, 42, 0, 16, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 34, 0, 16, - 0, 2, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 0, - 63, 69, 0, 0, 9, 242, - 0, 16, 0, 2, 0, 0, - 0, 70, 0, 16, 0, 2, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 31, 0, 4, 3, 26, - 0, 16, 0, 0, 0, 0, - 0, 54, 0, 0, 8, 242, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 62, 0, 0, - 1, 21, 0, 0, 1, 52, - 0, 0, 7, 18, 0, 16, - 0, 0, 0, 0, 0, 26, - 0, 16, 0, 1, 0, 0, - 0, 10, 0, 16, 0, 1, - 0, 0, 0, 29, 0, 0, - 7, 18, 0, 16, 0, 0, - 0, 0, 0, 1, 64, 0, - 0, 0, 0, 0, 0, 10, - 0, 16, 0, 0, 0, 0, - 0, 31, 0, 4, 3, 10, - 0, 16, 0, 0, 0, 0, - 0, 54, 0, 0, 8, 242, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 62, 0, 0, - 1, 21, 0, 0, 1, 56, - 0, 0, 7, 114, 0, 16, - 0, 2, 0, 0, 0, 246, - 15, 16, 0, 2, 0, 0, - 0, 70, 2, 16, 0, 2, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 1, 0, 0, - 0, 0, 96, 16, 0, 1, - 0, 0, 0, 56, 0, 0, - 7, 242, 32, 16, 0, 0, - 0, 0, 0, 246, 15, 16, - 0, 0, 0, 0, 0, 70, - 14, 16, 0, 2, 0, 0, - 0, 62, 0, 0, 1, 83, - 84, 65, 84, 116, 0, 0, - 0, 33, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 17, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 3, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 68, 69, - 70, 100, 2, 0, 0, 1, - 0, 0, 0, 232, 0, 0, - 0, 5, 0, 0, 0, 28, - 0, 0, 0, 0, 4, 255, - 255, 0, 129, 0, 0, 51, - 2, 0, 0, 188, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 203, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 216, 0, 0, 0, 2, - 0, 0, 0, 5, 0, 0, - 0, 4, 0, 0, 0, 255, - 255, 255, 255, 0, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 220, 0, 0, - 0, 2, 0, 0, 0, 5, - 0, 0, 0, 4, 0, 0, - 0, 255, 255, 255, 255, 1, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 225, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 115, 77, 105, 114, 114, - 111, 114, 83, 97, 109, 112, - 108, 101, 114, 0, 115, 77, - 97, 115, 107, 83, 97, 109, - 112, 108, 101, 114, 0, 116, - 101, 120, 0, 109, 97, 115, - 107, 0, 99, 98, 50, 0, - 171, 171, 171, 225, 0, 0, - 0, 7, 0, 0, 0, 0, - 1, 0, 0, 112, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 168, 1, 0, - 0, 0, 0, 0, 0, 44, - 0, 0, 0, 0, 0, 0, - 0, 192, 1, 0, 0, 0, - 0, 0, 0, 208, 1, 0, - 0, 48, 0, 0, 0, 8, - 0, 0, 0, 0, 0, 0, - 0, 220, 1, 0, 0, 0, - 0, 0, 0, 236, 1, 0, - 0, 64, 0, 0, 0, 12, - 0, 0, 0, 2, 0, 0, - 0, 244, 1, 0, 0, 0, - 0, 0, 0, 4, 2, 0, - 0, 80, 0, 0, 0, 8, - 0, 0, 0, 2, 0, 0, - 0, 220, 1, 0, 0, 0, - 0, 0, 0, 12, 2, 0, - 0, 88, 0, 0, 0, 4, - 0, 0, 0, 2, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 32, 2, 0, - 0, 92, 0, 0, 0, 4, - 0, 0, 0, 2, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 40, 2, 0, - 0, 96, 0, 0, 0, 4, - 0, 0, 0, 2, 0, 0, - 0, 16, 2, 0, 0, 0, - 0, 0, 0, 68, 101, 118, - 105, 99, 101, 83, 112, 97, - 99, 101, 84, 111, 85, 115, - 101, 114, 83, 112, 97, 99, - 101, 0, 171, 3, 0, 3, - 0, 3, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 100, 105, 109, 101, 110, - 115, 105, 111, 110, 115, 0, - 171, 1, 0, 3, 0, 1, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 100, - 105, 102, 102, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 99, - 101, 110, 116, 101, 114, 49, - 0, 65, 0, 171, 171, 0, - 0, 3, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 114, 97, 100, - 105, 117, 115, 49, 0, 115, - 113, 95, 114, 97, 100, 105, - 117, 115, 49, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 73, - 83, 71, 78, 104, 0, 0, - 0, 3, 0, 0, 0, 8, - 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 3, - 3, 0, 0, 92, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 12, - 12, 0, 0, 83, 86, 95, - 80, 111, 115, 105, 116, 105, - 111, 110, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 171, 171, 171, 79, 83, 71, - 78, 44, 0, 0, 0, 1, - 0, 0, 0, 8, 0, 0, - 0, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 83, 86, 95, 84, 97, - 114, 103, 101, 116, 0, 171, - 171, 213, 165, 0, 0, 0, - 0, 0, 0, 65, 48, 77, - 105, 114, 114, 111, 114, 0, - 40, 7, 0, 0, 68, 88, - 66, 67, 46, 205, 200, 104, - 105, 244, 107, 100, 111, 73, - 199, 142, 36, 0, 178, 231, - 1, 0, 0, 0, 40, 7, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 148, 1, - 0, 0, 104, 3, 0, 0, - 228, 3, 0, 0, 132, 6, - 0, 0, 184, 6, 0, 0, - 65, 111, 110, 57, 84, 1, - 0, 0, 84, 1, 0, 0, - 0, 2, 254, 255, 252, 0, - 0, 0, 88, 0, 0, 0, - 4, 0, 36, 0, 0, 0, - 84, 0, 0, 0, 84, 0, - 0, 0, 36, 0, 1, 0, - 84, 0, 0, 0, 0, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 1, 0, 2, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 2, 0, 3, 0, 0, 0, - 0, 0, 1, 0, 3, 0, - 1, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 254, 255, 81, 0, - 0, 5, 6, 0, 15, 160, - 0, 0, 128, 63, 0, 0, - 0, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 4, 0, - 0, 4, 0, 0, 3, 224, - 0, 0, 228, 144, 2, 0, - 238, 160, 2, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 3, 128, 0, 0, 228, 144, - 1, 0, 238, 160, 1, 0, - 228, 160, 2, 0, 0, 3, - 0, 0, 4, 128, 0, 0, - 0, 128, 6, 0, 0, 160, - 5, 0, 0, 3, 0, 0, - 4, 128, 0, 0, 170, 128, - 5, 0, 0, 160, 5, 0, - 0, 3, 1, 0, 1, 128, - 0, 0, 170, 128, 6, 0, - 85, 160, 2, 0, 0, 3, - 0, 0, 4, 128, 0, 0, - 85, 129, 6, 0, 0, 160, - 2, 0, 0, 3, 0, 0, - 3, 192, 0, 0, 228, 128, - 0, 0, 228, 160, 5, 0, - 0, 3, 0, 0, 1, 128, - 0, 0, 170, 128, 5, 0, - 85, 160, 5, 0, 0, 3, - 1, 0, 2, 128, 0, 0, - 0, 128, 6, 0, 85, 160, - 1, 0, 0, 2, 1, 0, - 4, 128, 6, 0, 0, 160, - 8, 0, 0, 3, 0, 0, - 8, 224, 1, 0, 228, 128, - 3, 0, 228, 160, 8, 0, - 0, 3, 0, 0, 4, 224, - 1, 0, 228, 128, 4, 0, - 228, 160, 1, 0, 0, 2, - 0, 0, 12, 192, 6, 0, - 36, 160, 255, 255, 0, 0, - 83, 72, 68, 82, 204, 1, - 0, 0, 64, 0, 1, 0, - 115, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 1, 0, - 0, 0, 4, 0, 0, 0, - 95, 0, 0, 3, 50, 16, - 16, 0, 0, 0, 0, 0, - 103, 0, 0, 4, 242, 32, - 16, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 50, 32, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 194, 32, 16, 0, - 1, 0, 0, 0, 104, 0, - 0, 2, 2, 0, 0, 0, - 54, 0, 0, 8, 194, 32, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 128, 63, 50, 0, 0, 11, - 50, 0, 16, 0, 0, 0, - 0, 0, 70, 16, 16, 0, - 0, 0, 0, 0, 230, 138, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 70, 128, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, - 0, 5, 50, 32, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 7, 18, 0, - 16, 0, 0, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 1, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 0, 8, 34, 0, 16, 0, - 0, 0, 0, 0, 26, 0, - 16, 128, 65, 0, 0, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 56, 0, 0, 8, 50, 0, - 16, 0, 0, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 56, 0, 0, 10, - 50, 0, 16, 0, 1, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 63, - 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 66, 0, - 16, 0, 1, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 128, 63, 16, 0, 0, 8, - 66, 32, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 70, 130, - 32, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 8, 130, 32, 16, 0, - 1, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, - 70, 130, 32, 0, 1, 0, - 0, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 50, 32, - 16, 0, 1, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 12, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 152, 2, 0, 0, - 2, 0, 0, 0, 100, 0, - 0, 0, 2, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 254, 255, 0, 129, 0, 0, - 103, 2, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 99, 98, 48, 0, - 99, 98, 50, 0, 92, 0, - 0, 0, 4, 0, 0, 0, - 148, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 96, 0, - 0, 0, 7, 0, 0, 0, - 52, 1, 0, 0, 112, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 244, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 16, 1, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 26, 1, - 0, 0, 32, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 40, 1, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 81, 117, - 97, 100, 68, 101, 115, 99, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 77, 97, 115, 107, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 84, 101, 120, 116, - 67, 111, 108, 111, 114, 0, - 171, 171, 220, 1, 0, 0, - 0, 0, 0, 0, 44, 0, - 0, 0, 2, 0, 0, 0, - 244, 1, 0, 0, 0, 0, - 0, 0, 4, 2, 0, 0, - 48, 0, 0, 0, 8, 0, - 0, 0, 2, 0, 0, 0, - 16, 2, 0, 0, 0, 0, - 0, 0, 32, 2, 0, 0, - 64, 0, 0, 0, 12, 0, - 0, 0, 0, 0, 0, 0, - 40, 2, 0, 0, 0, 0, - 0, 0, 56, 2, 0, 0, - 80, 0, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 16, 2, 0, 0, 0, 0, - 0, 0, 64, 2, 0, 0, - 88, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 68, 2, 0, 0, 0, 0, - 0, 0, 84, 2, 0, 0, - 92, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 68, 2, 0, 0, 0, 0, - 0, 0, 92, 2, 0, 0, - 96, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 68, 2, 0, 0, 0, 0, - 0, 0, 68, 101, 118, 105, - 99, 101, 83, 112, 97, 99, - 101, 84, 111, 85, 115, 101, - 114, 83, 112, 97, 99, 101, - 0, 171, 3, 0, 3, 0, - 3, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 100, 105, 109, 101, 110, 115, - 105, 111, 110, 115, 0, 171, - 1, 0, 3, 0, 1, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 100, 105, - 102, 102, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 99, 101, - 110, 116, 101, 114, 49, 0, - 65, 0, 171, 171, 0, 0, - 3, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 114, 97, 100, 105, - 117, 115, 49, 0, 115, 113, - 95, 114, 97, 100, 105, 117, - 115, 49, 0, 77, 105, 99, - 114, 111, 115, 111, 102, 116, - 32, 40, 82, 41, 32, 72, - 76, 83, 76, 32, 83, 104, - 97, 100, 101, 114, 32, 67, - 111, 109, 112, 105, 108, 101, - 114, 32, 57, 46, 50, 57, - 46, 57, 53, 50, 46, 51, - 49, 49, 49, 0, 73, 83, - 71, 78, 44, 0, 0, 0, - 1, 0, 0, 0, 8, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 7, 3, - 0, 0, 80, 79, 83, 73, - 84, 73, 79, 78, 0, 171, - 171, 171, 79, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 12, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 3, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 206, 175, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 196, 7, 0, 0, - 68, 88, 66, 67, 127, 67, - 4, 97, 239, 85, 109, 254, - 152, 27, 18, 78, 129, 73, - 97, 175, 1, 0, 0, 0, - 196, 7, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 196, 1, 0, 0, 56, 4, - 0, 0, 180, 4, 0, 0, - 32, 7, 0, 0, 144, 7, - 0, 0, 65, 111, 110, 57, - 132, 1, 0, 0, 132, 1, - 0, 0, 0, 2, 255, 255, - 76, 1, 0, 0, 56, 0, - 0, 0, 1, 0, 44, 0, - 0, 0, 56, 0, 0, 0, - 56, 0, 2, 0, 36, 0, - 0, 0, 56, 0, 0, 0, - 0, 0, 1, 1, 1, 0, - 0, 0, 4, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 255, 255, 81, 0, - 0, 5, 2, 0, 15, 160, - 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 0, 0, 0, 128, - 0, 0, 15, 176, 31, 0, - 0, 2, 0, 0, 0, 144, - 0, 8, 15, 160, 31, 0, - 0, 2, 0, 0, 0, 144, - 1, 8, 15, 160, 5, 0, - 0, 3, 0, 0, 8, 128, - 1, 0, 255, 160, 1, 0, - 255, 160, 2, 0, 0, 3, - 0, 0, 3, 128, 0, 0, - 235, 176, 1, 0, 228, 161, - 90, 0, 0, 4, 0, 0, - 8, 128, 0, 0, 228, 128, - 0, 0, 228, 128, 0, 0, - 255, 129, 5, 0, 0, 3, - 0, 0, 8, 128, 0, 0, - 255, 128, 2, 0, 0, 160, - 1, 0, 0, 2, 0, 0, - 4, 128, 1, 0, 255, 160, - 8, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 228, 128, - 0, 0, 228, 160, 6, 0, - 0, 2, 0, 0, 1, 128, - 0, 0, 0, 128, 5, 0, - 0, 3, 0, 0, 1, 128, - 0, 0, 0, 128, 0, 0, - 255, 128, 1, 0, 0, 2, - 0, 0, 2, 128, 2, 0, - 0, 160, 66, 0, 0, 3, - 1, 0, 15, 128, 0, 0, - 228, 176, 1, 8, 228, 160, - 66, 0, 0, 3, 2, 0, - 15, 128, 0, 0, 228, 128, - 0, 8, 228, 160, 1, 0, - 0, 2, 0, 0, 8, 128, - 1, 0, 255, 160, 4, 0, - 0, 4, 0, 0, 1, 128, - 0, 0, 0, 128, 0, 0, - 170, 161, 0, 0, 255, 129, - 5, 0, 0, 3, 2, 0, - 7, 128, 2, 0, 255, 128, - 2, 0, 228, 128, 5, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 255, 128, 2, 0, - 228, 128, 88, 0, 0, 4, - 0, 0, 15, 128, 0, 0, - 0, 128, 2, 0, 85, 160, - 1, 0, 228, 128, 1, 0, - 0, 2, 0, 8, 15, 128, - 0, 0, 228, 128, 255, 255, - 0, 0, 83, 72, 68, 82, - 108, 2, 0, 0, 64, 0, - 0, 0, 155, 0, 0, 0, - 89, 0, 0, 4, 70, 142, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 90, 0, - 0, 3, 0, 96, 16, 0, - 0, 0, 0, 0, 90, 0, - 0, 3, 0, 96, 16, 0, - 1, 0, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 0, 0, 0, 0, 85, 85, - 0, 0, 88, 24, 0, 4, - 0, 112, 16, 0, 1, 0, - 0, 0, 85, 85, 0, 0, - 98, 16, 0, 3, 50, 16, - 16, 0, 1, 0, 0, 0, - 98, 16, 0, 3, 194, 16, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 242, 32, - 16, 0, 0, 0, 0, 0, - 104, 0, 0, 2, 2, 0, - 0, 0, 0, 0, 0, 9, - 50, 0, 16, 0, 0, 0, - 0, 0, 230, 26, 16, 0, - 1, 0, 0, 0, 70, 128, - 32, 128, 65, 0, 0, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 54, 0, 0, 6, - 66, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 16, 0, 0, 8, - 66, 0, 16, 0, 0, 0, - 0, 0, 70, 2, 16, 0, - 0, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 15, 0, - 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 70, 0, 16, 0, 0, 0, - 0, 0, 50, 0, 0, 12, - 18, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 128, - 65, 0, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 58, 128, 32, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 7, - 18, 0, 16, 0, 0, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 0, 63, - 14, 0, 0, 7, 18, 0, - 16, 0, 0, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 42, 0, 16, 0, - 0, 0, 0, 0, 56, 0, - 0, 8, 66, 0, 16, 0, - 0, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 42, 128, 32, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 29, 0, 0, 9, 66, 0, - 16, 0, 0, 0, 0, 0, - 58, 128, 32, 128, 65, 0, - 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 42, 0, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 34, 0, - 16, 0, 0, 0, 0, 0, - 1, 64, 0, 0, 0, 0, - 0, 63, 69, 0, 0, 9, - 242, 0, 16, 0, 1, 0, - 0, 0, 70, 0, 16, 0, - 0, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 31, 0, 4, 3, - 42, 0, 16, 0, 0, 0, - 0, 0, 54, 0, 0, 8, - 242, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 62, 0, - 0, 1, 21, 0, 0, 1, - 56, 0, 0, 7, 114, 0, - 16, 0, 1, 0, 0, 0, - 246, 15, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 1, 0, - 0, 0, 0, 96, 16, 0, - 1, 0, 0, 0, 56, 0, - 0, 7, 242, 32, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 0, 0, 0, 0, - 70, 14, 16, 0, 1, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 19, 0, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 100, 2, 0, 0, - 1, 0, 0, 0, 232, 0, - 0, 0, 5, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 255, 255, 0, 129, 0, 0, - 51, 2, 0, 0, 188, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 203, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 216, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 220, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 1, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 225, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 115, 77, 105, 114, - 114, 111, 114, 83, 97, 109, - 112, 108, 101, 114, 0, 115, - 77, 97, 115, 107, 83, 97, - 109, 112, 108, 101, 114, 0, - 116, 101, 120, 0, 109, 97, - 115, 107, 0, 99, 98, 50, - 0, 171, 171, 171, 225, 0, - 0, 0, 7, 0, 0, 0, - 0, 1, 0, 0, 112, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 168, 1, - 0, 0, 0, 0, 0, 0, - 44, 0, 0, 0, 0, 0, - 0, 0, 192, 1, 0, 0, - 0, 0, 0, 0, 208, 1, - 0, 0, 48, 0, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 220, 1, 0, 0, - 0, 0, 0, 0, 236, 1, - 0, 0, 64, 0, 0, 0, - 12, 0, 0, 0, 2, 0, - 0, 0, 244, 1, 0, 0, - 0, 0, 0, 0, 4, 2, - 0, 0, 80, 0, 0, 0, - 8, 0, 0, 0, 2, 0, - 0, 0, 220, 1, 0, 0, - 0, 0, 0, 0, 12, 2, - 0, 0, 88, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 16, 2, 0, 0, - 0, 0, 0, 0, 32, 2, - 0, 0, 92, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 16, 2, 0, 0, - 0, 0, 0, 0, 40, 2, - 0, 0, 96, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 16, 2, 0, 0, - 0, 0, 0, 0, 68, 101, - 118, 105, 99, 101, 83, 112, - 97, 99, 101, 84, 111, 85, - 115, 101, 114, 83, 112, 97, - 99, 101, 0, 171, 3, 0, - 3, 0, 3, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 100, 105, 109, 101, - 110, 115, 105, 111, 110, 115, - 0, 171, 1, 0, 3, 0, - 1, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 100, 105, 102, 102, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 99, 101, 110, 116, 101, 114, - 49, 0, 65, 0, 171, 171, - 0, 0, 3, 0, 1, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 114, 97, - 100, 105, 117, 115, 49, 0, - 115, 113, 95, 114, 97, 100, - 105, 117, 115, 49, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 57, 46, 57, 53, 50, - 46, 51, 49, 49, 49, 0, - 73, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 3, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 12, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 79, 83, - 71, 78, 44, 0, 0, 0, - 1, 0, 0, 0, 8, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 83, 86, 95, 84, - 97, 114, 103, 101, 116, 0, - 171, 171, 14, 183, 0, 0, - 0, 0, 0, 0, 83, 97, - 109, 112, 108, 101, 77, 97, - 115, 107, 101, 100, 84, 101, - 120, 116, 117, 114, 101, 0, - 68, 4, 0, 0, 68, 88, - 66, 67, 43, 219, 5, 122, - 32, 21, 232, 165, 63, 89, - 201, 32, 133, 13, 217, 23, - 1, 0, 0, 0, 68, 4, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 248, 0, - 0, 0, 244, 1, 0, 0, - 112, 2, 0, 0, 160, 3, - 0, 0, 212, 3, 0, 0, - 65, 111, 110, 57, 184, 0, - 0, 0, 184, 0, 0, 0, - 0, 2, 254, 255, 132, 0, - 0, 0, 52, 0, 0, 0, - 1, 0, 36, 0, 0, 0, - 48, 0, 0, 0, 48, 0, - 0, 0, 36, 0, 1, 0, - 48, 0, 0, 0, 0, 0, - 3, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 254, 255, 81, 0, - 0, 5, 4, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 4, 0, - 0, 4, 0, 0, 3, 224, - 0, 0, 228, 144, 2, 0, - 238, 160, 2, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 12, 224, 0, 0, 20, 144, - 3, 0, 180, 160, 3, 0, - 20, 160, 4, 0, 0, 4, - 0, 0, 3, 128, 0, 0, - 228, 144, 1, 0, 238, 160, - 1, 0, 228, 160, 2, 0, - 0, 3, 0, 0, 3, 192, - 0, 0, 228, 128, 0, 0, - 228, 160, 1, 0, 0, 2, - 0, 0, 12, 192, 4, 0, - 68, 160, 255, 255, 0, 0, - 83, 72, 68, 82, 244, 0, - 0, 0, 64, 0, 1, 0, - 61, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 95, 0, 0, 3, - 50, 16, 16, 0, 0, 0, - 0, 0, 103, 0, 0, 4, - 242, 32, 16, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 50, 32, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 194, 32, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 50, 32, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 8, - 194, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 50, 0, - 0, 11, 50, 32, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 194, 32, - 16, 0, 1, 0, 0, 0, - 6, 20, 16, 0, 0, 0, - 0, 0, 166, 142, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 6, 132, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 40, 1, 0, 0, - 1, 0, 0, 0, 64, 0, - 0, 0, 1, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 254, 255, 0, 129, 0, 0, - 246, 0, 0, 0, 60, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 99, 98, 48, 0, 60, 0, - 0, 0, 4, 0, 0, 0, - 88, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 212, 0, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 222, 0, - 0, 0, 32, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 236, 0, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 81, 117, - 97, 100, 68, 101, 115, 99, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 77, 97, 115, 107, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 84, 101, 120, 116, - 67, 111, 108, 111, 114, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 171, 73, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 7, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 171, 171, 171, - 79, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 12, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 3, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 242, 190, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 208, 3, 0, 0, 68, 88, - 66, 67, 147, 14, 97, 236, - 80, 216, 15, 184, 37, 39, - 37, 176, 48, 232, 200, 121, - 1, 0, 0, 0, 208, 3, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 224, 0, - 0, 0, 188, 1, 0, 0, - 56, 2, 0, 0, 44, 3, - 0, 0, 156, 3, 0, 0, - 65, 111, 110, 57, 160, 0, - 0, 0, 160, 0, 0, 0, - 0, 2, 255, 255, 116, 0, - 0, 0, 44, 0, 0, 0, - 0, 0, 44, 0, 0, 0, - 44, 0, 0, 0, 44, 0, - 2, 0, 36, 0, 0, 0, - 44, 0, 0, 0, 0, 0, - 1, 1, 1, 0, 1, 2, - 255, 255, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 1, 0, 0, 2, - 0, 0, 3, 128, 0, 0, - 235, 176, 66, 0, 0, 3, - 1, 0, 15, 128, 0, 0, - 228, 176, 0, 8, 228, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 128, - 1, 8, 228, 160, 5, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 255, 128, 1, 0, - 228, 128, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, - 228, 128, 255, 255, 0, 0, - 83, 72, 68, 82, 212, 0, - 0, 0, 64, 0, 0, 0, - 53, 0, 0, 0, 90, 0, - 0, 3, 0, 96, 16, 0, - 0, 0, 0, 0, 90, 0, - 0, 3, 0, 96, 16, 0, - 1, 0, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 0, 0, 0, 0, 85, 85, - 0, 0, 88, 24, 0, 4, - 0, 112, 16, 0, 1, 0, - 0, 0, 85, 85, 0, 0, - 98, 16, 0, 3, 50, 16, - 16, 0, 1, 0, 0, 0, - 98, 16, 0, 3, 194, 16, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 242, 32, - 16, 0, 0, 0, 0, 0, - 104, 0, 0, 2, 2, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 0, 0, - 0, 0, 70, 16, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 1, 0, - 0, 0, 230, 26, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 1, 0, 0, 0, - 0, 96, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 242, 32, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 1, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 236, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 255, 255, - 0, 129, 0, 0, 187, 0, - 0, 0, 156, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 165, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 178, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 1, 0, 0, 0, 12, 0, - 0, 0, 182, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 1, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 115, 83, - 97, 109, 112, 108, 101, 114, - 0, 115, 77, 97, 115, 107, - 83, 97, 109, 112, 108, 101, - 114, 0, 116, 101, 120, 0, - 109, 97, 115, 107, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 57, 46, 57, 53, 50, - 46, 51, 49, 49, 49, 0, - 73, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 3, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 12, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 79, 83, - 71, 78, 44, 0, 0, 0, - 1, 0, 0, 0, 8, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 83, 86, 95, 84, - 97, 114, 103, 101, 116, 0, - 171, 171, 78, 195, 0, 0, - 0, 0, 0, 0, 83, 97, - 109, 112, 108, 101, 84, 101, - 120, 116, 117, 114, 101, 87, - 105, 116, 104, 83, 104, 97, - 100, 111, 119, 0, 4, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 128, 63, 1, 0, - 0, 0, 0, 0, 128, 63, - 1, 0, 0, 0, 0, 0, - 128, 63, 1, 0, 0, 0, - 0, 0, 128, 63, 1, 0, - 0, 0, 3, 0, 0, 0, - 255, 255, 255, 255, 68, 4, - 0, 0, 68, 88, 66, 67, - 43, 219, 5, 122, 32, 21, - 232, 165, 63, 89, 201, 32, - 133, 13, 217, 23, 1, 0, - 0, 0, 68, 4, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 248, 0, 0, 0, - 244, 1, 0, 0, 112, 2, - 0, 0, 160, 3, 0, 0, - 212, 3, 0, 0, 65, 111, - 110, 57, 184, 0, 0, 0, - 184, 0, 0, 0, 0, 2, - 254, 255, 132, 0, 0, 0, - 52, 0, 0, 0, 1, 0, - 36, 0, 0, 0, 48, 0, - 0, 0, 48, 0, 0, 0, - 36, 0, 1, 0, 48, 0, - 0, 0, 0, 0, 3, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 2, - 254, 255, 81, 0, 0, 5, - 4, 0, 15, 160, 0, 0, - 0, 0, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 5, 0, 0, 128, 0, 0, - 15, 144, 4, 0, 0, 4, - 0, 0, 3, 224, 0, 0, - 228, 144, 2, 0, 238, 160, - 2, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 12, 224, - 0, 0, 20, 144, 3, 0, - 180, 160, 3, 0, 20, 160, - 4, 0, 0, 4, 0, 0, - 3, 128, 0, 0, 228, 144, - 1, 0, 238, 160, 1, 0, - 228, 160, 2, 0, 0, 3, - 0, 0, 3, 192, 0, 0, - 228, 128, 0, 0, 228, 160, - 1, 0, 0, 2, 0, 0, - 12, 192, 4, 0, 68, 160, - 255, 255, 0, 0, 83, 72, - 68, 82, 244, 0, 0, 0, - 64, 0, 1, 0, 61, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 95, 0, 0, 3, 50, 16, - 16, 0, 0, 0, 0, 0, - 103, 0, 0, 4, 242, 32, - 16, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 50, 32, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 194, 32, 16, 0, - 1, 0, 0, 0, 50, 0, - 0, 11, 50, 32, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 54, 0, 0, 8, 194, 32, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 128, 63, 50, 0, 0, 11, - 50, 32, 16, 0, 1, 0, - 0, 0, 70, 16, 16, 0, - 0, 0, 0, 0, 230, 138, - 32, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 70, 128, - 32, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 50, 0, - 0, 11, 194, 32, 16, 0, - 1, 0, 0, 0, 6, 20, - 16, 0, 0, 0, 0, 0, - 166, 142, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 6, 132, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 40, 1, 0, 0, 1, 0, - 0, 0, 64, 0, 0, 0, - 1, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 254, 255, - 0, 129, 0, 0, 246, 0, - 0, 0, 60, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 99, 98, - 48, 0, 60, 0, 0, 0, - 4, 0, 0, 0, 88, 0, - 0, 0, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 184, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 0, 0, - 16, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 222, 0, 0, 0, - 32, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 236, 0, 0, 0, - 48, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 81, 117, 97, 100, - 68, 101, 115, 99, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 77, 97, - 115, 107, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 84, 101, 120, 116, 67, 111, - 108, 111, 114, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 171, - 73, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 7, 3, 0, 0, 80, 79, - 83, 73, 84, 73, 79, 78, - 0, 171, 171, 171, 79, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 12, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 3, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 114, 199, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 232, 9, - 0, 0, 68, 88, 66, 67, - 102, 229, 72, 238, 7, 152, - 131, 180, 98, 126, 245, 206, - 107, 91, 80, 215, 1, 0, - 0, 0, 232, 9, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 248, 2, 0, 0, - 8, 7, 0, 0, 132, 7, - 0, 0, 68, 9, 0, 0, - 180, 9, 0, 0, 65, 111, - 110, 57, 184, 2, 0, 0, - 184, 2, 0, 0, 0, 2, - 255, 255, 120, 2, 0, 0, - 64, 0, 0, 0, 2, 0, - 40, 0, 0, 0, 64, 0, - 0, 0, 64, 0, 1, 0, - 36, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 6, 0, 4, 0, 3, 0, - 0, 0, 0, 0, 1, 2, - 255, 255, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 2, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 0, 176, 0, 0, 85, 160, - 1, 0, 0, 2, 0, 0, - 2, 128, 0, 0, 85, 176, - 2, 0, 0, 3, 1, 0, - 1, 128, 0, 0, 0, 176, - 0, 0, 0, 160, 1, 0, - 0, 2, 1, 0, 2, 128, - 0, 0, 85, 176, 66, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 228, 128, 0, 8, - 228, 160, 66, 0, 0, 3, - 1, 0, 15, 128, 1, 0, - 228, 128, 0, 8, 228, 160, - 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 255, 128, - 3, 0, 85, 160, 4, 0, - 0, 4, 0, 0, 1, 128, - 3, 0, 0, 160, 1, 0, - 255, 128, 0, 0, 0, 128, - 2, 0, 0, 3, 1, 0, - 1, 128, 0, 0, 0, 176, - 0, 0, 170, 160, 1, 0, - 0, 2, 1, 0, 2, 128, - 0, 0, 85, 176, 2, 0, - 0, 3, 2, 0, 1, 128, - 0, 0, 0, 176, 0, 0, - 255, 160, 1, 0, 0, 2, - 2, 0, 2, 128, 0, 0, - 85, 176, 66, 0, 0, 3, - 1, 0, 15, 128, 1, 0, - 228, 128, 0, 8, 228, 160, - 66, 0, 0, 3, 2, 0, - 15, 128, 2, 0, 228, 128, - 0, 8, 228, 160, 4, 0, - 0, 4, 0, 0, 1, 128, - 3, 0, 170, 160, 1, 0, - 255, 128, 0, 0, 0, 128, - 4, 0, 0, 4, 0, 0, - 1, 128, 3, 0, 255, 160, - 2, 0, 255, 128, 0, 0, - 0, 128, 2, 0, 0, 3, - 1, 0, 1, 128, 0, 0, - 0, 176, 1, 0, 0, 160, - 1, 0, 0, 2, 1, 0, - 2, 128, 0, 0, 85, 176, - 2, 0, 0, 3, 2, 0, - 1, 128, 0, 0, 0, 176, - 1, 0, 85, 160, 1, 0, - 0, 2, 2, 0, 2, 128, - 0, 0, 85, 176, 66, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 228, 128, 0, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 2, 0, - 228, 128, 0, 8, 228, 160, - 4, 0, 0, 4, 0, 0, - 1, 128, 4, 0, 0, 160, - 1, 0, 255, 128, 0, 0, - 0, 128, 4, 0, 0, 4, - 0, 0, 1, 128, 4, 0, - 85, 160, 2, 0, 255, 128, - 0, 0, 0, 128, 2, 0, - 0, 3, 1, 0, 1, 128, - 0, 0, 0, 176, 1, 0, - 170, 160, 1, 0, 0, 2, - 1, 0, 2, 128, 0, 0, - 85, 176, 2, 0, 0, 3, - 2, 0, 1, 128, 0, 0, - 0, 176, 1, 0, 255, 160, - 1, 0, 0, 2, 2, 0, - 2, 128, 0, 0, 85, 176, - 66, 0, 0, 3, 1, 0, - 15, 128, 1, 0, 228, 128, - 0, 8, 228, 160, 66, 0, - 0, 3, 2, 0, 15, 128, - 2, 0, 228, 128, 0, 8, - 228, 160, 4, 0, 0, 4, - 0, 0, 1, 128, 4, 0, - 170, 160, 1, 0, 255, 128, - 0, 0, 0, 128, 4, 0, - 0, 4, 0, 0, 1, 128, - 4, 0, 255, 160, 2, 0, - 255, 128, 0, 0, 0, 128, - 2, 0, 0, 3, 1, 0, - 1, 128, 0, 0, 0, 176, - 2, 0, 0, 160, 1, 0, - 0, 2, 1, 0, 2, 128, - 0, 0, 85, 176, 66, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 228, 128, 0, 8, - 228, 160, 4, 0, 0, 4, - 0, 0, 1, 128, 5, 0, - 0, 160, 1, 0, 255, 128, - 0, 0, 0, 128, 5, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 0, 128, 6, 0, - 228, 160, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, - 228, 128, 255, 255, 0, 0, - 83, 72, 68, 82, 8, 4, - 0, 0, 64, 0, 0, 0, - 2, 1, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 10, 0, - 0, 0, 90, 0, 0, 3, - 0, 96, 16, 0, 0, 0, - 0, 0, 88, 24, 0, 4, - 0, 112, 16, 0, 0, 0, - 0, 0, 85, 85, 0, 0, - 98, 16, 0, 3, 50, 16, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 242, 32, - 16, 0, 0, 0, 0, 0, - 104, 0, 0, 2, 4, 0, - 0, 0, 0, 0, 0, 8, - 242, 0, 16, 0, 0, 0, - 0, 0, 6, 16, 16, 0, - 1, 0, 0, 0, 38, 135, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, - 0, 5, 82, 0, 16, 0, - 1, 0, 0, 0, 86, 7, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 162, 0, - 16, 0, 1, 0, 0, 0, - 86, 21, 16, 0, 1, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 2, 0, - 0, 0, 230, 10, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 1, 0, - 0, 0, 70, 0, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 8, - 18, 0, 16, 0, 1, 0, - 0, 0, 58, 0, 16, 0, - 2, 0, 0, 0, 26, 128, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 50, 0, - 0, 10, 18, 0, 16, 0, - 1, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 58, 0, - 16, 0, 1, 0, 0, 0, - 10, 0, 16, 0, 1, 0, - 0, 0, 54, 0, 0, 5, - 162, 0, 16, 0, 0, 0, - 0, 0, 86, 21, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 2, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 230, 10, - 16, 0, 0, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 18, 0, 16, 0, - 0, 0, 0, 0, 42, 128, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 58, 0, - 16, 0, 2, 0, 0, 0, - 10, 0, 16, 0, 1, 0, - 0, 0, 50, 0, 0, 10, - 18, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 0, - 0, 0, 0, 0, 6, 0, - 0, 0, 58, 0, 16, 0, - 0, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 242, 0, - 16, 0, 1, 0, 0, 0, - 6, 16, 16, 0, 1, 0, - 0, 0, 38, 135, 32, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 54, 0, 0, 5, - 82, 0, 16, 0, 2, 0, - 0, 0, 86, 7, 16, 0, - 1, 0, 0, 0, 54, 0, - 0, 5, 162, 0, 16, 0, - 2, 0, 0, 0, 86, 21, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 3, 0, 0, 0, - 70, 0, 16, 0, 2, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 2, 0, 0, 0, - 230, 10, 16, 0, 2, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 50, 0, 0, 10, 18, 0, - 16, 0, 0, 0, 0, 0, - 10, 128, 32, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 58, 0, 16, 0, 3, 0, - 0, 0, 10, 0, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 18, 0, 16, 0, - 0, 0, 0, 0, 26, 128, - 32, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 58, 0, - 16, 0, 2, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 162, 0, 16, 0, 1, 0, - 0, 0, 86, 21, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 2, 0, 0, 0, 70, 0, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 230, 10, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 18, 0, 16, 0, - 0, 0, 0, 0, 42, 128, - 32, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 58, 0, - 16, 0, 2, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 50, 0, 0, 10, - 18, 0, 16, 0, 0, 0, - 0, 0, 58, 128, 32, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 58, 0, 16, 0, - 1, 0, 0, 0, 10, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 18, 0, - 16, 0, 1, 0, 0, 0, - 10, 16, 16, 0, 1, 0, - 0, 0, 10, 128, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 54, 0, 0, 5, - 34, 0, 16, 0, 1, 0, - 0, 0, 26, 16, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 70, 0, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 18, 0, 16, 0, - 0, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 8, 0, 0, 0, 58, 0, - 16, 0, 1, 0, 0, 0, - 10, 0, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 8, - 242, 32, 16, 0, 0, 0, - 0, 0, 6, 0, 16, 0, - 0, 0, 0, 0, 70, 142, - 32, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 62, 0, - 0, 1, 83, 84, 65, 84, - 116, 0, 0, 0, 30, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 184, 1, - 0, 0, 1, 0, 0, 0, - 148, 0, 0, 0, 3, 0, - 0, 0, 28, 0, 0, 0, - 0, 4, 255, 255, 0, 129, - 0, 0, 132, 1, 0, 0, - 124, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 139, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 143, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 115, 83, 104, 97, 100, 111, - 119, 83, 97, 109, 112, 108, - 101, 114, 0, 116, 101, 120, - 0, 99, 98, 49, 0, 171, - 143, 0, 0, 0, 4, 0, - 0, 0, 172, 0, 0, 0, - 160, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 12, 1, 0, 0, 0, 0, - 0, 0, 48, 0, 0, 0, - 2, 0, 0, 0, 28, 1, - 0, 0, 0, 0, 0, 0, - 44, 1, 0, 0, 48, 0, - 0, 0, 48, 0, 0, 0, - 0, 0, 0, 0, 60, 1, - 0, 0, 0, 0, 0, 0, - 76, 1, 0, 0, 96, 0, - 0, 0, 48, 0, 0, 0, - 2, 0, 0, 0, 88, 1, - 0, 0, 0, 0, 0, 0, - 104, 1, 0, 0, 144, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 116, 1, - 0, 0, 0, 0, 0, 0, - 66, 108, 117, 114, 79, 102, - 102, 115, 101, 116, 115, 72, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 66, 108, 117, 114, - 79, 102, 102, 115, 101, 116, - 115, 86, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 66, 108, - 117, 114, 87, 101, 105, 103, - 104, 116, 115, 0, 1, 0, - 3, 0, 1, 0, 4, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 83, 104, 97, 100, - 111, 119, 67, 111, 108, 111, - 114, 0, 1, 0, 3, 0, - 1, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 171, 171, 171, 73, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 3, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 0, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 97, 114, - 103, 101, 116, 0, 171, 171, - 206, 203, 0, 0, 0, 0, - 0, 0, 80, 49, 0, 4, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 128, 63, 1, - 0, 0, 0, 0, 0, 128, - 63, 1, 0, 0, 0, 0, - 0, 128, 63, 1, 0, 0, - 0, 0, 0, 128, 63, 1, - 0, 0, 0, 3, 0, 0, - 0, 255, 255, 255, 255, 68, - 4, 0, 0, 68, 88, 66, - 67, 43, 219, 5, 122, 32, - 21, 232, 165, 63, 89, 201, - 32, 133, 13, 217, 23, 1, - 0, 0, 0, 68, 4, 0, - 0, 6, 0, 0, 0, 56, - 0, 0, 0, 248, 0, 0, - 0, 244, 1, 0, 0, 112, - 2, 0, 0, 160, 3, 0, - 0, 212, 3, 0, 0, 65, - 111, 110, 57, 184, 0, 0, - 0, 184, 0, 0, 0, 0, - 2, 254, 255, 132, 0, 0, - 0, 52, 0, 0, 0, 1, - 0, 36, 0, 0, 0, 48, - 0, 0, 0, 48, 0, 0, - 0, 36, 0, 1, 0, 48, - 0, 0, 0, 0, 0, 3, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 2, 254, 255, 81, 0, 0, - 5, 4, 0, 15, 160, 0, - 0, 0, 0, 0, 0, 128, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 31, 0, 0, - 2, 5, 0, 0, 128, 0, - 0, 15, 144, 4, 0, 0, - 4, 0, 0, 3, 224, 0, - 0, 228, 144, 2, 0, 238, - 160, 2, 0, 228, 160, 4, - 0, 0, 4, 0, 0, 12, - 224, 0, 0, 20, 144, 3, - 0, 180, 160, 3, 0, 20, - 160, 4, 0, 0, 4, 0, - 0, 3, 128, 0, 0, 228, - 144, 1, 0, 238, 160, 1, - 0, 228, 160, 2, 0, 0, - 3, 0, 0, 3, 192, 0, - 0, 228, 128, 0, 0, 228, - 160, 1, 0, 0, 2, 0, - 0, 12, 192, 4, 0, 68, - 160, 255, 255, 0, 0, 83, - 72, 68, 82, 244, 0, 0, - 0, 64, 0, 1, 0, 61, - 0, 0, 0, 89, 0, 0, - 4, 70, 142, 32, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 95, 0, 0, 3, 50, - 16, 16, 0, 0, 0, 0, - 0, 103, 0, 0, 4, 242, - 32, 16, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 50, 32, 16, - 0, 1, 0, 0, 0, 101, - 0, 0, 3, 194, 32, 16, - 0, 1, 0, 0, 0, 50, - 0, 0, 11, 50, 32, 16, - 0, 0, 0, 0, 0, 70, - 16, 16, 0, 0, 0, 0, - 0, 230, 138, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 70, 128, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 8, 194, - 32, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 128, 63, 50, 0, 0, - 11, 50, 32, 16, 0, 1, - 0, 0, 0, 70, 16, 16, - 0, 0, 0, 0, 0, 230, - 138, 32, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 70, - 128, 32, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 50, - 0, 0, 11, 194, 32, 16, - 0, 1, 0, 0, 0, 6, - 20, 16, 0, 0, 0, 0, - 0, 166, 142, 32, 0, 0, - 0, 0, 0, 2, 0, 0, - 0, 6, 132, 32, 0, 0, - 0, 0, 0, 2, 0, 0, - 0, 62, 0, 0, 1, 83, - 84, 65, 84, 116, 0, 0, - 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 68, 69, - 70, 40, 1, 0, 0, 1, - 0, 0, 0, 64, 0, 0, - 0, 1, 0, 0, 0, 28, - 0, 0, 0, 0, 4, 254, - 255, 0, 129, 0, 0, 246, - 0, 0, 0, 60, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 99, - 98, 48, 0, 60, 0, 0, - 0, 4, 0, 0, 0, 88, - 0, 0, 0, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 184, 0, 0, - 0, 0, 0, 0, 0, 16, - 0, 0, 0, 2, 0, 0, - 0, 196, 0, 0, 0, 0, - 0, 0, 0, 212, 0, 0, - 0, 16, 0, 0, 0, 16, - 0, 0, 0, 2, 0, 0, - 0, 196, 0, 0, 0, 0, - 0, 0, 0, 222, 0, 0, - 0, 32, 0, 0, 0, 16, - 0, 0, 0, 2, 0, 0, - 0, 196, 0, 0, 0, 0, - 0, 0, 0, 236, 0, 0, - 0, 48, 0, 0, 0, 16, - 0, 0, 0, 0, 0, 0, - 0, 196, 0, 0, 0, 0, - 0, 0, 0, 81, 117, 97, - 100, 68, 101, 115, 99, 0, - 171, 171, 171, 1, 0, 3, - 0, 1, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 84, 101, 120, 67, 111, - 111, 114, 100, 115, 0, 77, - 97, 115, 107, 84, 101, 120, - 67, 111, 111, 114, 100, 115, - 0, 84, 101, 120, 116, 67, - 111, 108, 111, 114, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 57, 46, 57, 53, 50, - 46, 51, 49, 49, 49, 0, - 171, 73, 83, 71, 78, 44, - 0, 0, 0, 1, 0, 0, - 0, 8, 0, 0, 0, 32, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 7, 3, 0, 0, 80, - 79, 83, 73, 84, 73, 79, - 78, 0, 171, 171, 171, 79, - 83, 71, 78, 104, 0, 0, - 0, 3, 0, 0, 0, 8, - 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 3, - 12, 0, 0, 92, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 12, - 3, 0, 0, 83, 86, 95, - 80, 111, 115, 105, 116, 105, - 111, 110, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 171, 171, 171, 245, 213, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 172, - 9, 0, 0, 68, 88, 66, - 67, 3, 49, 75, 182, 79, - 108, 171, 188, 143, 169, 209, - 116, 53, 82, 194, 78, 1, - 0, 0, 0, 172, 9, 0, - 0, 6, 0, 0, 0, 56, - 0, 0, 0, 220, 2, 0, - 0, 204, 6, 0, 0, 72, - 7, 0, 0, 8, 9, 0, - 0, 120, 9, 0, 0, 65, - 111, 110, 57, 156, 2, 0, - 0, 156, 2, 0, 0, 0, - 2, 255, 255, 104, 2, 0, - 0, 52, 0, 0, 0, 1, - 0, 40, 0, 0, 0, 52, - 0, 0, 0, 52, 0, 1, - 0, 36, 0, 0, 0, 52, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 1, - 2, 255, 255, 31, 0, 0, - 2, 0, 0, 0, 128, 0, - 0, 15, 176, 31, 0, 0, - 2, 0, 0, 0, 144, 0, - 8, 15, 160, 2, 0, 0, - 3, 0, 0, 2, 128, 0, - 0, 85, 176, 0, 0, 85, - 160, 1, 0, 0, 2, 0, - 0, 1, 128, 0, 0, 0, - 176, 2, 0, 0, 3, 1, - 0, 2, 128, 0, 0, 85, - 176, 0, 0, 0, 160, 1, - 0, 0, 2, 1, 0, 1, - 128, 0, 0, 0, 176, 66, - 0, 0, 3, 0, 0, 15, - 128, 0, 0, 228, 128, 0, - 8, 228, 160, 66, 0, 0, - 3, 1, 0, 15, 128, 1, - 0, 228, 128, 0, 8, 228, - 160, 5, 0, 0, 3, 0, - 0, 15, 128, 0, 0, 228, - 128, 3, 0, 85, 160, 4, - 0, 0, 4, 0, 0, 15, - 128, 3, 0, 0, 160, 1, - 0, 228, 128, 0, 0, 228, - 128, 2, 0, 0, 3, 1, - 0, 2, 128, 0, 0, 85, - 176, 0, 0, 170, 160, 1, - 0, 0, 2, 1, 0, 1, - 128, 0, 0, 0, 176, 2, - 0, 0, 3, 2, 0, 2, - 128, 0, 0, 85, 176, 0, - 0, 255, 160, 1, 0, 0, - 2, 2, 0, 1, 128, 0, - 0, 0, 176, 66, 0, 0, - 3, 1, 0, 15, 128, 1, - 0, 228, 128, 0, 8, 228, - 160, 66, 0, 0, 3, 2, - 0, 15, 128, 2, 0, 228, - 128, 0, 8, 228, 160, 4, - 0, 0, 4, 0, 0, 15, - 128, 3, 0, 170, 160, 1, - 0, 228, 128, 0, 0, 228, - 128, 4, 0, 0, 4, 0, - 0, 15, 128, 3, 0, 255, - 160, 2, 0, 228, 128, 0, - 0, 228, 128, 2, 0, 0, - 3, 1, 0, 2, 128, 0, - 0, 85, 176, 1, 0, 0, - 160, 1, 0, 0, 2, 1, - 0, 1, 128, 0, 0, 0, - 176, 2, 0, 0, 3, 2, - 0, 2, 128, 0, 0, 85, - 176, 1, 0, 85, 160, 1, - 0, 0, 2, 2, 0, 1, - 128, 0, 0, 0, 176, 66, - 0, 0, 3, 1, 0, 15, - 128, 1, 0, 228, 128, 0, - 8, 228, 160, 66, 0, 0, - 3, 2, 0, 15, 128, 2, - 0, 228, 128, 0, 8, 228, - 160, 4, 0, 0, 4, 0, - 0, 15, 128, 4, 0, 0, - 160, 1, 0, 228, 128, 0, - 0, 228, 128, 4, 0, 0, - 4, 0, 0, 15, 128, 4, - 0, 85, 160, 2, 0, 228, - 128, 0, 0, 228, 128, 2, - 0, 0, 3, 1, 0, 2, - 128, 0, 0, 85, 176, 1, - 0, 170, 160, 1, 0, 0, - 2, 1, 0, 1, 128, 0, - 0, 0, 176, 2, 0, 0, - 3, 2, 0, 2, 128, 0, - 0, 85, 176, 1, 0, 255, - 160, 1, 0, 0, 2, 2, - 0, 1, 128, 0, 0, 0, - 176, 66, 0, 0, 3, 1, - 0, 15, 128, 1, 0, 228, - 128, 0, 8, 228, 160, 66, - 0, 0, 3, 2, 0, 15, - 128, 2, 0, 228, 128, 0, - 8, 228, 160, 4, 0, 0, - 4, 0, 0, 15, 128, 4, - 0, 170, 160, 1, 0, 228, - 128, 0, 0, 228, 128, 4, - 0, 0, 4, 0, 0, 15, - 128, 4, 0, 255, 160, 2, - 0, 228, 128, 0, 0, 228, - 128, 2, 0, 0, 3, 1, - 0, 2, 128, 0, 0, 85, - 176, 2, 0, 0, 160, 1, - 0, 0, 2, 1, 0, 1, - 128, 0, 0, 0, 176, 66, - 0, 0, 3, 1, 0, 15, - 128, 1, 0, 228, 128, 0, - 8, 228, 160, 4, 0, 0, - 4, 0, 0, 15, 128, 5, - 0, 0, 160, 1, 0, 228, - 128, 0, 0, 228, 128, 1, - 0, 0, 2, 0, 8, 15, - 128, 0, 0, 228, 128, 255, - 255, 0, 0, 83, 72, 68, - 82, 232, 3, 0, 0, 64, - 0, 0, 0, 250, 0, 0, - 0, 89, 0, 0, 4, 70, - 142, 32, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 90, - 0, 0, 3, 0, 96, 16, - 0, 0, 0, 0, 0, 88, - 24, 0, 4, 0, 112, 16, - 0, 0, 0, 0, 0, 85, - 85, 0, 0, 98, 16, 0, - 3, 50, 16, 16, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 242, 32, 16, 0, 0, - 0, 0, 0, 104, 0, 0, - 2, 4, 0, 0, 0, 54, - 0, 0, 5, 82, 0, 16, - 0, 0, 0, 0, 0, 6, - 16, 16, 0, 1, 0, 0, - 0, 0, 0, 0, 8, 242, - 0, 16, 0, 1, 0, 0, - 0, 86, 21, 16, 0, 1, - 0, 0, 0, 134, 141, 32, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 54, 0, 0, - 5, 162, 0, 16, 0, 0, - 0, 0, 0, 6, 8, 16, - 0, 1, 0, 0, 0, 69, - 0, 0, 9, 242, 0, 16, - 0, 2, 0, 0, 0, 230, - 10, 16, 0, 0, 0, 0, - 0, 70, 126, 16, 0, 0, - 0, 0, 0, 0, 96, 16, - 0, 0, 0, 0, 0, 69, - 0, 0, 9, 242, 0, 16, - 0, 0, 0, 0, 0, 70, - 0, 16, 0, 0, 0, 0, - 0, 70, 126, 16, 0, 0, - 0, 0, 0, 0, 96, 16, - 0, 0, 0, 0, 0, 56, - 0, 0, 8, 242, 0, 16, - 0, 2, 0, 0, 0, 70, - 14, 16, 0, 2, 0, 0, - 0, 86, 133, 32, 0, 0, - 0, 0, 0, 6, 0, 0, - 0, 50, 0, 0, 10, 242, - 0, 16, 0, 0, 0, 0, - 0, 6, 128, 32, 0, 0, - 0, 0, 0, 6, 0, 0, - 0, 70, 14, 16, 0, 0, - 0, 0, 0, 70, 14, 16, - 0, 2, 0, 0, 0, 54, - 0, 0, 5, 82, 0, 16, - 0, 1, 0, 0, 0, 6, - 16, 16, 0, 1, 0, 0, - 0, 69, 0, 0, 9, 242, - 0, 16, 0, 2, 0, 0, - 0, 70, 0, 16, 0, 1, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 69, 0, 0, 9, 242, - 0, 16, 0, 1, 0, 0, - 0, 230, 10, 16, 0, 1, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 50, 0, 0, 10, 242, - 0, 16, 0, 0, 0, 0, - 0, 166, 138, 32, 0, 0, - 0, 0, 0, 6, 0, 0, - 0, 70, 14, 16, 0, 2, - 0, 0, 0, 70, 14, 16, - 0, 0, 0, 0, 0, 50, - 0, 0, 10, 242, 0, 16, - 0, 0, 0, 0, 0, 246, - 143, 32, 0, 0, 0, 0, - 0, 6, 0, 0, 0, 70, - 14, 16, 0, 1, 0, 0, - 0, 70, 14, 16, 0, 0, - 0, 0, 0, 54, 0, 0, - 5, 82, 0, 16, 0, 1, - 0, 0, 0, 6, 16, 16, - 0, 1, 0, 0, 0, 0, - 0, 0, 8, 242, 0, 16, - 0, 2, 0, 0, 0, 86, - 21, 16, 0, 1, 0, 0, - 0, 134, 141, 32, 0, 0, - 0, 0, 0, 4, 0, 0, - 0, 54, 0, 0, 5, 162, - 0, 16, 0, 1, 0, 0, - 0, 6, 8, 16, 0, 2, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 3, - 0, 0, 0, 70, 0, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 0, 0, 0, - 0, 0, 96, 16, 0, 0, - 0, 0, 0, 69, 0, 0, - 9, 242, 0, 16, 0, 1, - 0, 0, 0, 230, 10, 16, - 0, 1, 0, 0, 0, 70, - 126, 16, 0, 0, 0, 0, - 0, 0, 96, 16, 0, 0, - 0, 0, 0, 50, 0, 0, - 10, 242, 0, 16, 0, 0, - 0, 0, 0, 6, 128, 32, - 0, 0, 0, 0, 0, 7, - 0, 0, 0, 70, 14, 16, - 0, 3, 0, 0, 0, 70, - 14, 16, 0, 0, 0, 0, - 0, 50, 0, 0, 10, 242, - 0, 16, 0, 0, 0, 0, - 0, 86, 133, 32, 0, 0, - 0, 0, 0, 7, 0, 0, - 0, 70, 14, 16, 0, 1, - 0, 0, 0, 70, 14, 16, - 0, 0, 0, 0, 0, 54, - 0, 0, 5, 82, 0, 16, - 0, 2, 0, 0, 0, 6, - 16, 16, 0, 1, 0, 0, - 0, 69, 0, 0, 9, 242, - 0, 16, 0, 1, 0, 0, - 0, 70, 0, 16, 0, 2, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 69, 0, 0, 9, 242, - 0, 16, 0, 2, 0, 0, - 0, 230, 10, 16, 0, 2, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 50, 0, 0, 10, 242, - 0, 16, 0, 0, 0, 0, - 0, 166, 138, 32, 0, 0, - 0, 0, 0, 7, 0, 0, - 0, 70, 14, 16, 0, 1, - 0, 0, 0, 70, 14, 16, - 0, 0, 0, 0, 0, 50, - 0, 0, 10, 242, 0, 16, - 0, 0, 0, 0, 0, 246, - 143, 32, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 70, - 14, 16, 0, 2, 0, 0, - 0, 70, 14, 16, 0, 0, - 0, 0, 0, 0, 0, 0, - 8, 34, 0, 16, 0, 1, - 0, 0, 0, 26, 16, 16, - 0, 1, 0, 0, 0, 10, - 128, 32, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 54, - 0, 0, 5, 18, 0, 16, - 0, 1, 0, 0, 0, 10, - 16, 16, 0, 1, 0, 0, - 0, 69, 0, 0, 9, 242, - 0, 16, 0, 1, 0, 0, - 0, 70, 0, 16, 0, 1, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 50, 0, 0, 10, 242, - 32, 16, 0, 0, 0, 0, - 0, 6, 128, 32, 0, 0, - 0, 0, 0, 8, 0, 0, - 0, 70, 14, 16, 0, 1, - 0, 0, 0, 70, 14, 16, - 0, 0, 0, 0, 0, 62, - 0, 0, 1, 83, 84, 65, - 84, 116, 0, 0, 0, 29, - 0, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 2, - 0, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 82, 68, 69, 70, 184, - 1, 0, 0, 1, 0, 0, - 0, 148, 0, 0, 0, 3, - 0, 0, 0, 28, 0, 0, - 0, 0, 4, 255, 255, 0, - 129, 0, 0, 132, 1, 0, - 0, 124, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 139, 0, 0, - 0, 2, 0, 0, 0, 5, - 0, 0, 0, 4, 0, 0, - 0, 255, 255, 255, 255, 0, - 0, 0, 0, 1, 0, 0, - 0, 12, 0, 0, 0, 143, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 115, 83, 104, 97, 100, - 111, 119, 83, 97, 109, 112, - 108, 101, 114, 0, 116, 101, - 120, 0, 99, 98, 49, 0, - 171, 143, 0, 0, 0, 4, - 0, 0, 0, 172, 0, 0, - 0, 160, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 12, 1, 0, 0, 0, - 0, 0, 0, 48, 0, 0, - 0, 0, 0, 0, 0, 28, - 1, 0, 0, 0, 0, 0, - 0, 44, 1, 0, 0, 48, - 0, 0, 0, 48, 0, 0, - 0, 2, 0, 0, 0, 60, - 1, 0, 0, 0, 0, 0, - 0, 76, 1, 0, 0, 96, - 0, 0, 0, 48, 0, 0, - 0, 2, 0, 0, 0, 88, - 1, 0, 0, 0, 0, 0, - 0, 104, 1, 0, 0, 144, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 116, - 1, 0, 0, 0, 0, 0, - 0, 66, 108, 117, 114, 79, - 102, 102, 115, 101, 116, 115, - 72, 0, 171, 171, 171, 1, - 0, 3, 0, 1, 0, 4, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 66, 108, 117, - 114, 79, 102, 102, 115, 101, - 116, 115, 86, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 4, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 66, - 108, 117, 114, 87, 101, 105, - 103, 104, 116, 115, 0, 1, - 0, 3, 0, 1, 0, 4, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 83, 104, 97, - 100, 111, 119, 67, 111, 108, - 111, 114, 0, 1, 0, 3, - 0, 1, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 57, 46, 50, 57, 46, 57, - 53, 50, 46, 51, 49, 49, - 49, 0, 171, 171, 171, 73, - 83, 71, 78, 104, 0, 0, - 0, 3, 0, 0, 0, 8, - 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 3, - 3, 0, 0, 92, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 83, 86, 95, - 80, 111, 115, 105, 116, 105, - 111, 110, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 171, 171, 171, 79, 83, 71, - 78, 44, 0, 0, 0, 1, - 0, 0, 0, 8, 0, 0, - 0, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 83, 86, 95, 84, 97, - 114, 103, 101, 116, 0, 171, - 171, 81, 218, 0, 0, 0, - 0, 0, 0, 80, 50, 0, - 4, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 128, 63, - 1, 0, 0, 0, 0, 0, - 128, 63, 1, 0, 0, 0, - 0, 0, 128, 63, 1, 0, - 0, 0, 0, 0, 128, 63, - 1, 0, 0, 0, 3, 0, - 0, 0, 255, 255, 255, 255, - 68, 4, 0, 0, 68, 88, - 66, 67, 43, 219, 5, 122, - 32, 21, 232, 165, 63, 89, - 201, 32, 133, 13, 217, 23, - 1, 0, 0, 0, 68, 4, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 248, 0, - 0, 0, 244, 1, 0, 0, - 112, 2, 0, 0, 160, 3, - 0, 0, 212, 3, 0, 0, - 65, 111, 110, 57, 184, 0, - 0, 0, 184, 0, 0, 0, - 0, 2, 254, 255, 132, 0, - 0, 0, 52, 0, 0, 0, - 1, 0, 36, 0, 0, 0, - 48, 0, 0, 0, 48, 0, - 0, 0, 36, 0, 1, 0, - 48, 0, 0, 0, 0, 0, - 3, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 2, 254, 255, 81, 0, - 0, 5, 4, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 4, 0, - 0, 4, 0, 0, 3, 224, - 0, 0, 228, 144, 2, 0, - 238, 160, 2, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 12, 224, 0, 0, 20, 144, - 3, 0, 180, 160, 3, 0, - 20, 160, 4, 0, 0, 4, - 0, 0, 3, 128, 0, 0, - 228, 144, 1, 0, 238, 160, - 1, 0, 228, 160, 2, 0, - 0, 3, 0, 0, 3, 192, - 0, 0, 228, 128, 0, 0, - 228, 160, 1, 0, 0, 2, - 0, 0, 12, 192, 4, 0, - 68, 160, 255, 255, 0, 0, - 83, 72, 68, 82, 244, 0, - 0, 0, 64, 0, 1, 0, - 61, 0, 0, 0, 89, 0, - 0, 4, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 95, 0, 0, 3, - 50, 16, 16, 0, 0, 0, - 0, 0, 103, 0, 0, 4, - 242, 32, 16, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 50, 32, - 16, 0, 1, 0, 0, 0, - 101, 0, 0, 3, 194, 32, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 50, 32, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 0, 0, - 0, 0, 230, 138, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 70, 128, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 8, - 194, 32, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 128, 63, 50, 0, - 0, 11, 50, 32, 16, 0, - 1, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 50, 0, 0, 11, 194, 32, - 16, 0, 1, 0, 0, 0, - 6, 20, 16, 0, 0, 0, - 0, 0, 166, 142, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 6, 132, 32, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 40, 1, 0, 0, - 1, 0, 0, 0, 64, 0, - 0, 0, 1, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 254, 255, 0, 129, 0, 0, - 246, 0, 0, 0, 60, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 99, 98, 48, 0, 60, 0, - 0, 0, 4, 0, 0, 0, - 88, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 212, 0, - 0, 0, 16, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 222, 0, - 0, 0, 32, 0, 0, 0, - 16, 0, 0, 0, 2, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 236, 0, - 0, 0, 48, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 196, 0, 0, 0, - 0, 0, 0, 0, 81, 117, - 97, 100, 68, 101, 115, 99, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 77, 97, 115, 107, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 84, 101, 120, 116, - 67, 111, 108, 111, 114, 0, - 77, 105, 99, 114, 111, 115, - 111, 102, 116, 32, 40, 82, - 41, 32, 72, 76, 83, 76, - 32, 83, 104, 97, 100, 101, - 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 57, - 46, 50, 57, 46, 57, 53, - 50, 46, 51, 49, 49, 49, - 0, 171, 73, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 7, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 171, 171, 171, - 79, 83, 71, 78, 104, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 3, 12, 0, 0, 92, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 12, 3, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 171, 171, 60, 228, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 164, 10, 0, 0, 68, 88, - 66, 67, 163, 148, 241, 166, - 84, 180, 45, 196, 165, 247, - 224, 37, 57, 34, 240, 145, - 1, 0, 0, 0, 164, 10, - 0, 0, 6, 0, 0, 0, - 56, 0, 0, 0, 24, 3, - 0, 0, 112, 7, 0, 0, - 236, 7, 0, 0, 0, 10, - 0, 0, 112, 10, 0, 0, - 65, 111, 110, 57, 216, 2, - 0, 0, 216, 2, 0, 0, - 0, 2, 255, 255, 160, 2, - 0, 0, 56, 0, 0, 0, - 1, 0, 44, 0, 0, 0, - 56, 0, 0, 0, 56, 0, - 2, 0, 36, 0, 0, 0, - 56, 0, 1, 0, 0, 0, - 0, 1, 1, 0, 0, 0, - 3, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 1, 2, - 255, 255, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 2, 0, 0, 3, - 0, 0, 2, 128, 0, 0, - 85, 176, 0, 0, 85, 160, - 1, 0, 0, 2, 0, 0, - 1, 128, 0, 0, 0, 176, - 2, 0, 0, 3, 1, 0, - 2, 128, 0, 0, 85, 176, - 0, 0, 0, 160, 1, 0, - 0, 2, 1, 0, 1, 128, - 0, 0, 0, 176, 66, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 228, 128, 1, 8, - 228, 160, 66, 0, 0, 3, - 1, 0, 15, 128, 1, 0, - 228, 128, 1, 8, 228, 160, - 5, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 128, - 3, 0, 85, 160, 4, 0, - 0, 4, 0, 0, 15, 128, - 3, 0, 0, 160, 1, 0, - 228, 128, 0, 0, 228, 128, - 2, 0, 0, 3, 1, 0, - 2, 128, 0, 0, 85, 176, - 0, 0, 170, 160, 1, 0, - 0, 2, 1, 0, 1, 128, - 0, 0, 0, 176, 2, 0, - 0, 3, 2, 0, 2, 128, - 0, 0, 85, 176, 0, 0, - 255, 160, 1, 0, 0, 2, - 2, 0, 1, 128, 0, 0, - 0, 176, 66, 0, 0, 3, - 1, 0, 15, 128, 1, 0, - 228, 128, 1, 8, 228, 160, - 66, 0, 0, 3, 2, 0, - 15, 128, 2, 0, 228, 128, - 1, 8, 228, 160, 4, 0, - 0, 4, 0, 0, 15, 128, - 3, 0, 170, 160, 1, 0, - 228, 128, 0, 0, 228, 128, - 4, 0, 0, 4, 0, 0, - 15, 128, 3, 0, 255, 160, - 2, 0, 228, 128, 0, 0, - 228, 128, 2, 0, 0, 3, - 1, 0, 2, 128, 0, 0, - 85, 176, 1, 0, 0, 160, - 1, 0, 0, 2, 1, 0, - 1, 128, 0, 0, 0, 176, - 2, 0, 0, 3, 2, 0, - 2, 128, 0, 0, 85, 176, - 1, 0, 85, 160, 1, 0, - 0, 2, 2, 0, 1, 128, - 0, 0, 0, 176, 66, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 228, 128, 1, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 2, 0, - 228, 128, 1, 8, 228, 160, - 4, 0, 0, 4, 0, 0, - 15, 128, 4, 0, 0, 160, - 1, 0, 228, 128, 0, 0, - 228, 128, 4, 0, 0, 4, - 0, 0, 15, 128, 4, 0, - 85, 160, 2, 0, 228, 128, - 0, 0, 228, 128, 2, 0, - 0, 3, 1, 0, 2, 128, - 0, 0, 85, 176, 1, 0, - 170, 160, 1, 0, 0, 2, - 1, 0, 1, 128, 0, 0, - 0, 176, 2, 0, 0, 3, - 2, 0, 2, 128, 0, 0, - 85, 176, 1, 0, 255, 160, - 1, 0, 0, 2, 2, 0, - 1, 128, 0, 0, 0, 176, - 66, 0, 0, 3, 1, 0, - 15, 128, 1, 0, 228, 128, - 1, 8, 228, 160, 66, 0, - 0, 3, 2, 0, 15, 128, - 2, 0, 228, 128, 1, 8, - 228, 160, 4, 0, 0, 4, - 0, 0, 15, 128, 4, 0, - 170, 160, 1, 0, 228, 128, - 0, 0, 228, 128, 4, 0, - 0, 4, 0, 0, 15, 128, - 4, 0, 255, 160, 2, 0, - 228, 128, 0, 0, 228, 128, - 2, 0, 0, 3, 1, 0, - 2, 128, 0, 0, 85, 176, - 2, 0, 0, 160, 1, 0, - 0, 2, 1, 0, 1, 128, - 0, 0, 0, 176, 1, 0, - 0, 2, 2, 0, 3, 128, - 0, 0, 235, 176, 66, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 228, 128, 1, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 2, 0, - 228, 128, 0, 8, 228, 160, - 4, 0, 0, 4, 0, 0, - 15, 128, 5, 0, 0, 160, - 1, 0, 228, 128, 0, 0, - 228, 128, 5, 0, 0, 3, - 0, 0, 15, 128, 2, 0, - 255, 128, 0, 0, 228, 128, - 1, 0, 0, 2, 0, 8, - 15, 128, 0, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 80, 4, 0, 0, - 64, 0, 0, 0, 20, 1, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 9, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 1, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 1, 0, - 0, 0, 98, 16, 0, 3, - 194, 16, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 104, 0, 0, 2, - 4, 0, 0, 0, 54, 0, - 0, 5, 82, 0, 16, 0, - 0, 0, 0, 0, 6, 16, - 16, 0, 1, 0, 0, 0, - 0, 0, 0, 8, 242, 0, - 16, 0, 1, 0, 0, 0, - 86, 21, 16, 0, 1, 0, - 0, 0, 134, 141, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 54, 0, 0, 5, - 162, 0, 16, 0, 0, 0, - 0, 0, 6, 8, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 2, 0, 0, 0, 230, 10, - 16, 0, 0, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 0, - 16, 0, 0, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 1, 0, 0, 0, 56, 0, - 0, 8, 242, 0, 16, 0, - 2, 0, 0, 0, 70, 14, - 16, 0, 2, 0, 0, 0, - 86, 133, 32, 0, 0, 0, - 0, 0, 6, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 6, 128, 32, 0, 0, 0, - 0, 0, 6, 0, 0, 0, - 70, 14, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 2, 0, 0, 0, 54, 0, - 0, 5, 82, 0, 16, 0, - 1, 0, 0, 0, 6, 16, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 2, 0, 0, 0, - 70, 0, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 1, 0, 0, 0, - 230, 10, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 166, 138, 32, 0, 0, 0, - 0, 0, 6, 0, 0, 0, - 70, 14, 16, 0, 2, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 242, 0, 16, 0, - 0, 0, 0, 0, 246, 143, - 32, 0, 0, 0, 0, 0, - 6, 0, 0, 0, 70, 14, - 16, 0, 1, 0, 0, 0, - 70, 14, 16, 0, 0, 0, - 0, 0, 54, 0, 0, 5, - 82, 0, 16, 0, 1, 0, - 0, 0, 6, 16, 16, 0, - 1, 0, 0, 0, 0, 0, - 0, 8, 242, 0, 16, 0, - 2, 0, 0, 0, 86, 21, - 16, 0, 1, 0, 0, 0, - 134, 141, 32, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 54, 0, 0, 5, 162, 0, - 16, 0, 1, 0, 0, 0, - 6, 8, 16, 0, 2, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 3, 0, - 0, 0, 70, 0, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 1, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 1, 0, - 0, 0, 230, 10, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 0, 0, 0, 0, - 0, 96, 16, 0, 1, 0, - 0, 0, 50, 0, 0, 10, - 242, 0, 16, 0, 0, 0, - 0, 0, 6, 128, 32, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 70, 14, 16, 0, - 3, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 86, 133, 32, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 70, 14, 16, 0, 1, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 54, 0, - 0, 5, 82, 0, 16, 0, - 2, 0, 0, 0, 6, 16, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 1, 0, 0, 0, - 70, 0, 16, 0, 2, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 2, 0, 0, 0, - 230, 10, 16, 0, 2, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 166, 138, 32, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 70, 14, 16, 0, 1, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 10, 242, 0, 16, 0, - 0, 0, 0, 0, 246, 143, - 32, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 70, 14, - 16, 0, 2, 0, 0, 0, - 70, 14, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 8, - 34, 0, 16, 0, 1, 0, - 0, 0, 26, 16, 16, 0, - 1, 0, 0, 0, 10, 128, - 32, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 54, 0, - 0, 5, 18, 0, 16, 0, - 1, 0, 0, 0, 10, 16, - 16, 0, 1, 0, 0, 0, - 69, 0, 0, 9, 242, 0, - 16, 0, 1, 0, 0, 0, - 70, 0, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 1, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 6, 128, 32, 0, 0, 0, - 0, 0, 8, 0, 0, 0, - 70, 14, 16, 0, 1, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 1, 0, 0, 0, 230, 26, - 16, 0, 1, 0, 0, 0, - 70, 126, 16, 0, 1, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 56, 0, - 0, 7, 242, 32, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 246, 15, 16, 0, 1, 0, - 0, 0, 62, 0, 0, 1, - 83, 84, 65, 84, 116, 0, - 0, 0, 31, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 68, - 69, 70, 12, 2, 0, 0, - 1, 0, 0, 0, 232, 0, - 0, 0, 5, 0, 0, 0, - 28, 0, 0, 0, 0, 4, - 255, 255, 0, 129, 0, 0, - 216, 1, 0, 0, 188, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 201, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 216, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 220, 0, - 0, 0, 2, 0, 0, 0, - 5, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 1, 0, 0, 0, 1, 0, - 0, 0, 12, 0, 0, 0, - 225, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 115, 77, 97, 115, - 107, 83, 97, 109, 112, 108, - 101, 114, 0, 115, 83, 104, - 97, 100, 111, 119, 83, 97, - 109, 112, 108, 101, 114, 0, - 116, 101, 120, 0, 109, 97, - 115, 107, 0, 99, 98, 49, - 0, 171, 171, 171, 225, 0, - 0, 0, 4, 0, 0, 0, - 0, 1, 0, 0, 160, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 96, 1, - 0, 0, 0, 0, 0, 0, - 48, 0, 0, 0, 0, 0, - 0, 0, 112, 1, 0, 0, - 0, 0, 0, 0, 128, 1, - 0, 0, 48, 0, 0, 0, - 48, 0, 0, 0, 2, 0, - 0, 0, 144, 1, 0, 0, - 0, 0, 0, 0, 160, 1, - 0, 0, 96, 0, 0, 0, - 48, 0, 0, 0, 2, 0, - 0, 0, 172, 1, 0, 0, - 0, 0, 0, 0, 188, 1, - 0, 0, 144, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 200, 1, 0, 0, - 0, 0, 0, 0, 66, 108, - 117, 114, 79, 102, 102, 115, - 101, 116, 115, 72, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 66, 108, 117, 114, 79, 102, - 102, 115, 101, 116, 115, 86, - 0, 171, 171, 171, 1, 0, - 3, 0, 1, 0, 4, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 66, 108, 117, 114, - 87, 101, 105, 103, 104, 116, - 115, 0, 1, 0, 3, 0, - 1, 0, 4, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 83, 104, 97, 100, 111, 119, - 67, 111, 108, 111, 114, 0, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 171, - 171, 171, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 3, 3, 0, 0, - 92, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 12, 12, 0, 0, - 83, 86, 95, 80, 111, 115, - 105, 116, 105, 111, 110, 0, - 84, 69, 88, 67, 79, 79, - 82, 68, 0, 171, 171, 171, - 79, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 83, 86, - 95, 84, 97, 114, 103, 101, - 116, 0, 171, 171, 152, 232, - 0, 0, 0, 0, 0, 0, - 83, 97, 109, 112, 108, 101, - 84, 101, 120, 116, 84, 101, - 120, 116, 117, 114, 101, 0, - 85, 110, 109, 97, 115, 107, - 101, 100, 0, 4, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 255, - 255, 255, 255, 68, 4, 0, - 0, 68, 88, 66, 67, 43, - 219, 5, 122, 32, 21, 232, - 165, 63, 89, 201, 32, 133, - 13, 217, 23, 1, 0, 0, - 0, 68, 4, 0, 0, 6, - 0, 0, 0, 56, 0, 0, - 0, 248, 0, 0, 0, 244, - 1, 0, 0, 112, 2, 0, - 0, 160, 3, 0, 0, 212, - 3, 0, 0, 65, 111, 110, - 57, 184, 0, 0, 0, 184, - 0, 0, 0, 0, 2, 254, - 255, 132, 0, 0, 0, 52, - 0, 0, 0, 1, 0, 36, - 0, 0, 0, 48, 0, 0, - 0, 48, 0, 0, 0, 36, - 0, 1, 0, 48, 0, 0, - 0, 0, 0, 3, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 254, - 255, 81, 0, 0, 5, 4, - 0, 15, 160, 0, 0, 0, - 0, 0, 0, 128, 63, 0, - 0, 0, 0, 0, 0, 0, - 0, 31, 0, 0, 2, 5, - 0, 0, 128, 0, 0, 15, - 144, 4, 0, 0, 4, 0, - 0, 3, 224, 0, 0, 228, - 144, 2, 0, 238, 160, 2, - 0, 228, 160, 4, 0, 0, - 4, 0, 0, 12, 224, 0, - 0, 20, 144, 3, 0, 180, - 160, 3, 0, 20, 160, 4, - 0, 0, 4, 0, 0, 3, - 128, 0, 0, 228, 144, 1, - 0, 238, 160, 1, 0, 228, - 160, 2, 0, 0, 3, 0, - 0, 3, 192, 0, 0, 228, - 128, 0, 0, 228, 160, 1, - 0, 0, 2, 0, 0, 12, - 192, 4, 0, 68, 160, 255, - 255, 0, 0, 83, 72, 68, - 82, 244, 0, 0, 0, 64, - 0, 1, 0, 61, 0, 0, - 0, 89, 0, 0, 4, 70, - 142, 32, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 95, - 0, 0, 3, 50, 16, 16, - 0, 0, 0, 0, 0, 103, - 0, 0, 4, 242, 32, 16, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 50, 32, 16, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 194, 32, 16, 0, 1, - 0, 0, 0, 50, 0, 0, - 11, 50, 32, 16, 0, 0, - 0, 0, 0, 70, 16, 16, - 0, 0, 0, 0, 0, 230, - 138, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 70, - 128, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 54, - 0, 0, 8, 194, 32, 16, - 0, 0, 0, 0, 0, 2, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 128, - 63, 50, 0, 0, 11, 50, - 32, 16, 0, 1, 0, 0, - 0, 70, 16, 16, 0, 0, - 0, 0, 0, 230, 138, 32, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 70, 128, 32, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 50, 0, 0, - 11, 194, 32, 16, 0, 1, - 0, 0, 0, 6, 20, 16, - 0, 0, 0, 0, 0, 166, - 142, 32, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 6, - 132, 32, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 62, - 0, 0, 1, 83, 84, 65, - 84, 116, 0, 0, 0, 5, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 82, 68, 69, 70, 40, - 1, 0, 0, 1, 0, 0, - 0, 64, 0, 0, 0, 1, - 0, 0, 0, 28, 0, 0, - 0, 0, 4, 254, 255, 0, - 129, 0, 0, 246, 0, 0, - 0, 60, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 99, 98, 48, - 0, 60, 0, 0, 0, 4, - 0, 0, 0, 88, 0, 0, - 0, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 184, 0, 0, 0, 0, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 196, - 0, 0, 0, 0, 0, 0, - 0, 212, 0, 0, 0, 16, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 196, - 0, 0, 0, 0, 0, 0, - 0, 222, 0, 0, 0, 32, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 196, - 0, 0, 0, 0, 0, 0, - 0, 236, 0, 0, 0, 48, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 196, - 0, 0, 0, 0, 0, 0, - 0, 81, 117, 97, 100, 68, - 101, 115, 99, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 77, 97, 115, - 107, 84, 101, 120, 67, 111, - 111, 114, 100, 115, 0, 84, - 101, 120, 116, 67, 111, 108, - 111, 114, 0, 77, 105, 99, - 114, 111, 115, 111, 102, 116, - 32, 40, 82, 41, 32, 72, - 76, 83, 76, 32, 83, 104, - 97, 100, 101, 114, 32, 67, - 111, 109, 112, 105, 108, 101, - 114, 32, 57, 46, 50, 57, - 46, 57, 53, 50, 46, 51, - 49, 49, 49, 0, 171, 73, - 83, 71, 78, 44, 0, 0, - 0, 1, 0, 0, 0, 8, - 0, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 7, - 3, 0, 0, 80, 79, 83, - 73, 84, 73, 79, 78, 0, - 171, 171, 171, 79, 83, 71, - 78, 104, 0, 0, 0, 3, - 0, 0, 0, 8, 0, 0, - 0, 80, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 3, 12, 0, - 0, 92, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 12, 3, 0, - 0, 83, 86, 95, 80, 111, - 115, 105, 116, 105, 111, 110, - 0, 84, 69, 88, 67, 79, - 79, 82, 68, 0, 171, 171, - 171, 147, 243, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 152, 4, 0, - 0, 68, 88, 66, 67, 191, - 104, 250, 147, 73, 213, 250, - 163, 155, 188, 140, 103, 174, - 191, 212, 77, 1, 0, 0, - 0, 152, 4, 0, 0, 6, - 0, 0, 0, 56, 0, 0, - 0, 4, 1, 0, 0, 224, - 1, 0, 0, 92, 2, 0, - 0, 220, 3, 0, 0, 76, - 4, 0, 0, 65, 111, 110, - 57, 196, 0, 0, 0, 196, - 0, 0, 0, 0, 2, 255, - 255, 144, 0, 0, 0, 52, - 0, 0, 0, 1, 0, 40, - 0, 0, 0, 52, 0, 0, - 0, 52, 0, 1, 0, 36, - 0, 0, 0, 52, 0, 0, - 0, 0, 0, 0, 0, 3, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 255, - 255, 81, 0, 0, 5, 1, - 0, 15, 160, 0, 0, 128, - 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 31, 0, 0, 2, 0, - 0, 0, 128, 0, 0, 15, - 176, 31, 0, 0, 2, 0, - 0, 0, 144, 0, 8, 15, - 160, 1, 0, 0, 2, 0, - 0, 7, 128, 0, 0, 228, - 160, 4, 0, 0, 4, 0, - 0, 15, 128, 0, 0, 36, - 128, 1, 0, 64, 160, 1, - 0, 21, 160, 1, 0, 0, - 2, 0, 8, 15, 128, 0, - 0, 228, 128, 66, 0, 0, - 3, 0, 0, 15, 128, 0, - 0, 228, 176, 0, 8, 228, - 160, 5, 0, 0, 3, 0, - 0, 15, 128, 0, 0, 70, - 128, 0, 0, 255, 160, 1, - 0, 0, 2, 1, 8, 15, - 128, 0, 0, 228, 128, 255, - 255, 0, 0, 83, 72, 68, - 82, 212, 0, 0, 0, 64, - 0, 0, 0, 53, 0, 0, - 0, 89, 0, 0, 4, 70, - 142, 32, 0, 0, 0, 0, - 0, 4, 0, 0, 0, 90, - 0, 0, 3, 0, 96, 16, - 0, 0, 0, 0, 0, 88, - 24, 0, 4, 0, 112, 16, - 0, 0, 0, 0, 0, 85, - 85, 0, 0, 98, 16, 0, - 3, 50, 16, 16, 0, 1, - 0, 0, 0, 101, 0, 0, - 3, 242, 32, 16, 0, 0, - 0, 0, 0, 101, 0, 0, - 3, 242, 32, 16, 0, 1, - 0, 0, 0, 104, 0, 0, - 2, 1, 0, 0, 0, 54, - 0, 0, 6, 114, 32, 16, - 0, 0, 0, 0, 0, 70, - 130, 32, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 54, - 0, 0, 5, 130, 32, 16, - 0, 0, 0, 0, 0, 1, - 64, 0, 0, 0, 0, 128, - 63, 69, 0, 0, 9, 242, - 0, 16, 0, 0, 0, 0, - 0, 70, 16, 16, 0, 1, - 0, 0, 0, 70, 126, 16, - 0, 0, 0, 0, 0, 0, - 96, 16, 0, 0, 0, 0, - 0, 56, 0, 0, 8, 242, - 32, 16, 0, 1, 0, 0, - 0, 102, 4, 16, 0, 0, - 0, 0, 0, 246, 143, 32, - 0, 0, 0, 0, 0, 3, - 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, - 0, 0, 0, 5, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, - 68, 69, 70, 120, 1, 0, - 0, 1, 0, 0, 0, 144, - 0, 0, 0, 3, 0, 0, - 0, 28, 0, 0, 0, 0, - 4, 255, 255, 0, 129, 0, - 0, 70, 1, 0, 0, 124, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 133, 0, 0, 0, 2, - 0, 0, 0, 5, 0, 0, - 0, 4, 0, 0, 0, 255, - 255, 255, 255, 0, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 137, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 115, - 83, 97, 109, 112, 108, 101, - 114, 0, 116, 101, 120, 0, - 99, 98, 48, 0, 171, 171, - 171, 137, 0, 0, 0, 4, - 0, 0, 0, 168, 0, 0, - 0, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 8, 1, 0, 0, 0, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 20, - 1, 0, 0, 0, 0, 0, - 0, 36, 1, 0, 0, 16, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 20, - 1, 0, 0, 0, 0, 0, - 0, 46, 1, 0, 0, 32, - 0, 0, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 20, - 1, 0, 0, 0, 0, 0, - 0, 60, 1, 0, 0, 48, - 0, 0, 0, 16, 0, 0, - 0, 2, 0, 0, 0, 20, - 1, 0, 0, 0, 0, 0, - 0, 81, 117, 97, 100, 68, - 101, 115, 99, 0, 171, 171, - 171, 1, 0, 3, 0, 1, - 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, - 101, 120, 67, 111, 111, 114, - 100, 115, 0, 77, 97, 115, - 107, 84, 101, 120, 67, 111, - 111, 114, 100, 115, 0, 84, - 101, 120, 116, 67, 111, 108, - 111, 114, 0, 77, 105, 99, - 114, 111, 115, 111, 102, 116, - 32, 40, 82, 41, 32, 72, - 76, 83, 76, 32, 83, 104, - 97, 100, 101, 114, 32, 67, - 111, 109, 112, 105, 108, 101, - 114, 32, 57, 46, 50, 57, - 46, 57, 53, 50, 46, 51, - 49, 49, 49, 0, 171, 73, - 83, 71, 78, 104, 0, 0, - 0, 3, 0, 0, 0, 8, - 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 15, - 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 3, - 3, 0, 0, 92, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 0, 1, 0, 0, 0, 12, - 0, 0, 0, 83, 86, 95, - 80, 111, 115, 105, 116, 105, - 111, 110, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 171, 171, 171, 79, 83, 71, - 78, 68, 0, 0, 0, 2, - 0, 0, 0, 8, 0, 0, - 0, 56, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, - 0, 0, 0, 15, 0, 0, - 0, 56, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 1, - 0, 0, 0, 15, 0, 0, - 0, 83, 86, 95, 84, 97, - 114, 103, 101, 116, 0, 171, - 171, 239, 247, 0, 0, 0, - 0, 0, 0, 77, 97, 115, - 107, 101, 100, 0, 4, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 255, 255, 255, 255, 68, 4, - 0, 0, 68, 88, 66, 67, - 43, 219, 5, 122, 32, 21, - 232, 165, 63, 89, 201, 32, - 133, 13, 217, 23, 1, 0, - 0, 0, 68, 4, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 248, 0, 0, 0, - 244, 1, 0, 0, 112, 2, - 0, 0, 160, 3, 0, 0, - 212, 3, 0, 0, 65, 111, - 110, 57, 184, 0, 0, 0, - 184, 0, 0, 0, 0, 2, - 254, 255, 132, 0, 0, 0, - 52, 0, 0, 0, 1, 0, - 36, 0, 0, 0, 48, 0, - 0, 0, 48, 0, 0, 0, - 36, 0, 1, 0, 48, 0, - 0, 0, 0, 0, 3, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 2, - 254, 255, 81, 0, 0, 5, - 4, 0, 15, 160, 0, 0, - 0, 0, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 5, 0, 0, 128, 0, 0, - 15, 144, 4, 0, 0, 4, - 0, 0, 3, 224, 0, 0, - 228, 144, 2, 0, 238, 160, - 2, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 12, 224, - 0, 0, 20, 144, 3, 0, - 180, 160, 3, 0, 20, 160, - 4, 0, 0, 4, 0, 0, - 3, 128, 0, 0, 228, 144, - 1, 0, 238, 160, 1, 0, - 228, 160, 2, 0, 0, 3, - 0, 0, 3, 192, 0, 0, - 228, 128, 0, 0, 228, 160, - 1, 0, 0, 2, 0, 0, - 12, 192, 4, 0, 68, 160, - 255, 255, 0, 0, 83, 72, - 68, 82, 244, 0, 0, 0, - 64, 0, 1, 0, 61, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 95, 0, 0, 3, 50, 16, - 16, 0, 0, 0, 0, 0, - 103, 0, 0, 4, 242, 32, - 16, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 50, 32, 16, 0, - 1, 0, 0, 0, 101, 0, - 0, 3, 194, 32, 16, 0, - 1, 0, 0, 0, 50, 0, - 0, 11, 50, 32, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 0, 0, 0, 0, - 230, 138, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 128, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 54, 0, 0, 8, 194, 32, - 16, 0, 0, 0, 0, 0, - 2, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 128, 63, 50, 0, 0, 11, - 50, 32, 16, 0, 1, 0, - 0, 0, 70, 16, 16, 0, - 0, 0, 0, 0, 230, 138, - 32, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 70, 128, - 32, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 50, 0, - 0, 11, 194, 32, 16, 0, - 1, 0, 0, 0, 6, 20, - 16, 0, 0, 0, 0, 0, - 166, 142, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 6, 132, 32, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 40, 1, 0, 0, 1, 0, - 0, 0, 64, 0, 0, 0, - 1, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 254, 255, - 0, 129, 0, 0, 246, 0, - 0, 0, 60, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 99, 98, - 48, 0, 60, 0, 0, 0, - 4, 0, 0, 0, 88, 0, - 0, 0, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 184, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 0, 0, - 16, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 222, 0, 0, 0, - 32, 0, 0, 0, 16, 0, - 0, 0, 2, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 236, 0, 0, 0, - 48, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 196, 0, 0, 0, 0, 0, - 0, 0, 81, 117, 97, 100, - 68, 101, 115, 99, 0, 171, - 171, 171, 1, 0, 3, 0, - 1, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 77, 97, - 115, 107, 84, 101, 120, 67, - 111, 111, 114, 100, 115, 0, - 84, 101, 120, 116, 67, 111, - 108, 111, 114, 0, 77, 105, - 99, 114, 111, 115, 111, 102, - 116, 32, 40, 82, 41, 32, - 72, 76, 83, 76, 32, 83, - 104, 97, 100, 101, 114, 32, - 67, 111, 109, 112, 105, 108, - 101, 114, 32, 57, 46, 50, - 57, 46, 57, 53, 50, 46, - 51, 49, 49, 49, 0, 171, - 73, 83, 71, 78, 44, 0, - 0, 0, 1, 0, 0, 0, - 8, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 7, 3, 0, 0, 80, 79, - 83, 73, 84, 73, 79, 78, - 0, 171, 171, 171, 79, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 12, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 3, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 202, 252, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 140, 5, - 0, 0, 68, 88, 66, 67, - 77, 207, 207, 67, 183, 90, - 222, 238, 92, 123, 223, 68, - 157, 129, 171, 161, 1, 0, - 0, 0, 140, 5, 0, 0, - 6, 0, 0, 0, 56, 0, - 0, 0, 64, 1, 0, 0, - 132, 2, 0, 0, 0, 3, - 0, 0, 208, 4, 0, 0, - 64, 5, 0, 0, 65, 111, - 110, 57, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 2, - 255, 255, 200, 0, 0, 0, - 56, 0, 0, 0, 1, 0, - 44, 0, 0, 0, 56, 0, - 0, 0, 56, 0, 2, 0, - 36, 0, 0, 0, 56, 0, - 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 3, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 255, 255, - 81, 0, 0, 5, 1, 0, - 15, 160, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 15, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 1, 8, 15, 160, - 1, 0, 0, 2, 0, 0, - 7, 128, 0, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 15, 128, 0, 0, 36, 128, - 1, 0, 64, 160, 1, 0, - 21, 160, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, - 228, 128, 1, 0, 0, 2, - 0, 0, 3, 128, 0, 0, - 235, 176, 66, 0, 0, 3, - 1, 0, 15, 128, 0, 0, - 228, 176, 0, 8, 228, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 128, - 1, 8, 228, 160, 5, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 70, 128, 0, 0, - 255, 160, 5, 0, 0, 3, - 0, 0, 15, 128, 0, 0, - 255, 128, 1, 0, 228, 128, - 1, 0, 0, 2, 1, 8, - 15, 128, 0, 0, 228, 128, - 255, 255, 0, 0, 83, 72, - 68, 82, 60, 1, 0, 0, - 64, 0, 0, 0, 79, 0, - 0, 0, 89, 0, 0, 4, - 70, 142, 32, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 0, 0, 0, 0, - 90, 0, 0, 3, 0, 96, - 16, 0, 1, 0, 0, 0, - 88, 24, 0, 4, 0, 112, - 16, 0, 0, 0, 0, 0, - 85, 85, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 1, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 1, 0, - 0, 0, 98, 16, 0, 3, - 194, 16, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 1, 0, - 0, 0, 104, 0, 0, 2, - 2, 0, 0, 0, 54, 0, - 0, 6, 114, 32, 16, 0, - 0, 0, 0, 0, 70, 130, - 32, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 54, 0, - 0, 5, 130, 32, 16, 0, - 0, 0, 0, 0, 1, 64, - 0, 0, 0, 0, 128, 63, - 69, 0, 0, 9, 242, 0, - 16, 0, 0, 0, 0, 0, - 70, 16, 16, 0, 1, 0, - 0, 0, 70, 126, 16, 0, - 0, 0, 0, 0, 0, 96, - 16, 0, 0, 0, 0, 0, - 56, 0, 0, 8, 242, 0, - 16, 0, 0, 0, 0, 0, - 102, 4, 16, 0, 0, 0, - 0, 0, 246, 143, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 69, 0, 0, 9, - 242, 0, 16, 0, 1, 0, - 0, 0, 230, 26, 16, 0, - 1, 0, 0, 0, 70, 126, - 16, 0, 1, 0, 0, 0, - 0, 96, 16, 0, 1, 0, - 0, 0, 56, 0, 0, 7, - 242, 32, 16, 0, 1, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 246, 15, - 16, 0, 1, 0, 0, 0, - 62, 0, 0, 1, 83, 84, - 65, 84, 116, 0, 0, 0, - 7, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 82, 68, 69, 70, - 200, 1, 0, 0, 1, 0, - 0, 0, 224, 0, 0, 0, - 5, 0, 0, 0, 28, 0, - 0, 0, 0, 4, 255, 255, - 0, 129, 0, 0, 150, 1, - 0, 0, 188, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 197, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 210, 0, 0, 0, 2, 0, - 0, 0, 5, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 1, 0, 0, 0, 12, 0, - 0, 0, 214, 0, 0, 0, - 2, 0, 0, 0, 5, 0, - 0, 0, 4, 0, 0, 0, - 255, 255, 255, 255, 1, 0, - 0, 0, 1, 0, 0, 0, - 12, 0, 0, 0, 219, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 115, 83, 97, 109, 112, 108, - 101, 114, 0, 115, 77, 97, - 115, 107, 83, 97, 109, 112, - 108, 101, 114, 0, 116, 101, - 120, 0, 109, 97, 115, 107, - 0, 99, 98, 48, 0, 171, - 219, 0, 0, 0, 4, 0, - 0, 0, 248, 0, 0, 0, - 64, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 88, 1, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 100, 1, - 0, 0, 0, 0, 0, 0, - 116, 1, 0, 0, 16, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 100, 1, - 0, 0, 0, 0, 0, 0, - 126, 1, 0, 0, 32, 0, - 0, 0, 16, 0, 0, 0, - 0, 0, 0, 0, 100, 1, - 0, 0, 0, 0, 0, 0, - 140, 1, 0, 0, 48, 0, - 0, 0, 16, 0, 0, 0, - 2, 0, 0, 0, 100, 1, - 0, 0, 0, 0, 0, 0, - 81, 117, 97, 100, 68, 101, - 115, 99, 0, 171, 171, 171, - 1, 0, 3, 0, 1, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 84, 101, - 120, 67, 111, 111, 114, 100, - 115, 0, 77, 97, 115, 107, - 84, 101, 120, 67, 111, 111, - 114, 100, 115, 0, 84, 101, - 120, 116, 67, 111, 108, 111, - 114, 0, 77, 105, 99, 114, - 111, 115, 111, 102, 116, 32, - 40, 82, 41, 32, 72, 76, - 83, 76, 32, 83, 104, 97, - 100, 101, 114, 32, 67, 111, - 109, 112, 105, 108, 101, 114, - 32, 57, 46, 50, 57, 46, - 57, 53, 50, 46, 51, 49, - 49, 49, 0, 171, 73, 83, - 71, 78, 104, 0, 0, 0, - 3, 0, 0, 0, 8, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 3, 0, 0, 0, - 0, 0, 0, 0, 15, 0, - 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 3, 3, - 0, 0, 92, 0, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, - 1, 0, 0, 0, 12, 12, - 0, 0, 83, 86, 95, 80, - 111, 115, 105, 116, 105, 111, - 110, 0, 84, 69, 88, 67, - 79, 79, 82, 68, 0, 171, - 171, 171, 79, 83, 71, 78, - 68, 0, 0, 0, 2, 0, - 0, 0, 8, 0, 0, 0, - 56, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 56, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 97, 114, - 103, 101, 116, 0, 171, 171, - 38, 1, 1, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 16, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 46, 0, 0, 0, - 18, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 54, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 93, 0, 0, 0, 65, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 102, 0, - 0, 0, 65, 0, 0, 0, - 0, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 112, 0, 0, 0, - 65, 0, 0, 0, 0, 0, - 0, 0, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 126, 0, 0, 0, 65, 0, - 0, 0, 0, 0, 0, 0, - 48, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 136, 0, - 0, 0, 160, 0, 0, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 168, 0, - 0, 0, 140, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 181, 0, 0, 0, - 140, 0, 0, 0, 0, 0, - 0, 0, 48, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 194, 0, 0, 0, 140, 0, - 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 206, 0, - 0, 0, 65, 0, 0, 0, - 0, 0, 0, 0, 144, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 218, 0, 0, 0, - 112, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 3, 1, 0, 0, - 231, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 61, 1, 0, 0, 33, 1, - 0, 0, 0, 0, 0, 0, - 48, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 107, 1, - 0, 0, 79, 1, 0, 0, - 0, 0, 0, 0, 64, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 112, 1, 0, 0, - 33, 1, 0, 0, 0, 0, - 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 154, 1, 0, 0, 126, 1, - 0, 0, 0, 0, 0, 0, - 88, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 156, 1, - 0, 0, 126, 1, 0, 0, - 0, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 164, 1, 0, 0, - 126, 1, 0, 0, 0, 0, - 0, 0, 96, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 213, 1, 0, 0, 185, 1, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 0, 0, - 0, 0, 217, 1, 0, 0, - 185, 1, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 0, 0, 0, 0, 224, 1, - 0, 0, 185, 1, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 0, 0, 0, 0, - 14, 2, 0, 0, 242, 1, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 4, 0, - 0, 0, 45, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 23, 2, 0, 0, - 55, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 213, 1, 0, 0, 46, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 35, 2, - 0, 0, 47, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 47, 2, 0, 0, - 0, 0, 0, 0, 59, 2, - 0, 0, 242, 1, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 4, 0, 0, 0, - 45, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 71, 2, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 217, 1, - 0, 0, 46, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 83, 2, 0, 0, - 47, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 95, 2, 0, 0, 0, 0, - 0, 0, 107, 2, 0, 0, - 242, 1, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 4, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 120, 2, - 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 213, 1, 0, 0, - 46, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 132, 2, 0, 0, 47, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 144, 2, - 0, 0, 0, 0, 0, 0, - 156, 2, 0, 0, 242, 1, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 4, 0, - 0, 0, 45, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 171, 2, 0, 0, - 55, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 213, 1, 0, 0, 46, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 183, 2, - 0, 0, 47, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 195, 2, 0, 0, - 0, 0, 0, 0, 207, 2, - 0, 0, 242, 1, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 4, 0, 0, 0, - 45, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 220, 2, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 224, 1, - 0, 0, 46, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 232, 2, 0, 0, - 47, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 244, 2, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, - 242, 1, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 5, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 15, 3, - 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 213, 1, 0, 0, - 46, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 27, 3, 0, 0, 47, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 39, 3, - 0, 0, 52, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 51, 3, 0, 0, - 0, 0, 0, 0, 131, 3, - 0, 0, 103, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 2, 0, 0, 0, - 19, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 143, 3, 0, 0, 13, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 155, 3, - 0, 0, 0, 0, 0, 0, - 206, 3, 0, 0, 178, 3, - 0, 0, 0, 0, 0, 0, - 255, 255, 255, 255, 2, 0, - 0, 0, 37, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 219, 3, 0, 0, - 44, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 231, 3, 0, 0, 0, 0, - 0, 0, 243, 3, 0, 0, - 178, 3, 0, 0, 0, 0, - 0, 0, 255, 255, 255, 255, - 8, 0, 0, 0, 37, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 4, - 0, 0, 38, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 12, 4, 0, 0, - 39, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 24, 4, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 36, 4, - 0, 0, 41, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 48, 4, 0, 0, - 42, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 60, 4, 0, 0, 43, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 72, 4, - 0, 0, 44, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 84, 4, 0, 0, - 0, 0, 0, 0, 96, 4, - 0, 0, 178, 3, 0, 0, - 0, 0, 0, 0, 255, 255, - 255, 255, 9, 0, 0, 0, - 36, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 107, 4, 0, 0, 37, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 119, 4, - 0, 0, 38, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 131, 4, 0, 0, - 39, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 143, 4, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 155, 4, - 0, 0, 41, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 167, 4, 0, 0, - 42, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 179, 4, 0, 0, 43, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 191, 4, - 0, 0, 44, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 203, 4, 0, 0, - 0, 0, 0, 0, 215, 4, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 229, 4, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 48, 9, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 56, 9, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 28, 12, - 0, 0, 36, 12, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 229, 4, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 131, 3, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 144, 16, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 152, 16, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 236, 29, 0, 0, - 244, 29, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 229, 4, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 131, 3, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 96, 34, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 104, 34, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 112, 51, 0, 0, 120, 51, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 229, 4, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 229, 55, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 237, 55, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 237, 93, - 0, 0, 245, 93, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 10, 94, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 131, 3, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 59, 101, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 67, 101, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 47, 111, 0, 0, - 55, 111, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 131, 3, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 102, 118, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 110, 118, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 58, 126, 0, 0, 66, 126, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 119, 133, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 127, 133, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 111, 143, - 0, 0, 119, 143, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 131, 3, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 170, 150, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 178, 150, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 130, 158, 0, 0, - 138, 158, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 131, 3, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 193, 165, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 201, 165, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 189, 175, 0, 0, 197, 175, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 250, 182, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 2, 183, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 214, 190, - 0, 0, 222, 190, 0, 0, - 1, 0, 0, 0, 0, 0, - 0, 0, 229, 4, 0, 0, - 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 131, 3, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 58, 195, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 66, 195, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 34, 199, 0, 0, - 42, 199, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 229, 4, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 131, 3, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 66, 199, - 0, 0, 11, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 102, 199, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 206, 3, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 186, 203, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 194, 203, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 186, 213, 0, 0, 194, 213, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 10, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 197, 213, 0, 0, - 11, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 233, 213, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 243, 3, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 61, 218, 0, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 69, 218, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 1, 228, - 0, 0, 9, 228, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 131, 3, 0, 0, - 10, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 12, 228, 0, 0, 11, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 48, 228, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 2, 0, - 0, 0, 243, 3, 0, 0, - 6, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 132, 232, 0, 0, 8, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 140, 232, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 64, 243, 0, 0, - 72, 243, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 90, 243, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 131, 3, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 99, 243, - 0, 0, 11, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 135, 243, 0, 0, - 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, - 96, 4, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 219, 247, - 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 227, 247, 0, 0, - 7, 0, 0, 0, 0, 0, - 0, 0, 7, 0, 0, 0, - 139, 252, 0, 0, 147, 252, - 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 131, 3, - 0, 0, 10, 0, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 154, 252, 0, 0, - 11, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 190, 252, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 96, 4, - 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 7, 0, - 0, 0, 18, 1, 1, 0, - 8, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 26, 1, 1, 0, 7, 0, - 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 182, 6, - 1, 0 -}; diff --git a/libazure/src/gfx/2d/SourceSurfaceRawData.cpp b/libazure/src/gfx/2d/SourceSurfaceRawData.cpp deleted file mode 100644 index 7f775e5..0000000 --- a/libazure/src/gfx/2d/SourceSurfaceRawData.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SourceSurfaceRawData.h" -#include "Logging.h" -#include "Tools.h" - -namespace mozilla { -namespace gfx { - -bool -SourceSurfaceRawData::InitWrappingData(uint8_t *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat, - bool aOwnData) -{ - mRawData = aData; - mSize = aSize; - mStride = aStride; - mFormat = aFormat; - mOwnData = aOwnData; - - return true; -} - -} -} diff --git a/libazure/src/gfx/2d/Tools.h b/libazure/src/gfx/2d/Tools.h deleted file mode 100644 index 60e89fa..0000000 --- a/libazure/src/gfx/2d/Tools.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_TOOLS_H_ -#define MOZILLA_GFX_TOOLS_H_ - -#include "Types.h" -#include "Point.h" -#include -#if defined(_MSC_VER) && (_MSC_VER < 1600) -#define hypotf _hypotf -#endif - -namespace mozilla { -namespace gfx { - -static inline bool -IsOperatorBoundByMask(CompositionOp aOp) { - switch (aOp) { - case OP_IN: - case OP_OUT: - case OP_DEST_IN: - case OP_DEST_ATOP: - case OP_SOURCE: - return false; - default: - return true; - } -} - -template -struct ClassStorage -{ - char bytes[sizeof(T)]; - - const T *addr() const { return (const T *)bytes; } - T *addr() { return (T *)(void *)bytes; } -}; - -static inline bool -FuzzyEqual(Float aA, Float aB, Float aErr) -{ - if ((aA + aErr >= aB) && (aA - aErr <= aB)) { - return true; - } - return false; -} - -static inline void -NudgeToInteger(float *aVal) -{ - float r = floorf(*aVal + 0.5f); - // The error threshold should be proportional to the rounded value. This - // bounds the relative error introduced by the nudge operation. However, - // when the rounded value is 0, the error threshold can't be proportional - // to the rounded value (we'd never round), so we just choose the same - // threshold as for a rounded value of 1. - if (FuzzyEqual(r, *aVal, r == 0.0f ? 1e-6f : fabs(r*1e-6f))) { - *aVal = r; - } -} - -static inline Float -Distance(Point aA, Point aB) -{ - return hypotf(aB.x - aA.x, aB.y - aA.y); -} - -static inline int -BytesPerPixel(SurfaceFormat aFormat) -{ - switch (aFormat) { - case FORMAT_A8: - return 1; - case FORMAT_R5G6B5: - return 2; - default: - return 4; - } -} - -template -struct AlignedArray -{ - AlignedArray() - : mStorage(nullptr) - , mPtr(nullptr) - { - } - - MOZ_ALWAYS_INLINE AlignedArray(size_t aSize) - : mStorage(nullptr) - { - Realloc(aSize); - } - - MOZ_ALWAYS_INLINE ~AlignedArray() - { - delete [] mStorage; - } - - void Dealloc() - { - delete [] mStorage; - mStorage = mPtr = nullptr; - } - - MOZ_ALWAYS_INLINE void Realloc(size_t aSize) - { - delete [] mStorage; - mStorage = new T[aSize + (alignment - 1)]; - if (uintptr_t(mStorage) % alignment) { - // Our storage does not start at a -byte boundary. Make sure mData does! - mPtr = (uint32_t*)(uintptr_t(mStorage) + - (alignment - (uintptr_t(mStorage) % alignment))); - } else { - mPtr = mStorage; - } - } - - MOZ_ALWAYS_INLINE operator T*() - { - return mPtr; - } - - T *mStorage; - T *mPtr; -}; - -template -int32_t GetAlignedStride(int32_t aStride) -{ - if (aStride % alignment) { - return aStride + (alignment - (aStride % alignment)); - } - - return aStride; -} - -} -} - -#endif /* MOZILLA_GFX_TOOLS_H_ */ diff --git a/libazure/src/gfx/2d/convolver.cpp b/libazure/src/gfx/2d/convolver.cpp deleted file mode 100644 index f8a52fb..0000000 --- a/libazure/src/gfx/2d/convolver.cpp +++ /dev/null @@ -1,910 +0,0 @@ -// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google, Inc. nor the names of its contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -#include "convolver.h" - -#include -// #include "nsAlgorithm.h" - -#include "SkTypes.h" - -// note: SIMD_SSE2 is not enabled because of bugs, apparently - -#if defined(SIMD_SSE2) -#include // ARCH_CPU_X86_FAMILY was defined in build/config.h -#endif - -#if defined(SK_CPU_LENDIAN) -#define R_OFFSET_IDX 0 -#define G_OFFSET_IDX 1 -#define B_OFFSET_IDX 2 -#define A_OFFSET_IDX 3 -#else -#define R_OFFSET_IDX 3 -#define G_OFFSET_IDX 2 -#define B_OFFSET_IDX 1 -#define A_OFFSET_IDX 0 -#endif - -namespace skia { - -namespace { - -// Converts the argument to an 8-bit unsigned value by clamping to the range -// 0-255. -inline unsigned char ClampTo8(int a) { - if (static_cast(a) < 256) - return a; // Avoid the extra check in the common case. - if (a < 0) - return 0; - return 255; -} - -// Stores a list of rows in a circular buffer. The usage is you write into it -// by calling AdvanceRow. It will keep track of which row in the buffer it -// should use next, and the total number of rows added. -class CircularRowBuffer { - public: - // The number of pixels in each row is given in |source_row_pixel_width|. - // The maximum number of rows needed in the buffer is |max_y_filter_size| - // (we only need to store enough rows for the biggest filter). - // - // We use the |first_input_row| to compute the coordinates of all of the - // following rows returned by Advance(). - CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size, - int first_input_row) - : row_byte_width_(dest_row_pixel_width * 4), - num_rows_(max_y_filter_size), - next_row_(0), - next_row_coordinate_(first_input_row) { - buffer_.resize(row_byte_width_ * max_y_filter_size); - row_addresses_.resize(num_rows_); - } - - // Moves to the next row in the buffer, returning a pointer to the beginning - // of it. - unsigned char* AdvanceRow() { - unsigned char* row = &buffer_[next_row_ * row_byte_width_]; - next_row_coordinate_++; - - // Set the pointer to the next row to use, wrapping around if necessary. - next_row_++; - if (next_row_ == num_rows_) - next_row_ = 0; - return row; - } - - // Returns a pointer to an "unrolled" array of rows. These rows will start - // at the y coordinate placed into |*first_row_index| and will continue in - // order for the maximum number of rows in this circular buffer. - // - // The |first_row_index_| may be negative. This means the circular buffer - // starts before the top of the image (it hasn't been filled yet). - unsigned char* const* GetRowAddresses(int* first_row_index) { - // Example for a 4-element circular buffer holding coords 6-9. - // Row 0 Coord 8 - // Row 1 Coord 9 - // Row 2 Coord 6 <- next_row_ = 2, next_row_coordinate_ = 10. - // Row 3 Coord 7 - // - // The "next" row is also the first (lowest) coordinate. This computation - // may yield a negative value, but that's OK, the math will work out - // since the user of this buffer will compute the offset relative - // to the first_row_index and the negative rows will never be used. - *first_row_index = next_row_coordinate_ - num_rows_; - - int cur_row = next_row_; - for (int i = 0; i < num_rows_; i++) { - row_addresses_[i] = &buffer_[cur_row * row_byte_width_]; - - // Advance to the next row, wrapping if necessary. - cur_row++; - if (cur_row == num_rows_) - cur_row = 0; - } - return &row_addresses_[0]; - } - - private: - // The buffer storing the rows. They are packed, each one row_byte_width_. - std::vector buffer_; - - // Number of bytes per row in the |buffer_|. - int row_byte_width_; - - // The number of rows available in the buffer. - int num_rows_; - - // The next row index we should write into. This wraps around as the - // circular buffer is used. - int next_row_; - - // The y coordinate of the |next_row_|. This is incremented each time a - // new row is appended and does not wrap. - int next_row_coordinate_; - - // Buffer used by GetRowAddresses(). - std::vector row_addresses_; -}; - -// Convolves horizontally along a single row. The row data is given in -// |src_data| and continues for the num_values() of the filter. -template -// This function is miscompiled with gcc 4.5 with pgo. See bug 827946. -#if defined(__GNUC__) && defined(MOZ_GCC_VERSION_AT_LEAST) -#if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) && !MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) -__attribute__((optimize("-O1"))) -#endif -#endif -void ConvolveHorizontally(const unsigned char* src_data, - const ConvolutionFilter1D& filter, - unsigned char* out_row) { - // Loop over each pixel on this row in the output image. - int num_values = filter.num_values(); - for (int out_x = 0; out_x < num_values; out_x++) { - // Get the filter that determines the current output pixel. - int filter_offset, filter_length; - const ConvolutionFilter1D::Fixed* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filter_length| pixels (4 bytes each) after this. - const unsigned char* row_to_filter = &src_data[filter_offset * 4]; - - // Apply the filter to the row to get the destination pixel in |accum|. - int accum[4] = {0}; - for (int filter_x = 0; filter_x < filter_length; filter_x++) { - ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_x]; - accum[0] += cur_filter * row_to_filter[filter_x * 4 + R_OFFSET_IDX]; - accum[1] += cur_filter * row_to_filter[filter_x * 4 + G_OFFSET_IDX]; - accum[2] += cur_filter * row_to_filter[filter_x * 4 + B_OFFSET_IDX]; - if (has_alpha) - accum[3] += cur_filter * row_to_filter[filter_x * 4 + A_OFFSET_IDX]; - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of fractional part. - accum[0] >>= ConvolutionFilter1D::kShiftBits; - accum[1] >>= ConvolutionFilter1D::kShiftBits; - accum[2] >>= ConvolutionFilter1D::kShiftBits; - if (has_alpha) - accum[3] >>= ConvolutionFilter1D::kShiftBits; - - // Store the new pixel. - out_row[out_x * 4 + R_OFFSET_IDX] = ClampTo8(accum[0]); - out_row[out_x * 4 + G_OFFSET_IDX] = ClampTo8(accum[1]); - out_row[out_x * 4 + B_OFFSET_IDX] = ClampTo8(accum[2]); - if (has_alpha) - out_row[out_x * 4 + A_OFFSET_IDX] = ClampTo8(accum[3]); - } -} - -// Does vertical convolution to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |source_data_rows| array, with each row -// being |pixel_width| wide. -// -// The output must have room for |pixel_width * 4| bytes. -template -void ConvolveVertically(const ConvolutionFilter1D::Fixed* filter_values, - int filter_length, - unsigned char* const* source_data_rows, - int pixel_width, - unsigned char* out_row) { - // We go through each column in the output and do a vertical convolution, - // generating one output pixel each time. - for (int out_x = 0; out_x < pixel_width; out_x++) { - // Compute the number of bytes over in each row that the current column - // we're convolving starts at. The pixel will cover the next 4 bytes. - int byte_offset = out_x * 4; - - // Apply the filter to one column of pixels. - int accum[4] = {0}; - for (int filter_y = 0; filter_y < filter_length; filter_y++) { - ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_y]; - accum[0] += cur_filter - * source_data_rows[filter_y][byte_offset + R_OFFSET_IDX]; - accum[1] += cur_filter - * source_data_rows[filter_y][byte_offset + G_OFFSET_IDX]; - accum[2] += cur_filter - * source_data_rows[filter_y][byte_offset + B_OFFSET_IDX]; - if (has_alpha) - accum[3] += cur_filter - * source_data_rows[filter_y][byte_offset + A_OFFSET_IDX]; - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of precision. - accum[0] >>= ConvolutionFilter1D::kShiftBits; - accum[1] >>= ConvolutionFilter1D::kShiftBits; - accum[2] >>= ConvolutionFilter1D::kShiftBits; - if (has_alpha) - accum[3] >>= ConvolutionFilter1D::kShiftBits; - - // Store the new pixel. - out_row[byte_offset + R_OFFSET_IDX] = ClampTo8(accum[0]); - out_row[byte_offset + G_OFFSET_IDX] = ClampTo8(accum[1]); - out_row[byte_offset + B_OFFSET_IDX] = ClampTo8(accum[2]); - if (has_alpha) { - unsigned char alpha = ClampTo8(accum[3]); - - // Make sure the alpha channel doesn't come out smaller than any of the - // color channels. We use premultipled alpha channels, so this should - // never happen, but rounding errors will cause this from time to time. - // These "impossible" colors will cause overflows (and hence random pixel - // values) when the resulting bitmap is drawn to the screen. - // - // We only need to do this when generating the final output row (here). - int max_color_channel = std::max(out_row[byte_offset + R_OFFSET_IDX], - std::max(out_row[byte_offset + G_OFFSET_IDX], out_row[byte_offset + B_OFFSET_IDX])); - if (alpha < max_color_channel) - out_row[byte_offset + A_OFFSET_IDX] = max_color_channel; - else - out_row[byte_offset + A_OFFSET_IDX] = alpha; - } else { - // No alpha channel, the image is opaque. - out_row[byte_offset + A_OFFSET_IDX] = 0xff; - } - } -} - - -// Convolves horizontally along a single row. The row data is given in -// |src_data| and continues for the num_values() of the filter. -void ConvolveHorizontally_SSE2(const unsigned char* src_data, - const ConvolutionFilter1D& filter, - unsigned char* out_row) { -#if defined(SIMD_SSE2) - int num_values = filter.num_values(); - - int filter_offset, filter_length; - __m128i zero = _mm_setzero_si128(); - __m128i mask[4]; - // |mask| will be used to decimate all extra filter coefficients that are - // loaded by SIMD when |filter_length| is not divisible by 4. - // mask[0] is not used in following algorithm. - mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); - mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); - mask[3] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); - - // Output one pixel each iteration, calculating all channels (RGBA) together. - for (int out_x = 0; out_x < num_values; out_x++) { - const ConvolutionFilter1D::Fixed* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - __m128i accum = _mm_setzero_si128(); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filter_length| pixels (4 bytes each) after this. - const __m128i* row_to_filter = - reinterpret_cast(&src_data[filter_offset << 2]); - - // We will load and accumulate with four coefficients per iteration. - for (int filter_x = 0; filter_x < filter_length >> 2; filter_x++) { - - // Load 4 coefficients => duplicate 1st and 2nd of them for all channels. - __m128i coeff, coeff16; - // [16] xx xx xx xx c3 c2 c1 c0 - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // [16] xx xx xx xx c1 c1 c0 c0 - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - // [16] c1 c1 c1 c1 c0 c0 c0 c0 - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - - // Load four pixels => unpack the first two pixels to 16 bits => - // multiply with coefficients => accumulate the convolution result. - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src8 = _mm_loadu_si128(row_to_filter); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0*c0 b0*c0 g0*c0 r0*c0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - // [32] a1*c1 b1*c1 g1*c1 r1*c1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - // Duplicate 3rd and 4th coefficients for all channels => - // unpack the 3rd and 4th pixels to 16 bits => multiply with coefficients - // => accumulate the convolution results. - // [16] xx xx xx xx c3 c3 c2 c2 - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - // [16] c3 c3 c3 c3 c2 c2 c2 c2 - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - // [16] a3 g3 b3 r3 a2 g2 b2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2*c2 b2*c2 g2*c2 r2*c2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - // [32] a3*c3 b3*c3 g3*c3 r3*c3 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - // Advance the pixel and coefficients pointers. - row_to_filter += 1; - filter_values += 4; - } - - // When |filter_length| is not divisible by 4, we need to decimate some of - // the filter coefficient that was loaded incorrectly to zero; Other than - // that the algorithm is same with above, exceot that the 4th pixel will be - // always absent. - int r = filter_length&3; - if (r) { - // Note: filter_values must be padded to align_up(filter_offset, 8). - __m128i coeff, coeff16; - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // Mask out extra filter taps. - coeff = _mm_and_si128(coeff, mask[r]); - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - - // Note: line buffer must be padded to align_up(filter_offset, 16). - // We resolve this by use C-version for the last horizontal line. - __m128i src8 = _mm_loadu_si128(row_to_filter); - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - - src16 = _mm_unpackhi_epi8(src8, zero); - coeff16 = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - coeff16 = _mm_unpacklo_epi16(coeff16, coeff16); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum = _mm_add_epi32(accum, t); - } - - // Shift right for fixed point implementation. - accum = _mm_srai_epi32(accum, ConvolutionFilter1D::kShiftBits); - - // Packing 32 bits |accum| to 16 bits per channel (signed saturation). - accum = _mm_packs_epi32(accum, zero); - // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). - accum = _mm_packus_epi16(accum, zero); - - // Store the pixel value of 32 bits. - *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum); - out_row += 4; - } -#endif -} - -// Convolves horizontally along four rows. The row data is given in -// |src_data| and continues for the num_values() of the filter. -// The algorithm is almost same as |ConvolveHorizontally_SSE2|. Please -// refer to that function for detailed comments. -void ConvolveHorizontally4_SSE2(const unsigned char* src_data[4], - const ConvolutionFilter1D& filter, - unsigned char* out_row[4]) { -#if defined(SIMD_SSE2) - int num_values = filter.num_values(); - - int filter_offset, filter_length; - __m128i zero = _mm_setzero_si128(); - __m128i mask[4]; - // |mask| will be used to decimate all extra filter coefficients that are - // loaded by SIMD when |filter_length| is not divisible by 4. - // mask[0] is not used in following algorithm. - mask[1] = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, -1); - mask[2] = _mm_set_epi16(0, 0, 0, 0, 0, 0, -1, -1); - mask[3] = _mm_set_epi16(0, 0, 0, 0, 0, -1, -1, -1); - - // Output one pixel each iteration, calculating all channels (RGBA) together. - for (int out_x = 0; out_x < num_values; out_x++) { - const ConvolutionFilter1D::Fixed* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - // four pixels in a column per iteration. - __m128i accum0 = _mm_setzero_si128(); - __m128i accum1 = _mm_setzero_si128(); - __m128i accum2 = _mm_setzero_si128(); - __m128i accum3 = _mm_setzero_si128(); - int start = (filter_offset<<2); - // We will load and accumulate with four coefficients per iteration. - for (int filter_x = 0; filter_x < (filter_length >> 2); filter_x++) { - __m128i coeff, coeff16lo, coeff16hi; - // [16] xx xx xx xx c3 c2 c1 c0 - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // [16] xx xx xx xx c1 c1 c0 c0 - coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - // [16] c1 c1 c1 c1 c0 c0 c0 c0 - coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); - // [16] xx xx xx xx c3 c3 c2 c2 - coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - // [16] c3 c3 c3 c3 c2 c2 c2 c2 - coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); - - __m128i src8, src16, mul_hi, mul_lo, t; - -#define ITERATION(src, accum) \ - src8 = _mm_loadu_si128(reinterpret_cast(src)); \ - src16 = _mm_unpacklo_epi8(src8, zero); \ - mul_hi = _mm_mulhi_epi16(src16, coeff16lo); \ - mul_lo = _mm_mullo_epi16(src16, coeff16lo); \ - t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - src16 = _mm_unpackhi_epi8(src8, zero); \ - mul_hi = _mm_mulhi_epi16(src16, coeff16hi); \ - mul_lo = _mm_mullo_epi16(src16, coeff16hi); \ - t = _mm_unpacklo_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t); \ - t = _mm_unpackhi_epi16(mul_lo, mul_hi); \ - accum = _mm_add_epi32(accum, t) - - ITERATION(src_data[0] + start, accum0); - ITERATION(src_data[1] + start, accum1); - ITERATION(src_data[2] + start, accum2); - ITERATION(src_data[3] + start, accum3); - - start += 16; - filter_values += 4; - } - - int r = filter_length & 3; - if (r) { - // Note: filter_values must be padded to align_up(filter_offset, 8); - __m128i coeff; - coeff = _mm_loadl_epi64(reinterpret_cast(filter_values)); - // Mask out extra filter taps. - coeff = _mm_and_si128(coeff, mask[r]); - - __m128i coeff16lo = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(1, 1, 0, 0)); - /* c1 c1 c1 c1 c0 c0 c0 c0 */ - coeff16lo = _mm_unpacklo_epi16(coeff16lo, coeff16lo); - __m128i coeff16hi = _mm_shufflelo_epi16(coeff, _MM_SHUFFLE(3, 3, 2, 2)); - coeff16hi = _mm_unpacklo_epi16(coeff16hi, coeff16hi); - - __m128i src8, src16, mul_hi, mul_lo, t; - - ITERATION(src_data[0] + start, accum0); - ITERATION(src_data[1] + start, accum1); - ITERATION(src_data[2] + start, accum2); - ITERATION(src_data[3] + start, accum3); - } - - accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); - accum0 = _mm_packs_epi32(accum0, zero); - accum0 = _mm_packus_epi16(accum0, zero); - accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); - accum1 = _mm_packs_epi32(accum1, zero); - accum1 = _mm_packus_epi16(accum1, zero); - accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); - accum2 = _mm_packs_epi32(accum2, zero); - accum2 = _mm_packus_epi16(accum2, zero); - accum3 = _mm_srai_epi32(accum3, ConvolutionFilter1D::kShiftBits); - accum3 = _mm_packs_epi32(accum3, zero); - accum3 = _mm_packus_epi16(accum3, zero); - - *(reinterpret_cast(out_row[0])) = _mm_cvtsi128_si32(accum0); - *(reinterpret_cast(out_row[1])) = _mm_cvtsi128_si32(accum1); - *(reinterpret_cast(out_row[2])) = _mm_cvtsi128_si32(accum2); - *(reinterpret_cast(out_row[3])) = _mm_cvtsi128_si32(accum3); - - out_row[0] += 4; - out_row[1] += 4; - out_row[2] += 4; - out_row[3] += 4; - } -#endif -} - -// Does vertical convolution to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |source_data_rows| array, with each row -// being |pixel_width| wide. -// -// The output must have room for |pixel_width * 4| bytes. -template -void ConvolveVertically_SSE2(const ConvolutionFilter1D::Fixed* filter_values, - int filter_length, - unsigned char* const* source_data_rows, - int pixel_width, - unsigned char* out_row) { -#if defined(SIMD_SSE2) - int width = pixel_width & ~3; - - __m128i zero = _mm_setzero_si128(); - __m128i accum0, accum1, accum2, accum3, coeff16; - const __m128i* src; - // Output four pixels per iteration (16 bytes). - for (int out_x = 0; out_x < width; out_x += 4) { - - // Accumulated result for each pixel. 32 bits per RGBA channel. - accum0 = _mm_setzero_si128(); - accum1 = _mm_setzero_si128(); - accum2 = _mm_setzero_si128(); - accum3 = _mm_setzero_si128(); - - // Convolve with one filter coefficient per iteration. - for (int filter_y = 0; filter_y < filter_length; filter_y++) { - - // Duplicate the filter coefficient 8 times. - // [16] cj cj cj cj cj cj cj cj - coeff16 = _mm_set1_epi16(filter_values[filter_y]); - - // Load four pixels (16 bytes) together. - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - src = reinterpret_cast( - &source_data_rows[filter_y][out_x << 2]); - __m128i src8 = _mm_loadu_si128(src); - - // Unpack 1st and 2nd pixels from 8 bits to 16 bits for each channels => - // multiply with current coefficient => accumulate the result. - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0 b0 g0 r0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum0 = _mm_add_epi32(accum0, t); - // [32] a1 b1 g1 r1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum1 = _mm_add_epi32(accum1, t); - - // Unpack 3rd and 4th pixels from 8 bits to 16 bits for each channels => - // multiply with current coefficient => accumulate the result. - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2 b2 g2 r2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum2 = _mm_add_epi32(accum2, t); - // [32] a3 b3 g3 r3 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum3 = _mm_add_epi32(accum3, t); - } - - // Shift right for fixed point implementation. - accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); - accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); - accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); - accum3 = _mm_srai_epi32(accum3, ConvolutionFilter1D::kShiftBits); - - // Packing 32 bits |accum| to 16 bits per channel (signed saturation). - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packs_epi32(accum0, accum1); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - accum2 = _mm_packs_epi32(accum2, accum3); - - // Packing 16 bits |accum| to 8 bits per channel (unsigned saturation). - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packus_epi16(accum0, accum2); - - if (has_alpha) { - // Compute the max(ri, gi, bi) for each pixel. - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - __m128i a = _mm_srli_epi32(accum0, 8); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = _mm_srli_epi32(accum0, 16); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = _mm_max_epu8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = _mm_slli_epi32(b, 24); - - // Make sure the value of alpha channel is always larger than maximum - // value of color channels. - accum0 = _mm_max_epu8(b, accum0); - } else { - // Set value of alpha channels to 0xFF. - __m128i mask = _mm_set1_epi32(0xff000000); - accum0 = _mm_or_si128(accum0, mask); - } - - // Store the convolution result (16 bytes) and advance the pixel pointers. - _mm_storeu_si128(reinterpret_cast<__m128i*>(out_row), accum0); - out_row += 16; - } - - // When the width of the output is not divisible by 4, We need to save one - // pixel (4 bytes) each time. And also the fourth pixel is always absent. - if (pixel_width & 3) { - accum0 = _mm_setzero_si128(); - accum1 = _mm_setzero_si128(); - accum2 = _mm_setzero_si128(); - for (int filter_y = 0; filter_y < filter_length; ++filter_y) { - coeff16 = _mm_set1_epi16(filter_values[filter_y]); - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - src = reinterpret_cast( - &source_data_rows[filter_y][width<<2]); - __m128i src8 = _mm_loadu_si128(src); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - __m128i src16 = _mm_unpacklo_epi8(src8, zero); - __m128i mul_hi = _mm_mulhi_epi16(src16, coeff16); - __m128i mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a0 b0 g0 r0 - __m128i t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum0 = _mm_add_epi32(accum0, t); - // [32] a1 b1 g1 r1 - t = _mm_unpackhi_epi16(mul_lo, mul_hi); - accum1 = _mm_add_epi32(accum1, t); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - src16 = _mm_unpackhi_epi8(src8, zero); - mul_hi = _mm_mulhi_epi16(src16, coeff16); - mul_lo = _mm_mullo_epi16(src16, coeff16); - // [32] a2 b2 g2 r2 - t = _mm_unpacklo_epi16(mul_lo, mul_hi); - accum2 = _mm_add_epi32(accum2, t); - } - - accum0 = _mm_srai_epi32(accum0, ConvolutionFilter1D::kShiftBits); - accum1 = _mm_srai_epi32(accum1, ConvolutionFilter1D::kShiftBits); - accum2 = _mm_srai_epi32(accum2, ConvolutionFilter1D::kShiftBits); - // [16] a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packs_epi32(accum0, accum1); - // [16] a3 b3 g3 r3 a2 b2 g2 r2 - accum2 = _mm_packs_epi32(accum2, zero); - // [8] a3 b3 g3 r3 a2 b2 g2 r2 a1 b1 g1 r1 a0 b0 g0 r0 - accum0 = _mm_packus_epi16(accum0, accum2); - if (has_alpha) { - // [8] xx a3 b3 g3 xx a2 b2 g2 xx a1 b1 g1 xx a0 b0 g0 - __m128i a = _mm_srli_epi32(accum0, 8); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - __m128i b = _mm_max_epu8(a, accum0); // Max of r and g. - // [8] xx xx a3 b3 xx xx a2 b2 xx xx a1 b1 xx xx a0 b0 - a = _mm_srli_epi32(accum0, 16); - // [8] xx xx xx max3 xx xx xx max2 xx xx xx max1 xx xx xx max0 - b = _mm_max_epu8(a, b); // Max of r and g and b. - // [8] max3 00 00 00 max2 00 00 00 max1 00 00 00 max0 00 00 00 - b = _mm_slli_epi32(b, 24); - accum0 = _mm_max_epu8(b, accum0); - } else { - __m128i mask = _mm_set1_epi32(0xff000000); - accum0 = _mm_or_si128(accum0, mask); - } - - for (int out_x = width; out_x < pixel_width; out_x++) { - *(reinterpret_cast(out_row)) = _mm_cvtsi128_si32(accum0); - accum0 = _mm_srli_si128(accum0, 4); - out_row += 4; - } - } -#endif -} - -} // namespace - -// ConvolutionFilter1D --------------------------------------------------------- - -ConvolutionFilter1D::ConvolutionFilter1D() - : max_filter_(0) { -} - -ConvolutionFilter1D::~ConvolutionFilter1D() { -} - -void ConvolutionFilter1D::AddFilter(int filter_offset, - const float* filter_values, - int filter_length) { - SkASSERT(filter_length > 0); - - std::vector fixed_values; - fixed_values.reserve(filter_length); - - for (int i = 0; i < filter_length; ++i) - fixed_values.push_back(FloatToFixed(filter_values[i])); - - AddFilter(filter_offset, &fixed_values[0], filter_length); -} - -void ConvolutionFilter1D::AddFilter(int filter_offset, - const Fixed* filter_values, - int filter_length) { - // It is common for leading/trailing filter values to be zeros. In such - // cases it is beneficial to only store the central factors. - // For a scaling to 1/4th in each dimension using a Lanczos-2 filter on - // a 1080p image this optimization gives a ~10% speed improvement. - int first_non_zero = 0; - while (first_non_zero < filter_length && filter_values[first_non_zero] == 0) - first_non_zero++; - - if (first_non_zero < filter_length) { - // Here we have at least one non-zero factor. - int last_non_zero = filter_length - 1; - while (last_non_zero >= 0 && filter_values[last_non_zero] == 0) - last_non_zero--; - - filter_offset += first_non_zero; - filter_length = last_non_zero + 1 - first_non_zero; - SkASSERT(filter_length > 0); - - for (int i = first_non_zero; i <= last_non_zero; i++) - filter_values_.push_back(filter_values[i]); - } else { - // Here all the factors were zeroes. - filter_length = 0; - } - - FilterInstance instance; - - // We pushed filter_length elements onto filter_values_ - instance.data_location = (static_cast(filter_values_.size()) - - filter_length); - instance.offset = filter_offset; - instance.length = filter_length; - filters_.push_back(instance); - - max_filter_ = std::max(max_filter_, filter_length); -} - -void BGRAConvolve2D(const unsigned char* source_data, - int source_byte_row_stride, - bool source_has_alpha, - const ConvolutionFilter1D& filter_x, - const ConvolutionFilter1D& filter_y, - int output_byte_row_stride, - unsigned char* output, - bool use_sse2) { -#if !defined(SIMD_SSE2) - // Even we have runtime support for SSE2 instructions, since the binary - // was not built with SSE2 support, we had to fallback to C version. - use_sse2 = false; -#endif - - int max_y_filter_size = filter_y.max_filter(); - - // The next row in the input that we will generate a horizontally - // convolved row for. If the filter doesn't start at the beginning of the - // image (this is the case when we are only resizing a subset), then we - // don't want to generate any output rows before that. Compute the starting - // row for convolution as the first pixel for the first vertical filter. - int filter_offset, filter_length; - const ConvolutionFilter1D::Fixed* filter_values = - filter_y.FilterForValue(0, &filter_offset, &filter_length); - int next_x_row = filter_offset; - - // We loop over each row in the input doing a horizontal convolution. This - // will result in a horizontally convolved image. We write the results into - // a circular buffer of convolved rows and do vertical convolution as rows - // are available. This prevents us from having to store the entire - // intermediate image and helps cache coherency. - // We will need four extra rows to allow horizontal convolution could be done - // simultaneously. We also padding each row in row buffer to be aligned-up to - // 16 bytes. - // TODO(jiesun): We do not use aligned load from row buffer in vertical - // convolution pass yet. Somehow Windows does not like it. - int row_buffer_width = (filter_x.num_values() + 15) & ~0xF; - int row_buffer_height = max_y_filter_size + (use_sse2 ? 4 : 0); - CircularRowBuffer row_buffer(row_buffer_width, - row_buffer_height, - filter_offset); - - // Loop over every possible output row, processing just enough horizontal - // convolutions to run each subsequent vertical convolution. - SkASSERT(output_byte_row_stride >= filter_x.num_values() * 4); - int num_output_rows = filter_y.num_values(); - - // We need to check which is the last line to convolve before we advance 4 - // lines in one iteration. - int last_filter_offset, last_filter_length; - filter_y.FilterForValue(num_output_rows - 1, &last_filter_offset, - &last_filter_length); - - for (int out_y = 0; out_y < num_output_rows; out_y++) { - filter_values = filter_y.FilterForValue(out_y, - &filter_offset, &filter_length); - - // Generate output rows until we have enough to run the current filter. - if (use_sse2) { - while (next_x_row < filter_offset + filter_length) { - if (next_x_row + 3 < last_filter_offset + last_filter_length - 1) { - const unsigned char* src[4]; - unsigned char* out_row[4]; - for (int i = 0; i < 4; ++i) { - src[i] = &source_data[(next_x_row + i) * source_byte_row_stride]; - out_row[i] = row_buffer.AdvanceRow(); - } - ConvolveHorizontally4_SSE2(src, filter_x, out_row); - next_x_row += 4; - } else { - // For the last row, SSE2 load possibly to access data beyond the - // image area. therefore we use C version here. - if (next_x_row == last_filter_offset + last_filter_length - 1) { - if (source_has_alpha) { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } else { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } - } else { - ConvolveHorizontally_SSE2( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } - next_x_row++; - } - } - } else { - while (next_x_row < filter_offset + filter_length) { - if (source_has_alpha) { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } else { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } - next_x_row++; - } - } - - // Compute where in the output image this row of final data will go. - unsigned char* cur_output_row = &output[out_y * output_byte_row_stride]; - - // Get the list of rows that the circular buffer has, in order. - int first_row_in_circular_buffer; - unsigned char* const* rows_to_convolve = - row_buffer.GetRowAddresses(&first_row_in_circular_buffer); - - // Now compute the start of the subset of those rows that the filter - // needs. - unsigned char* const* first_row_for_filter = - &rows_to_convolve[filter_offset - first_row_in_circular_buffer]; - - if (source_has_alpha) { - if (use_sse2) { - ConvolveVertically_SSE2(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } else { - ConvolveVertically(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } - } else { - if (use_sse2) { - ConvolveVertically_SSE2(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } else { - ConvolveVertically(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } - } - } -} - -} // namespace skia diff --git a/libazure/src/gfx/2d/gfx2d.sln b/libazure/src/gfx/2d/gfx2d.sln deleted file mode 100644 index 40a137a..0000000 --- a/libazure/src/gfx/2d/gfx2d.sln +++ /dev/null @@ -1,29 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx2d", "gfx2d.vcxproj", "{49E973D7-53C9-3D66-BE58-52125FAE193D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest", "unittest\unittest.vcxproj", "{CCF4BC8B-0CED-47CA-B621-ABF1832527D9}" - ProjectSection(ProjectDependencies) = postProject - {49E973D7-53C9-3D66-BE58-52125FAE193D} = {49E973D7-53C9-3D66-BE58-52125FAE193D} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {49E973D7-53C9-3D66-BE58-52125FAE193D}.Debug|Win32.ActiveCfg = Debug|Win32 - {49E973D7-53C9-3D66-BE58-52125FAE193D}.Debug|Win32.Build.0 = Debug|Win32 - {49E973D7-53C9-3D66-BE58-52125FAE193D}.Release|Win32.ActiveCfg = Release|Win32 - {49E973D7-53C9-3D66-BE58-52125FAE193D}.Release|Win32.Build.0 = Release|Win32 - {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug|Win32.ActiveCfg = Debug|Win32 - {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Debug|Win32.Build.0 = Debug|Win32 - {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release|Win32.ActiveCfg = Release|Win32 - {CCF4BC8B-0CED-47CA-B621-ABF1832527D9}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libazure/src/gfx/2d/gfx2d.vcxproj b/libazure/src/gfx/2d/gfx2d.vcxproj deleted file mode 100644 index dfd0a1f..0000000 --- a/libazure/src/gfx/2d/gfx2d.vcxproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - Win32Proj - - - - StaticLibrary - true - - - StaticLibrary - false - - - - - - - - - - - - - true - $(DXSDK_DIR)\Utilities\bin\x86;$(ExecutablePath) - $(ProjectDir);$(IncludePath) - - - true - - - - INITGUID;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN - MultiThreadedDebugDLL - Level3 - ProgramDatabase - Disabled - - - MachineX86 - true - Windows - - - - - xcopy $(ProjectDir)..\..\mfbt\*.h mozilla\ /Y - Copying MFBT files - - - - - INITGUID;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - ProgramDatabase - ./ - - - MachineX86 - true - Windows - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Document - fxc /Tfx_4_0 /FhShadersD2D.h ShadersD2D.fx /Vn d2deffect - ShadersD2D.h - - - - - - \ No newline at end of file diff --git a/libazure/src/gfx/2d/moz.build b/libazure/src/gfx/2d/moz.build deleted file mode 100644 index 38d1298..0000000 --- a/libazure/src/gfx/2d/moz.build +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MODULE = 'gfx2d' - diff --git a/libazure/src/gfx/2d/unittest/GTestMain.cpp b/libazure/src/gfx/2d/unittest/GTestMain.cpp deleted file mode 100644 index fdfbb80..0000000 --- a/libazure/src/gfx/2d/unittest/GTestMain.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gtest/gtest.h" -#include "TestBase.h" -#include "TestPoint.h" -#include "TestScaling.h" - -TEST(Moz2D, Point) { - TestBase* test = new TestPoint(); - int failures = 0; - int totalTests = test->RunTests(&failures); - delete test; - - ASSERT_EQ(failures, 0); -} - -TEST(Moz2D, Scaling) { - TestBase* test = new TestScaling(); - int failures = 0; - int totalTests = test->RunTests(&failures); - delete test; - - ASSERT_EQ(failures, 0); -} diff --git a/libazure/src/gfx/2d/unittest/Main.cpp b/libazure/src/gfx/2d/unittest/Main.cpp deleted file mode 100644 index 8439c76..0000000 --- a/libazure/src/gfx/2d/unittest/Main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SanityChecks.h" -#include "TestPoint.h" -#include "TestScaling.h" -#ifdef WIN32 -#include "TestDrawTargetD2D.h" -#endif - -#include -#include - -struct TestObject { - TestBase *test; - std::string name; -}; - - -using namespace std; - -int -main() -{ - TestObject tests[] = - { - { new SanityChecks(), "Sanity Checks" }, - #ifdef WIN32 - { new TestDrawTargetD2D(), "DrawTarget (D2D)" }, - #endif - { new TestPoint(), "Point Tests" }, - { new TestScaling(), "Scaling Tests" } - }; - - int totalFailures = 0; - int totalTests = 0; - stringstream message; - printf("------ STARTING RUNNING TESTS ------\n"); - for (int i = 0; i < sizeof(tests) / sizeof(TestObject); i++) { - message << "--- RUNNING TESTS: " << tests[i].name << " ---\n"; - printf(message.str().c_str()); - message.str(""); - int failures = 0; - totalTests += tests[i].test->RunTests(&failures); - totalFailures += failures; - // Done with this test! - delete tests[i].test; - } - message << "------ FINISHED RUNNING TESTS ------\nTests run: " << totalTests << " - Passes: " << totalTests - totalFailures << " - Failures: " << totalFailures << "\n"; - printf(message.str().c_str()); - return totalFailures; -} diff --git a/libazure/src/gfx/2d/unittest/TestBase.h b/libazure/src/gfx/2d/unittest/TestBase.h deleted file mode 100644 index 97f3788..0000000 --- a/libazure/src/gfx/2d/unittest/TestBase.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include - -#ifdef _MSC_VER -// On MSVC otherwise our generic member pointer trick doesn't work. -#pragma pointers_to_members(full_generality, single_inheritance) -#endif - -#define VERIFY(arg) if (!(arg)) { \ - LogMessage("VERIFY FAILED: "#arg"\n"); \ - mTestFailed = true; \ - } - -#define REGISTER_TEST(className, testName) \ - mTests.push_back(Test(static_cast(&className::testName), #testName, this)) - -class TestBase -{ -public: - TestBase() {} - - typedef void (TestBase::*TestCall)(); - - int RunTests(int *aFailures); - -protected: - static void LogMessage(std::string aMessage); - - struct Test { - Test(TestCall aCall, std::string aName, void *aImplPointer) - : funcCall(aCall) - , name(aName) - , implPointer(aImplPointer) - { - } - TestCall funcCall; - std::string name; - void *implPointer; - }; - std::vector mTests; - - bool mTestFailed; - -private: - // This doesn't really work with our generic member pointer trick. - TestBase(const TestBase &aOther); -}; diff --git a/libazure/src/gfx/2d/unittest/TestCairo.cpp b/libazure/src/gfx/2d/unittest/TestCairo.cpp deleted file mode 100644 index f73e177..0000000 --- a/libazure/src/gfx/2d/unittest/TestCairo.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -#include "cairo.h" - -#include "gtest/gtest.h" - -namespace mozilla { -namespace layers { - -void TryCircle(double centerX, double centerY, double radius) { - printf("TestCairo:TryArcs centerY %f, radius %f\n",centerY,radius); - - cairo_surface_t *surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,8,21); - ASSERT_TRUE(surf != nullptr); - - cairo_t *cairo = cairo_create(surf); - ASSERT_TRUE(cairo != nullptr); - - cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); - cairo_arc(cairo, 0.0, centerY, radius, 0.0, 6.2831853071795862); - cairo_fill_preserve(cairo); - - cairo_surface_destroy(surf); - cairo_destroy(cairo); -} - -TEST(Cairo, Simple) { - TryCircle(0.0, 0.0, 14.0); - TryCircle(0.0, 1.0, 22.4); - TryCircle(1.0, 0.0, 1422.4); - TryCircle(1.0, 1.0, 3422.4); - TryCircle(-10.0, 1.0, -2); -} - -TEST(Cairo, Bug825721) { - // OK: - TryCircle(0.0, 0.0, 8761126469220696064.0); - TryCircle(0.0, 1.0, 8761126469220696064.0); - - // OK: - TryCircle(1.0, 0.0, 5761126469220696064.0); - - // This was the crash in 825721. Note that centerY has to be non-zero, - // and radius has to be not only large, but in particular range. - // 825721 has a band-aid fix, where the crash is inevitable, but does - // not fix the cause. The same code crashes in cairo standalone. - TryCircle(0.0, 1.0, 5761126469220696064.0); -} - -} -} diff --git a/libazure/src/gfx/2d/unittest/TestDrawTargetBase.cpp b/libazure/src/gfx/2d/unittest/TestDrawTargetBase.cpp deleted file mode 100644 index 020da02..0000000 --- a/libazure/src/gfx/2d/unittest/TestDrawTargetBase.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestDrawTargetBase.h" -#include - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace std; - -TestDrawTargetBase::TestDrawTargetBase() -{ - REGISTER_TEST(TestDrawTargetBase, Initialized); - REGISTER_TEST(TestDrawTargetBase, FillCompletely); - REGISTER_TEST(TestDrawTargetBase, FillRect); -} - -void -TestDrawTargetBase::Initialized() -{ - VERIFY(mDT); -} - -void -TestDrawTargetBase::FillCompletely() -{ - mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f))); - - RefreshSnapshot(); - - VerifyAllPixels(Color(0, 0.5f, 0, 1.0f)); -} - -void -TestDrawTargetBase::FillRect() -{ - mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f))); - mDT->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.5f, 0, 0, 1.0f))); - - RefreshSnapshot(); - - VerifyPixel(IntPoint(49, 49), Color(0, 0.5f, 0, 1.0f)); - VerifyPixel(IntPoint(50, 50), Color(0.5f, 0, 0, 1.0f)); - VerifyPixel(IntPoint(99, 99), Color(0.5f, 0, 0, 1.0f)); - VerifyPixel(IntPoint(100, 100), Color(0, 0.5f, 0, 1.0f)); -} - -void -TestDrawTargetBase::RefreshSnapshot() -{ - RefPtr snapshot = mDT->Snapshot(); - mDataSnapshot = snapshot->GetDataSurface(); -} - -void -TestDrawTargetBase::VerifyAllPixels(const Color &aColor) -{ - uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData(); - - uint32_t expected = RGBAPixelFromColor(aColor); - - for (int y = 0; y < DT_HEIGHT; y++) { - for (int x = 0; x < DT_WIDTH; x++) { - if (colVal[y * (mDataSnapshot->Stride() / 4) + x] != expected) { - LogMessage("VerifyAllPixels Failed\n"); - mTestFailed = true; - return; - } - } - } -} - -void -TestDrawTargetBase::VerifyPixel(const IntPoint &aPoint, mozilla::gfx::Color &aColor) -{ - uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData(); - - uint32_t expected = RGBAPixelFromColor(aColor); - uint32_t rawActual = colVal[aPoint.y * (mDataSnapshot->Stride() / 4) + aPoint.x]; - - if (rawActual != expected) { - stringstream message; - uint32_t actb = rawActual & 0xFF; - uint32_t actg = (rawActual & 0xFF00) >> 8; - uint32_t actr = (rawActual & 0xFF0000) >> 16; - uint32_t acta = (rawActual & 0xFF000000) >> 24; - uint32_t expb = expected & 0xFF; - uint32_t expg = (expected & 0xFF00) >> 8; - uint32_t expr = (expected & 0xFF0000) >> 16; - uint32_t expa = (expected & 0xFF000000) >> 24; - - message << "Verify Pixel (" << aPoint.x << "x" << aPoint.y << ") Failed." - " Expected (" << expr << "," << expg << "," << expb << "," << expa << ") " - " Got (" << actr << "," << actg << "," << actb << "," << acta << ")\n"; - - LogMessage(message.str()); - mTestFailed = true; - return; - } -} - -uint32_t -TestDrawTargetBase::RGBAPixelFromColor(const Color &aColor) -{ - return uint8_t((aColor.b * 255) + 0.5f) | uint8_t((aColor.g * 255) + 0.5f) << 8 | - uint8_t((aColor.r * 255) + 0.5f) << 16 | uint8_t((aColor.a * 255) + 0.5f) << 24; -} diff --git a/libazure/src/gfx/2d/unittest/TestDrawTargetBase.h b/libazure/src/gfx/2d/unittest/TestDrawTargetBase.h deleted file mode 100644 index d373666..0000000 --- a/libazure/src/gfx/2d/unittest/TestDrawTargetBase.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include "2D.h" -#include "TestBase.h" - -#define DT_WIDTH 500 -#define DT_HEIGHT 500 - -/* This general DrawTarget test class can be reimplemented by a child class - * with optional additional drawtarget-specific tests. And is intended to run - * on a 500x500 32 BPP drawtarget. - */ -class TestDrawTargetBase : public TestBase -{ -public: - void Initialized(); - void FillCompletely(); - void FillRect(); - -protected: - TestDrawTargetBase(); - - void RefreshSnapshot(); - - void VerifyAllPixels(const mozilla::gfx::Color &aColor); - void VerifyPixel(const mozilla::gfx::IntPoint &aPoint, - mozilla::gfx::Color &aColor); - - uint32_t RGBAPixelFromColor(const mozilla::gfx::Color &aColor); - - mozilla::RefPtr mDT; - mozilla::RefPtr mDataSnapshot; -}; diff --git a/libazure/src/gfx/2d/unittest/unittest.vcxproj b/libazure/src/gfx/2d/unittest/unittest.vcxproj deleted file mode 100644 index 7ddf925..0000000 --- a/libazure/src/gfx/2d/unittest/unittest.vcxproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {CCF4BC8B-0CED-47CA-B621-ABF1832527D9} - unittest - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib - $(ProjectDir)..\;$(IncludePath) - - - $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib - - - - Level3 - Disabled - ../ - WIN32;_MBCS;%(PreprocessorDefinitions) - - - true - ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Level3 - MaxSpeed - true - true - ../ - WIN32;_MBCS;%(PreprocessorDefinitions) - - - true - true - true - ../$(Configuration)/gfx2d.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libazure/src/gfx/gl/ForceDiscreteGPUHelperCGL.h b/libazure/src/gfx/gl/ForceDiscreteGPUHelperCGL.h deleted file mode 100644 index 3b4cb07..0000000 --- a/libazure/src/gfx/gl/ForceDiscreteGPUHelperCGL.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef ForceDiscreteGPUHelperCGL_h_ -#define ForceDiscreteGPUHelperCGL_h_ - -#include - -/** This RAII helper guarantees that we're on the discrete GPU during its lifetime. - * - * As long as any ForceDiscreteGPUHelperCGL object is alive, we're on the discrete GPU. - */ -class ForceDiscreteGPUHelperCGL -{ - CGLPixelFormatObj mPixelFormatObj; - -public: - ForceDiscreteGPUHelperCGL() - { - // the code in this function is taken from Chromium, src/ui/gfx/gl/gl_context_cgl.cc, r122013 - // BSD-style license, (c) The Chromium Authors - CGLPixelFormatAttribute attribs[1]; - attribs[0] = static_cast(0); - GLint num_pixel_formats = 0; - CGLChoosePixelFormat(attribs, &mPixelFormatObj, &num_pixel_formats); - } - - ~ForceDiscreteGPUHelperCGL() - { - CGLReleasePixelFormat(mPixelFormatObj); - } -}; - -#endif // ForceDiscreteGPUHelperCGL_h_ diff --git a/libazure/src/gfx/gl/GLContext.cpp b/libazure/src/gfx/gl/GLContext.cpp deleted file mode 100644 index e6913d0..0000000 --- a/libazure/src/gfx/gl/GLContext.cpp +++ /dev/null @@ -1,2976 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include - -#include "GLContext.h" - -#include "gfxCrashReporterUtils.h" -#include "gfxPlatform.h" -#include "gfxUtils.h" -#include "GLContextProvider.h" -#include "GLTextureImage.h" -#include "nsIMemoryReporter.h" -#include "nsThreadUtils.h" -#include "prenv.h" -#include "prlink.h" -#include "SurfaceStream.h" - -#include "mozilla/DebugOnly.h" -#include "mozilla/Preferences.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -#ifdef DEBUG -unsigned GLContext::sCurrentGLContextTLS = -1; -#endif - -uint32_t GLContext::sDebugMode = 0; - - -#define MAX_SYMBOL_LENGTH 128 -#define MAX_SYMBOL_NAMES 5 - -// should match the order of GLExtensions, and be null-terminated. -static const char *sExtensionNames[] = { - "GL_EXT_framebuffer_object", - "GL_ARB_framebuffer_object", - "GL_ARB_texture_rectangle", - "GL_EXT_bgra", - "GL_EXT_texture_format_BGRA8888", - "GL_OES_depth24", - "GL_OES_depth32", - "GL_OES_stencil8", - "GL_OES_texture_npot", - "GL_OES_depth_texture", - "GL_OES_packed_depth_stencil", - "GL_IMG_read_format", - "GL_EXT_read_format_bgra", - "GL_APPLE_client_storage", - "GL_ARB_texture_non_power_of_two", - "GL_ARB_pixel_buffer_object", - "GL_ARB_ES2_compatibility", - "GL_OES_texture_float", - "GL_ARB_texture_float", - "GL_EXT_unpack_subimage", - "GL_OES_standard_derivatives", - "GL_EXT_texture_filter_anisotropic", - "GL_EXT_texture_compression_s3tc", - "GL_EXT_texture_compression_dxt1", - "GL_ANGLE_texture_compression_dxt3", - "GL_ANGLE_texture_compression_dxt5", - "GL_AMD_compressed_ATC_texture", - "GL_IMG_texture_compression_pvrtc", - "GL_EXT_framebuffer_blit", - "GL_ANGLE_framebuffer_blit", - "GL_EXT_framebuffer_multisample", - "GL_ANGLE_framebuffer_multisample", - "GL_OES_rgb8_rgba8", - "GL_ARB_robustness", - "GL_EXT_robustness", - "GL_ARB_sync", - "GL_OES_EGL_image", - "GL_OES_EGL_sync", - "GL_OES_EGL_image_external", - "GL_EXT_packed_depth_stencil", - nullptr -}; - -static int64_t sTextureMemoryUsage = 0; - -static int64_t -GetTextureMemoryUsage() -{ - return sTextureMemoryUsage; -} - -void -GLContext::UpdateTextureMemoryUsage(MemoryUse action, GLenum format, GLenum type, uint16_t tileSize) -{ - uint32_t bytesPerTexel = mozilla::gl::GetBitsPerTexel(format, type) / 8; - int64_t bytes = (int64_t)(tileSize * tileSize * bytesPerTexel); - if (action == MemoryFreed) { - sTextureMemoryUsage -= bytes; - } else { - sTextureMemoryUsage += bytes; - } -} - -NS_MEMORY_REPORTER_IMPLEMENT(TextureMemoryUsage, - "gfx-textures", - KIND_OTHER, - UNITS_BYTES, - GetTextureMemoryUsage, - "Memory used for storing GL textures.") - -/* - * XXX - we should really know the ARB/EXT variants of these - * instead of only handling the symbol if it's exposed directly. - */ - -bool -GLContext::InitWithPrefix(const char *prefix, bool trygl) -{ - ScopedGfxFeatureReporter reporter("GL Context"); - - if (mInitialized) { - reporter.SetSuccessful(); - return true; - } - - mWorkAroundDriverBugs = gfxPlatform::GetPlatform()->WorkAroundDriverBugs(); - - SymLoadStruct symbols[] = { - { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", NULL } }, - { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", NULL } }, - { (PRFuncPtr*) &mSymbols.fBlendEquationSeparate, { "BlendEquationSeparate", "BlendEquationSeparateEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fBlendFunc, { "BlendFunc", NULL } }, - { (PRFuncPtr*) &mSymbols.fBlendFuncSeparate, { "BlendFuncSeparate", "BlendFuncSeparateEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fBufferData, { "BufferData", NULL } }, - { (PRFuncPtr*) &mSymbols.fBufferSubData, { "BufferSubData", NULL } }, - { (PRFuncPtr*) &mSymbols.fClear, { "Clear", NULL } }, - { (PRFuncPtr*) &mSymbols.fClearColor, { "ClearColor", NULL } }, - { (PRFuncPtr*) &mSymbols.fClearStencil, { "ClearStencil", NULL } }, - { (PRFuncPtr*) &mSymbols.fColorMask, { "ColorMask", NULL } }, - { (PRFuncPtr*) &mSymbols.fCompressedTexImage2D, {"CompressedTexImage2D", NULL} }, - { (PRFuncPtr*) &mSymbols.fCompressedTexSubImage2D, {"CompressedTexSubImage2D", NULL} }, - { (PRFuncPtr*) &mSymbols.fCullFace, { "CullFace", NULL } }, - { (PRFuncPtr*) &mSymbols.fDetachShader, { "DetachShader", "DetachShaderARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDepthFunc, { "DepthFunc", NULL } }, - { (PRFuncPtr*) &mSymbols.fDepthMask, { "DepthMask", NULL } }, - { (PRFuncPtr*) &mSymbols.fDisable, { "Disable", NULL } }, - { (PRFuncPtr*) &mSymbols.fDisableVertexAttribArray, { "DisableVertexAttribArray", "DisableVertexAttribArrayARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDrawArrays, { "DrawArrays", NULL } }, - { (PRFuncPtr*) &mSymbols.fDrawElements, { "DrawElements", NULL } }, - { (PRFuncPtr*) &mSymbols.fEnable, { "Enable", NULL } }, - { (PRFuncPtr*) &mSymbols.fEnableVertexAttribArray, { "EnableVertexAttribArray", "EnableVertexAttribArrayARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fFinish, { "Finish", NULL } }, - { (PRFuncPtr*) &mSymbols.fFlush, { "Flush", NULL } }, - { (PRFuncPtr*) &mSymbols.fFrontFace, { "FrontFace", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetActiveAttrib, { "GetActiveAttrib", "GetActiveAttribARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetActiveUniform, { "GetActiveUniform", "GetActiveUniformARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetAttachedShaders, { "GetAttachedShaders", "GetAttachedShadersARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetAttribLocation, { "GetAttribLocation", "GetAttribLocationARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetIntegerv, { "GetIntegerv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetFloatv, { "GetFloatv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetBooleanv, { "GetBooleanv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetError, { "GetError", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetProgramiv, { "GetProgramiv", "GetProgramivARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", NULL } }, - { (PRFuncPtr*) &mSymbols.fTexParameteriv, { "TexParameteriv", NULL } }, - { (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetString, { "GetString", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetUniformiv, { "GetUniformiv", "GetUniformivARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetUniformLocation, { "GetUniformLocation", "GetUniformLocationARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetVertexAttribfv, { "GetVertexAttribfv", "GetVertexAttribfvARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetVertexAttribiv, { "GetVertexAttribiv", "GetVertexAttribivARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetVertexAttribPointerv, { "GetVertexAttribPointerv", NULL } }, - { (PRFuncPtr*) &mSymbols.fHint, { "Hint", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsBuffer, { "IsBuffer", "IsBufferARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsEnabled, { "IsEnabled", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsProgram, { "IsProgram", "IsProgramARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsShader, { "IsShader", "IsShaderARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsTexture, { "IsTexture", "IsTextureARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fLineWidth, { "LineWidth", NULL } }, - { (PRFuncPtr*) &mSymbols.fLinkProgram, { "LinkProgram", "LinkProgramARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fPixelStorei, { "PixelStorei", NULL } }, - { (PRFuncPtr*) &mSymbols.fPolygonOffset, { "PolygonOffset", NULL } }, - { (PRFuncPtr*) &mSymbols.fReadPixels, { "ReadPixels", NULL } }, - { (PRFuncPtr*) &mSymbols.fSampleCoverage, { "SampleCoverage", NULL } }, - { (PRFuncPtr*) &mSymbols.fScissor, { "Scissor", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilFunc, { "StencilFunc", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilFuncSeparate, { "StencilFuncSeparate", "StencilFuncSeparateEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilMask, { "StencilMask", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilMaskSeparate, { "StencilMaskSeparate", "StencilMaskSeparateEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilOp, { "StencilOp", NULL } }, - { (PRFuncPtr*) &mSymbols.fStencilOpSeparate, { "StencilOpSeparate", "StencilOpSeparateEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fTexImage2D, { "TexImage2D", NULL } }, - { (PRFuncPtr*) &mSymbols.fTexSubImage2D, { "TexSubImage2D", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform1f, { "Uniform1f", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform1fv, { "Uniform1fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform1i, { "Uniform1i", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform1iv, { "Uniform1iv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform2f, { "Uniform2f", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform2fv, { "Uniform2fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform2i, { "Uniform2i", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform2iv, { "Uniform2iv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform3f, { "Uniform3f", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform3fv, { "Uniform3fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform3i, { "Uniform3i", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform3iv, { "Uniform3iv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform4f, { "Uniform4f", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform4fv, { "Uniform4fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform4i, { "Uniform4i", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniform4iv, { "Uniform4iv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniformMatrix2fv, { "UniformMatrix2fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniformMatrix3fv, { "UniformMatrix3fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUniformMatrix4fv, { "UniformMatrix4fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fUseProgram, { "UseProgram", NULL } }, - { (PRFuncPtr*) &mSymbols.fValidateProgram, { "ValidateProgram", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib1f, { "VertexAttrib1f", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib2f, { "VertexAttrib2f", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib3f, { "VertexAttrib3f", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib4f, { "VertexAttrib4f", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib1fv, { "VertexAttrib1fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib2fv, { "VertexAttrib2fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib3fv, { "VertexAttrib3fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttrib4fv, { "VertexAttrib4fv", NULL } }, - { (PRFuncPtr*) &mSymbols.fViewport, { "Viewport", NULL } }, - { (PRFuncPtr*) &mSymbols.fCompileShader, { "CompileShader", NULL } }, - { (PRFuncPtr*) &mSymbols.fCopyTexImage2D, { "CopyTexImage2D", NULL } }, - { (PRFuncPtr*) &mSymbols.fCopyTexSubImage2D, { "CopyTexSubImage2D", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetShaderiv, { "GetShaderiv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetShaderInfoLog, { "GetShaderInfoLog", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetShaderSource, { "GetShaderSource", NULL } }, - { (PRFuncPtr*) &mSymbols.fShaderSource, { "ShaderSource", NULL } }, - { (PRFuncPtr*) &mSymbols.fVertexAttribPointer, { "VertexAttribPointer", NULL } }, - { (PRFuncPtr*) &mSymbols.fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", NULL } }, - - { (PRFuncPtr*) &mSymbols.fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGenTextures, { "GenTextures", NULL } }, - { (PRFuncPtr*) &mSymbols.fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fCreateShader, { "CreateShader", "CreateShaderARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } }, - - { (PRFuncPtr*) &mSymbols.fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } }, - - { NULL, { NULL } }, - - }; - - mInitialized = LoadSymbols(&symbols[0], trygl, prefix); - - // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2. - if (mInitialized) { - if (mIsGLES2) { - SymLoadStruct symbols_ES2[] = { - { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", NULL } }, - { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", NULL } }, - { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", NULL } }, - { NULL, { NULL } }, - }; - - if (!LoadSymbols(&symbols_ES2[0], trygl, prefix)) { - NS_ERROR("OpenGL ES 2.0 supported, but symbols could not be loaded."); - mInitialized = false; - } - } else { - SymLoadStruct symbols_desktop[] = { - { (PRFuncPtr*) &mSymbols.fClearDepth, { "ClearDepth", NULL } }, - { (PRFuncPtr*) &mSymbols.fDepthRange, { "DepthRange", NULL } }, - { (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", NULL } }, - { (PRFuncPtr*) &mSymbols.fMapBuffer, { "MapBuffer", NULL } }, - { (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", NULL } }, - { (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", NULL } }, - { (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuiv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueries", NULL } }, - { (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueries", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryiv", NULL } }, - { (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", NULL } }, - { (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQuery", NULL } }, - { (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", NULL } }, - { (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", NULL } }, - { NULL, { NULL } }, - }; - - if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) { - NS_ERROR("Desktop symbols failed to load."); - mInitialized = false; - } - } - } - - const char *glVendorString = nullptr; - const char *glRendererString = nullptr; - - if (mInitialized) { - // The order of these strings must match up with the order of the enum - // defined in GLContext.h for vendor IDs - glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR); - if (!glVendorString) - mInitialized = false; - - const char *vendorMatchStrings[VendorOther] = { - "Intel", - "NVIDIA", - "ATI", - "Qualcomm", - "Imagination", - "nouveau" - }; - - mVendor = VendorOther; - for (int i = 0; i < VendorOther; ++i) { - if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) { - mVendor = i; - break; - } - } - - // The order of these strings must match up with the order of the enum - // defined in GLContext.h for renderer IDs - glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER); - if (!glRendererString) - mInitialized = false; - - const char *rendererMatchStrings[RendererOther] = { - "Adreno 200", - "Adreno 205", - "Adreno (TM) 320", - "PowerVR SGX 530", - "PowerVR SGX 540" - }; - - mRenderer = RendererOther; - for (int i = 0; i < RendererOther; ++i) { - if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) { - mRenderer = i; - break; - } - } - } - - -#ifdef DEBUG - if (PR_GetEnv("MOZ_GL_DEBUG")) - sDebugMode |= DebugEnabled; - - // enables extra verbose output, informing of the start and finish of every GL call. - // useful e.g. to record information to investigate graphics system crashes/lockups - if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE")) - sDebugMode |= DebugTrace; - - // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle. - if (PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR")) - sDebugMode |= DebugAbortOnError; -#endif - - if (mInitialized) { -#ifdef DEBUG - static bool firstRun = true; - if (firstRun && DebugMode()) { - const char *vendors[VendorOther] = { - "Intel", - "NVIDIA", - "ATI", - "Qualcomm" - }; - - MOZ_ASSERT(glVendorString); - if (mVendor < VendorOther) { - printf_stderr("OpenGL vendor ('%s') recognized as: %s\n", - glVendorString, vendors[mVendor]); - } else { - printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString); - } - } - firstRun = false; -#endif - - InitExtensions(); - - NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) || - (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer), - "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!"); - - if (SupportsRobustness()) { - if (IsExtensionSupported(ARB_robustness)) { - SymLoadStruct robustnessSymbols[] = { - { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", nullptr } }, - { nullptr, { nullptr } }, - }; - - if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports ARB_robustness without supplying GetGraphicsResetStatusARB."); - - MarkExtensionUnsupported(ARB_robustness); - mSymbols.fGetGraphicsResetStatus = nullptr; - } else { - mHasRobustness = true; - } - } - if (!IsExtensionSupported(ARB_robustness) && - IsExtensionSupported(EXT_robustness)) { - SymLoadStruct robustnessSymbols[] = { - { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusEXT", nullptr } }, - { nullptr, { nullptr } }, - }; - - if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports EXT_robustness without supplying GetGraphicsResetStatusEXT."); - - MarkExtensionUnsupported(EXT_robustness); - mSymbols.fGetGraphicsResetStatus = nullptr; - } else { - mHasRobustness = true; - } - } - } - - // Check for aux symbols based on extensions - if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) || - IsExtensionSupported(GLContext::EXT_framebuffer_blit)) - { - SymLoadStruct auxSymbols[] = { - { - (PRFuncPtr*) &mSymbols.fBlitFramebuffer, - { - "BlitFramebuffer", - "BlitFramebufferEXT", - "BlitFramebufferANGLE", - nullptr - } - }, - { nullptr, { nullptr } }, - }; - if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer"); - - MarkExtensionUnsupported(ANGLE_framebuffer_blit); - MarkExtensionUnsupported(EXT_framebuffer_blit); - mSymbols.fBlitFramebuffer = nullptr; - } - } - - if (SupportsFramebufferMultisample()) - { - MOZ_ASSERT(SupportsSplitFramebuffer()); - SymLoadStruct auxSymbols[] = { - { - (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, - { - "RenderbufferStorageMultisample", - "RenderbufferStorageMultisampleEXT", - "RenderbufferStorageMultisampleANGLE", - nullptr - } - }, - { nullptr, { nullptr } }, - }; - if (!LoadSymbols(&auxSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports framebuffer_multisample without supplying glRenderbufferStorageMultisample"); - - MarkExtensionUnsupported(ANGLE_framebuffer_multisample); - MarkExtensionUnsupported(EXT_framebuffer_multisample); - mSymbols.fRenderbufferStorageMultisample = nullptr; - } - } - - if (IsExtensionSupported(ARB_sync)) { - SymLoadStruct syncSymbols[] = { - { (PRFuncPtr*) &mSymbols.fFenceSync, { "FenceSync", nullptr } }, - { (PRFuncPtr*) &mSymbols.fIsSync, { "IsSync", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDeleteSync, { "DeleteSync", nullptr } }, - { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "ClientWaitSync", nullptr } }, - { (PRFuncPtr*) &mSymbols.fWaitSync, { "WaitSync", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetInteger64v, { "GetInteger64v", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetSynciv, { "GetSynciv", nullptr } }, - { nullptr, { nullptr } }, - }; - - if (!LoadSymbols(&syncSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports ARB_sync without supplying its functions."); - - MarkExtensionUnsupported(ARB_sync); - mSymbols.fFenceSync = nullptr; - mSymbols.fIsSync = nullptr; - mSymbols.fDeleteSync = nullptr; - mSymbols.fClientWaitSync = nullptr; - mSymbols.fWaitSync = nullptr; - mSymbols.fGetInteger64v = nullptr; - mSymbols.fGetSynciv = nullptr; - } - } - - if (IsExtensionSupported(OES_EGL_image)) { - SymLoadStruct imageSymbols[] = { - { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } }, - { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } }, - { nullptr, { nullptr } }, - }; - - if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) { - NS_ERROR("GL supports OES_EGL_image without supplying its functions."); - - MarkExtensionUnsupported(OES_EGL_image); - mSymbols.fEGLImageTargetTexture2D = nullptr; - mSymbols.fEGLImageTargetRenderbufferStorage = nullptr; - } - } - - // Load developer symbols, don't fail if we can't find them. - SymLoadStruct auxSymbols[] = { - { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } }, - { nullptr, { nullptr } }, - }; - bool warnOnFailures = DebugMode(); - LoadSymbols(&auxSymbols[0], trygl, prefix, warnOnFailures); - } - - if (mInitialized) { - GLint v[4]; - - fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v); - mScissorStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3])); - - fGetIntegerv(LOCAL_GL_VIEWPORT, v); - mViewportStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3])); - - raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize); - raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); - -#ifdef XP_MACOSX - if (mWorkAroundDriverBugs && - mVendor == VendorIntel) { - // see bug 737182 for 2D textures, bug 684882 for cube map textures. - mMaxTextureSize = std::min(mMaxTextureSize, 4096); - mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512); - // for good measure, we align renderbuffers on what we do for 2D textures - mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096); - mNeedsTextureSizeChecks = true; - } -#endif -#ifdef MOZ_X11 - if (mWorkAroundDriverBugs && - mVendor == VendorNouveau) { - // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau. - mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048); - mNeedsTextureSizeChecks = true; - } -#endif - - mMaxTextureImageSize = mMaxTextureSize; - - mMaxSamples = 0; - if (SupportsFramebufferMultisample()) { - fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples); - } - - // We're ready for final setup. - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - - if (mCaps.any) - DetermineCaps(); - - UpdatePixelFormat(); - UpdateGLFormats(mCaps); - - mTexGarbageBin = new TextureGarbageBin(this); - - MOZ_ASSERT(IsCurrent()); - } - - if (mInitialized) - reporter.SetSuccessful(); - else { - // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs - mSymbols.Zero(); - NS_WARNING("InitWithPrefix failed!"); - } - - return mInitialized; -} - -void -GLContext::InitExtensions() -{ - MakeCurrent(); - const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS); - if (!extensions) - return; - -#ifdef DEBUG - static bool firstRun = true; -#else - // Non-DEBUG, so never spew. - const bool firstRun = false; -#endif - - mAvailableExtensions.Load(extensions, sExtensionNames, firstRun && DebugMode()); - - if (WorkAroundDriverBugs() && - Vendor() == VendorQualcomm) { - - // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it. - MarkExtensionSupported(OES_EGL_sync); - } - -#ifdef XP_MACOSX - // The Mac Nvidia driver, for versions up to and including 10.8, don't seem - // to properly support this. See 814839 - if (WorkAroundDriverBugs() && - Vendor() == gl::GLContext::VendorNVIDIA) - { - MarkExtensionUnsupported(gl::GLContext::EXT_packed_depth_stencil); - } -#endif - -#ifdef DEBUG - firstRun = false; -#endif -} - - -// Take texture data in a given buffer and copy it into a larger buffer, -// padding out the edge pixels for filtering if necessary -static void -CopyAndPadTextureData(const GLvoid* srcBuffer, - GLvoid* dstBuffer, - GLsizei srcWidth, GLsizei srcHeight, - GLsizei dstWidth, GLsizei dstHeight, - GLsizei stride, GLint pixelsize) -{ - unsigned char *rowDest = static_cast(dstBuffer); - const unsigned char *source = static_cast(srcBuffer); - - for (GLsizei h = 0; h < srcHeight; ++h) { - memcpy(rowDest, source, srcWidth * pixelsize); - rowDest += dstWidth * pixelsize; - source += stride; - } - - GLsizei padHeight = srcHeight; - - // Pad out an extra row of pixels so that edge filtering doesn't use garbage data - if (dstHeight > srcHeight) { - memcpy(rowDest, source - stride, srcWidth * pixelsize); - padHeight++; - } - - // Pad out an extra column of pixels - if (dstWidth > srcWidth) { - rowDest = static_cast(dstBuffer) + srcWidth * pixelsize; - for (GLsizei h = 0; h < padHeight; ++h) { - memcpy(rowDest, rowDest - pixelsize, pixelsize); - rowDest += dstWidth * pixelsize; - } - } -} - -// In both of these cases (for the Adreno at least) it is impossible -// to determine good or bad driver versions for POT texture uploads, -// so blacklist them all. Newer drivers use a different rendering -// string in the form "Adreno (TM) 200" and the drivers we've seen so -// far work fine with NPOT textures, so don't blacklist those until we -// have evidence of any problems with them. -bool -GLContext::CanUploadSubTextures() -{ - if (!mWorkAroundDriverBugs) - return true; - - // Lock surface feature allows to mmap texture memory and modify it directly - // this feature allow us modify texture partially without full upload - if (HasLockSurface()) - return true; - - // There are certain GPUs that we don't want to use glTexSubImage2D on - // because that function can be very slow and/or buggy - if (Renderer() == RendererAdreno200 || Renderer() == RendererAdreno205) - return false; - - // On PowerVR glTexSubImage does a readback, so it will be slower - // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms - if (Renderer() == RendererSGX540 || Renderer() == RendererSGX530) - return false; - - return true; -} - -bool GLContext::sPowerOfTwoForced = false; -bool GLContext::sPowerOfTwoPrefCached = false; - -void -GLContext::PlatformStartup() -{ - CacheCanUploadNPOT(); - NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(TextureMemoryUsage)); -} - -void -GLContext::CacheCanUploadNPOT() -{ - MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread."); - MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!"); - - sPowerOfTwoPrefCached = true; - mozilla::Preferences::AddBoolVarCache(&sPowerOfTwoForced, - "gfx.textures.poweroftwo.force-enabled"); -} - -bool -GLContext::CanUploadNonPowerOfTwo() -{ - MOZ_ASSERT(sPowerOfTwoPrefCached); - - if (!mWorkAroundDriverBugs) - return true; - - // Some GPUs driver crash when uploading non power of two 565 textures. - return sPowerOfTwoForced ? false : (Renderer() != RendererAdreno200 && - Renderer() != RendererAdreno205); -} - -bool -GLContext::WantsSmallTiles() -{ - // We must use small tiles for good performance if we can't use - // glTexSubImage2D() for some reason. - if (!CanUploadSubTextures()) - return true; - - // We can't use small tiles on the SGX 540, because of races in texture upload. - if (mWorkAroundDriverBugs && - Renderer() == RendererSGX540) - return false; - - // Don't use small tiles otherwise. (If we implement incremental texture upload, - // then we will want to revisit this.) - return false; -} - -// Common code for checking for both GL extensions and GLX extensions. -bool -GLContext::ListHasExtension(const GLubyte *extensions, const char *extension) -{ - // fix bug 612572 - we were crashing as we were calling this function with extensions==null - if (extensions == nullptr || extension == nullptr) - return false; - - const GLubyte *start; - GLubyte *where, *terminator; - - /* Extension names should not have spaces. */ - where = (GLubyte *) strchr(extension, ' '); - if (where || *extension == '\0') - return false; - - /* - * It takes a bit of care to be fool-proof about parsing the - * OpenGL extensions string. Don't be fooled by sub-strings, - * etc. - */ - start = extensions; - for (;;) { - where = (GLubyte *) strstr((const char *) start, extension); - if (!where) { - break; - } - terminator = where + strlen(extension); - if (where == start || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return true; - } - } - start = terminator; - } - return false; -} - -already_AddRefed -GLContext::CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags) -{ - bool useNearestFilter = aFlags & TextureImage::UseNearestFilter; - MakeCurrent(); - - GLuint texture; - fGenTextures(1, &texture); - - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, texture); - - GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode); - - return CreateBasicTextureImage(texture, aSize, aWrapMode, aContentType, this, aFlags); -} - -already_AddRefed -GLContext::CreateBasicTextureImage(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - TextureImage::ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags) -{ - nsRefPtr teximage( - new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags)); - return teximage.forget(); -} - -void GLContext::ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter) -{ - ApplyFilterToBoundTexture(LOCAL_GL_TEXTURE_2D, aFilter); -} - -void GLContext::ApplyFilterToBoundTexture(GLuint aTarget, - gfxPattern::GraphicsFilter aFilter) -{ - if (aFilter == gfxPattern::FILTER_NEAREST) { - fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); - fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); - } else { - fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - } -} - - -void -GLContext::DetermineCaps() -{ - PixelBufferFormat format = QueryPixelFormat(); - - SurfaceCaps caps; - caps.color = !!format.red && !!format.green && !!format.blue; - caps.bpp16 = caps.color && format.ColorBits() == 16; - caps.alpha = !!format.alpha; - caps.depth = !!format.depth; - caps.stencil = !!format.stencil; - caps.antialias = format.samples > 1; - caps.preserve = true; - - mCaps = caps; -} - -PixelBufferFormat -GLContext::QueryPixelFormat() -{ - PixelBufferFormat format; - - ScopedBindFramebuffer autoFB(this, 0); - - fGetIntegerv(LOCAL_GL_RED_BITS , &format.red ); - fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green); - fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue ); - fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha); - - fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth); - fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil); - - fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples); - - return format; -} - -void -GLContext::UpdatePixelFormat() -{ - PixelBufferFormat format = QueryPixelFormat(); -#ifdef DEBUG - const SurfaceCaps& caps = Caps(); - MOZ_ASSERT(caps.color == !!format.red); - MOZ_ASSERT(caps.color == !!format.green); - MOZ_ASSERT(caps.color == !!format.blue); - MOZ_ASSERT(caps.alpha == !!format.alpha); - MOZ_ASSERT(caps.depth == !!format.depth); - MOZ_ASSERT(caps.stencil == !!format.stencil); - MOZ_ASSERT(caps.antialias == (format.samples > 1)); -#endif - mPixelFormat = new PixelBufferFormat(format); -} - -GLFormats -GLContext::ChooseGLFormats(const SurfaceCaps& caps) const -{ - GLFormats formats; - - // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less - // OR we don't support full 8-bit color, return a 4444 or 565 format. - bool bpp16 = caps.bpp16; - if (mIsGLES2) { - if (!IsExtensionSupported(OES_rgb8_rgba8)) - bpp16 = true; - } else { - // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility. - // Since it's also vanishingly useless there, let's not support it. - bpp16 = false; - } - - if (bpp16) { - MOZ_ASSERT(mIsGLES2); - if (caps.alpha) { - formats.color_texInternalFormat = LOCAL_GL_RGBA; - formats.color_texFormat = LOCAL_GL_RGBA; - formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4; - formats.color_rbFormat = LOCAL_GL_RGBA4; - } else { - formats.color_texInternalFormat = LOCAL_GL_RGB; - formats.color_texFormat = LOCAL_GL_RGB; - formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_5_6_5; - formats.color_rbFormat = LOCAL_GL_RGB565; - } - } else { - formats.color_texType = LOCAL_GL_UNSIGNED_BYTE; - - if (caps.alpha) { - formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8; - formats.color_texFormat = LOCAL_GL_RGBA; - formats.color_rbFormat = LOCAL_GL_RGBA8; - } else { - formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGB : LOCAL_GL_RGB8; - formats.color_texFormat = LOCAL_GL_RGB; - formats.color_rbFormat = LOCAL_GL_RGB8; - } - } - - uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2); - GLsizei samples = msaaLevel * msaaLevel; - samples = std::min(samples, mMaxSamples); - - // Bug 778765. - if (WorkAroundDriverBugs() && samples == 1) { - samples = 0; - } - formats.samples = samples; - - - // Be clear that these are 0 if unavailable. - formats.depthStencil = 0; - if (!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil)) { - formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8; - } - - formats.depth = 0; - if (mIsGLES2) { - if (IsExtensionSupported(OES_depth24)) { - formats.depth = LOCAL_GL_DEPTH_COMPONENT24; - } else { - formats.depth = LOCAL_GL_DEPTH_COMPONENT16; - } - } else { - formats.depth = LOCAL_GL_DEPTH_COMPONENT24; - } - - formats.stencil = LOCAL_GL_STENCIL_INDEX8; - - return formats; -} - -GLuint -GLContext::CreateTextureForOffscreen(const GLFormats& formats, const gfxIntSize& size) -{ - MOZ_ASSERT(formats.color_texInternalFormat); - MOZ_ASSERT(formats.color_texFormat); - MOZ_ASSERT(formats.color_texType); - - return CreateTexture(formats.color_texInternalFormat, - formats.color_texFormat, - formats.color_texType, - size); -} - -GLuint -GLContext::CreateTexture(GLenum internalFormat, GLenum format, GLenum type, const gfxIntSize& size) -{ - GLuint tex = 0; - fGenTextures(1, &tex); - ScopedBindTexture autoTex(this, tex); - - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); - - fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - internalFormat, - size.width, size.height, - 0, - format, - type, - nullptr); - - return tex; -} - -static inline void -RenderbufferStorageBySamples(GLContext* gl, GLsizei samples, GLenum internalFormat, const gfxIntSize& size) -{ - if (samples) { - gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, - samples, - internalFormat, - size.width, size.height); - } else { - gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, - internalFormat, - size.width, size.height); - } -} - -GLuint -GLContext::CreateRenderbuffer(GLenum format, GLsizei samples, const gfxIntSize& size) -{ - GLuint rb = 0; - fGenRenderbuffers(1, &rb); - ScopedBindRenderbuffer autoRB(this, rb); - - RenderbufferStorageBySamples(this, samples, format, size); - - return rb; -} - -void -GLContext::CreateRenderbuffersForOffscreen(const GLFormats& formats, const gfxIntSize& size, - bool multisample, - GLuint* colorMSRB, GLuint* depthRB, GLuint* stencilRB) -{ - GLsizei samples = multisample ? formats.samples : 0; - if (colorMSRB) { - MOZ_ASSERT(formats.samples > 0); - MOZ_ASSERT(formats.color_rbFormat); - - *colorMSRB = CreateRenderbuffer(formats.color_rbFormat, samples, size); - } - - if (depthRB && - stencilRB && - formats.depthStencil) - { - *depthRB = CreateRenderbuffer(formats.depthStencil, samples, size); - *stencilRB = *depthRB; - } else { - if (depthRB) { - MOZ_ASSERT(formats.depth); - - *depthRB = CreateRenderbuffer(formats.depth, samples, size); - } - - if (stencilRB) { - MOZ_ASSERT(formats.stencil); - - *stencilRB = CreateRenderbuffer(formats.stencil, samples, size); - } - } -} - -bool -GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) -{ - MOZ_ASSERT(fb); - - ScopedBindFramebuffer autoFB(this, fb); - MOZ_ASSERT(fIsFramebuffer(fb)); - - GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (pStatus) - *pStatus = status; - - return status == LOCAL_GL_FRAMEBUFFER_COMPLETE; -} - -void -GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB, - GLuint depthRB, GLuint stencilRB, - GLuint fb) -{ - MOZ_ASSERT(fb); - MOZ_ASSERT( !(colorTex && colorRB) ); - - ScopedBindFramebuffer autoFB(this, fb); - MOZ_ASSERT(fIsFramebuffer(fb)); // It only counts after being bound. - - if (colorTex) { - MOZ_ASSERT(fIsTexture(colorTex)); - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - colorTex, - 0); - } else if (colorRB) { - MOZ_ASSERT(fIsRenderbuffer(colorRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, - colorRB); - } - - if (depthRB) { - MOZ_ASSERT(fIsRenderbuffer(depthRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - depthRB); - } - - if (stencilRB) { - MOZ_ASSERT(fIsRenderbuffer(stencilRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - stencilRB); - } -} - -bool -GLContext::AssembleOffscreenFBs(const GLuint colorMSRB, - const GLuint depthRB, - const GLuint stencilRB, - const GLuint texture, - GLuint* drawFB_out, - GLuint* readFB_out) -{ - if (!colorMSRB && !texture) { - MOZ_ASSERT(!depthRB && !stencilRB); - - if (drawFB_out) - *drawFB_out = 0; - if (readFB_out) - *readFB_out = 0; - - return true; - } - - ScopedBindFramebuffer autoFB(this); - - GLuint drawFB = 0; - GLuint readFB = 0; - - if (texture) { - readFB = 0; - fGenFramebuffers(1, &readFB); - BindFB(readFB); - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - texture, - 0); - } - - if (colorMSRB) { - drawFB = 0; - fGenFramebuffers(1, &drawFB); - BindFB(drawFB); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, - colorMSRB); - } else { - drawFB = readFB; - } - MOZ_ASSERT(GetFB() == drawFB); - - if (depthRB) { - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - depthRB); - } - - if (stencilRB) { - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - stencilRB); - } - - // We should be all resized. Check for framebuffer completeness. - GLenum status; - bool isComplete = true; - - if (!IsFramebufferComplete(drawFB, &status)) { - NS_WARNING("DrawFBO: Incomplete"); - #ifdef DEBUG - if (DebugMode()) { - printf_stderr("Framebuffer status: %X\n", status); - } - #endif - isComplete = false; - } - - if (!IsFramebufferComplete(readFB, &status)) { - NS_WARNING("ReadFBO: Incomplete"); - #ifdef DEBUG - if (DebugMode()) { - printf_stderr("Framebuffer status: %X\n", status); - } - #endif - isComplete = false; - } - - if (drawFB_out) { - *drawFB_out = drawFB; - } else if (drawFB) { - NS_RUNTIMEABORT("drawFB created when not requested!"); - } - - if (readFB_out) { - *readFB_out = readFB; - } else if (readFB) { - NS_RUNTIMEABORT("readFB created when not requested!"); - } - - return isComplete; -} - - - -bool -GLContext::PublishFrame() -{ - MOZ_ASSERT(mScreen); - - if (!mScreen->PublishFrame(OffscreenSize())) - return false; - - return true; -} - -SharedSurface* -GLContext::RequestFrame() -{ - MOZ_ASSERT(mScreen); - - return mScreen->Stream()->SwapConsumer(); -} - - - -void -GLContext::ClearSafely() -{ - // bug 659349 --- we must be very careful here: clearing a GL framebuffer is nontrivial, relies on a lot of state, - // and in the case of the backbuffer of a WebGL context, state is exposed to scripts. - // - // The code here is taken from WebGLContext::ForceClearFramebufferWithDefaultValues, but I didn't find a good way of - // sharing code with it. WebGL's code is somewhat performance-critical as it is typically called on every frame, so - // WebGL keeps track of GL state to avoid having to query it everytime, and also tries to only do work for actually - // present buffers (e.g. stencil buffer). Doing that here seems like premature optimization, - // as ClearSafely() is called only when e.g. a canvas is resized, not on every animation frame. - - realGLboolean scissorTestEnabled; - realGLboolean ditherEnabled; - realGLboolean colorWriteMask[4]; - realGLboolean depthWriteMask; - GLint stencilWriteMaskFront, stencilWriteMaskBack; - GLfloat colorClearValue[4]; - GLfloat depthClearValue; - GLint stencilClearValue; - - // save current GL state - fGetBooleanv(LOCAL_GL_SCISSOR_TEST, &scissorTestEnabled); - fGetBooleanv(LOCAL_GL_DITHER, &ditherEnabled); - fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask); - fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask); - fGetIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &stencilWriteMaskFront); - fGetIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack); - fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); - fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); - fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue); - - // prepare GL state for clearing - fDisable(LOCAL_GL_SCISSOR_TEST); - fDisable(LOCAL_GL_DITHER); - PushViewportRect(nsIntRect(0, 0, OffscreenSize().width, OffscreenSize().height)); - - fColorMask(1, 1, 1, 1); - fClearColor(0.f, 0.f, 0.f, 0.f); - - fDepthMask(1); - fClearDepth(1.0f); - - fStencilMask(0xffffffff); - fClearStencil(0); - - // do clear - fClear(LOCAL_GL_COLOR_BUFFER_BIT | - LOCAL_GL_DEPTH_BUFFER_BIT | - LOCAL_GL_STENCIL_BUFFER_BIT); - - // restore GL state after clearing - fColorMask(colorWriteMask[0], - colorWriteMask[1], - colorWriteMask[2], - colorWriteMask[3]); - fClearColor(colorClearValue[0], - colorClearValue[1], - colorClearValue[2], - colorClearValue[3]); - - fDepthMask(depthWriteMask); - fClearDepth(depthClearValue); - - fStencilMaskSeparate(LOCAL_GL_FRONT, stencilWriteMaskFront); - fStencilMaskSeparate(LOCAL_GL_BACK, stencilWriteMaskBack); - fClearStencil(stencilClearValue); - - PopViewportRect(); - - if (ditherEnabled) - fEnable(LOCAL_GL_DITHER); - else - fDisable(LOCAL_GL_DITHER); - - if (scissorTestEnabled) - fEnable(LOCAL_GL_SCISSOR_TEST); - else - fDisable(LOCAL_GL_SCISSOR_TEST); - -} - -void -GLContext::MarkDestroyed() -{ - if (IsDestroyed()) - return; - - if (MakeCurrent()) { - DestroyScreenBuffer(); - - // This is for Blit{Tex,FB}To{TexFB}. - DeleteTexBlitProgram(); - - // Likely used by OGL Layers. - fDeleteProgram(mBlitProgram); - mBlitProgram = 0; - fDeleteFramebuffers(1, &mBlitFramebuffer); - mBlitFramebuffer = 0; - - mTexGarbageBin->GLContextTeardown(); - } else { - NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown."); - } - - mSymbols.Zero(); -} - -static void SwapRAndBComponents(gfxImageSurface* surf) -{ - for (int j = 0; j < surf->Height(); ++j) { - uint32_t* row = (uint32_t*)(surf->Data() + surf->Stride() * j); - for (int i = 0; i < surf->Width(); ++i) { - *row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16); - row++; - } - } -} - -static already_AddRefed YInvertImageSurface(gfxImageSurface* aSurf) -{ - gfxIntSize size = aSurf->GetSize(); - nsRefPtr temp = new gfxImageSurface(size, aSurf->Format()); - nsRefPtr ctx = new gfxContext(temp); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->Scale(1.0, -1.0); - ctx->Translate(-gfxPoint(0.0, size.height)); - ctx->SetSource(aSurf); - ctx->Paint(); - return temp.forget(); -} - -already_AddRefed -GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader) -{ - MakeCurrent(); - GuaranteeResolve(); - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); - - gfxIntSize size; - fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width); - fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height); - - nsRefPtr surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32); - if (!surf || surf->CairoStatus()) { - return NULL; - } - - uint32_t currentPackAlignment = 0; - fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)¤tPackAlignment); - if (currentPackAlignment != 4) { - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); - } - fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->Data()); - if (currentPackAlignment != 4) { - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); - } - - if (aShader == RGBALayerProgramType || aShader == RGBXLayerProgramType) { - SwapRAndBComponents(surf); - } - - if (aYInvert) { - surf = YInvertImageSurface(surf); - } - return surf.forget(); -} - -already_AddRefed -GLContext::ReadTextureImage(GLuint aTexture, - const gfxIntSize& aSize, - GLenum aTextureFormat, - bool aYInvert) -{ - MakeCurrent(); - - nsRefPtr isurf; - - GLint oldrb, oldfb, oldprog, oldPackAlignment; - GLint success; - - GLuint rb = 0, fb = 0; - GLuint vs = 0, fs = 0, prog = 0; - - const char *vShader = - "attribute vec4 aVertex;\n" - "attribute vec2 aTexCoord;\n" - "varying vec2 vTexCoord;\n" - "void main() { gl_Position = aVertex; vTexCoord = aTexCoord; }"; - const char *fShader = - "#ifdef GL_ES\n" - "precision mediump float;\n" - "#endif\n" - "varying vec2 vTexCoord;\n" - "uniform sampler2D uTexture;\n" - "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"; - - float verts[4*4] = { - -1.0f, -1.0f, 0.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, - -1.0f, 1.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 0.0f, 1.0f - }; - - float texcoords[2*4] = { - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f - }; - - fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb); - fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb); - fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog); - fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &oldPackAlignment); - - PushViewportRect(nsIntRect(0, 0, aSize.width, aSize.height)); - - fGenRenderbuffers(1, &rb); - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb); - fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA, - aSize.width, aSize.height); - - fGenFramebuffers(1, &fb); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, rb); - - if (fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != - LOCAL_GL_FRAMEBUFFER_COMPLETE) - { - goto cleanup; - } - - vs = fCreateShader(LOCAL_GL_VERTEX_SHADER); - fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER); - fShaderSource(vs, 1, (const GLchar**) &vShader, NULL); - fShaderSource(fs, 1, (const GLchar**) &fShader, NULL); - fCompileShader(vs); - fCompileShader(fs); - prog = fCreateProgram(); - fAttachShader(prog, vs); - fAttachShader(prog, fs); - fBindAttribLocation(prog, 0, "aVertex"); - fBindAttribLocation(prog, 1, "aTexCoord"); - fLinkProgram(prog); - - fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, &success); - if (!success) { - goto cleanup; - } - - fUseProgram(prog); - - fEnableVertexAttribArray(0); - fEnableVertexAttribArray(1); - - fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, verts); - fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, texcoords); - - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); - - fUniform1i(fGetUniformLocation(prog, "uTexture"), 0); - - fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); - - fDisableVertexAttribArray(1); - fDisableVertexAttribArray(0); - - isurf = new gfxImageSurface(aSize, gfxASurface::ImageFormatARGB32); - if (!isurf || isurf->CairoStatus()) { - isurf = nullptr; - goto cleanup; - } - - if (oldPackAlignment != 4) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); - - fReadPixels(0, 0, aSize.width, aSize.height, - LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, - isurf->Data()); - - SwapRAndBComponents(isurf); - - if (oldPackAlignment != 4) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment); - - if (aYInvert) { - isurf = YInvertImageSurface(isurf); - } - - cleanup: - // note that deleting 0 has no effect in any of these calls - fDeleteRenderbuffers(1, &rb); - fDeleteFramebuffers(1, &fb); - fDeleteShader(vs); - fDeleteShader(fs); - fDeleteProgram(prog); - - fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb); - fUseProgram(oldprog); - - PopViewportRect(); - - return isurf.forget(); -} - -static bool -GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, - GLenum& readFormat, GLenum& readType) -{ - if (destFormat == LOCAL_GL_RGBA && - destType == LOCAL_GL_UNSIGNED_BYTE) - { - readFormat = destFormat; - readType = destType; - return true; - } - - bool fallback = true; - if (gl->IsGLES2()) { - GLenum auxFormat = 0; - GLenum auxType = 0; - - gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*)&auxFormat); - gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&auxType); - - if (destFormat == auxFormat && - destType == auxType) - { - fallback = false; - } - } else { - switch (destFormat) { - case LOCAL_GL_RGB: { - if (destType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV) - fallback = false; - break; - } - case LOCAL_GL_BGRA: { - if (destType == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) - fallback = false; - break; - } - } - } - - if (fallback) { - readFormat = LOCAL_GL_RGBA; - readType = LOCAL_GL_UNSIGNED_BYTE; - return false; - } else { - readFormat = destFormat; - readType = destType; - return true; - } -} - -void -GLContext::ReadScreenIntoImageSurface(gfxImageSurface* dest) -{ - ScopedBindFramebuffer autoFB(this, 0); - - ReadPixelsIntoImageSurface(dest); -} - -void -GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) -{ - MakeCurrent(); - MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0)); - - /* ImageFormatARGB32: - * RGBA+UByte: be[RGBA], le[ABGR] - * RGBA+UInt: le[RGBA] - * BGRA+UInt: le[BGRA] - * BGRA+UIntRev: le[ARGB] - * - * ImageFormatRGB16_565: - * RGB+UShort: le[rrrrrggg,gggbbbbb] - */ - bool hasAlpha = dest->Format() == gfxASurface::ImageFormatARGB32; - - int destPixelSize; - GLenum destFormat; - GLenum destType; - - switch (dest->Format()) { - case gfxASurface::ImageFormatRGB24: // XRGB - case gfxASurface::ImageFormatARGB32: - destPixelSize = 4; - // Needs host (little) endian ARGB. - destFormat = LOCAL_GL_BGRA; - destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; - break; - - case gfxASurface::ImageFormatRGB16_565: - destPixelSize = 2; - destFormat = LOCAL_GL_RGB; - destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; - break; - - default: - MOZ_NOT_REACHED("Bad format."); - return; - } - MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize); - - GLenum readFormat = destFormat; - GLenum readType = destType; - bool needsTempSurf = !GetActualReadFormats(this, - destFormat, destType, - readFormat, readType); - - nsAutoPtr tempSurf; - gfxImageSurface* readSurf = nullptr; - int readPixelSize = 0; - if (needsTempSurf) { - if (DebugMode()) { - NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); - } - gfxASurface::gfxImageFormat readFormatGFX; - - switch (readFormat) { - case LOCAL_GL_RGBA: - case LOCAL_GL_BGRA: { - readFormatGFX = hasAlpha ? gfxASurface::ImageFormatARGB32 - : gfxASurface::ImageFormatRGB24; - break; - } - case LOCAL_GL_RGB: { - MOZ_ASSERT(readPixelSize == 2); - MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); - readFormatGFX = gfxASurface::ImageFormatRGB16_565; - break; - } - default: { - MOZ_NOT_REACHED("Bad read format."); - return; - } - } - - switch (readType) { - case LOCAL_GL_UNSIGNED_BYTE: { - MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); - readPixelSize = 4; - break; - } - case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { - MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); - readPixelSize = 4; - break; - } - case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { - MOZ_ASSERT(readFormat == LOCAL_GL_RGB); - readPixelSize = 2; - break; - } - default: { - MOZ_NOT_REACHED("Bad read type."); - return; - } - } - - tempSurf = new gfxImageSurface(dest->GetSize(), readFormatGFX, false); - readSurf = tempSurf; - } else { - readPixelSize = destPixelSize; - readSurf = dest; - } - MOZ_ASSERT(readPixelSize); - - GLint currentPackAlignment = 0; - fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment); - - if (currentPackAlignment != readPixelSize) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize); - - GLsizei width = dest->Width(); - GLsizei height = dest->Height(); - - readSurf->Flush(); - fReadPixels(0, 0, - width, height, - readFormat, readType, - readSurf->Data()); - readSurf->MarkDirty(); - - if (currentPackAlignment != readPixelSize) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); - - if (readSurf != dest) { - MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); - MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); - // So we just copied in RGBA in big endian, or le: 0xAABBGGRR. - // We want 0xAARRGGBB, so swap R and B: - dest->Flush(); - SwapRAndBComponents(readSurf); - dest->MarkDirty(); - - gfxContext ctx(dest); - ctx.SetOperator(gfxContext::OPERATOR_SOURCE); - ctx.SetSource(readSurf); - ctx.Paint(); - } - - // Check if GL is giving back 1.0 alpha for - // RGBA reads to RGBA images from no-alpha buffers. -#ifdef XP_MACOSX - if (WorkAroundDriverBugs() && - mVendor == VendorNVIDIA && - dest->Format() == gfxASurface::ImageFormatARGB32 && - width && height) - { - GLint alphaBits = 0; - fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits); - if (!alphaBits) { - const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0); - - dest->Flush(); - uint32_t* itr = (uint32_t*)dest->Data(); - uint32_t testPixel = *itr; - if ((testPixel & alphaMask) != alphaMask) { - // We need to set the alpha channel to 1.0 manually. - uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4. - - for (; itr != itrEnd; itr++) { - *itr |= alphaMask; - } - } - dest->MarkDirty(); - } - } -#endif -} - -void -GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, - TextureImage *aDst, const nsIntRect& aDstRect) -{ - NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!"); - NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!"); - - if (aSrcRect.IsEmpty() || aDstRect.IsEmpty()) - return; - - // only save/restore this stuff on Qualcomm Adreno, to work - // around an apparent bug - int savedFb = 0; - if (mWorkAroundDriverBugs && - mVendor == VendorQualcomm) - { - fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb); - } - - fDisable(LOCAL_GL_SCISSOR_TEST); - fDisable(LOCAL_GL_BLEND); - - // 2.0 means scale up by two - float blitScaleX = float(aDstRect.width) / float(aSrcRect.width); - float blitScaleY = float(aDstRect.height) / float(aSrcRect.height); - - // We start iterating over all destination tiles - aDst->BeginTileIteration(); - do { - // calculate portion of the tile that is going to be painted to - nsIntRect dstSubRect; - nsIntRect dstTextureRect = aDst->GetTileRect(); - dstSubRect.IntersectRect(aDstRect, dstTextureRect); - - // this tile is not part of the destination rectangle aDstRect - if (dstSubRect.IsEmpty()) - continue; - - // (*) transform the rect of this tile into the rectangle defined by aSrcRect... - nsIntRect dstInSrcRect(dstSubRect); - dstInSrcRect.MoveBy(-aDstRect.TopLeft()); - // ...which might be of different size, hence scale accordingly - dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY); - dstInSrcRect.MoveBy(aSrcRect.TopLeft()); - - SetBlitFramebufferForDestTexture(aDst->GetTextureID()); - UseBlitProgram(); - - aSrc->BeginTileIteration(); - // now iterate over all tiles in the source Image... - do { - // calculate portion of the source tile that is in the source rect - nsIntRect srcSubRect; - nsIntRect srcTextureRect = aSrc->GetTileRect(); - srcSubRect.IntersectRect(aSrcRect, srcTextureRect); - - // this tile is not part of the source rect - if (srcSubRect.IsEmpty()) { - continue; - } - // calculate intersection of source rect with destination rect - srcSubRect.IntersectRect(srcSubRect, dstInSrcRect); - // this tile does not overlap the current destination tile - if (srcSubRect.IsEmpty()) { - continue; - } - // We now have the intersection of - // the current source tile - // and the desired source rectangle - // and the destination tile - // and the desired destination rectange - // in destination space. - // We need to transform this back into destination space, inverting the transform from (*) - nsIntRect srcSubInDstRect(srcSubRect); - srcSubInDstRect.MoveBy(-aSrcRect.TopLeft()); - srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY); - srcSubInDstRect.MoveBy(aDstRect.TopLeft()); - - // we transform these rectangles to be relative to the current src and dst tiles, respectively - nsIntSize srcSize = srcTextureRect.Size(); - nsIntSize dstSize = dstTextureRect.Size(); - srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y); - srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y); - - float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f; - float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f; - float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f; - float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f; - PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height)); - - RectTriangles rects; - - nsIntSize realTexSize = srcSize; - if (!CanUploadNonPowerOfTwo()) { - realTexSize = nsIntSize(NextPowerOfTwo(srcSize.width), - NextPowerOfTwo(srcSize.height)); - } - - if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) { - rects.addRect(/* dest rectangle */ - dx0, dy0, dx1, dy1, - /* tex coords */ - srcSubRect.x / float(realTexSize.width), - srcSubRect.y / float(realTexSize.height), - srcSubRect.XMost() / float(realTexSize.width), - srcSubRect.YMost() / float(realTexSize.height)); - } else { - DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects); - - // now put the coords into the d[xy]0 .. d[xy]1 coordinate space - // from the 0..1 that it comes out of decompose - RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer(); - - for (unsigned int i = 0; i < rects.elements(); ++i) { - v[i].x = (v[i].x * (dx1 - dx0)) + dx0; - v[i].y = (v[i].y * (dy1 - dy0)) + dy0; - } - } - - TextureImage::ScopedBindTexture texBind(aSrc, LOCAL_GL_TEXTURE0); - - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); - - fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer()); - fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer()); - - fEnableVertexAttribArray(0); - fEnableVertexAttribArray(1); - - fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); - - fDisableVertexAttribArray(0); - fDisableVertexAttribArray(1); - - PopViewportRect(); - } while (aSrc->NextTile()); - } while (aDst->NextTile()); - - fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL); - fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL); - - // unbind the previous texture from the framebuffer - SetBlitFramebufferForDestTexture(0); - - // then put back the previous framebuffer, and don't - // enable stencil if it wasn't enabled on entry to work - // around Adreno 200 bug that causes us to crash if - // we enable scissor test while the current FBO is invalid - // (which it will be, once we assign texture 0 to the color - // attachment) - if (mWorkAroundDriverBugs && - mVendor == VendorQualcomm) { - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb); - } - - fEnable(LOCAL_GL_SCISSOR_TEST); - fEnable(LOCAL_GL_BLEND); -} - -static unsigned int -DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint) -{ - unsigned int data = aPoint.y * aSurf->Stride(); - data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aSurf->Format()); - return data; -} - -ShaderProgramType -GLContext::UploadSurfaceToTexture(gfxASurface *aSurface, - const nsIntRegion& aDstRegion, - GLuint& aTexture, - bool aOverwrite, - const nsIntPoint& aSrcPoint, - bool aPixelBuffer, - GLenum aTextureUnit) -{ - bool textureInited = aOverwrite ? false : true; - MakeCurrent(); - fActiveTexture(aTextureUnit); - - if (!aTexture) { - fGenTextures(1, &aTexture); - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); - fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_MIN_FILTER, - LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_MAG_FILTER, - LOCAL_GL_LINEAR); - fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_WRAP_S, - LOCAL_GL_CLAMP_TO_EDGE); - fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_WRAP_T, - LOCAL_GL_CLAMP_TO_EDGE); - textureInited = false; - } else { - fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); - } - - nsIntRegion paintRegion; - if (!textureInited) { - paintRegion = nsIntRegion(aDstRegion.GetBounds()); - } else { - paintRegion = aDstRegion; - } - - nsRefPtr imageSurface = aSurface->GetAsImageSurface(); - unsigned char* data = NULL; - - if (!imageSurface || - (imageSurface->Format() != gfxASurface::ImageFormatARGB32 && - imageSurface->Format() != gfxASurface::ImageFormatRGB24 && - imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 && - imageSurface->Format() != gfxASurface::ImageFormatA8)) { - // We can't get suitable pixel data for the surface, make a copy - nsIntRect bounds = aDstRegion.GetBounds(); - imageSurface = - new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), - gfxASurface::ImageFormatARGB32); - - nsRefPtr context = new gfxContext(imageSurface); - - context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y)); - context->SetSource(aSurface); - context->Paint(); - data = imageSurface->Data(); - NS_ASSERTION(!aPixelBuffer, - "Must be using an image compatible surface with pixel buffers!"); - } else { - // If a pixel buffer is bound the data pointer parameter is relative - // to the start of the data block. - if (!aPixelBuffer) { - data = imageSurface->Data(); - } - data += DataOffset(imageSurface, aSrcPoint); - } - - MOZ_ASSERT(imageSurface); - imageSurface->Flush(); - - GLenum format; - GLenum type; - int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format()); - ShaderProgramType shader; - - switch (imageSurface->Format()) { - case gfxASurface::ImageFormatARGB32: - format = LOCAL_GL_RGBA; - type = LOCAL_GL_UNSIGNED_BYTE; - shader = BGRALayerProgramType; - break; - case gfxASurface::ImageFormatRGB24: - // Treat RGB24 surfaces as RGBA32 except for the shader - // program used. - format = LOCAL_GL_RGBA; - type = LOCAL_GL_UNSIGNED_BYTE; - shader = BGRXLayerProgramType; - break; - case gfxASurface::ImageFormatRGB16_565: - format = LOCAL_GL_RGB; - type = LOCAL_GL_UNSIGNED_SHORT_5_6_5; - shader = RGBALayerProgramType; - break; - case gfxASurface::ImageFormatA8: - format = LOCAL_GL_LUMINANCE; - type = LOCAL_GL_UNSIGNED_BYTE; - // We don't have a specific luminance shader - shader = ShaderProgramType(0); - break; - default: - NS_ASSERTION(false, "Unhandled image surface format!"); - format = 0; - type = 0; - shader = ShaderProgramType(0); - } - - int32_t stride = imageSurface->Stride(); - - nsIntRegionRectIterator iter(paintRegion); - const nsIntRect *iterRect; - - // Top left point of the region's bounding rectangle. - nsIntPoint topLeft = paintRegion.GetBounds().TopLeft(); - - while ((iterRect = iter.Next())) { - // The inital data pointer is at the top left point of the region's - // bounding rectangle. We need to find the offset of this rect - // within the region and adjust the data pointer accordingly. - unsigned char *rectData = - data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft); - - NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0), - "Must be uploading to the origin when we don't have an existing texture"); - - if (textureInited && CanUploadSubTextures()) { - TexSubImage2D(LOCAL_GL_TEXTURE_2D, - 0, - iterRect->x, - iterRect->y, - iterRect->width, - iterRect->height, - stride, - pixelSize, - format, - type, - rectData); - } else { - TexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - format, - iterRect->width, - iterRect->height, - stride, - pixelSize, - 0, - format, - type, - rectData); - } - - } - - return shader; -} - -static GLint GetAddressAlignment(ptrdiff_t aAddress) -{ - if (!(aAddress & 0x7)) { - return 8; - } else if (!(aAddress & 0x3)) { - return 4; - } else if (!(aAddress & 0x1)) { - return 2; - } else { - return 1; - } -} - -void -GLContext::TexImage2D(GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLsizei stride, - GLint pixelsize, GLint border, GLenum format, - GLenum type, const GLvoid *pixels) -{ - if (mIsGLES2) { - - NS_ASSERTION(format == (GLenum)internalformat, - "format and internalformat not the same for glTexImage2D on GLES2"); - - if (!CanUploadNonPowerOfTwo() - && (stride != width * pixelsize - || !IsPowerOfTwo(width) - || !IsPowerOfTwo(height))) { - - // Pad out texture width and height to the next power of two - // as we don't support/want non power of two texture uploads - GLsizei paddedWidth = NextPowerOfTwo(width); - GLsizei paddedHeight = NextPowerOfTwo(height); - - GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize]; - - // Pad out texture data to be in a POT sized buffer for uploading to - // a POT sized texture - CopyAndPadTextureData(pixels, paddedPixels, width, height, - paddedWidth, paddedHeight, stride, pixelsize); - - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)paddedPixels), - GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize))); - fTexImage2D(target, - border, - internalformat, - paddedWidth, - paddedHeight, - border, - format, - type, - paddedPixels); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); - - delete[] static_cast(paddedPixels); - return; - } - - if (stride == width * pixelsize) { - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)pixels), - GetAddressAlignment((ptrdiff_t)stride))); - fTexImage2D(target, - border, - internalformat, - width, - height, - border, - format, - type, - pixels); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); - } else { - // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are - // implemented in TexSubImage2D. - fTexImage2D(target, - border, - internalformat, - width, - height, - border, - format, - type, - NULL); - TexSubImage2D(target, - level, - 0, - 0, - width, - height, - stride, - pixelsize, - format, - type, - pixels); - } - } else { - // desktop GL (non-ES) path - - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)pixels), - GetAddressAlignment((ptrdiff_t)stride))); - int rowLength = stride/pixelsize; - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); - fTexImage2D(target, - level, - internalformat, - width, - height, - border, - format, - type, - pixels); - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); - } -} - -void -GLContext::TexSubImage2D(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLsizei stride, - GLint pixelsize, GLenum format, - GLenum type, const GLvoid* pixels) -{ - if (mIsGLES2) { - if (stride == width * pixelsize) { - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)pixels), - GetAddressAlignment((ptrdiff_t)stride))); - fTexSubImage2D(target, - level, - xoffset, - yoffset, - width, - height, - format, - type, - pixels); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); - } else if (IsExtensionSupported(EXT_unpack_subimage)) { - TexSubImage2DWithUnpackSubimageGLES(target, level, xoffset, yoffset, - width, height, stride, - pixelsize, format, type, pixels); - - } else { - TexSubImage2DWithoutUnpackSubimage(target, level, xoffset, yoffset, - width, height, stride, - pixelsize, format, type, pixels); - } - } else { - // desktop GL (non-ES) path - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)pixels), - GetAddressAlignment((ptrdiff_t)stride))); - int rowLength = stride/pixelsize; - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); - fTexSubImage2D(target, - level, - xoffset, - yoffset, - width, - height, - format, - type, - pixels); - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); - } -} - -void -GLContext::TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLsizei stride, GLint pixelsize, - GLenum format, GLenum type, - const GLvoid* pixels) -{ - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)pixels), - GetAddressAlignment((ptrdiff_t)stride))); - // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra - // driver crash where the driver apparently tries to read - // (stride - width * pixelsize) bytes past the end of the last input - // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH, - // and then we upload the final row separately. See bug 697990. - int rowLength = stride/pixelsize; - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); - fTexSubImage2D(target, - level, - xoffset, - yoffset, - width, - height-1, - format, - type, - pixels); - fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0); - fTexSubImage2D(target, - level, - xoffset, - yoffset+height-1, - width, - 1, - format, - type, - (const unsigned char *)pixels+(height-1)*stride); - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); -} - -void -GLContext::TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLsizei stride, GLint pixelsize, - GLenum format, GLenum type, - const GLvoid* pixels) -{ - // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH - // isn't supported. We make a copy of the texture data we're using, - // such that we're using the whole row of data in the copy. This turns - // out to be more efficient than uploading row-by-row; see bug 698197. - unsigned char *newPixels = new unsigned char[width*height*pixelsize]; - unsigned char *rowDest = newPixels; - const unsigned char *rowSource = (const unsigned char *)pixels; - for (int h = 0; h < height; h++) { - memcpy(rowDest, rowSource, width*pixelsize); - rowDest += width*pixelsize; - rowSource += stride; - } - - stride = width*pixelsize; - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, - std::min(GetAddressAlignment((ptrdiff_t)newPixels), - GetAddressAlignment((ptrdiff_t)stride))); - fTexSubImage2D(target, - level, - xoffset, - yoffset, - width, - height, - format, - type, - newPixels); - delete [] newPixels; - fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); -} - -void -GLContext::RectTriangles::addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, - GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1, - bool flip_y /* = false */) -{ - vert_coord v; - v.x = x0; v.y = y0; - vertexCoords.AppendElement(v); - v.x = x1; v.y = y0; - vertexCoords.AppendElement(v); - v.x = x0; v.y = y1; - vertexCoords.AppendElement(v); - - v.x = x0; v.y = y1; - vertexCoords.AppendElement(v); - v.x = x1; v.y = y0; - vertexCoords.AppendElement(v); - v.x = x1; v.y = y1; - vertexCoords.AppendElement(v); - - if (flip_y) { - tex_coord t; - t.u = tx0; t.v = ty1; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty1; - texCoords.AppendElement(t); - t.u = tx0; t.v = ty0; - texCoords.AppendElement(t); - - t.u = tx0; t.v = ty0; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty1; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty0; - texCoords.AppendElement(t); - } else { - tex_coord t; - t.u = tx0; t.v = ty0; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty0; - texCoords.AppendElement(t); - t.u = tx0; t.v = ty1; - texCoords.AppendElement(t); - - t.u = tx0; t.v = ty1; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty0; - texCoords.AppendElement(t); - t.u = tx1; t.v = ty1; - texCoords.AppendElement(t); - } -} - -static GLfloat -WrapTexCoord(GLfloat v) -{ - // fmodf gives negative results for negative numbers; - // that is, fmodf(0.75, 1.0) == 0.75, but - // fmodf(-0.75, 1.0) == -0.75. For the negative case, - // the result we need is 0.25, so we add 1.0f. - if (v < 0.0f) { - return 1.0f + fmodf(v, 1.0f); - } - - return fmodf(v, 1.0f); -} - -void -GLContext::DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect, - const nsIntSize& aTexSize, - RectTriangles& aRects, - bool aFlipY /* = false */) -{ - // normalize this - nsIntRect tcr(aTexCoordRect); - while (tcr.x >= aTexSize.width) - tcr.x -= aTexSize.width; - while (tcr.y >= aTexSize.height) - tcr.y -= aTexSize.height; - - // Compute top left and bottom right tex coordinates - GLfloat tl[2] = - { GLfloat(tcr.x) / GLfloat(aTexSize.width), - GLfloat(tcr.y) / GLfloat(aTexSize.height) }; - GLfloat br[2] = - { GLfloat(tcr.XMost()) / GLfloat(aTexSize.width), - GLfloat(tcr.YMost()) / GLfloat(aTexSize.height) }; - - // then check if we wrap in either the x or y axis; if we do, - // then also use fmod to figure out the "true" non-wrapping - // texture coordinates. - - bool xwrap = false, ywrap = false; - if (tcr.x < 0 || tcr.x > aTexSize.width || - tcr.XMost() < 0 || tcr.XMost() > aTexSize.width) - { - xwrap = true; - tl[0] = WrapTexCoord(tl[0]); - br[0] = WrapTexCoord(br[0]); - } - - if (tcr.y < 0 || tcr.y > aTexSize.height || - tcr.YMost() < 0 || tcr.YMost() > aTexSize.height) - { - ywrap = true; - tl[1] = WrapTexCoord(tl[1]); - br[1] = WrapTexCoord(br[1]); - } - - NS_ASSERTION(tl[0] >= 0.0f && tl[0] <= 1.0f && - tl[1] >= 0.0f && tl[1] <= 1.0f && - br[0] >= 0.0f && br[0] <= 1.0f && - br[1] >= 0.0f && br[1] <= 1.0f, - "Somehow generated invalid texture coordinates"); - - // If xwrap is false, the texture will be sampled from tl[0] - // .. br[0]. If xwrap is true, then it will be split into tl[0] - // .. 1.0, and 0.0 .. br[0]. Same for the Y axis. The - // destination rectangle is also split appropriately, according - // to the calculated xmid/ymid values. - - // There isn't a 1:1 mapping between tex coords and destination coords; - // when computing midpoints, we have to take that into account. We - // need to map the texture coords, which are (in the wrap case): - // |tl->1| and |0->br| to the |0->1| range of the vertex coords. So - // we have the length (1-tl)+(br) that needs to map into 0->1. - // These are only valid if there is wrap involved, they won't be used - // otherwise. - GLfloat xlen = (1.0f - tl[0]) + br[0]; - GLfloat ylen = (1.0f - tl[1]) + br[1]; - - NS_ASSERTION(!xwrap || xlen > 0.0f, "xlen isn't > 0, what's going on?"); - NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?"); - NS_ASSERTION(aTexCoordRect.width <= aTexSize.width && - aTexCoordRect.height <= aTexSize.height, "tex coord rect would cause tiling!"); - - if (!xwrap && !ywrap) { - aRects.addRect(0.0f, 0.0f, - 1.0f, 1.0f, - tl[0], tl[1], - br[0], br[1], - aFlipY); - } else if (!xwrap && ywrap) { - GLfloat ymid = (1.0f - tl[1]) / ylen; - aRects.addRect(0.0f, 0.0f, - 1.0f, ymid, - tl[0], tl[1], - br[0], 1.0f, - aFlipY); - aRects.addRect(0.0f, ymid, - 1.0f, 1.0f, - tl[0], 0.0f, - br[0], br[1], - aFlipY); - } else if (xwrap && !ywrap) { - GLfloat xmid = (1.0f - tl[0]) / xlen; - aRects.addRect(0.0f, 0.0f, - xmid, 1.0f, - tl[0], tl[1], - 1.0f, br[1], - aFlipY); - aRects.addRect(xmid, 0.0f, - 1.0f, 1.0f, - 0.0f, tl[1], - br[0], br[1], - aFlipY); - } else { - GLfloat xmid = (1.0f - tl[0]) / xlen; - GLfloat ymid = (1.0f - tl[1]) / ylen; - aRects.addRect(0.0f, 0.0f, - xmid, ymid, - tl[0], tl[1], - 1.0f, 1.0f, - aFlipY); - aRects.addRect(xmid, 0.0f, - 1.0f, ymid, - 0.0f, tl[1], - br[0], 1.0f, - aFlipY); - aRects.addRect(0.0f, ymid, - xmid, 1.0f, - tl[0], 0.0f, - 1.0f, br[1], - aFlipY); - aRects.addRect(xmid, ymid, - 1.0f, 1.0f, - 0.0f, 0.0f, - br[0], br[1], - aFlipY); - } -} - -void -GLContext::UseBlitProgram() -{ - if (mBlitProgram) { - fUseProgram(mBlitProgram); - return; - } - - mBlitProgram = fCreateProgram(); - - GLuint shaders[2]; - shaders[0] = fCreateShader(LOCAL_GL_VERTEX_SHADER); - shaders[1] = fCreateShader(LOCAL_GL_FRAGMENT_SHADER); - - const char *blitVSSrc = - "attribute vec2 aVertex;" - "attribute vec2 aTexCoord;" - "varying vec2 vTexCoord;" - "void main() {" - " vTexCoord = aTexCoord;" - " gl_Position = vec4(aVertex, 0.0, 1.0);" - "}"; - const char *blitFSSrc = "#ifdef GL_ES\nprecision mediump float;\n#endif\n" - "uniform sampler2D uSrcTexture;" - "varying vec2 vTexCoord;" - "void main() {" - " gl_FragColor = texture2D(uSrcTexture, vTexCoord);" - "}"; - - fShaderSource(shaders[0], 1, (const GLchar**) &blitVSSrc, NULL); - fShaderSource(shaders[1], 1, (const GLchar**) &blitFSSrc, NULL); - - for (int i = 0; i < 2; ++i) { - GLint success, len = 0; - - fCompileShader(shaders[i]); - fGetShaderiv(shaders[i], LOCAL_GL_COMPILE_STATUS, &success); - NS_ASSERTION(success, "Shader compilation failed!"); - - if (!success) { - nsAutoCString log; - fGetShaderiv(shaders[i], LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); - log.SetCapacity(len); - fGetShaderInfoLog(shaders[i], len, (GLint*) &len, (char*) log.BeginWriting()); - log.SetLength(len); - - printf_stderr("Shader %d compilation failed:\n%s\n", log.get()); - return; - } - - fAttachShader(mBlitProgram, shaders[i]); - fDeleteShader(shaders[i]); - } - - fBindAttribLocation(mBlitProgram, 0, "aVertex"); - fBindAttribLocation(mBlitProgram, 1, "aTexCoord"); - - fLinkProgram(mBlitProgram); - - GLint success, len = 0; - fGetProgramiv(mBlitProgram, LOCAL_GL_LINK_STATUS, &success); - NS_ASSERTION(success, "Shader linking failed!"); - - if (!success) { - nsAutoCString log; - fGetProgramiv(mBlitProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); - log.SetCapacity(len); - fGetProgramInfoLog(mBlitProgram, len, (GLint*) &len, (char*) log.BeginWriting()); - log.SetLength(len); - - printf_stderr("Program linking failed:\n%s\n", log.get()); - return; - } - - fUseProgram(mBlitProgram); - fUniform1i(fGetUniformLocation(mBlitProgram, "uSrcTexture"), 0); -} - -void -GLContext::SetBlitFramebufferForDestTexture(GLuint aTexture) -{ - if (!mBlitFramebuffer) { - fGenFramebuffers(1, &mBlitFramebuffer); - } - - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBlitFramebuffer); - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - aTexture, - 0); - - GLenum result = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (aTexture && (result != LOCAL_GL_FRAMEBUFFER_COMPLETE)) { - nsAutoCString msg; - msg.Append("Framebuffer not complete -- error 0x"); - msg.AppendInt(result, 16); - // Note: if you are hitting this, it is likely that - // your texture is not texture complete -- that is, you - // allocated a texture name, but didn't actually define its - // size via a call to TexImage2D. - NS_RUNTIMEABORT(msg.get()); - } -} - -#ifdef DEBUG - -void -GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName) -{ - mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName)); -} - -void -GLContext::CreatedShader(GLContext *aOrigin, GLuint aName) -{ - mTrackedShaders.AppendElement(NamedResource(aOrigin, aName)); -} - -void -GLContext::CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - for (GLsizei i = 0; i < aCount; ++i) { - mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i])); - } -} - -void -GLContext::CreatedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - for (GLsizei i = 0; i < aCount; ++i) { - mTrackedQueries.AppendElement(NamedResource(aOrigin, aNames[i])); - } -} - -void -GLContext::CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - for (GLsizei i = 0; i < aCount; ++i) { - mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i])); - } -} - -void -GLContext::CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - for (GLsizei i = 0; i < aCount; ++i) { - mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i])); - } -} - -void -GLContext::CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - for (GLsizei i = 0; i < aCount; ++i) { - mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i])); - } -} - -static void -RemoveNamesFromArray(GLContext *aOrigin, GLsizei aCount, GLuint *aNames, nsTArray& aArray) -{ - for (GLsizei j = 0; j < aCount; ++j) { - GLuint name = aNames[j]; - // name 0 can be ignored - if (name == 0) - continue; - - for (uint32_t i = 0; i < aArray.Length(); ++i) { - if (aArray[i].name == name) { - aArray.RemoveElementAt(i); - break; - } - } - } -} - -void -GLContext::DeletedProgram(GLContext *aOrigin, GLuint aName) -{ - RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms); -} - -void -GLContext::DeletedShader(GLContext *aOrigin, GLuint aName) -{ - RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders); -} - -void -GLContext::DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers); -} - -void -GLContext::DeletedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedQueries); -} - -void -GLContext::DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures); -} - -void -GLContext::DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers); -} - -void -GLContext::DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames) -{ - RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers); -} - -static void -MarkContextDestroyedInArray(GLContext *aContext, nsTArray& aArray) -{ - for (uint32_t i = 0; i < aArray.Length(); ++i) { - if (aArray[i].origin == aContext) - aArray[i].originDeleted = true; - } -} - -void -GLContext::SharedContextDestroyed(GLContext *aChild) -{ - MarkContextDestroyedInArray(aChild, mTrackedPrograms); - MarkContextDestroyedInArray(aChild, mTrackedShaders); - MarkContextDestroyedInArray(aChild, mTrackedTextures); - MarkContextDestroyedInArray(aChild, mTrackedFramebuffers); - MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers); - MarkContextDestroyedInArray(aChild, mTrackedBuffers); - MarkContextDestroyedInArray(aChild, mTrackedQueries); -} - -static void -ReportArrayContents(const char *title, const nsTArray& aArray) -{ - if (aArray.Length() == 0) - return; - - printf_stderr("%s:\n", title); - - nsTArray copy(aArray); - copy.Sort(); - - GLContext *lastContext = NULL; - for (uint32_t i = 0; i < copy.Length(); ++i) { - if (lastContext != copy[i].origin) { - if (lastContext) - printf_stderr("\n"); - printf_stderr(" [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live"); - lastContext = copy[i].origin; - } - printf_stderr("%d ", copy[i].name); - } - printf_stderr("\n"); -} - -void -GLContext::ReportOutstandingNames() -{ - if (!DebugMode()) - return; - - printf_stderr("== GLContext %p Outstanding ==\n", this); - - ReportArrayContents("Outstanding Textures", mTrackedTextures); - ReportArrayContents("Outstanding Buffers", mTrackedBuffers); - ReportArrayContents("Outstanding Queries", mTrackedQueries); - ReportArrayContents("Outstanding Programs", mTrackedPrograms); - ReportArrayContents("Outstanding Shaders", mTrackedShaders); - ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers); - ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers); -} - -#endif /* DEBUG */ - - -void -GLContext::GuaranteeResolve() -{ - mScreen->AssureBlitted(); - fFinish(); -} - -const gfxIntSize& -GLContext::OffscreenSize() const -{ - MOZ_ASSERT(IsOffscreen()); - return mScreen->Size(); -} - -bool -GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps) -{ - GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps); - if (!newScreen) - return false; - - if (!newScreen->Resize(size)) { - delete newScreen; - return false; - } - - DestroyScreenBuffer(); - - // This will rebind to 0 (Screen) if needed when - // it falls out of scope. - ScopedBindFramebuffer autoFB(this); - - mScreen = newScreen; - - return true; -} - -bool -GLContext::ResizeScreenBuffer(const gfxIntSize& size) -{ - if (!IsOffscreenSizeAllowed(size)) - return false; - - return mScreen->Resize(size); -} - - -void -GLContext::DestroyScreenBuffer() -{ - delete mScreen; - mScreen = nullptr; -} - -void -GLContext::ForceDirtyScreen() -{ - ScopedBindFramebuffer autoFB(0); - - BeforeGLDrawCall(); - // no-op; just pretend we did something - AfterGLDrawCall(); -} - -void -GLContext::CleanDirtyScreen() -{ - ScopedBindFramebuffer autoFB(0); - - BeforeGLReadCall(); - // no-op; we just want to make sure the Read FBO is updated if it needs to be - AfterGLReadCall(); -} - -void -GLContext::EmptyTexGarbageBin() -{ - TexGarbageBin()->EmptyGarbage(); -} - - -void -TextureGarbageBin::GLContextTeardown() -{ - EmptyGarbage(); - - MutexAutoLock lock(mMutex); - mGL = nullptr; -} - -void -TextureGarbageBin::Trash(GLuint tex) -{ - MutexAutoLock lock(mMutex); - if (!mGL) - return; - - mGarbageTextures.push(tex); -} - -void -TextureGarbageBin::EmptyGarbage() -{ - MutexAutoLock lock(mMutex); - if (!mGL) - return; - - while (!mGarbageTextures.empty()) { - GLuint tex = mGarbageTextures.top(); - mGarbageTextures.pop(); - mGL->fDeleteTextures(1, &tex); - } -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLContext.h b/libazure/src/gfx/gl/GLContext.h deleted file mode 100644 index 5781e45..0000000 --- a/libazure/src/gfx/gl/GLContext.h +++ /dev/null @@ -1,3280 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLCONTEXT_H_ -#define GLCONTEXT_H_ - -#include -#include -#if defined(XP_UNIX) -#include -#endif -#include -#include -#include -#include - -#ifdef WIN32 -#include -#endif - -#include "GLDefs.h" -#include "GLLibraryLoader.h" -#include "gfxASurface.h" -#include "gfxImageSurface.h" -#include "gfxContext.h" -#include "gfxRect.h" -#include "gfx3DMatrix.h" -#include "nsISupportsImpl.h" -#include "prlink.h" -#include "plstr.h" - -#include "nsDataHashtable.h" -#include "nsHashKeys.h" -#include "nsRegion.h" -#include "nsAutoPtr.h" -#include "nsThreadUtils.h" -#include "GLContextTypes.h" -#include "GLTextureImage.h" -#include "SurfaceTypes.h" -#include "GLScreenBuffer.h" - -typedef char realGLboolean; - -#include "GLContextSymbols.h" - -#include "mozilla/mozalloc.h" -#include "mozilla/Preferences.h" -#include "mozilla/StandardInteger.h" -#include "mozilla/Mutex.h" - -namespace android { - class GraphicBuffer; -} - -namespace mozilla { - namespace gfx { - class SharedSurface; - struct SurfaceCaps; - } - - namespace gl { - class GLContext; - class GLLibraryEGL; - class GLScreenBuffer; - class TextureGarbageBin; - } - - namespace layers { - class ColorTextureLayerProgram; - class LayerManagerOGL; - } -} - -namespace mozilla { -namespace gl { -typedef uintptr_t SharedTextureHandle; - -class GLContext - : public GLLibraryLoader -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext) - -protected: - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SharedSurfaceType SharedSurfaceType; - -public: - typedef struct gfx::SurfaceCaps SurfaceCaps; - - GLContext(const SurfaceCaps& caps, - GLContext* sharedContext = nullptr, - bool isOffscreen = false) - : mTexBlit_Buffer(0), - mTexBlit_VertShader(0), - mTexBlit_FragShader(0), - mTexBlit_Program(0), - mTexBlit_UseDrawNotCopy(false), - mInitialized(false), - mIsOffscreen(isOffscreen), - mIsGLES2(false), - mIsGlobalSharedContext(false), - mHasRobustness(false), - mContextLost(false), - mVendor(-1), - mRenderer(-1), - mSharedContext(sharedContext), - mFlipped(false), - mBlitProgram(0), - mBlitFramebuffer(0), - mCaps(caps), - mScreen(nullptr), - mLockedSurface(nullptr), - mMaxTextureSize(0), - mMaxCubeMapTextureSize(0), - mMaxTextureImageSize(0), - mMaxRenderbufferSize(0), - mNeedsTextureSizeChecks(false), - mWorkAroundDriverBugs(true) -#ifdef DEBUG - , mGLError(LOCAL_GL_NO_ERROR) -#endif - { - mUserData.Init(); - mOwningThread = NS_GetCurrentThread(); - - mTexBlit_UseDrawNotCopy = Preferences::GetBool("gl.blit-draw-not-copy", false); - } - - virtual ~GLContext() { - NS_ASSERTION(IsDestroyed(), "GLContext implementation must call MarkDestroyed in destructor!"); -#ifdef DEBUG - if (mSharedContext) { - GLContext *tip = mSharedContext; - while (tip->mSharedContext) - tip = tip->mSharedContext; - tip->SharedContextDestroyed(this); - tip->ReportOutstandingNames(); - } else { - ReportOutstandingNames(); - } -#endif - } - - enum ContextFlags { - ContextFlagsNone = 0x0, - ContextFlagsGlobal = 0x1, - ContextFlagsMesaLLVMPipe = 0x2 - }; - - enum GLContextType { - ContextTypeUnknown, - ContextTypeWGL, - ContextTypeCGL, - ContextTypeGLX, - ContextTypeEGL - }; - - virtual GLContextType GetContextType() { return ContextTypeUnknown; } - - virtual bool MakeCurrentImpl(bool aForce = false) = 0; - -#ifdef DEBUG - static void StaticInit() { - PR_NewThreadPrivateIndex(&sCurrentGLContextTLS, NULL); - } -#endif - - bool MakeCurrent(bool aForce = false) { -#ifdef DEBUG - PR_SetThreadPrivate(sCurrentGLContextTLS, this); - - // XXX this assertion is disabled because it's triggering on Mac; - // we need to figure out why and reenable it. -#if 0 - // IsOwningThreadCurrent is a bit of a misnomer; - // the "owning thread" is the creation thread, - // and the only thread that can own this. We don't - // support contexts used on multiple threads. - NS_ASSERTION(IsOwningThreadCurrent(), - "MakeCurrent() called on different thread than this context was created on!"); -#endif -#endif - return MakeCurrentImpl(aForce); - } - - virtual bool IsCurrent() = 0; - - bool IsContextLost() { return mContextLost; } - - virtual bool SetupLookupFunction() = 0; - - virtual void ReleaseSurface() {} - - void *GetUserData(void *aKey) { - void *result = nullptr; - mUserData.Get(aKey, &result); - return result; - } - - void SetUserData(void *aKey, void *aValue) { - mUserData.Put(aKey, aValue); - } - - // Mark this context as destroyed. This will NULL out all - // the GL function pointers! - void THEBES_API MarkDestroyed(); - - bool IsDestroyed() { - // MarkDestroyed will mark all these as null. - return mSymbols.fUseProgram == nullptr; - } - - enum NativeDataType { - NativeGLContext, - NativeImageSurface, - NativeThebesSurface, - NativeDataTypeMax - }; - - virtual void *GetNativeData(NativeDataType aType) { return NULL; } - GLContext *GetSharedContext() { return mSharedContext; } - - bool IsGlobalSharedContext() { return mIsGlobalSharedContext; } - void SetIsGlobalSharedContext(bool aIsOne) { mIsGlobalSharedContext = aIsOne; } - - /** - * Returns true if the thread on which this context was created is the currently - * executing thread. - */ - bool IsOwningThreadCurrent() { return NS_GetCurrentThread() == mOwningThread; } - - void DispatchToOwningThread(nsIRunnable *event) { - // Before dispatching, we need to ensure we're not in the middle of - // shutting down. Dispatching runnables in the middle of shutdown - // (that is, when the main thread is no longer get-able) can cause them - // to leak. See Bug 741319, and Bug 744115. - nsCOMPtr mainThread; - if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) { - mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL); - } - } - - virtual EGLContext GetEGLContext() { return nullptr; } - virtual GLLibraryEGL* GetLibraryEGL() { return nullptr; } - - virtual void MakeCurrent_EGLSurface(void* surf) { - MOZ_NOT_REACHED("Must be called against a GLContextEGL."); - } - - /** - * If this context is double-buffered, returns TRUE. - */ - virtual bool IsDoubleBuffered() { return false; } - - /** - * If this context is the GLES2 API, returns TRUE. - * This means that various GLES2 restrictions might be in effect (modulo - * extensions). - */ - bool IsGLES2() const { - return mIsGLES2; - } - - /** - * Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension - */ - bool HasES2Compatibility() { - return mIsGLES2 || IsExtensionSupported(ARB_ES2_compatibility); - } - - /** - * Returns true if the context is using ANGLE. This should only be overridden for an ANGLE - * implementation. - */ - virtual bool IsANGLE() { - return false; - } - - /** - * The derived class is expected to provide information on whether or not it - * supports robustness. - */ - virtual bool SupportsRobustness() = 0; - - enum { - VendorIntel, - VendorNVIDIA, - VendorATI, - VendorQualcomm, - VendorImagination, - VendorNouveau, - VendorOther - }; - - enum { - RendererAdreno200, - RendererAdreno205, - RendererAdreno320, - RendererSGX530, - RendererSGX540, - RendererOther - }; - - int Vendor() const { - return mVendor; - } - - int Renderer() const { - return mRenderer; - } - - bool CanUploadSubTextures(); - - static void PlatformStartup(); - -protected: - static bool sPowerOfTwoForced; - static bool sPowerOfTwoPrefCached; - static void CacheCanUploadNPOT(); - -public: - bool CanUploadNonPowerOfTwo(); - - bool WantsSmallTiles(); - virtual bool HasLockSurface() { return false; } - - /** - * If this context wraps a double-buffered target, swap the back - * and front buffers. It should be assumed that after a swap, the - * contents of the new back buffer are undefined. - */ - virtual bool SwapBuffers() { return false; } - - /** - * Defines a two-dimensional texture image for context target surface - */ - virtual bool BindTexImage() { return false; } - /* - * Releases a color buffer that is being used as a texture - */ - virtual bool ReleaseTexImage() { return false; } - - /** - * Applies aFilter to the texture currently bound to GL_TEXTURE_2D. - */ - void ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter); - - /** - * Applies aFilter to the texture currently bound to aTarget. - */ - void ApplyFilterToBoundTexture(GLuint aTarget, - gfxPattern::GraphicsFilter aFilter); - - virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; } - virtual bool UnbindExternalBuffer(GLuint texture) { return false; } - - virtual already_AddRefed - CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode) - { return nullptr; } - - // Before reads from offscreen texture - void GuaranteeResolve(); - -protected: - GLuint mTexBlit_Buffer; - GLuint mTexBlit_VertShader; - GLuint mTexBlit_FragShader; - GLuint mTexBlit_Program; - - bool mTexBlit_UseDrawNotCopy; - - bool UseTexQuadProgram(); - void DeleteTexBlitProgram(); - -public: - // If you don't have |srcFormats| for the 2nd definition, - // then you'll need the framebuffer_blit extensions to use - // the first BlitFramebufferToFramebuffer. - void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize); - void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, - const GLFormats& srcFormats); - void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize); - void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize); - void BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize); - - /* - * Resize the current offscreen buffer. Returns true on success. - * If it returns false, the context should be treated as unusable - * and should be recreated. After the resize, the viewport is not - * changed; glViewport should be called as appropriate. - * - * Only valid if IsOffscreen() returns true. - */ - virtual bool ResizeOffscreen(const gfxIntSize& size) { - return ResizeScreenBuffer(size); - } - - /* - * Return size of this offscreen context. - * - * Only valid if IsOffscreen() returns true. - */ - const gfxIntSize& OffscreenSize() const; - - virtual bool SupportsFramebufferMultisample() const { - return IsExtensionSupported(EXT_framebuffer_multisample) || - IsExtensionSupported(ANGLE_framebuffer_multisample); - } - - virtual bool SupportsSplitFramebuffer() { - return IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit); - } - - - enum SharedTextureShareType { - SameProcess = 0, - CrossProcess - }; - - enum SharedTextureBufferType { - TextureID -#ifdef MOZ_WIDGET_ANDROID - , SurfaceTexture -#endif - }; - - /** - * Create new shared GLContext content handle, must be released by ReleaseSharedHandle. - */ - virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType) - { return 0; } - /* - * Create a new shared GLContext content handle, using the passed buffer as a source. - * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect - * on handles created with this method, as the caller owns the source (the passed buffer) - * and is responsible for updating it accordingly. - */ - virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType, - void* buffer, - SharedTextureBufferType bufferType) - { return 0; } - /** - * Publish GLContext content to intermediate buffer attached to shared handle. - * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required. - * GLContext must be current before this call - */ - virtual void UpdateSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) - { } - /** - * - It is better to call ReleaseSharedHandle before original GLContext destroyed, - * otherwise warning will be thrown on attempt to destroy Texture associated with SharedHandle, depends on backend implementation. - * - It does not require to be called on context where it was created, - * because SharedHandle suppose to keep Context reference internally, - * or don't require specific context at all, for example IPC SharedHandle. - * - Not recommended to call this between AttachSharedHandle and Draw Target call. - * if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation. - * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release, - * otherwise some artifacts might appear or even crash if API backend implementation does not expect that. - * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed - * at any time, unless EGLImage have siblings (which are not expected with current API). - */ - virtual void ReleaseSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) - { } - - - typedef struct { - GLenum mTarget; - ShaderProgramType mProgramType; - gfx3DMatrix mTextureTransform; - } SharedHandleDetails; - - /** - * Returns information necessary for rendering a shared handle. - * These values change depending on what sharing mechanism is in use - */ - virtual bool GetSharedHandleDetails(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle, - SharedHandleDetails& details) - { return false; } - /** - * Attach Shared GL Handle to GL_TEXTURE_2D target - * GLContext must be current before this call - */ - virtual bool AttachSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) - { return false; } - - /** - * Detach Shared GL Handle from GL_TEXTURE_2D target - */ - virtual void DetachSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) - { } - - void fBindFramebuffer(GLenum target, GLuint framebuffer) { - if (!mScreen) { - raw_fBindFramebuffer(target, framebuffer); - return; - } - - switch (target) { - case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: - mScreen->BindDrawFB(framebuffer); - return; - - case LOCAL_GL_READ_FRAMEBUFFER_EXT: - mScreen->BindReadFB(framebuffer); - return; - - case LOCAL_GL_FRAMEBUFFER: - mScreen->BindFB(framebuffer); - return; - - default: - // Nothing we care about, likely an error. - break; - } - - raw_fBindFramebuffer(target, framebuffer); - } - - void BindFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); - MOZ_ASSERT(!fb || fIsFramebuffer(fb)); - } - - void BindDrawFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); - } - - void BindReadFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); - } - - void fGetIntegerv(GLenum pname, GLint *params) { - switch (pname) - { - // LOCAL_GL_FRAMEBUFFER_BINDING is equal to - // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, - // so we don't need two cases. - case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT: - if (mScreen) { - *params = mScreen->GetDrawFB(); - } else { - raw_fGetIntegerv(pname, params); - } - break; - - case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT: - if (mScreen) { - *params = mScreen->GetReadFB(); - } else { - raw_fGetIntegerv(pname, params); - } - break; - - case LOCAL_GL_MAX_TEXTURE_SIZE: - MOZ_ASSERT(mMaxTextureSize>0); - *params = mMaxTextureSize; - break; - - case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: - MOZ_ASSERT(mMaxCubeMapTextureSize>0); - *params = mMaxCubeMapTextureSize; - break; - - case LOCAL_GL_MAX_RENDERBUFFER_SIZE: - MOZ_ASSERT(mMaxRenderbufferSize>0); - *params = mMaxRenderbufferSize; - break; - - default: - raw_fGetIntegerv(pname, params); - break; - } - } - - GLuint GetDrawFB() { - if (mScreen) - return mScreen->GetDrawFB(); - - GLuint ret = 0; - GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret); - return ret; - } - - GLuint GetReadFB() { - if (mScreen) - return mScreen->GetReadFB(); - - GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT - : LOCAL_GL_FRAMEBUFFER_BINDING; - - GLuint ret = 0; - GetUIntegerv(bindEnum, &ret); - return ret; - } - - GLuint GetFB() { - if (mScreen) { - // This has a very important extra assert that checks that we're - // not accidentally ignoring a situation where the draw and read - // FBs differ. - return mScreen->GetFB(); - } - - GLuint ret = 0; - GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); - return ret; - } - -private: - void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { - switch (precisiontype) { - case LOCAL_GL_LOW_FLOAT: - case LOCAL_GL_MEDIUM_FLOAT: - case LOCAL_GL_HIGH_FLOAT: - // Assume IEEE 754 precision - range[0] = 127; - range[1] = 127; - *precision = 23; - break; - case LOCAL_GL_LOW_INT: - case LOCAL_GL_MEDIUM_INT: - case LOCAL_GL_HIGH_INT: - // Some (most) hardware only supports single-precision floating-point numbers, - // which can accurately represent integers up to +/-16777216 - range[0] = 24; - range[1] = 24; - *precision = 0; - break; - } - } - - // Do whatever setup is necessary to draw to our offscreen FBO, if it's - // bound. - void BeforeGLDrawCall() { - } - - // Do whatever tear-down is necessary after drawing to our offscreen FBO, - // if it's bound. - void AfterGLDrawCall() { - if (mScreen) - mScreen->AfterDrawCall(); - } - - // Do whatever setup is necessary to read from our offscreen FBO, if it's - // bound. - void BeforeGLReadCall() { - if (mScreen) - mScreen->BeforeReadCall(); - } - - // Do whatever tear-down is necessary after reading from our offscreen FBO, - // if it's bound. - void AfterGLReadCall() { - } - -public: - // Draw call hooks: - void fClear(GLbitfield mask) { - BeforeGLDrawCall(); - raw_fClear(mask); - AfterGLDrawCall(); - } - - void fDrawArrays(GLenum mode, GLint first, GLsizei count) { - BeforeGLDrawCall(); - raw_fDrawArrays(mode, first, count); - AfterGLDrawCall(); - } - - void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { - BeforeGLDrawCall(); - raw_fDrawElements(mode, count, type, indices); - AfterGLDrawCall(); - } - - // Read call hooks: - void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { - y = FixYValue(y, height); - - BeforeGLReadCall(); - raw_fReadPixels(x, y, width, height, format, type, pixels); - AfterGLReadCall(); - } - - void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { - y = FixYValue(y, height); - - if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { - // pass wrong values to cause the GL to generate GL_INVALID_VALUE. - // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. - level = -1; - width = -1; - height = -1; - border = -1; - } - - BeforeGLReadCall(); - raw_fCopyTexImage2D(target, level, internalformat, - x, y, width, height, border); - AfterGLReadCall(); - } - - void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - y = FixYValue(y, height); - - BeforeGLReadCall(); - raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, - x, y, width, height); - AfterGLReadCall(); - } - - void ForceDirtyScreen(); - void CleanDirtyScreen(); - - // Draw/Read - void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - BeforeGLDrawCall(); - BeforeGLReadCall(); - raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - AfterGLReadCall(); - AfterGLDrawCall(); - } - - virtual bool TextureImageSupportsGetBackingSurface() { - return false; - } - - virtual bool RenewSurface() { return false; } - - /**` - * Return a valid, allocated TextureImage of |aSize| with - * |aContentType|. The TextureImage's texture is configured to - * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by - * default, GL_LINEAR filtering. Specify - * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify - * |aFlags=NeedsYFlip| if the image is flipped. Return - * NULL if creating the TextureImage fails. - * - * The returned TextureImage may only be used with this GLContext. - * Attempting to use the returned TextureImage after this - * GLContext is destroyed will result in undefined (and likely - * crashy) behavior. - */ - virtual already_AddRefed - CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags = TextureImage::NoFlags); - - /** - * In EGL we want to use Tiled Texture Images, which we return - * from CreateTextureImage above. - * Inside TiledTextureImage we need to create actual images and to - * prevent infinite recursion we need to differentiate the two - * functions. - **/ - virtual already_AddRefed - TileGenFunc(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - TextureImage::Flags aFlags = TextureImage::NoFlags) - { - return nullptr; - } - - /** - * Read the image data contained in aTexture, and return it as an ImageSurface. - * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned. - * Not implemented yet: - * If GL_RGB is given as the format, a ImageFormatRGB24 surface is returned. - * If GL_LUMINANCE is given as the format, a ImageFormatA8 surface is returned. - * - * THIS IS EXPENSIVE. It is ridiculously expensive. Only do this - * if you absolutely positively must, and never in any performance - * critical path. - */ - already_AddRefed ReadTextureImage(GLuint aTexture, - const gfxIntSize& aSize, - GLenum aTextureFormat, - bool aYInvert = false); - - already_AddRefed GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader); - - /** - * Call ReadPixels into an existing gfxImageSurface. - * The image surface must be using image format RGBA32 or RGB24, - * and must have stride == width*4. - * Note that neither ReadPixelsIntoImageSurface nor - * ReadScreenIntoImageSurface call dest->Flush/MarkDirty. - */ - void THEBES_API ReadPixelsIntoImageSurface(gfxImageSurface* dest); - - // Similar to ReadPixelsIntoImageSurface, but pulls from the screen - // instead of the currently bound framebuffer. - void ReadScreenIntoImageSurface(gfxImageSurface* dest); - - /** - * Copy a rectangle from one TextureImage into another. The - * source and destination are given in integer coordinates, and - * will be converted to texture coordinates. - * - * For the source texture, the wrap modes DO apply -- it's valid - * to use REPEAT or PAD and expect appropriate behaviour if the source - * rectangle extends beyond its bounds. - * - * For the destination texture, the wrap modes DO NOT apply -- the - * destination will be clipped by the bounds of the texture. - * - * Note: calling this function will cause the following OpenGL state - * to be changed: - * - * - current program - * - framebuffer binding - * - viewport - * - blend state (will be enabled at end) - * - scissor state (will be enabled at end) - * - vertex attrib 0 and 1 (pointer and enable state [enable state will be disabled at exit]) - * - array buffer binding (will be 0) - * - active texture (will be 0) - * - texture 0 binding - */ - void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, - TextureImage *aDst, const nsIntRect& aDstRect); - - /** - * Creates a RGB/RGBA texture (or uses one provided) and uploads the surface - * contents to it within aSrcRect. - * - * aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size - * of the texture with be aSrcRect.width/height. - * - * If an existing texture is passed through aTexture, it is assumed it - * has already been initialised with glTexImage2D (or this function), - * and that its size is equal to or greater than aSrcRect + aDstPoint. - * You can alternatively set the overwrite flag to true and have a new - * texture memory block allocated. - * - * The aDstPoint parameter is ignored if no texture was provided - * or aOverwrite is true. - * - * \param aSurface Surface to upload. - * \param aDstRegion Region of texture to upload to. - * \param aTexture Texture to use, or 0 to have one created for you. - * \param aOverwrite Over an existing texture with a new one. - * \param aSrcPoint Offset into aSrc where the region's bound's - * TopLeft() sits. - * \param aPixelBuffer Pass true to upload texture data with an - * offset from the base data (generally for pixel buffer objects), - * otherwise textures are upload with an absolute pointer to the data. - * \param aTextureUnit, the texture unit used temporarily to upload the - * surface. This testure may be overridden, clients should not rely on - * the contents of this texture after this call or even on this - * texture unit being active. - * \return Shader program needed to render this texture. - */ - ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface, - const nsIntRegion& aDstRegion, - GLuint& aTexture, - bool aOverwrite = false, - const nsIntPoint& aSrcPoint = nsIntPoint(0, 0), - bool aPixelBuffer = false, - GLenum aTextureUnit = LOCAL_GL_TEXTURE0); - - - void TexImage2D(GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLsizei stride, - GLint pixelsize, GLint border, GLenum format, - GLenum type, const GLvoid *pixels); - - void TexSubImage2D(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLsizei stride, - GLint pixelsize, GLenum format, - GLenum type, const GLvoid* pixels); - - /** - * Uses the Khronos GL_EXT_unpack_subimage extension, working around - * quirks in the Tegra implementation of this extension. - */ - void TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLsizei stride, GLint pixelsize, - GLenum format, GLenum type, - const GLvoid* pixels); - - void TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLsizei stride, GLint pixelsize, - GLenum format, GLenum type, - const GLvoid* pixels); - - /** Helper for DecomposeIntoNoRepeatTriangles - */ - struct RectTriangles { - RectTriangles() { } - - // Always pass texture coordinates upright. If you want to flip the - // texture coordinates emitted to the tex_coords array, set flip_y to - // true. - void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, - GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1, - bool flip_y = false); - - /** - * these return a float pointer to the start of each array respectively. - * Use it for glVertexAttribPointer calls. - * We can return NULL if we choose to use Vertex Buffer Objects here. - */ - float* vertexPointer() { - return &vertexCoords[0].x; - } - - float* texCoordPointer() { - return &texCoords[0].u; - } - - unsigned int elements() { - return vertexCoords.Length(); - } - - typedef struct { GLfloat x,y; } vert_coord; - typedef struct { GLfloat u,v; } tex_coord; - private: - // default is 4 rectangles, each made up of 2 triangles (3 coord vertices each) - nsAutoTArray vertexCoords; - nsAutoTArray texCoords; - }; - - /** - * Decompose drawing the possibly-wrapped aTexCoordRect rectangle - * of a texture of aTexSize into one or more rectangles (represented - * as 2 triangles) and associated tex coordinates, such that - * we don't have to use the REPEAT wrap mode. If aFlipY is true, the - * texture coordinates will be specified vertically flipped. - * - * The resulting triangle vertex coordinates will be in the space of - * (0.0, 0.0) to (1.0, 1.0) -- transform the coordinates appropriately - * if you need a different space. - * - * The resulting vertex coordinates should be drawn using GL_TRIANGLES, - * and rects.numRects * 3 * 6 - */ - static void DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect, - const nsIntSize& aTexSize, - RectTriangles& aRects, - bool aFlipY = false); - - - /** - * Known GL extensions that can be queried by - * IsExtensionSupported. The results of this are cached, and as - * such it's safe to use this even in performance critical code. - * If you add to this array, remember to add to the string names - * in GLContext.cpp. - */ - enum GLExtensions { - EXT_framebuffer_object, - ARB_framebuffer_object, - ARB_texture_rectangle, - EXT_bgra, - EXT_texture_format_BGRA8888, - OES_depth24, - OES_depth32, - OES_stencil8, - OES_texture_npot, - OES_depth_texture, - OES_packed_depth_stencil, - IMG_read_format, - EXT_read_format_bgra, - APPLE_client_storage, - ARB_texture_non_power_of_two, - ARB_pixel_buffer_object, - ARB_ES2_compatibility, - OES_texture_float, - ARB_texture_float, - EXT_unpack_subimage, - OES_standard_derivatives, - EXT_texture_filter_anisotropic, - EXT_texture_compression_s3tc, - EXT_texture_compression_dxt1, - ANGLE_texture_compression_dxt3, - ANGLE_texture_compression_dxt5, - AMD_compressed_ATC_texture, - IMG_texture_compression_pvrtc, - EXT_framebuffer_blit, - ANGLE_framebuffer_blit, - EXT_framebuffer_multisample, - ANGLE_framebuffer_multisample, - OES_rgb8_rgba8, - ARB_robustness, - EXT_robustness, - ARB_sync, - OES_EGL_image, - OES_EGL_sync, - OES_EGL_image_external, - EXT_packed_depth_stencil, - Extensions_Max - }; - - bool IsExtensionSupported(GLExtensions aKnownExtension) const { - return mAvailableExtensions[aKnownExtension]; - } - - void MarkExtensionUnsupported(GLExtensions aKnownExtension) { - mAvailableExtensions[aKnownExtension] = 0; - } - - void MarkExtensionSupported(GLExtensions aKnownExtension) { - mAvailableExtensions[aKnownExtension] = 1; - } - - // Shared code for GL extensions and GLX extensions. - static bool ListHasExtension(const GLubyte *extensions, - const char *extension); - - GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; } - void SetFlipped(bool aFlipped) { mFlipped = aFlipped; } - - // this should just be a std::bitset, but that ended up breaking - // MacOS X builds; see bug 584919. We can replace this with one - // later on. This is handy to use in WebGL contexts as well, - // so making it public. - template - struct ExtensionBitset { - ExtensionBitset() { - for (size_t i = 0; i < Size; ++i) - extensions[i] = false; - } - - void Load(const char* extStr, const char** extList, bool verbose = false) { - char* exts = strdup(extStr); - - if (verbose) - printf_stderr("Extensions: %s\n", exts); - - char* cur = exts; - bool done = false; - while (!done) { - char* space = strchr(cur, ' '); - if (space) { - *space = '\0'; - } else { - done = true; - } - - for (int i = 0; extList[i]; ++i) { - if (PL_strcasecmp(cur, extList[i]) == 0) { - if (verbose) - printf_stderr("Found extension %s\n", cur); - extensions[i] = 1; - } - } - - cur = space + 1; - } - - free(exts); - } - - bool& operator[](size_t index) { - MOZ_ASSERT(index < Size, "out of range"); - return extensions[index]; - } - - const bool& operator[](size_t index) const { - MOZ_ASSERT(index < Size, "out of range"); - return extensions[index]; - } - - bool extensions[Size]; - }; - -protected: - ExtensionBitset mAvailableExtensions; - -public: - /** - * Context reset constants. - * These are used to determine who is guilty when a context reset - * happens. - */ - enum ContextResetARB { - CONTEXT_NO_ERROR = 0, - CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253, - CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254, - CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255 - }; - - bool HasRobustness() { - return mHasRobustness; - } - - bool HasExt_FramebufferBlit() { - return IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit); - } - -protected: - bool mInitialized; - bool mIsOffscreen; - bool mIsGLES2; - bool mIsGlobalSharedContext; - bool mHasRobustness; - bool mContextLost; - - int32_t mVendor; - int32_t mRenderer; - -public: - enum { - DebugEnabled = 1 << 0, - DebugTrace = 1 << 1, - DebugAbortOnError = 1 << 2 - }; - - static uint32_t sDebugMode; - - static uint32_t DebugMode() { -#ifdef DEBUG - return sDebugMode; -#else - return 0; -#endif - } - -protected: - nsRefPtr mSharedContext; - - // The thread on which this context was created. - nsCOMPtr mOwningThread; - - GLContextSymbols mSymbols; - -#ifdef DEBUG - // GLDebugMode will check that we don't send call - // to a GLContext that isn't current on the current - // thread. - // Store the current context when binding to thread local - // storage to support DebugMode on an arbitrary thread. - static unsigned sCurrentGLContextTLS; -#endif - bool mFlipped; - - // lazy-initialized things - GLuint mBlitProgram, mBlitFramebuffer; - void UseBlitProgram(); - void SetBlitFramebufferForDestTexture(GLuint aTexture); - -public: - // Assumes shares are created by all sharing with the same global context. - bool SharesWith(const GLContext* other) const { - MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext); - MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext); - MOZ_ASSERT(!this->mSharedContext || - !other->mSharedContext || - this->mSharedContext == other->mSharedContext); - - const GLContext* thisShared = this->mSharedContext ? this->mSharedContext - : this; - const GLContext* otherShared = other->mSharedContext ? other->mSharedContext - : other; - - return thisShared == otherShared; - } - - bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) { - if (!CreateScreenBuffer(size, caps)) - return false; - - MakeCurrent(); - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - fScissor(0, 0, size.width, size.height); - fViewport(0, 0, size.width, size.height); - - mCaps = mScreen->Caps(); - UpdateGLFormats(caps); - UpdatePixelFormat(); - - return true; - } - -protected: - // Note that it does -not- clear the resized buffers. - bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) { - if (!IsOffscreenSizeAllowed(size)) - return false; - - SurfaceCaps tryCaps = caps; - if (tryCaps.antialias) { - // AA path - if (CreateScreenBufferImpl(size, tryCaps)) - return true; - - NS_WARNING("CreateScreenBuffer failed to initialize an AA context! Falling back to no AA..."); - tryCaps.antialias = false; - } - MOZ_ASSERT(!tryCaps.antialias); - - if (CreateScreenBufferImpl(size, tryCaps)) - return true; - - NS_WARNING("CreateScreenBuffer failed to initialize non-AA context!"); - return false; - } - - bool CreateScreenBufferImpl(const gfxIntSize& size, - const SurfaceCaps& caps); - -public: - bool ResizeScreenBuffer(const gfxIntSize& size); - -protected: - SurfaceCaps mCaps; - nsAutoPtr mGLFormats; - nsAutoPtr mPixelFormat; - -public: - void DetermineCaps(); - const SurfaceCaps& Caps() const { - return mCaps; - } - - // Only varies based on bpp16 and alpha. - GLFormats ChooseGLFormats(const SurfaceCaps& caps) const; - void UpdateGLFormats(const SurfaceCaps& caps) { - mGLFormats = new GLFormats(ChooseGLFormats(caps)); - } - - const GLFormats& GetGLFormats() const { - MOZ_ASSERT(mGLFormats); - return *mGLFormats; - } - - PixelBufferFormat QueryPixelFormat(); - void UpdatePixelFormat(); - - const PixelBufferFormat& GetPixelFormat() const { - MOZ_ASSERT(mPixelFormat); - return *mPixelFormat; - } - - - GLuint CreateTextureForOffscreen(const GLFormats& formats, - const gfxIntSize& size); - GLuint CreateTexture(GLenum internalFormat, - GLenum format, GLenum type, - const gfxIntSize& size); - GLuint CreateRenderbuffer(GLenum format, - GLsizei samples, - const gfxIntSize& size); - bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); - - // Pass null to an RB arg to disable its creation. - void CreateRenderbuffersForOffscreen(const GLFormats& formats, - const gfxIntSize& size, - bool multisample, - GLuint* colorMSRB, - GLuint* depthRB, - GLuint* stencilRB); - - // Does not check completeness. - void AttachBuffersToFB(GLuint colorTex, GLuint colorRB, - GLuint depthRB, GLuint stencilRB, - GLuint fb); - - // Passing null is fine if the value you'd get is 0. - bool AssembleOffscreenFBs(const GLuint colorMSRB, - const GLuint depthRB, - const GLuint stencilRB, - const GLuint texture, - GLuint* drawFB, - GLuint* readFB); - -protected: - friend class GLScreenBuffer; - GLScreenBuffer* mScreen; - - void DestroyScreenBuffer(); - - SharedSurface* mLockedSurface; - -public: - void LockSurface(SharedSurface* surf) { - MOZ_ASSERT(!mLockedSurface); - mLockedSurface = surf; - } - - void UnlockSurface(SharedSurface* surf) { - MOZ_ASSERT(mLockedSurface == surf); - mLockedSurface = nullptr; - } - - SharedSurface* GetLockedSurface() const { - return mLockedSurface; - } - - bool IsOffscreen() const { - return mScreen; - } - - GLScreenBuffer* Screen() const { - return mScreen; - } - - bool PublishFrame(); - SharedSurface* RequestFrame(); - - /* Clear to transparent black, with 0 depth and stencil, - * while preserving current ClearColor etc. values. - * Useful for resizing offscreen buffers. - */ - void ClearSafely(); - - bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } - -protected: - nsRefPtr mTexGarbageBin; - -public: - TextureGarbageBin* TexGarbageBin() { - MOZ_ASSERT(mTexGarbageBin); - return mTexGarbageBin; - } - - void EmptyTexGarbageBin(); - -protected: - nsDataHashtable, void*> mUserData; - - void SetIsGLES2(bool aIsGLES2) { - NS_ASSERTION(!mInitialized, "SetIsGLES2 can only be called before initialization!"); - mIsGLES2 = aIsGLES2; - } - - bool InitWithPrefix(const char *prefix, bool trygl); - - void InitExtensions(); - - virtual already_AddRefed - CreateBasicTextureImage(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - TextureImage::ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags = TextureImage::NoFlags); - - bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const { - int32_t biggerDimension = std::max(aSize.width, aSize.height); - int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize); - return biggerDimension <= maxAllowed; - } - - nsTArray mViewportStack; - nsTArray mScissorStack; - - GLint mMaxTextureSize; - GLint mMaxCubeMapTextureSize; - GLint mMaxTextureImageSize; - GLint mMaxRenderbufferSize; - GLsizei mMaxSamples; - bool mNeedsTextureSizeChecks; - bool mWorkAroundDriverBugs; - - bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const { - if (mNeedsTextureSizeChecks) { - // some drivers incorrectly handle some large texture sizes that are below the - // max texture size that they report. So we check ourselves against our own values - // (mMax[CubeMap]TextureSize). - // see bug 737182 for Mac Intel 2D textures - // see bug 684882 for Mac Intel cube map textures - // see bug 814716 for Mesa Nouveau - GLsizei maxSize = target == LOCAL_GL_TEXTURE_CUBE_MAP || - (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) - ? mMaxCubeMapTextureSize - : mMaxTextureSize; - return width <= maxSize && height <= maxSize; - } - return true; - } - -public: - - /** \returns the first GL error, and guarantees that all GL error flags are cleared, - * i.e. that a subsequent GetError call will return NO_ERROR - */ - GLenum GetAndClearError() { - // the first error is what we want to return - GLenum error = fGetError(); - - if (error) { - // clear all pending errors - while(fGetError()) {} - } - - return error; - } - -#ifdef DEBUG - -#ifndef MOZ_FUNCTION_NAME -# ifdef __GNUC__ -# define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ -# elif defined(_MSC_VER) -# define MOZ_FUNCTION_NAME __FUNCTION__ -# else -# define MOZ_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name. -# endif -#endif - -protected: - GLenum mGLError; - -public: - - void BeforeGLCall(const char* glFunction) { - MOZ_ASSERT(IsCurrent()); - if (DebugMode()) { - GLContext *currentGLContext = NULL; - - currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS); - - if (DebugMode() & DebugTrace) - printf_stderr("[gl:%p] > %s\n", this, glFunction); - if (this != currentGLContext) { - printf_stderr("Fatal: %s called on non-current context %p. " - "The current context for this thread is %p.\n", - glFunction, this, currentGLContext); - NS_ABORT(); - } - } - } - - void AfterGLCall(const char* glFunction) { - if (DebugMode()) { - // calling fFinish() immediately after every GL call makes sure that if this GL command crashes, - // the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces - // tend to be meaningless - mSymbols.fFinish(); - mGLError = mSymbols.fGetError(); - if (DebugMode() & DebugTrace) - printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError); - if (mGLError != LOCAL_GL_NO_ERROR) { - printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n", - glFunction, - GLErrorToString(mGLError), - mGLError); - if (DebugMode() & DebugAbortOnError) - NS_ABORT(); - } - } - } - - const char* GLErrorToString(GLenum aError) - { - switch (aError) { - case LOCAL_GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - case LOCAL_GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - case LOCAL_GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - case LOCAL_GL_STACK_OVERFLOW: - return "GL_STACK_OVERFLOW"; - case LOCAL_GL_STACK_UNDERFLOW: - return "GL_STACK_UNDERFLOW"; - case LOCAL_GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - case LOCAL_GL_TABLE_TOO_LARGE: - return "GL_TABLE_TOO_LARGE"; - case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - default: - return ""; - } - } - -#define BEFORE_GL_CALL do { \ - BeforeGLCall(MOZ_FUNCTION_NAME); \ -} while (0) - -#define AFTER_GL_CALL do { \ - AfterGLCall(MOZ_FUNCTION_NAME); \ -} while (0) - -#else - -#define BEFORE_GL_CALL do { } while (0) -#define AFTER_GL_CALL do { } while (0) - -#endif - -#define ASSERT_SYMBOL_PRESENT(func) \ - do {\ - MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, "Mismatched symbol check.");\ - if (MOZ_UNLIKELY(!mSymbols.func)) {\ - printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", #func);\ - MOZ_CRASH();\ - }\ - } while (0) - - /*** In GL debug mode, we completely override glGetError ***/ - - GLenum fGetError() { -#ifdef DEBUG - // debug mode ends up eating the error in AFTER_GL_CALL - if (DebugMode()) { - GLenum err = mGLError; - mGLError = LOCAL_GL_NO_ERROR; - return err; - } -#endif - - return mSymbols.fGetError(); - } - - - /*** Scissor functions ***/ - -protected: - GLint FixYValue(GLint y, GLint height) - { - MOZ_ASSERT( !(mIsOffscreen && mFlipped) ); - return mFlipped ? ViewportRect().height - (height + y) : y; - } - -public: - void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) { - ScissorRect().SetRect(x, y, width, height); - - // GL's coordinate system is flipped compared to the one we use in - // OGL Layers (in the Y axis), so we may need to flip our rectangle. - y = FixYValue(y, height); - raw_fScissor(x, y, width, height); - } - - nsIntRect& ScissorRect() { - return mScissorStack[mScissorStack.Length()-1]; - } - - void PushScissorRect() { - nsIntRect copy(ScissorRect()); - mScissorStack.AppendElement(copy); - } - - void PushScissorRect(const nsIntRect& aRect) { - mScissorStack.AppendElement(aRect); - fScissor(aRect.x, aRect.y, aRect.width, aRect.height); - } - - void PopScissorRect() { - if (mScissorStack.Length() < 2) { - NS_WARNING("PopScissorRect with Length < 2!"); - return; - } - - nsIntRect thisRect = ScissorRect(); - mScissorStack.TruncateLength(mScissorStack.Length() - 1); - if (!thisRect.IsEqualInterior(ScissorRect())) { - fScissor(ScissorRect().x, ScissorRect().y, - ScissorRect().width, ScissorRect().height); - } - } - - /*** Viewport functions ***/ - -private: - // only does the glViewport call, no ViewportRect business - void raw_fViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - BEFORE_GL_CALL; - // XXX: Flipping should really happen using the destination height, but - // we use viewport instead and assume viewport size matches the - // destination. If we ever try use partial viewports for layers we need - // to fix this, and remove the assertion. - NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect"); - mSymbols.fViewport(x, y, width, height); - AFTER_GL_CALL; - } - -public: - void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - ViewportRect().SetRect(x, y, width, height); - raw_fViewport(x, y, width, height); - } - - nsIntRect& ViewportRect() { - return mViewportStack[mViewportStack.Length()-1]; - } - - void PushViewportRect() { - nsIntRect copy(ViewportRect()); - mViewportStack.AppendElement(copy); - } - - void PushViewportRect(const nsIntRect& aRect) { - mViewportStack.AppendElement(aRect); - raw_fViewport(aRect.x, aRect.y, aRect.width, aRect.height); - } - - void PopViewportRect() { - if (mViewportStack.Length() < 2) { - NS_WARNING("PopViewportRect with Length < 2!"); - return; - } - - nsIntRect thisRect = ViewportRect(); - mViewportStack.TruncateLength(mViewportStack.Length() - 1); - if (!thisRect.IsEqualInterior(ViewportRect())) { - raw_fViewport(ViewportRect().x, ViewportRect().y, - ViewportRect().width, ViewportRect().height); - } - } - - /*** other GL functions ***/ - - void fActiveTexture(GLenum texture) { - BEFORE_GL_CALL; - mSymbols.fActiveTexture(texture); - AFTER_GL_CALL; - } - - void fAttachShader(GLuint program, GLuint shader) { - BEFORE_GL_CALL; - mSymbols.fAttachShader(program, shader); - AFTER_GL_CALL; - } - - void fBeginQuery(GLenum target, GLuint id) { - BEFORE_GL_CALL; - mSymbols.fBeginQuery(target, id); - AFTER_GL_CALL; - } - - void fBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { - BEFORE_GL_CALL; - mSymbols.fBindAttribLocation(program, index, name); - AFTER_GL_CALL; - } - - void fBindBuffer(GLenum target, GLuint buffer) { - BEFORE_GL_CALL; - mSymbols.fBindBuffer(target, buffer); - AFTER_GL_CALL; - } - - void fBindTexture(GLenum target, GLuint texture) { - BEFORE_GL_CALL; - mSymbols.fBindTexture(target, texture); - AFTER_GL_CALL; - } - - void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - BEFORE_GL_CALL; - mSymbols.fBlendColor(red, green, blue, alpha); - AFTER_GL_CALL; - } - - void fBlendEquation(GLenum mode) { - BEFORE_GL_CALL; - mSymbols.fBlendEquation(mode); - AFTER_GL_CALL; - } - - void fBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { - BEFORE_GL_CALL; - mSymbols.fBlendEquationSeparate(modeRGB, modeAlpha); - AFTER_GL_CALL; - } - - void fBlendFunc(GLenum sfactor, GLenum dfactor) { - BEFORE_GL_CALL; - mSymbols.fBlendFunc(sfactor, dfactor); - AFTER_GL_CALL; - } - - void fBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) { - BEFORE_GL_CALL; - mSymbols.fBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); - AFTER_GL_CALL; - } - -private: - void raw_fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - BEFORE_GL_CALL; - mSymbols.fBufferData(target, size, data, usage); - AFTER_GL_CALL; - } - -public: - void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - raw_fBufferData(target, size, data, usage); - - // bug 744888 - if (WorkAroundDriverBugs() && - !data && - Vendor() == VendorNVIDIA) - { - char c = 0; - fBufferSubData(target, size-1, 1, &c); - } - } - - void fBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { - BEFORE_GL_CALL; - mSymbols.fBufferSubData(target, offset, size, data); - AFTER_GL_CALL; - } - -private: - void raw_fClear(GLbitfield mask) { - BEFORE_GL_CALL; - mSymbols.fClear(mask); - AFTER_GL_CALL; - } - -public: - void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { - BEFORE_GL_CALL; - mSymbols.fClearColor(r, g, b, a); - AFTER_GL_CALL; - } - - void fClearStencil(GLint s) { - BEFORE_GL_CALL; - mSymbols.fClearStencil(s); - AFTER_GL_CALL; - } - - void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha) { - BEFORE_GL_CALL; - mSymbols.fColorMask(red, green, blue, alpha); - AFTER_GL_CALL; - } - - void fCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels) { - BEFORE_GL_CALL; - mSymbols.fCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, pixels); - AFTER_GL_CALL; - } - - void fCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels) { - BEFORE_GL_CALL; - mSymbols.fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, pixels); - AFTER_GL_CALL; - } - - void fCullFace(GLenum mode) { - BEFORE_GL_CALL; - mSymbols.fCullFace(mode); - AFTER_GL_CALL; - } - - void fDetachShader(GLuint program, GLuint shader) { - BEFORE_GL_CALL; - mSymbols.fDetachShader(program, shader); - AFTER_GL_CALL; - } - - void fDepthFunc(GLenum func) { - BEFORE_GL_CALL; - mSymbols.fDepthFunc(func); - AFTER_GL_CALL; - } - - void fDepthMask(realGLboolean flag) { - BEFORE_GL_CALL; - mSymbols.fDepthMask(flag); - AFTER_GL_CALL; - } - - void fDisable(GLenum capability) { - BEFORE_GL_CALL; - mSymbols.fDisable(capability); - AFTER_GL_CALL; - } - - void fDisableVertexAttribArray(GLuint index) { - BEFORE_GL_CALL; - mSymbols.fDisableVertexAttribArray(index); - AFTER_GL_CALL; - } - - void fDrawBuffer(GLenum mode) { - BEFORE_GL_CALL; - mSymbols.fDrawBuffer(mode); - AFTER_GL_CALL; - } - - void fDrawBuffers(GLsizei n, GLenum* bufs) { - BEFORE_GL_CALL; - mSymbols.fDrawBuffers(n, bufs); - AFTER_GL_CALL; - } - -private: - void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) { - BEFORE_GL_CALL; - mSymbols.fDrawArrays(mode, first, count); - AFTER_GL_CALL; - } - - void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { - BEFORE_GL_CALL; - mSymbols.fDrawElements(mode, count, type, indices); - AFTER_GL_CALL; - } - -public: - void fEnable(GLenum capability) { - BEFORE_GL_CALL; - mSymbols.fEnable(capability); - AFTER_GL_CALL; - } - - void fEnableVertexAttribArray(GLuint index) { - BEFORE_GL_CALL; - mSymbols.fEnableVertexAttribArray(index); - AFTER_GL_CALL; - } - - void fEndQuery(GLenum target) { - BEFORE_GL_CALL; - mSymbols.fEndQuery(target); - AFTER_GL_CALL; - } - - void fFinish() { - BEFORE_GL_CALL; - mSymbols.fFinish(); - AFTER_GL_CALL; - } - - void fFlush() { - BEFORE_GL_CALL; - mSymbols.fFlush(); - AFTER_GL_CALL; - } - - void fFrontFace(GLenum face) { - BEFORE_GL_CALL; - mSymbols.fFrontFace(face); - AFTER_GL_CALL; - } - - void fGetActiveAttrib(GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - BEFORE_GL_CALL; - mSymbols.fGetActiveAttrib(program, index, maxLength, length, size, type, name); - AFTER_GL_CALL; - } - - void fGetActiveUniform(GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - BEFORE_GL_CALL; - mSymbols.fGetActiveUniform(program, index, maxLength, length, size, type, name); - AFTER_GL_CALL; - } - - void fGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { - BEFORE_GL_CALL; - mSymbols.fGetAttachedShaders(program, maxCount, count, shaders); - AFTER_GL_CALL; - } - - GLint fGetAttribLocation (GLuint program, const GLchar* name) { - BEFORE_GL_CALL; - GLint retval = mSymbols.fGetAttribLocation(program, name); - AFTER_GL_CALL; - return retval; - } - - void fGetQueryiv(GLenum target, GLenum pname, GLint* params) { - BEFORE_GL_CALL; - mSymbols.fGetQueryiv(target, pname, params); - AFTER_GL_CALL; - } - - void fGetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { - BEFORE_GL_CALL; - mSymbols.fGetQueryObjectiv(id, pname, params); - AFTER_GL_CALL; - } - - void fGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { - BEFORE_GL_CALL; - mSymbols.fGetQueryObjectuiv(id, pname, params); - AFTER_GL_CALL; - } - -private: - void raw_fGetIntegerv(GLenum pname, GLint *params) { - BEFORE_GL_CALL; - mSymbols.fGetIntegerv(pname, params); - AFTER_GL_CALL; - } - -public: - void GetUIntegerv(GLenum pname, GLuint *params) { - fGetIntegerv(pname, reinterpret_cast(params)); - } - - void fGetFloatv(GLenum pname, GLfloat *params) { - BEFORE_GL_CALL; - mSymbols.fGetFloatv(pname, params); - AFTER_GL_CALL; - } - - void fGetBooleanv(GLenum pname, realGLboolean *params) { - BEFORE_GL_CALL; - mSymbols.fGetBooleanv(pname, params); - AFTER_GL_CALL; - } - - void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { - BEFORE_GL_CALL; - mSymbols.fGetBufferParameteriv(target, pname, params); - AFTER_GL_CALL; - } - - void fGenerateMipmap(GLenum target) { - BEFORE_GL_CALL; - mSymbols.fGenerateMipmap(target); - AFTER_GL_CALL; - } - - void fGetProgramiv(GLuint program, GLenum pname, GLint* param) { - BEFORE_GL_CALL; - mSymbols.fGetProgramiv(program, pname, param); - AFTER_GL_CALL; - } - - void fGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { - BEFORE_GL_CALL; - mSymbols.fGetProgramInfoLog(program, bufSize, length, infoLog); - AFTER_GL_CALL; - } - - void fTexParameteri(GLenum target, GLenum pname, GLint param) { - BEFORE_GL_CALL; - mSymbols.fTexParameteri(target, pname, param); - AFTER_GL_CALL; - } - - void fTexParameteriv(GLenum target, GLenum pname, GLint* params) { - BEFORE_GL_CALL; - mSymbols.fTexParameteriv(target, pname, params); - AFTER_GL_CALL; - } - - void fTexParameterf(GLenum target, GLenum pname, GLfloat param) { - BEFORE_GL_CALL; - mSymbols.fTexParameterf(target, pname, param); - AFTER_GL_CALL; - } - - const GLubyte* fGetString(GLenum name) { - BEFORE_GL_CALL; - const GLubyte *result = mSymbols.fGetString(name); - AFTER_GL_CALL; - return result; - } - - void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *img) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetTexImage); - mSymbols.fGetTexImage(target, level, format, type, img); - AFTER_GL_CALL; - } - - void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) - { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv); - mSymbols.fGetTexLevelParameteriv(target, level, pname, params); - AFTER_GL_CALL; - } - - void fGetTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) { - BEFORE_GL_CALL; - mSymbols.fGetTexParameterfv(target, pname, params); - AFTER_GL_CALL; - } - - void fGetTexParameteriv(GLenum target, GLenum pname, const GLint *params) { - BEFORE_GL_CALL; - mSymbols.fGetTexParameteriv(target, pname, params); - AFTER_GL_CALL; - } - - void fGetUniformfv(GLuint program, GLint location, GLfloat* params) { - BEFORE_GL_CALL; - mSymbols.fGetUniformfv(program, location, params); - AFTER_GL_CALL; - } - - void fGetUniformiv(GLuint program, GLint location, GLint* params) { - BEFORE_GL_CALL; - mSymbols.fGetUniformiv(program, location, params); - AFTER_GL_CALL; - } - - GLint fGetUniformLocation (GLint programObj, const GLchar* name) { - BEFORE_GL_CALL; - GLint retval = mSymbols.fGetUniformLocation(programObj, name); - AFTER_GL_CALL; - return retval; - } - - void fGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* retval) { - BEFORE_GL_CALL; - mSymbols.fGetVertexAttribfv(index, pname, retval); - AFTER_GL_CALL; - } - - void fGetVertexAttribiv(GLuint index, GLenum pname, GLint* retval) { - BEFORE_GL_CALL; - mSymbols.fGetVertexAttribiv(index, pname, retval); - AFTER_GL_CALL; - } - - void fGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** retval) { - BEFORE_GL_CALL; - mSymbols.fGetVertexAttribPointerv(index, pname, retval); - AFTER_GL_CALL; - } - - void fHint(GLenum target, GLenum mode) { - BEFORE_GL_CALL; - mSymbols.fHint(target, mode); - AFTER_GL_CALL; - } - - realGLboolean fIsBuffer(GLuint buffer) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsBuffer(buffer); - AFTER_GL_CALL; - return retval; - } - - realGLboolean fIsEnabled(GLenum capability) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsEnabled(capability); - AFTER_GL_CALL; - return retval; - } - - realGLboolean fIsProgram(GLuint program) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsProgram(program); - AFTER_GL_CALL; - return retval; - } - - realGLboolean fIsShader(GLuint shader) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsShader(shader); - AFTER_GL_CALL; - return retval; - } - - realGLboolean fIsTexture(GLuint texture) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsTexture(texture); - AFTER_GL_CALL; - return retval; - } - - void fLineWidth(GLfloat width) { - BEFORE_GL_CALL; - mSymbols.fLineWidth(width); - AFTER_GL_CALL; - } - - void fLinkProgram(GLuint program) { - BEFORE_GL_CALL; - mSymbols.fLinkProgram(program); - AFTER_GL_CALL; - } - - void fPixelStorei(GLenum pname, GLint param) { - BEFORE_GL_CALL; - mSymbols.fPixelStorei(pname, param); - AFTER_GL_CALL; - } - - void fPointParameterf(GLenum pname, GLfloat param) { - BEFORE_GL_CALL; - mSymbols.fPointParameterf(pname, param); - AFTER_GL_CALL; - } - - void fPolygonOffset(GLfloat factor, GLfloat bias) { - BEFORE_GL_CALL; - mSymbols.fPolygonOffset(factor, bias); - AFTER_GL_CALL; - } - - void fReadBuffer(GLenum mode) { - BEFORE_GL_CALL; - mSymbols.fReadBuffer(mode); - AFTER_GL_CALL; - } - -private: - void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) { - BEFORE_GL_CALL; - mSymbols.fReadPixels(x, FixYValue(y, height), width, height, format, type, pixels); - AFTER_GL_CALL; - } - -public: - void fSampleCoverage(GLclampf value, realGLboolean invert) { - BEFORE_GL_CALL; - mSymbols.fSampleCoverage(value, invert); - AFTER_GL_CALL; - } - -private: - void raw_fScissor(GLint x, GLint y, GLsizei width, GLsizei height) { - BEFORE_GL_CALL; - mSymbols.fScissor(x, y, width, height); - AFTER_GL_CALL; - } - -public: - void fStencilFunc(GLenum func, GLint ref, GLuint mask) { - BEFORE_GL_CALL; - mSymbols.fStencilFunc(func, ref, mask); - AFTER_GL_CALL; - } - - void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) { - BEFORE_GL_CALL; - mSymbols.fStencilFuncSeparate(frontfunc, backfunc, ref, mask); - AFTER_GL_CALL; - } - - void fStencilMask(GLuint mask) { - BEFORE_GL_CALL; - mSymbols.fStencilMask(mask); - AFTER_GL_CALL; - } - - void fStencilMaskSeparate(GLenum face, GLuint mask) { - BEFORE_GL_CALL; - mSymbols.fStencilMaskSeparate(face, mask); - AFTER_GL_CALL; - } - - void fStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { - BEFORE_GL_CALL; - mSymbols.fStencilOp(fail, zfail, zpass); - AFTER_GL_CALL; - } - - void fStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) { - BEFORE_GL_CALL; - mSymbols.fStencilOpSeparate(face, sfail, dpfail, dppass); - AFTER_GL_CALL; - } - -private: - void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { - BEFORE_GL_CALL; - mSymbols.fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - AFTER_GL_CALL; - } - -public: - void fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { - if (!IsTextureSizeSafeToPassToDriver(target, width, height)) { - // pass wrong values to cause the GL to generate GL_INVALID_VALUE. - // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver. - level = -1; - width = -1; - height = -1; - border = -1; - } - - raw_fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } - - void fTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { - BEFORE_GL_CALL; - mSymbols.fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); - AFTER_GL_CALL; - } - - void fUniform1f(GLint location, GLfloat v0) { - BEFORE_GL_CALL; - mSymbols.fUniform1f(location, v0); - AFTER_GL_CALL; - } - - void fUniform1fv(GLint location, GLsizei count, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniform1fv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform1i(GLint location, GLint v0) { - BEFORE_GL_CALL; - mSymbols.fUniform1i(location, v0); - AFTER_GL_CALL; - } - - void fUniform1iv(GLint location, GLsizei count, const GLint* value) { - BEFORE_GL_CALL; - mSymbols.fUniform1iv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform2f(GLint location, GLfloat v0, GLfloat v1) { - BEFORE_GL_CALL; - mSymbols.fUniform2f(location, v0, v1); - AFTER_GL_CALL; - } - - void fUniform2fv(GLint location, GLsizei count, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniform2fv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform2i(GLint location, GLint v0, GLint v1) { - BEFORE_GL_CALL; - mSymbols.fUniform2i(location, v0, v1); - AFTER_GL_CALL; - } - - void fUniform2iv(GLint location, GLsizei count, const GLint* value) { - BEFORE_GL_CALL; - mSymbols.fUniform2iv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { - BEFORE_GL_CALL; - mSymbols.fUniform3f(location, v0, v1, v2); - AFTER_GL_CALL; - } - - void fUniform3fv(GLint location, GLsizei count, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniform3fv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform3i(GLint location, GLint v0, GLint v1, GLint v2) { - BEFORE_GL_CALL; - mSymbols.fUniform3i(location, v0, v1, v2); - AFTER_GL_CALL; - } - - void fUniform3iv(GLint location, GLsizei count, const GLint* value) { - BEFORE_GL_CALL; - mSymbols.fUniform3iv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { - BEFORE_GL_CALL; - mSymbols.fUniform4f(location, v0, v1, v2, v3); - AFTER_GL_CALL; - } - - void fUniform4fv(GLint location, GLsizei count, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniform4fv(location, count, value); - AFTER_GL_CALL; - } - - void fUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { - BEFORE_GL_CALL; - mSymbols.fUniform4i(location, v0, v1, v2, v3); - AFTER_GL_CALL; - } - - void fUniform4iv(GLint location, GLsizei count, const GLint* value) { - BEFORE_GL_CALL; - mSymbols.fUniform4iv(location, count, value); - AFTER_GL_CALL; - } - - void fUniformMatrix2fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniformMatrix2fv(location, count, transpose, value); - AFTER_GL_CALL; - } - - void fUniformMatrix3fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniformMatrix3fv(location, count, transpose, value); - AFTER_GL_CALL; - } - - void fUniformMatrix4fv(GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value) { - BEFORE_GL_CALL; - mSymbols.fUniformMatrix4fv(location, count, transpose, value); - AFTER_GL_CALL; - } - - void fUseProgram(GLuint program) { - BEFORE_GL_CALL; - mSymbols.fUseProgram(program); - AFTER_GL_CALL; - } - - void fValidateProgram(GLuint program) { - BEFORE_GL_CALL; - mSymbols.fValidateProgram(program); - AFTER_GL_CALL; - } - - void fVertexAttribPointer(GLuint index, GLint size, GLenum type, realGLboolean normalized, GLsizei stride, const GLvoid* pointer) { - BEFORE_GL_CALL; - mSymbols.fVertexAttribPointer(index, size, type, normalized, stride, pointer); - AFTER_GL_CALL; - } - - void fVertexAttrib1f(GLuint index, GLfloat x) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib1f(index, x); - AFTER_GL_CALL; - } - - void fVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib2f(index, x, y); - AFTER_GL_CALL; - } - - void fVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib3f(index, x, y, z); - AFTER_GL_CALL; - } - - void fVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib4f(index, x, y, z, w); - AFTER_GL_CALL; - } - - void fVertexAttrib1fv(GLuint index, const GLfloat* v) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib1fv(index, v); - AFTER_GL_CALL; - } - - void fVertexAttrib2fv(GLuint index, const GLfloat* v) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib2fv(index, v); - AFTER_GL_CALL; - } - - void fVertexAttrib3fv(GLuint index, const GLfloat* v) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib3fv(index, v); - AFTER_GL_CALL; - } - - void fVertexAttrib4fv(GLuint index, const GLfloat* v) { - BEFORE_GL_CALL; - mSymbols.fVertexAttrib4fv(index, v); - AFTER_GL_CALL; - } - - void fCompileShader(GLuint shader) { - BEFORE_GL_CALL; - mSymbols.fCompileShader(shader); - AFTER_GL_CALL; - } - -private: - void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { - BEFORE_GL_CALL; - mSymbols.fCopyTexImage2D(target, level, internalformat, x, y, width, height, border); - AFTER_GL_CALL; - } - - void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - BEFORE_GL_CALL; - mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); - AFTER_GL_CALL; - } - -public: - void fGetShaderiv(GLuint shader, GLenum pname, GLint* param) { - BEFORE_GL_CALL; - mSymbols.fGetShaderiv(shader, pname, param); - AFTER_GL_CALL; - } - - void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { - BEFORE_GL_CALL; - mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog); - AFTER_GL_CALL; - } - -private: - void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { - MOZ_ASSERT(mIsGLES2); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat); - mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); - AFTER_GL_CALL; - } - -public: - void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { - if (mIsGLES2) { - raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); - } else { - // Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions. - GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, precision); - } - } - - void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source) { - BEFORE_GL_CALL; - mSymbols.fGetShaderSource(obj, maxLength, length, source); - AFTER_GL_CALL; - } - - void fShaderSource(GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths) { - BEFORE_GL_CALL; - mSymbols.fShaderSource(shader, count, strings, lengths); - AFTER_GL_CALL; - } - -private: - void raw_fBindFramebuffer(GLenum target, GLuint framebuffer) { - BEFORE_GL_CALL; - mSymbols.fBindFramebuffer(target, framebuffer); - AFTER_GL_CALL; - } - -public: - void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { - BEFORE_GL_CALL; - mSymbols.fBindRenderbuffer(target, renderbuffer); - AFTER_GL_CALL; - } - - GLenum fCheckFramebufferStatus(GLenum target) { - BEFORE_GL_CALL; - GLenum retval = mSymbols.fCheckFramebufferStatus(target); - AFTER_GL_CALL; - return retval; - } - - void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer) { - BEFORE_GL_CALL; - mSymbols.fFramebufferRenderbuffer(target, attachmentPoint, renderbufferTarget, renderbuffer); - AFTER_GL_CALL; - } - - void fFramebufferTexture2D(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level) { - BEFORE_GL_CALL; - mSymbols.fFramebufferTexture2D(target, attachmentPoint, textureTarget, texture, level); - AFTER_GL_CALL; - } - - void fGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* value) { - BEFORE_GL_CALL; - mSymbols.fGetFramebufferAttachmentParameteriv(target, attachment, pname, value); - AFTER_GL_CALL; - } - - void fGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* value) { - BEFORE_GL_CALL; - mSymbols.fGetRenderbufferParameteriv(target, pname, value); - AFTER_GL_CALL; - } - - realGLboolean fIsFramebuffer (GLuint framebuffer) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsFramebuffer(framebuffer); - AFTER_GL_CALL; - return retval; - } - -private: - void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fBlitFramebuffer); - mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - AFTER_GL_CALL; - } - -public: - realGLboolean fIsRenderbuffer (GLuint renderbuffer) { - BEFORE_GL_CALL; - realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer); - AFTER_GL_CALL; - return retval; - } - - void fRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height) { - BEFORE_GL_CALL; - mSymbols.fRenderbufferStorage(target, internalFormat, width, height); - AFTER_GL_CALL; - } - - void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample); - mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height); - AFTER_GL_CALL; - } - -private: - void raw_fDepthRange(GLclampf a, GLclampf b) { - MOZ_ASSERT(!mIsGLES2); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fDepthRange); - mSymbols.fDepthRange(a, b); - AFTER_GL_CALL; - } - - void raw_fDepthRangef(GLclampf a, GLclampf b) { - MOZ_ASSERT(mIsGLES2); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fDepthRangef); - mSymbols.fDepthRangef(a, b); - AFTER_GL_CALL; - } - - void raw_fClearDepth(GLclampf v) { - MOZ_ASSERT(!mIsGLES2); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fClearDepth); - mSymbols.fClearDepth(v); - AFTER_GL_CALL; - } - - void raw_fClearDepthf(GLclampf v) { - MOZ_ASSERT(mIsGLES2); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fClearDepthf); - mSymbols.fClearDepthf(v); - AFTER_GL_CALL; - } - -public: - void fDepthRange(GLclampf a, GLclampf b) { - if (mIsGLES2) { - raw_fDepthRangef(a, b); - } else { - raw_fDepthRange(a, b); - } - } - - void fClearDepth(GLclampf v) { - if (mIsGLES2) { - raw_fClearDepthf(v); - } else { - raw_fClearDepth(v); - } - } - - void* fMapBuffer(GLenum target, GLenum access) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fMapBuffer); - void *ret = mSymbols.fMapBuffer(target, access); - AFTER_GL_CALL; - return ret; - } - - realGLboolean fUnmapBuffer(GLenum target) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fUnmapBuffer); - realGLboolean ret = mSymbols.fUnmapBuffer(target); - AFTER_GL_CALL; - return ret; - } - - -private: -#ifdef DEBUG - GLContext *TrackingContext() { - GLContext *tip = this; - while (tip->mSharedContext) - tip = tip->mSharedContext; - return tip; - } - -#define TRACKING_CONTEXT(a) do { TrackingContext()->a; } while (0) -#else -#define TRACKING_CONTEXT(a) do {} while (0) -#endif - - GLuint GLAPIENTRY raw_fCreateProgram() { - BEFORE_GL_CALL; - GLuint ret = mSymbols.fCreateProgram(); - AFTER_GL_CALL; - return ret; - } - - GLuint GLAPIENTRY raw_fCreateShader(GLenum t) { - BEFORE_GL_CALL; - GLuint ret = mSymbols.fCreateShader(t); - AFTER_GL_CALL; - return ret; - } - - void GLAPIENTRY raw_fGenBuffers(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fGenBuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fGenFramebuffers(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fGenFramebuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fGenQueries(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fGenQueries(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fGenRenderbuffers(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fGenRenderbuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fGenTextures(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fGenTextures(n, names); - AFTER_GL_CALL; - } - -public: - GLuint fCreateProgram() { - GLuint ret = raw_fCreateProgram(); - TRACKING_CONTEXT(CreatedProgram(this, ret)); - return ret; - } - - GLuint fCreateShader(GLenum t) { - GLuint ret = raw_fCreateShader(t); - TRACKING_CONTEXT(CreatedShader(this, ret)); - return ret; - } - - void fGenBuffers(GLsizei n, GLuint* names) { - raw_fGenBuffers(n, names); - TRACKING_CONTEXT(CreatedBuffers(this, n, names)); - } - - void fGenFramebuffers(GLsizei n, GLuint* names) { - raw_fGenFramebuffers(n, names); - TRACKING_CONTEXT(CreatedFramebuffers(this, n, names)); - } - - void fGenQueries(GLsizei n, GLuint* names) { - raw_fGenQueries(n, names); - TRACKING_CONTEXT(CreatedQueries(this, n, names)); - } - - void fGenRenderbuffers(GLsizei n, GLuint* names) { - raw_fGenRenderbuffers(n, names); - TRACKING_CONTEXT(CreatedRenderbuffers(this, n, names)); - } - - void fGenTextures(GLsizei n, GLuint* names) { - raw_fGenTextures(n, names); - TRACKING_CONTEXT(CreatedTextures(this, n, names)); - } - -private: - void GLAPIENTRY raw_fDeleteProgram(GLuint program) { - BEFORE_GL_CALL; - mSymbols.fDeleteProgram(program); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteShader(GLuint shader) { - BEFORE_GL_CALL; - mSymbols.fDeleteShader(shader); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteBuffers(GLsizei n, GLuint *names) { - BEFORE_GL_CALL; - mSymbols.fDeleteBuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteFramebuffers(GLsizei n, GLuint *names) { - BEFORE_GL_CALL; - mSymbols.fDeleteFramebuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteRenderbuffers(GLsizei n, GLuint *names) { - BEFORE_GL_CALL; - mSymbols.fDeleteRenderbuffers(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteTextures(GLsizei n, GLuint *names) { - BEFORE_GL_CALL; - mSymbols.fDeleteTextures(n, names); - AFTER_GL_CALL; - } - - void GLAPIENTRY raw_fDeleteQueries(GLsizei n, GLuint* names) { - BEFORE_GL_CALL; - mSymbols.fDeleteQueries(n, names); - AFTER_GL_CALL; - } - -public: - void GLAPIENTRY fDeleteQueries(GLsizei n, GLuint* names) { - raw_fDeleteQueries(n, names); - TRACKING_CONTEXT(DeletedQueries(this, n, names)); - } - - void fDeleteProgram(GLuint program) { - raw_fDeleteProgram(program); - TRACKING_CONTEXT(DeletedProgram(this, program)); - } - - void fDeleteShader(GLuint shader) { - raw_fDeleteShader(shader); - TRACKING_CONTEXT(DeletedShader(this, shader)); - } - - void fDeleteBuffers(GLsizei n, GLuint *names) { - raw_fDeleteBuffers(n, names); - TRACKING_CONTEXT(DeletedBuffers(this, n, names)); - } - - void fDeleteFramebuffers(GLsizei n, GLuint *names) { - if (mScreen) { - // Notify mScreen which framebuffers we're deleting. - // Otherwise, we will get framebuffer binding mispredictions. - for (int i = 0; i < n; i++) { - mScreen->DeletingFB(names[i]); - } - } - - if (n == 1 && *names == 0) { - // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228. - } else { - raw_fDeleteFramebuffers(n, names); - } - TRACKING_CONTEXT(DeletedFramebuffers(this, n, names)); - } - - void fDeleteRenderbuffers(GLsizei n, GLuint *names) { - raw_fDeleteRenderbuffers(n, names); - TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names)); - } - - void fDeleteTextures(GLsizei n, GLuint *names) { - raw_fDeleteTextures(n, names); - TRACKING_CONTEXT(DeletedTextures(this, n, names)); - } - - - GLenum GLAPIENTRY fGetGraphicsResetStatus() { - MOZ_ASSERT(mHasRobustness); - - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetGraphicsResetStatus); - GLenum ret = mSymbols.fGetGraphicsResetStatus(); - AFTER_GL_CALL; - return ret; - } - - GLsync GLAPIENTRY fFenceSync(GLenum condition, GLbitfield flags) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fFenceSync); - GLsync ret = mSymbols.fFenceSync(condition, flags); - AFTER_GL_CALL; - return ret; - } - - realGLboolean GLAPIENTRY fIsSync(GLsync sync) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fIsSync); - realGLboolean ret = mSymbols.fIsSync(sync); - AFTER_GL_CALL; - return ret; - } - - void GLAPIENTRY fDeleteSync(GLsync sync) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fDeleteSync); - mSymbols.fDeleteSync(sync); - AFTER_GL_CALL; - } - - GLenum GLAPIENTRY fClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fClientWaitSync); - GLenum ret = mSymbols.fClientWaitSync(sync, flags, timeout); - AFTER_GL_CALL; - return ret; - } - - void GLAPIENTRY fWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fWaitSync); - mSymbols.fWaitSync(sync, flags, timeout); - AFTER_GL_CALL; - } - - void GLAPIENTRY fGetInteger64v(GLenum pname, GLint64 *params) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetInteger64v); - mSymbols.fGetInteger64v(pname, params); - AFTER_GL_CALL; - } - - void GLAPIENTRY fGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fGetSynciv); - mSymbols.fGetSynciv(sync, pname, bufSize, length, values); - AFTER_GL_CALL; - } - - // OES_EGL_image (GLES) - void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D); - mSymbols.fEGLImageTargetTexture2D(target, image); - AFTER_GL_CALL; - } - - void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image) - { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage); - mSymbols.fEGLImageTargetRenderbufferStorage(target, image); - AFTER_GL_CALL; - } - -#undef ASSERT_SYMBOL_PRESENT - -#ifdef DEBUG - void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName); - void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName); - void THEBES_API CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API CreatedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API DeletedProgram(GLContext *aOrigin, GLuint aName); - void THEBES_API DeletedShader(GLContext *aOrigin, GLuint aName); - void THEBES_API DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API DeletedQueries(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - void THEBES_API DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); - - void SharedContextDestroyed(GLContext *aChild); - void ReportOutstandingNames(); - - struct NamedResource { - NamedResource() - : origin(nullptr), name(0), originDeleted(false) - { } - - NamedResource(GLContext *aOrigin, GLuint aName) - : origin(aOrigin), name(aName), originDeleted(false) - { } - - GLContext *origin; - GLuint name; - bool originDeleted; - - // for sorting - bool operator<(const NamedResource& aOther) const { - if (intptr_t(origin) < intptr_t(aOther.origin)) - return true; - if (name < aOther.name) - return true; - return false; - } - bool operator==(const NamedResource& aOther) const { - return origin == aOther.origin && - name == aOther.name && - originDeleted == aOther.originDeleted; - } - }; - - nsTArray mTrackedPrograms; - nsTArray mTrackedShaders; - nsTArray mTrackedTextures; - nsTArray mTrackedFramebuffers; - nsTArray mTrackedRenderbuffers; - nsTArray mTrackedBuffers; - nsTArray mTrackedQueries; -#endif - -public: - enum MemoryUse { - // when memory being allocated is reported to a memory reporter - MemoryAllocated, - // when memory being freed is reported to a memory reporter - MemoryFreed - }; - - // When memory is used/freed for tile textures, call this method - // to update the value reported by the memory reporter. - static void UpdateTextureMemoryUsage(MemoryUse action, - GLenum format, - GLenum type, - uint16_t tileSize); -}; - -inline bool -DoesStringMatch(const char* aString, const char *aWantedString) -{ - if (!aString || !aWantedString) - return false; - - const char *occurrence = strstr(aString, aWantedString); - - // aWanted not found - if (!occurrence) - return false; - - // aWantedString preceded by alpha character - if (occurrence != aString && isalpha(*(occurrence-1))) - return false; - - // aWantedVendor followed by alpha character - const char *afterOccurrence = occurrence + strlen(aWantedString); - if (isalpha(*afterOccurrence)) - return false; - - return true; -} - -//RAII via CRTP! -template -struct ScopedGLWrapper -{ -private: - bool mIsUnwrapped; - -protected: - GLContext* const mGL; - - ScopedGLWrapper(GLContext* gl) - : mIsUnwrapped(false) - , mGL(gl) - { - MOZ_ASSERT(&ScopedGLWrapper::Unwrap == &Derived::Unwrap); - MOZ_ASSERT(&Derived::UnwrapImpl); - MOZ_ASSERT(mGL->IsCurrent()); - } - - virtual ~ScopedGLWrapper() { - if (!mIsUnwrapped) - Unwrap(); - } - -public: - void Unwrap() { - MOZ_ASSERT(!mIsUnwrapped); - - Derived* derived = static_cast(this); - derived->UnwrapImpl(); - - mIsUnwrapped = true; - } -}; - -// Wraps glEnable/Disable. -struct ScopedGLState - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - const GLenum mCapability; - bool mOldState; - -public: - // Use |newState = true| to enable, |false| to disable. - ScopedGLState(GLContext* gl, GLenum capability, bool newState) - : ScopedGLWrapper(gl) - , mCapability(capability) - { - mOldState = mGL->fIsEnabled(mCapability); - - // Early out if we're already in the right state. - if (newState == mOldState) - return; - - if (newState) - mGL->fEnable(mCapability); - else - mGL->fDisable(mCapability); - } - -protected: - void UnwrapImpl() { - if (mOldState) - mGL->fEnable(mCapability); - else - mGL->fDisable(mCapability); - } -}; - -// Saves and restores with GetUserBoundFB and BindUserFB. -struct ScopedBindFramebuffer - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - GLuint mOldFB; - -private: - void Init() { - mOldFB = mGL->GetFB(); - } - -public: - explicit ScopedBindFramebuffer(GLContext* gl) - : ScopedGLWrapper(gl) - { - Init(); - } - - ScopedBindFramebuffer(GLContext* gl, GLuint newFB) - : ScopedGLWrapper(gl) - { - Init(); - mGL->BindFB(newFB); - } - -protected: - void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. - MOZ_ASSERT(mGL->IsCurrent()); - - mGL->BindFB(mOldFB); - } -}; - -struct ScopedBindTexture - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - GLuint mOldTex; - -private: - void Init() { - mOldTex = 0; - mGL->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &mOldTex); - } - -public: - explicit ScopedBindTexture(GLContext* gl) - : ScopedGLWrapper(gl) - { - Init(); - } - - ScopedBindTexture(GLContext* gl, GLuint newTex) - : ScopedGLWrapper(gl) - { - Init(); - mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, newTex); - } - -protected: - void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. - MOZ_ASSERT(mGL->IsCurrent()); - - mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mOldTex); - } -}; - - -struct ScopedBindRenderbuffer - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - GLuint mOldRB; - -private: - void Init() { - mOldRB = 0; - mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB); - } - -public: - explicit ScopedBindRenderbuffer(GLContext* gl) - : ScopedGLWrapper(gl) - { - Init(); - } - - ScopedBindRenderbuffer(GLContext* gl, GLuint newRB) - : ScopedGLWrapper(gl) - { - Init(); - mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newRB); - } - -protected: - void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. - MOZ_ASSERT(mGL->IsCurrent()); - - mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB); - } -}; - -struct ScopedFramebufferForTexture - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - bool mComplete; // True if the framebuffer we create is complete. - GLuint mFB; - -public: - ScopedFramebufferForTexture(GLContext* gl, GLuint texture) - : ScopedGLWrapper(gl) - , mComplete(false) - , mFB(0) - { - mGL->fGenFramebuffers(1, &mFB); - ScopedBindFramebuffer autoFB(gl, mFB); - mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - texture, - 0); - - GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { - mComplete = true; - } else { - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - } - -protected: - void UnwrapImpl() { - if (!mFB) - return; - - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - -public: - GLuint FB() const { - MOZ_ASSERT(IsComplete()); - return mFB; - } - - bool IsComplete() const { - return mComplete; - } -}; - -struct ScopedFramebufferForRenderbuffer - : public ScopedGLWrapper -{ - friend struct ScopedGLWrapper; - -protected: - bool mComplete; // True if the framebuffer we create is complete. - GLuint mFB; - -public: - ScopedFramebufferForRenderbuffer(GLContext* gl, GLuint rb) - : ScopedGLWrapper(gl) - , mComplete(false) - , mFB(0) - { - mGL->fGenFramebuffers(1, &mFB); - ScopedBindFramebuffer autoFB(gl, mFB); - mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, - rb); - - GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { - mComplete = true; - } else { - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - } - -protected: - void UnwrapImpl() { - if (!mFB) - return; - - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - -public: - GLuint FB() const { - return mFB; - } - - bool IsComplete() const { - return mComplete; - } -}; - - -class TextureGarbageBin { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureGarbageBin) - -protected: - GLContext* mGL; - Mutex mMutex; - std::stack mGarbageTextures; - -public: - TextureGarbageBin(GLContext* gl) - : mGL(gl) - , mMutex("TextureGarbageBin mutex") - {} - - void GLContextTeardown(); - void Trash(GLuint tex); - void EmptyGarbage(); -}; - -uint32_t GetBitsPerTexel(GLenum format, GLenum type); - -} /* namespace gl */ -} /* namespace mozilla */ - -#endif /* GLCONTEXT_H_ */ diff --git a/libazure/src/gfx/gl/GLContextProvider.h b/libazure/src/gfx/gl/GLContextProvider.h deleted file mode 100644 index b2042da..0000000 --- a/libazure/src/gfx/gl/GLContextProvider.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLCONTEXTPROVIDER_H_ -#define GLCONTEXTPROVIDER_H_ - -#include "GLContext.h" -#include "gfxTypes.h" -#include "gfxPoint.h" -#include "nsAutoPtr.h" -#include "SurfaceTypes.h" - -class nsIWidget; -class gfxASurface; - -namespace mozilla { -namespace gl { - -#define IN_GL_CONTEXT_PROVIDER_H - -// Null is always there -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME - -#ifdef XP_WIN -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL -#define DEFAULT_IMPL WGL -#endif - -#ifdef XP_MACOSX -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL -#endif - -#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) || defined(XP_WIN) -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME - -#ifndef GL_CONTEXT_PROVIDER_DEFAULT -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL -#endif -#endif - -#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT) -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX -#endif - -#ifdef MOZ_GL_PROVIDER -#define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER -#endif - -#ifdef GL_CONTEXT_PROVIDER_DEFAULT -typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; -#else -typedef GLContextProviderNull GLContextProvider; -#endif - -#undef IN_GL_CONTEXT_PROVIDER_H - -} -} - -#endif diff --git a/libazure/src/gfx/gl/GLContextProviderCGL.mm b/libazure/src/gfx/gl/GLContextProviderCGL.mm deleted file mode 100644 index a44073c..0000000 --- a/libazure/src/gfx/gl/GLContextProviderCGL.mm +++ /dev/null @@ -1,424 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContextProvider.h" -#include "nsDebug.h" -#include "nsIWidget.h" -#include "OpenGL/OpenGL.h" -#include -#include -#include "gfxASurface.h" -#include "gfxImageSurface.h" -#include "gfxQuartzSurface.h" -#include "gfxPlatform.h" -#include "gfxFailure.h" -#include "prenv.h" -#include "mozilla/Preferences.h" -#include "GeckoProfiler.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -static bool gUseDoubleBufferedWindows = true; - -class CGLLibrary -{ -public: - CGLLibrary() - : mInitialized(false), - mOGLLibrary(nullptr), - mPixelFormat(nullptr) - { } - - bool EnsureInitialized() - { - if (mInitialized) { - return true; - } - if (!mOGLLibrary) { - mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL"); - if (!mOGLLibrary) { - NS_WARNING("Couldn't load OpenGL Framework."); - return false; - } - } - - const char* db = PR_GetEnv("MOZ_CGL_DB"); - gUseDoubleBufferedWindows = (!db || *db != '0'); - - mInitialized = true; - return true; - } - - NSOpenGLPixelFormat *PixelFormat() - { - if (mPixelFormat == nullptr) { - NSOpenGLPixelFormatAttribute attribs[] = { - NSOpenGLPFAAccelerated, - NSOpenGLPFAAllowOfflineRenderers, - NSOpenGLPFADoubleBuffer, - 0 - }; - - if (!gUseDoubleBufferedWindows) { - attribs[2] = 0; - } - - mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - } - - return mPixelFormat; - } -private: - bool mInitialized; - PRLibrary *mOGLLibrary; - NSOpenGLPixelFormat *mPixelFormat; -}; - -CGLLibrary sCGLLibrary; - -class GLContextCGL : public GLContext -{ - friend class GLContextProviderCGL; - -public: - GLContextCGL(const SurfaceCaps& caps, - GLContext *shareContext, - NSOpenGLContext *context, - bool isOffscreen = false) - : GLContext(caps, shareContext, isOffscreen), - mContext(context), - mTempTextureName(0) - {} - - ~GLContextCGL() - { - MarkDestroyed(); - - if (mContext) - [mContext release]; - } - - GLContextType GetContextType() { - return ContextTypeCGL; - } - - bool Init() - { - MakeCurrent(); - if (!InitWithPrefix("gl", true)) - return false; - - return true; - } - - void *GetNativeData(NativeDataType aType) - { - switch (aType) { - case NativeGLContext: - return mContext; - - default: - return nullptr; - } - } - - bool MakeCurrentImpl(bool aForce = false) - { - if (!aForce && [NSOpenGLContext currentContext] == mContext) { - return true; - } - - if (mContext) { - [mContext makeCurrentContext]; - GLint swapInt = 1; - [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; - } - return true; - } - - virtual bool IsCurrent() { - return [NSOpenGLContext currentContext] == mContext; - } - - bool SetupLookupFunction() - { - return false; - } - - bool IsDoubleBuffered() - { - return gUseDoubleBufferedWindows; - } - - bool SupportsRobustness() - { - return false; - } - - bool SwapBuffers() - { - PROFILER_LABEL("GLContext", "SwapBuffers"); - [mContext flushBuffer]; - return true; - } - - bool ResizeOffscreen(const gfxIntSize& aNewSize); - - virtual already_AddRefed - CreateBasicTextureImage(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - TextureImage::ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags = TextureImage::NoFlags); - - NSOpenGLContext *mContext; - GLuint mTempTextureName; -}; - -bool -GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) -{ - return ResizeScreenBuffer(aNewSize); -} - -class TextureImageCGL : public BasicTextureImage -{ - friend already_AddRefed - GLContextCGL::CreateBasicTextureImage(GLuint, - const nsIntSize&, - GLenum, - TextureImage::ContentType, - GLContext*, - TextureImage::Flags); -public: - ~TextureImageCGL() - { - if (mPixelBuffer) { - mGLContext->MakeCurrent(); - mGLContext->fDeleteBuffers(1, &mPixelBuffer); - } - } - -protected: - already_AddRefed - GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt) - { - gfxIntSize size(aSize.width + 1, aSize.height + 1); - mGLContext->MakeCurrent(); - if (!mGLContext-> - IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) - { - return gfxPlatform::GetPlatform()-> - CreateOffscreenSurface(size, - gfxASurface::ContentFromFormat(aFmt)); - } - - if (!mPixelBuffer) { - mGLContext->fGenBuffers(1, &mPixelBuffer); - } - mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer); - int32_t length = size.width * 4 * size.height; - - if (length > mPixelBufferSize) { - mGLContext->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER, length, - NULL, LOCAL_GL_STREAM_DRAW); - mPixelBufferSize = length; - } - unsigned char* data = - (unsigned char*)mGLContext-> - fMapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, - LOCAL_GL_WRITE_ONLY); - - mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); - - if (!data) { - nsAutoCString failure; - failure += "Pixel buffer binding failed: "; - failure.AppendPrintf("%dx%d\n", size.width, size.height); - gfx::LogFailure(failure); - - mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); - return gfxPlatform::GetPlatform()-> - CreateOffscreenSurface(size, - gfxASurface::ContentFromFormat(aFmt)); - } - - nsRefPtr surf = - new gfxQuartzSurface(data, size, size.width * 4, aFmt); - - mBoundPixelBuffer = true; - return surf.forget(); - } - - bool FinishedSurfaceUpdate() - { - if (mBoundPixelBuffer) { - mGLContext->MakeCurrent(); - mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer); - mGLContext->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER); - return true; - } - return false; - } - - void FinishedSurfaceUpload() - { - if (mBoundPixelBuffer) { - mGLContext->MakeCurrent(); - mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); - mBoundPixelBuffer = false; - } - } - -private: - TextureImageCGL(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags = TextureImage::NoFlags) - : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags) - , mPixelBuffer(0) - , mPixelBufferSize(0) - , mBoundPixelBuffer(false) - {} - - GLuint mPixelBuffer; - int32_t mPixelBufferSize; - bool mBoundPixelBuffer; -}; - -already_AddRefed -GLContextCGL::CreateBasicTextureImage(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - TextureImage::ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags) -{ - nsRefPtr teximage - (new TextureImageCGL(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags)); - return teximage.forget(); -} - -static GLContextCGL * -GetGlobalContextCGL() -{ - return static_cast(GLContextProviderCGL::GetGlobalContext()); -} - -already_AddRefed -GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget) -{ - if (!sCGLLibrary.EnsureInitialized()) { - return nullptr; - } - - GLContextCGL *shareContext = GetGlobalContextCGL(); - - NSOpenGLContext *context = [[NSOpenGLContext alloc] - initWithFormat:sCGLLibrary.PixelFormat() - shareContext:(shareContext ? shareContext->mContext : NULL)]; - if (!context) { - return nullptr; - } - - // make the context transparent - GLint opaque = 0; - [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; - - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr glContext = new GLContextCGL(caps, - shareContext, - context); - if (!glContext->Init()) { - return nullptr; - } - - return glContext.forget(); -} - -static already_AddRefed -CreateOffscreenFBOContext(bool aShare = true) -{ - if (!sCGLLibrary.EnsureInitialized()) { - return nullptr; - } - - GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; - if (aShare && !shareContext) { - // if there is no share context, then we can't use FBOs. - return nullptr; - } - - NSOpenGLContext *context = [[NSOpenGLContext alloc] - initWithFormat:sCGLLibrary.PixelFormat() - shareContext:shareContext ? shareContext->mContext : NULL]; - if (!context) { - return nullptr; - } - - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = new GLContextCGL(dummyCaps, shareContext, context, true); - - return glContext.forget(); -} - -already_AddRefed -GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - const ContextFlags flags) -{ - nsRefPtr glContext = CreateOffscreenFBOContext(); - if (glContext && - glContext->Init() && - glContext->InitOffscreen(size, caps)) - { - return glContext.forget(); - } - - // everything failed - return nullptr; -} - -static nsRefPtr gGlobalContext; - -GLContext * -GLContextProviderCGL::GetGlobalContext(const ContextFlags) -{ - if (!sCGLLibrary.EnsureInitialized()) { - return nullptr; - } - - if (!gGlobalContext) { - // There are bugs in some older drivers with pbuffers less - // than 16x16 in size; also 16x16 is POT so that we can do - // a FBO with it on older video cards. A FBO context for - // sharing is preferred since it has no associated target. - gGlobalContext = CreateOffscreenFBOContext(false); - if (!gGlobalContext || !static_cast(gGlobalContext.get())->Init()) { - NS_WARNING("Couldn't init gGlobalContext."); - gGlobalContext = nullptr; - return nullptr; - } - - gGlobalContext->SetIsGlobalSharedContext(true); - } - - return gGlobalContext; -} - -void -GLContextProviderCGL::Shutdown() -{ - gGlobalContext = nullptr; -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLContextProviderEGL.cpp b/libazure/src/gfx/gl/GLContextProviderEGL.cpp deleted file mode 100644 index 5e96d41..0000000 --- a/libazure/src/gfx/gl/GLContextProviderEGL.cpp +++ /dev/null @@ -1,2365 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Util.h" -// please add new includes below Qt, otherwise it break Qt build due malloc wrapper conflicts - -#if defined(XP_UNIX) - -#ifdef MOZ_WIDGET_GTK -#include -// we're using default display for now -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#elif defined(MOZ_WIDGET_QT) -#include -#define GLdouble_defined 1 -// we're using default display for now -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)static_cast(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->winId() -#elif defined(MOZ_WIDGET_GONK) -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#include "HwcComposer2D.h" -#endif - -#if defined(MOZ_X11) -#include -#include -#include "mozilla/X11Util.h" -#include "gfxXlibSurface.h" -#endif - -#if defined(ANDROID) -/* from widget */ -#if defined(MOZ_WIDGET_ANDROID) -#include "AndroidBridge.h" -#include "nsSurfaceTexture.h" -#endif - -#include -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - -# if defined(MOZ_WIDGET_GONK) -# include "cutils/properties.h" -# include - -using namespace android; -# endif - -#endif - -#define GLES2_LIB "libGLESv2.so" -#define GLES2_LIB2 "libGLESv2.so.2" - -#elif defined(XP_WIN) - -#include "nsIFile.h" - -#define GLES2_LIB "libGLESv2.dll" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#include - -// a little helper -class AutoDestroyHWND { -public: - AutoDestroyHWND(HWND aWnd = NULL) - : mWnd(aWnd) - { - } - - ~AutoDestroyHWND() { - if (mWnd) { - ::DestroyWindow(mWnd); - } - } - - operator HWND() { - return mWnd; - } - - HWND forget() { - HWND w = mWnd; - mWnd = NULL; - return w; - } - - HWND operator=(HWND aWnd) { - if (mWnd && mWnd != aWnd) { - ::DestroyWindow(mWnd); - } - mWnd = aWnd; - return mWnd; - } - - HWND mWnd; -}; - -#else - -#error "Platform not recognized" - -#endif - -#include "mozilla/Preferences.h" -#include "gfxUtils.h" -#include "gfxFailure.h" -#include "gfxASurface.h" -#include "gfxImageSurface.h" -#include "gfxPlatform.h" -#include "GLContextProvider.h" -#include "GLLibraryEGL.h" -#include "nsDebug.h" -#include "nsThreadUtils.h" - -#include "nsIWidget.h" - -#include "gfxCrashReporterUtils.h" - - -#if defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_WIDGET_GONK) -static bool gUseBackingSurface = true; -#else -static bool gUseBackingSurface = false; -#endif - -#ifdef MOZ_WIDGET_GONK -extern nsIntRect gScreenBounds; -#endif - -#define EGL_DISPLAY() sEGLLibrary.Display() - -namespace mozilla { -namespace gl { - -static GLLibraryEGL sEGLLibrary; - -#define ADD_ATTR_2(_array, _k, _v) do { \ - (_array).AppendElement(_k); \ - (_array).AppendElement(_v); \ -} while (0) - -#define ADD_ATTR_1(_array, _k) do { \ - (_array).AppendElement(_k); \ -} while (0) - -#ifndef MOZ_ANDROID_OMTC -static EGLSurface -CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config); -#endif - -static bool -CreateConfig(EGLConfig* aConfig); -#ifdef MOZ_X11 - -static EGLConfig -CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nullptr); -#endif - -static EGLint gContextAttribs[] = { - LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, - LOCAL_EGL_NONE -}; - -static EGLint gContextAttribsRobustness[] = { - LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, - //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE, - LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT, - LOCAL_EGL_NONE -}; - -static int -next_power_of_two(int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - return v; -} - -static bool -is_power_of_two(int v) -{ - NS_ASSERTION(v >= 0, "bad value"); - - if (v == 0) - return true; - - return (v & (v-1)) == 0; -} - -class GLContextEGL : public GLContext -{ - friend class TextureImageEGL; - - static already_AddRefed - CreateGLContext(const SurfaceCaps& caps, - GLContextEGL *shareContext, - bool isOffscreen, - EGLConfig config, - EGLSurface surface) - { - if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) { - NS_WARNING("Failed to bind API to GLES!"); - return nullptr; - } - - EGLContext eglShareContext = shareContext ? shareContext->mContext - : EGL_NO_CONTEXT; - EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness - : gContextAttribs; - - EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), - config, - eglShareContext, - attribs); - if (!context && shareContext) { - shareContext = nullptr; - context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), - config, - EGL_NO_CONTEXT, - attribs); - } - if (!context) { - NS_WARNING("Failed to create EGLContext!"); - return nullptr; - } - - nsRefPtr glContext = new GLContextEGL(caps, - shareContext, - isOffscreen, - config, - surface, - context); - - if (!glContext->Init()) - return nullptr; - - return glContext.forget(); - } - -public: - GLContextEGL(const SurfaceCaps& caps, - GLContext* shareContext, - bool isOffscreen, - EGLConfig config, - EGLSurface surface, - EGLContext context) - : GLContext(caps, shareContext, isOffscreen) - , mConfig(config) - , mSurface(surface) - , mCurSurface(surface) - , mContext(context) - , mPlatformContext(nullptr) - , mThebesSurface(nullptr) - , mBound(false) - , mIsPBuffer(false) - , mIsDoubleBuffered(false) - , mCanBindToTexture(false) - , mShareWithEGLImage(false) - , mTemporaryEGLImageTexture(0) - { - // any EGL contexts will always be GLESv2 - SetIsGLES2(true); - -#ifdef DEBUG - printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); -#endif -#ifdef MOZ_WIDGET_GONK - if (!mIsOffscreen) { - mHwc = HwcComposer2D::GetInstance(); - MOZ_ASSERT(!mHwc->Initialized()); - - if (mHwc->Init(EGL_DISPLAY(), mSurface)) { - NS_WARNING("HWComposer initialization failed!"); - mHwc = nullptr; - } - } -#endif - } - - ~GLContextEGL() - { - if (MakeCurrent()) { - if (mTemporaryEGLImageTexture != 0) { - fDeleteTextures(1, &mTemporaryEGLImageTexture); - mTemporaryEGLImageTexture = 0; - } - } - - MarkDestroyed(); - - // If mGLWidget is non-null, then we've been given it by the GL context provider, - // and it's managed by the widget implementation. In this case, We can't destroy - // our contexts. - if (mPlatformContext) - return; - -#ifdef DEBUG - printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); -#endif - - sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext); - if (mSurface && !mPlatformContext) { - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); - } - } - - GLContextType GetContextType() { - return ContextTypeEGL; - } - - bool Init() - { -#if defined(ANDROID) - // We can't use LoadApitraceLibrary here because the GLContext - // expects its own handle to the GL library - if (!OpenLibrary(APITRACE_LIB)) -#endif - if (!OpenLibrary(GLES2_LIB)) { -#if defined(XP_UNIX) - if (!OpenLibrary(GLES2_LIB2)) { - NS_WARNING("Couldn't load GLES2 LIB."); - return false; - } -#endif - } - -#ifdef MOZ_WIDGET_GONK - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.build.version.sdk", propValue, "0"); - if (atoi(propValue) < 15) - gUseBackingSurface = false; -#endif - - bool current = MakeCurrent(); - if (!current) { - gfx::LogFailure(NS_LITERAL_CSTRING( - "Couldn't get device attachments for device.")); - return false; - } - - SetupLookupFunction(); - if (!InitWithPrefix("gl", true)) - return false; - - PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t)); - mMaxTextureImageSize = INT32_MAX; - - mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() && - sEGLLibrary.HasKHRImageTexture2D() && - IsExtensionSupported(OES_EGL_image); - - return true; - } - - bool IsDoubleBuffered() { - return mIsDoubleBuffered; - } - - void SetIsDoubleBuffered(bool aIsDB) { - mIsDoubleBuffered = aIsDB; - } - - virtual EGLContext GetEGLContext() { - return mContext; - } - - virtual GLLibraryEGL* GetLibraryEGL() { - return &sEGLLibrary; - } - - - bool SupportsRobustness() - { - return sEGLLibrary.HasRobustness(); - } - - virtual bool IsANGLE() - { - return sEGLLibrary.IsANGLE(); - } - - bool BindTexImage() - { - if (!mSurface) - return false; - - if (mBound && !ReleaseTexImage()) - return false; - - EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(), - (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER); - if (success == LOCAL_EGL_FALSE) - return false; - - mBound = true; - return true; - } - - bool ReleaseTexImage() - { - if (!mBound) - return true; - - if (!mSurface) - return false; - - EGLBoolean success; - success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), - (EGLSurface)mSurface, - LOCAL_EGL_BACK_BUFFER); - if (success == LOCAL_EGL_FALSE) - return false; - - mBound = false; - return true; - } - - bool BindExternalBuffer(GLuint texture, void* buffer) - { -#if defined(MOZ_WIDGET_GONK) - EGLint attrs[] = { - LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, - LOCAL_EGL_NONE, LOCAL_EGL_NONE - }; - EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(), - EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, - buffer, attrs); - fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, texture); - fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, image); - sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image); - return true; -#else - return false; -#endif - } - - bool UnbindExternalBuffer(GLuint texture) - { -#if defined(MOZ_WIDGET_GONK) - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, texture); - fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, - LOCAL_GL_RGBA, - 1, 1, 0, - LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, - nullptr); - return true; -#else - return false; -#endif - } - -#ifdef MOZ_WIDGET_GONK - virtual already_AddRefed - CreateDirectTextureImage(GraphicBuffer* aBuffer, GLenum aWrapMode) MOZ_OVERRIDE; -#endif - - virtual void MakeCurrent_EGLSurface(void* surf) { - EGLSurface eglSurface = (EGLSurface)surf; - if (!eglSurface) - eglSurface = mSurface; - - if (eglSurface == mCurSurface) - return; - - // Else, surface changed... - mCurSurface = eglSurface; - MakeCurrent(true); - } - - bool MakeCurrentImpl(bool aForce = false) { - bool succeeded = true; - - // Assume that EGL has the same problem as WGL does, - // where MakeCurrent with an already-current context is - // still expensive. -#ifndef MOZ_WIDGET_QT - if (!mSurface) { - // We need to be able to bind NO_SURFACE when we don't - // have access to a surface. We won't be drawing to the screen - // but we will be able to do things like resource releases. - succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), - EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (!succeeded && sEGLLibrary.fGetError() == LOCAL_EGL_CONTEXT_LOST) { - mContextLost = true; - NS_WARNING("EGL context has been lost."); - } - NS_ASSERTION(succeeded, "Failed to make GL context current!"); - return succeeded; - } -#endif - if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) { -#ifdef MOZ_WIDGET_QT - // Shared Qt GL context need to be informed about context switch - if (mSharedContext) { - QGLContext* qglCtx = static_cast(static_cast(mSharedContext.get())->mPlatformContext); - if (qglCtx) { - qglCtx->doneCurrent(); - } - } -#endif - succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), - mCurSurface, mCurSurface, - mContext); - - int eglError = sEGLLibrary.fGetError(); - if (!succeeded) { - if (eglError == LOCAL_EGL_CONTEXT_LOST) { - mContextLost = true; - NS_WARNING("EGL context has been lost."); - } else { - NS_WARNING("Failed to make GL context current!"); -#ifdef DEBUG - printf_stderr("EGL Error: 0x%04x\n", eglError); -#endif - } - } - } - - return succeeded; - } - - virtual bool IsCurrent() { - return sEGLLibrary.fGetCurrentContext() == mContext; - } - -#ifdef MOZ_WIDGET_QT - virtual bool - RenewSurface() { - /* We don't support renewing on QT because we don't create the surface ourselves */ - return false; - } -#else - virtual bool - RenewSurface() { - sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (!mSurface) { -#ifdef MOZ_ANDROID_OMTC - mSurface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface(); - if (!mSurface) { - return false; - } -#else - EGLConfig config; - CreateConfig(&config); - mSurface = CreateSurfaceForWindow(NULL, config); -#endif - } - return sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), - mSurface, mSurface, - mContext); - } -#endif - - virtual void - ReleaseSurface() { - if (mSurface && !mPlatformContext) { - sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); - mSurface = NULL; - } - } - - bool SetupLookupFunction() - { - mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress; - return true; - } - - void *GetNativeData(NativeDataType aType) - { - switch (aType) { - case NativeGLContext: - return mContext; - - default: - return nullptr; - } - } - - bool SwapBuffers() - { - if (mSurface && !mPlatformContext) { -#ifdef MOZ_WIDGET_GONK - if (mHwc) - return !mHwc->swapBuffers((hwc_display_t)EGL_DISPLAY(), - (hwc_surface_t)mSurface); - else -#endif - return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface); - } else { - return false; - } - } - // GLContext interface - returns Tiled Texture Image in our case - virtual already_AddRefed - CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags = TextureImage::NoFlags); - - // a function to generate Tiles for Tiled Texture Image - virtual already_AddRefed - TileGenFunc(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - TextureImage::Flags aFlags = TextureImage::NoFlags); - // hold a reference to the given surface - // for the lifetime of this context. - void HoldSurface(gfxASurface *aSurf) { - mThebesSurface = aSurf; - } - - void SetPlatformContext(void *context) { - mPlatformContext = context; - } - - EGLContext Context() { - return mContext; - } - - bool BindTex2DOffscreen(GLContext *aOffscreen); - void UnbindTex2DOffscreen(GLContext *aOffscreen); - bool ResizeOffscreen(const gfxIntSize& aNewSize); - void BindOffscreenFramebuffer(); - - static already_AddRefed - CreateEGLPixmapOffscreenContext(const gfxIntSize& size); - - static already_AddRefed - CreateEGLPBufferOffscreenContext(const gfxIntSize& size); - - virtual bool HasLockSurface() { - return sEGLLibrary.HasKHRLockSurface(); - } - - virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType); - virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType, - void* buffer, - SharedTextureBufferType bufferType); - virtual void UpdateSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle); - virtual void ReleaseSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle); - virtual bool GetSharedHandleDetails(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle, - SharedHandleDetails& details); - virtual bool AttachSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle); - -protected: - friend class GLContextProviderEGL; - - EGLConfig mConfig; - EGLSurface mSurface; - EGLSurface mCurSurface; - EGLContext mContext; - void *mPlatformContext; - nsRefPtr mThebesSurface; - bool mBound; - - bool mIsPBuffer; - bool mIsDoubleBuffered; - bool mCanBindToTexture; - bool mShareWithEGLImage; -#ifdef MOZ_WIDGET_GONK - nsRefPtr mHwc; -#endif - - // A dummy texture ID that can be used when we need a texture object whose - // images we're going to define with EGLImageTargetTexture2D. - GLuint mTemporaryEGLImageTexture; - - static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config, - EGLenum bindToTextureFormat, - gfxIntSize& pbsize) - { - nsTArray pbattrs(16); - EGLSurface surface = nullptr; - - TRY_AGAIN_POWER_OF_TWO: - pbattrs.Clear(); - pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width); - pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height); - - if (bindToTextureFormat != LOCAL_EGL_NONE) { - pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET); - pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D); - - pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT); - pbattrs.AppendElement(bindToTextureFormat); - } - - pbattrs.AppendElement(LOCAL_EGL_NONE); - - surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]); - if (!surface) { - if (!is_power_of_two(pbsize.width) || - !is_power_of_two(pbsize.height)) - { - if (!is_power_of_two(pbsize.width)) - pbsize.width = next_power_of_two(pbsize.width); - if (!is_power_of_two(pbsize.height)) - pbsize.height = next_power_of_two(pbsize.height); - - NS_WARNING("Failed to create pbuffer, trying power of two dims"); - goto TRY_AGAIN_POWER_OF_TWO; - } - - NS_WARNING("Failed to create pbuffer surface"); - return nullptr; - } - - return surface; - } -}; - - -typedef enum { - Image -#ifdef MOZ_WIDGET_ANDROID - , SurfaceTexture -#endif -} SharedHandleType; - -class SharedTextureHandleWrapper -{ -public: - SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType) - { - } - - virtual ~SharedTextureHandleWrapper() - { - } - - SharedHandleType Type() { return mHandleType; } - - SharedHandleType mHandleType; -}; - -#ifdef MOZ_WIDGET_ANDROID - -class SurfaceTextureWrapper: public SharedTextureHandleWrapper -{ -public: - SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) : - SharedTextureHandleWrapper(SharedHandleType::SurfaceTexture) - , mSurfaceTexture(aSurfaceTexture) - { - } - - virtual ~SurfaceTextureWrapper() { - mSurfaceTexture = nullptr; - } - - nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; } - - nsRefPtr mSurfaceTexture; -}; - -#endif // MOZ_WIDGET_ANDROID - -class EGLTextureWrapper : public SharedTextureHandleWrapper -{ -public: - EGLTextureWrapper() : - SharedTextureHandleWrapper(SharedHandleType::Image) - , mEGLImage(nullptr) - , mSyncObject(nullptr) - { - } - - // Args are the active GL context, and a texture in that GL - // context for which to create an EGLImage. After the EGLImage - // is created, the texture is unused by EGLTextureWrapper. - bool CreateEGLImage(GLContextEGL *ctx, GLuint texture) { - MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase()); - static const EGLint eglAttributes[] = { - LOCAL_EGL_NONE - }; - EGLContext eglContext = (EGLContext)ctx->GetEGLContext(); - mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, - (EGLClientBuffer)texture, eglAttributes); - if (!mEGLImage) { -#ifdef DEBUG - printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); -#endif - return false; - } - return true; - } - - virtual ~EGLTextureWrapper() { - if (mEGLImage) { - sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage); - mEGLImage = nullptr; - } - } - - const EGLImage GetEGLImage() { - return mEGLImage; - } - - // Insert a sync point on the given context, which should be the current active - // context. - bool MakeSync(GLContext *ctx) { - MOZ_ASSERT(mSyncObject == nullptr); - - if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) { - mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr); - // We need to flush to make sure the sync object enters the command stream; - // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait - // happens on a different thread/context. - ctx->fFlush(); - } - - if (mSyncObject == EGL_NO_SYNC) { - // we failed to create one, so just do a finish - ctx->fFinish(); - } - - return true; - } - - bool WaitSync() { - if (!mSyncObject) { - // if we have no sync object, then we did a Finish() earlier - return true; - } - - // wait at most 1 second; this should really be never/rarely hit - const uint64_t ns_per_ms = 1000 * 1000; - EGLTime timeout = 1000 * ns_per_ms; - - EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout); - sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject); - mSyncObject = nullptr; - - return result == LOCAL_EGL_CONDITION_SATISFIED; - } - -private: - EGLImage mEGLImage; - EGLSync mSyncObject; -}; - -void -GLContextEGL::UpdateSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) -{ - if (shareType != SameProcess) { - NS_ERROR("Implementation not available for this sharing type"); - return; - } - - SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); - - NS_ASSERTION(wrapper->Type() == SharedHandleType::Image, "Expected EGLImage shared handle"); - NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); - - EGLTextureWrapper* wrap = reinterpret_cast(wrapper); - // We need to copy the current GLContext drawing buffer to the texture - // exported by the EGLImage. Need to save both the read FBO and the texture - // binding, because we're going to munge them to do this. - ScopedBindTexture autoTex(this, mTemporaryEGLImageTexture); - fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); - - // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with - // draw quads, but if we want that, we need to assure that our default - // framebuffer is texture-backed. - gfxIntSize size = OffscreenSize(); - BlitFramebufferToTexture(0, mTemporaryEGLImageTexture, size, size); - - // Make sure our copy is finished, so that we can be ready to draw - // in different thread GLContext. If we have KHR_fence_sync, then - // we insert a sync object, otherwise we have to do a GuaranteeResolve. - wrap->MakeSync(this); -} - -SharedTextureHandle -GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType) -{ - if (shareType != SameProcess) - return 0; - - if (!mShareWithEGLImage) - return 0; - - MakeCurrent(); - mTemporaryEGLImageTexture = CreateTextureForOffscreen(GetGLFormats(), OffscreenSize()); - - EGLTextureWrapper* tex = new EGLTextureWrapper(); - bool ok = tex->CreateEGLImage(this, mTemporaryEGLImageTexture); - - if (!ok) { - NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); - ReleaseSharedHandle(shareType, (SharedTextureHandle)tex); - return 0; - } - - // Raw pointer shared across threads - return (SharedTextureHandle)tex; -} - -SharedTextureHandle -GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType, - void* buffer, - SharedTextureBufferType bufferType) -{ - // Both EGLImage and SurfaceTexture only support same-process currently, but - // it's possible to make SurfaceTexture work across processes. We should do that. - if (shareType != SameProcess) - return 0; - - switch (bufferType) { -#ifdef MOZ_WIDGET_ANDROID - case SharedTextureBufferType::SurfaceTexture: - if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) { - NS_WARNING("Missing GL_OES_EGL_image_external"); - return 0; - } - - return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast(buffer)); -#endif - case SharedTextureBufferType::TextureID: { - if (!mShareWithEGLImage) - return 0; - - GLuint texture = (uintptr_t)buffer; - EGLTextureWrapper* tex = new EGLTextureWrapper(); - if (!tex->CreateEGLImage(this, texture)) { - NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); - delete tex; - return 0; - } - - return (SharedTextureHandle)tex; - } - default: - NS_ERROR("Unknown shared texture buffer type"); - return 0; - } -} - -void GLContextEGL::ReleaseSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) -{ - if (shareType != SameProcess) { - NS_ERROR("Implementation not available for this sharing type"); - return; - } - - SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); - - switch (wrapper->Type()) { -#ifdef MOZ_WIDGET_ANDROID - case SharedHandleType::SurfaceTexture: - delete wrapper; - break; -#endif - - case SharedHandleType::Image: { - NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); - - EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; - delete wrap; - break; - } - - default: - NS_ERROR("Unknown shared handle type"); - return; - } -} - -bool GLContextEGL::GetSharedHandleDetails(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle, - SharedHandleDetails& details) -{ - if (shareType != SameProcess) - return false; - - SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); - - switch (wrapper->Type()) { -#ifdef MOZ_WIDGET_ANDROID - case SharedHandleType::SurfaceTexture: { - SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast(wrapper); - - details.mTarget = LOCAL_GL_TEXTURE_EXTERNAL; - details.mProgramType = RGBALayerExternalProgramType; - surfaceWrapper->SurfaceTexture()->GetTransformMatrix(details.mTextureTransform); - break; - } -#endif - - case SharedHandleType::Image: - details.mTarget = LOCAL_GL_TEXTURE_2D; - details.mProgramType = RGBALayerProgramType; - break; - - default: - NS_ERROR("Unknown shared handle type"); - return false; - } - - return true; -} - -bool GLContextEGL::AttachSharedHandle(SharedTextureShareType shareType, - SharedTextureHandle sharedHandle) -{ - if (shareType != SameProcess) - return false; - - SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); - - switch (wrapper->Type()) { -#ifdef MOZ_WIDGET_ANDROID - case SharedHandleType::SurfaceTexture: { -#ifndef DEBUG - /** - * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear - * them here in order to avoid that. - */ - GetAndClearError(); -#endif - SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast(wrapper); - - // FIXME: SurfaceTexture provides a transform matrix which is supposed to - // be applied to the texture coordinates. We should return that here - // so we can render correctly. Bug 775083 - surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage(); - break; - } -#endif // MOZ_WIDGET_ANDROID - - case SharedHandleType::Image: { - NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); - - EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; - wrap->WaitSync(); - fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); - break; - } - - default: - NS_ERROR("Unknown shared handle type"); - return false; - } - - return true; -} - -bool -GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) -{ - return ResizeScreenBuffer(aNewSize); -} - - -static GLContextEGL * -GetGlobalContextEGL() -{ - return static_cast(GLContextProviderEGL::GetGlobalContext()); -} - -static GLenum -GLFormatForImage(gfxASurface::gfxImageFormat aFormat) -{ - switch (aFormat) { - case gfxASurface::ImageFormatARGB32: - case gfxASurface::ImageFormatRGB24: - // Thebes only supports RGBX, not packed RGB. - return LOCAL_GL_RGBA; - case gfxASurface::ImageFormatRGB16_565: - return LOCAL_GL_RGB; - case gfxASurface::ImageFormatA8: - return LOCAL_GL_LUMINANCE; - default: - NS_WARNING("Unknown GL format for Image format"); - } - return 0; -} - -#ifdef MOZ_WIDGET_GONK -static PixelFormat -PixelFormatForImage(gfxASurface::gfxImageFormat aFormat) -{ - switch (aFormat) { - case gfxASurface::ImageFormatARGB32: - return PIXEL_FORMAT_RGBA_8888; - case gfxASurface::ImageFormatRGB24: - return PIXEL_FORMAT_RGBX_8888; - case gfxASurface::ImageFormatRGB16_565: - return PIXEL_FORMAT_RGB_565; - case gfxASurface::ImageFormatA8: - return PIXEL_FORMAT_L_8; - default: - MOZ_NOT_REACHED("Unknown gralloc pixel format for Image format"); - } - return 0; -} - -static gfxASurface::gfxContentType -ContentTypeForPixelFormat(PixelFormat aFormat) -{ - switch (aFormat) { - case PIXEL_FORMAT_L_8: - return gfxASurface::CONTENT_ALPHA; - case PIXEL_FORMAT_RGBA_8888: - return gfxASurface::CONTENT_COLOR_ALPHA; - case PIXEL_FORMAT_RGBX_8888: - case PIXEL_FORMAT_RGB_565: - return gfxASurface::CONTENT_COLOR; - default: - MOZ_NOT_REACHED("Unknown content type for gralloc pixel format"); - } - return gfxASurface::CONTENT_COLOR; -} -#endif - -static GLenum -GLTypeForImage(gfxASurface::gfxImageFormat aFormat) -{ - switch (aFormat) { - case gfxASurface::ImageFormatARGB32: - case gfxASurface::ImageFormatRGB24: - case gfxASurface::ImageFormatA8: - return LOCAL_GL_UNSIGNED_BYTE; - case gfxASurface::ImageFormatRGB16_565: - return LOCAL_GL_UNSIGNED_SHORT_5_6_5; - default: - NS_WARNING("Unknown GL format for Image format"); - } - return 0; -} - -class TextureImageEGL - : public TextureImage -{ -public: - TextureImageEGL(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - ContentType aContentType, - GLContext* aContext, - Flags aFlags = TextureImage::NoFlags, - TextureState aTextureState = Created) - : TextureImage(aSize, aWrapMode, aContentType, aFlags) - , mGLContext(aContext) - , mUpdateFormat(gfxASurface::ImageFormatUnknown) - , mEGLImage(nullptr) - , mTexture(aTexture) - , mSurface(nullptr) - , mConfig(nullptr) - , mTextureState(aTextureState) - , mBound(false) - , mIsLocked(false) - { - mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType()); - - if (gUseBackingSurface) { -#ifdef MOZ_WIDGET_GONK - switch (mUpdateFormat) { - case gfxASurface::ImageFormatARGB32: - mShaderType = BGRALayerProgramType; - break; - case gfxASurface::ImageFormatRGB24: - mUpdateFormat = gfxASurface::ImageFormatARGB32; - mShaderType = BGRXLayerProgramType; - break; - case gfxASurface::ImageFormatRGB16_565: - mShaderType = RGBXLayerProgramType; - break; - case gfxASurface::ImageFormatA8: - mShaderType = RGBALayerProgramType; - break; - default: - MOZ_NOT_REACHED("Unknown update format"); - } -#else - if (mUpdateFormat != gfxASurface::ImageFormatARGB32) { - mShaderType = RGBXLayerProgramType; - } else { - mShaderType = RGBALayerProgramType; - } -#endif - Resize(aSize); - } else { - if (mUpdateFormat == gfxASurface::ImageFormatRGB16_565) { - mShaderType = RGBXLayerProgramType; - } else if (mUpdateFormat == gfxASurface::ImageFormatRGB24) { - // RGB24 means really RGBX for Thebes, which means we have to - // use the right shader and ignore the uninitialized alpha - // value. - mShaderType = BGRXLayerProgramType; - } else { - mShaderType = BGRALayerProgramType; - } - } - } - - virtual ~TextureImageEGL() - { - GLContext *ctx = mGLContext; - if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) { - ctx = ctx->GetSharedContext(); - } - - // If we have a context, then we need to delete the texture; - // if we don't have a context (either real or shared), - // then they went away when the contex was deleted, because it - // was the only one that had access to it. - if (ctx && !ctx->IsDestroyed()) { - ctx->MakeCurrent(); - ctx->fDeleteTextures(1, &mTexture); - ReleaseTexImage(); - DestroyEGLSurface(); - } - } - - bool UsingDirectTexture() - { -#ifdef MOZ_WIDGET_GONK - if (mGraphicBuffer != nullptr) - return true; -#endif - return !!mBackingSurface; - } - - virtual void GetUpdateRegion(nsIntRegion& aForRegion) - { - if (mTextureState != Valid) { - // if the texture hasn't been initialized yet, force the - // client to paint everything - aForRegion = nsIntRect(nsIntPoint(0, 0), mSize); - } - - if (UsingDirectTexture()) { - return; - } - - // We can only draw a rectangle, not subregions due to - // the way that our texture upload functions work. If - // needed, we /could/ do multiple texture uploads if we have - // non-overlapping rects, but that's a tradeoff. - aForRegion = nsIntRegion(aForRegion.GetBounds()); - } - - virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) - { - NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?"); - - // determine the region the client will need to repaint - GetUpdateRegion(aRegion); - mUpdateRect = aRegion.GetBounds(); - - //printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height); - if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) { - NS_ERROR("update outside of image"); - return NULL; - } - -#ifdef MOZ_WIDGET_GONK - if (mGraphicBuffer != nullptr) { - mUpdateSurface = GetLockSurface(); - - return mUpdateSurface; - } -#endif - - if (mBackingSurface) { - if (sEGLLibrary.HasKHRLockSurface()) { - mUpdateSurface = GetLockSurface(); - } else { - mUpdateSurface = mBackingSurface; - } - - return mUpdateSurface; - } - - //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat); - - mUpdateSurface = - new gfxImageSurface(gfxIntSize(mUpdateRect.width, mUpdateRect.height), - mUpdateFormat); - - mUpdateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y)); - - return mUpdateSurface; - } - - virtual void EndUpdate() - { - NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?"); - - if (mIsLocked) { - UnlockSurface(); - mTextureState = Valid; - mUpdateSurface = nullptr; - return; - } - - if (mBackingSurface && mUpdateSurface == mBackingSurface) { -#ifdef MOZ_X11 - if (mBackingSurface->GetType() == gfxASurface::SurfaceTypeXlib) { - FinishX(DefaultXDisplay()); - } -#endif - - mBackingSurface->SetDeviceOffset(gfxPoint(0, 0)); - mTextureState = Valid; - mUpdateSurface = nullptr; - return; - } - - //printf_stderr("EndUpdate: slow path"); - - // This is the slower path -- we didn't have any way to set up - // a fast mapping between our cairo target surface and the GL - // texture, so we have to upload data. - - // Undo the device offset that BeginUpdate set; doesn't much - // matter for us here, but important if we ever do anything - // directly with the surface. - mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0)); - - nsRefPtr uploadImage = nullptr; - gfxIntSize updateSize(mUpdateRect.width, mUpdateRect.height); - - NS_ASSERTION(mUpdateSurface->GetType() == gfxASurface::SurfaceTypeImage && - mUpdateSurface->GetSize() == updateSize, - "Upload image isn't an image surface when one is expected, or is wrong size!"); - - uploadImage = static_cast(mUpdateSurface.get()); - - if (!uploadImage) { - return; - } - - mGLContext->MakeCurrent(); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - - if (mTextureState != Valid) { - NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 && - mUpdateRect.Size() == mSize, - "Bad initial update on non-created texture!"); - - mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - GLFormatForImage(mUpdateFormat), - mUpdateRect.width, - mUpdateRect.height, - 0, - GLFormatForImage(uploadImage->Format()), - GLTypeForImage(uploadImage->Format()), - uploadImage->Data()); - } else { - mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, - 0, - mUpdateRect.x, - mUpdateRect.y, - mUpdateRect.width, - mUpdateRect.height, - GLFormatForImage(uploadImage->Format()), - GLTypeForImage(uploadImage->Format()), - uploadImage->Data()); - } - - mUpdateSurface = nullptr; - mTextureState = Valid; - return; // mTexture is bound - } - - virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) - { - nsIntRect bounds = aRegion.GetBounds(); - - nsIntRegion region; - if (mTextureState != Valid) { - bounds = nsIntRect(0, 0, mSize.width, mSize.height); - region = nsIntRegion(bounds); - } else { - region = aRegion; - } - - if ((mBackingSurface && sEGLLibrary.HasKHRLockSurface()) -#ifdef MOZ_WIDGET_GONK - || (mGraphicBuffer != nullptr) -#endif - ) { - mUpdateSurface = GetLockSurface(); - if (mUpdateSurface) { - nsRefPtr ctx = new gfxContext(mUpdateSurface); - gfxUtils::ClipToRegion(ctx, aRegion); - ctx->SetSource(aSurf, gfxPoint(-aFrom.x, -aFrom.y)); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->Paint(); - mUpdateSurface = nullptr; - UnlockSurface(); - } - } else { - mShaderType = - mGLContext->UploadSurfaceToTexture(aSurf, - region, - mTexture, - mTextureState == Created, - bounds.TopLeft() + aFrom, - false); - } - - mTextureState = Valid; - return true; - } - - virtual void BindTexture(GLenum aTextureUnit) - { - // Ensure the texture is allocated before it is used. - if (mTextureState == Created) { - Resize(mSize); - } - -#ifdef MOZ_WIDGET_GONK - if (UsingDirectTexture()) { - mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - mGLContext->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage); - if (sEGLLibrary.fGetError() != LOCAL_EGL_SUCCESS) { - LOG("Could not set image target texture. ERROR (0x%04x)", sEGLLibrary.fGetError()); - } - } else -#endif - { - mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); - } - } - - virtual GLuint GetTextureID() - { - // Ensure the texture is allocated before it is used. - if (mTextureState == Created) { - Resize(mSize); - } - return mTexture; - }; - - virtual bool InUpdate() const { return !!mUpdateSurface; } - - virtual void Resize(const nsIntSize& aSize) - { - NS_ASSERTION(!mUpdateSurface, "Resize() while in update?"); - - if (mSize == aSize && mTextureState != Created) - return; - - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - - // Try to generate a backin surface first if we have the ability - if (gUseBackingSurface) { - CreateBackingSurface(gfxIntSize(aSize.width, aSize.height)); - } - - if (!UsingDirectTexture()) { - // If we don't have a backing surface or failed to obtain one, - // use the GL Texture failsafe - mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - GLFormatForImage(mUpdateFormat), - aSize.width, - aSize.height, - 0, - GLFormatForImage(mUpdateFormat), - GLTypeForImage(mUpdateFormat), - NULL); - } - - mTextureState = Allocated; - mSize = aSize; - } - - bool BindTexImage() - { - if (mBound && !ReleaseTexImage()) - return false; - - EGLBoolean success = - sEGLLibrary.fBindTexImage(EGL_DISPLAY(), - (EGLSurface)mSurface, - LOCAL_EGL_BACK_BUFFER); - - if (success == LOCAL_EGL_FALSE) - return false; - - mBound = true; - return true; - } - - bool ReleaseTexImage() - { - if (!mBound) - return true; - - EGLBoolean success = - sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), - (EGLSurface)mSurface, - LOCAL_EGL_BACK_BUFFER); - - if (success == LOCAL_EGL_FALSE) - return false; - - mBound = false; - return true; - } - - virtual already_AddRefed GetLockSurface() - { - if (mIsLocked) { - NS_WARNING("Can't lock surface twice"); - return nullptr; - } - -#ifdef MOZ_WIDGET_GONK - if (mGraphicBuffer != nullptr) { - // Unset the EGLImage target so that we don't get clashing locks - mGLContext->MakeCurrent(true); - mGLContext->UnbindExternalBuffer(mTexture); - - void *vaddr; - if (mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN, - &vaddr) != OK) { - LOG("Could not lock GraphicBuffer"); - return nullptr; - } - - nsRefPtr surface = - new gfxImageSurface(reinterpret_cast(vaddr), - gfxIntSize(mSize.width, mSize.height), - mGraphicBuffer->getStride() * gfxUtils::ImageFormatToDepth(mUpdateFormat) / 8, - mUpdateFormat); - - mIsLocked = true; - - return surface.forget(); - } -#endif - - if (!sEGLLibrary.HasKHRLockSurface()) { - NS_WARNING("GetLockSurface called, but no EGL_KHR_lock_surface extension!"); - return nullptr; - } - - if (!CreateEGLSurface(mBackingSurface)) { - NS_WARNING("Failed to create EGL surface"); - return nullptr; - } - - static EGLint lock_attribs[] = { - LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR, LOCAL_EGL_TRUE, - LOCAL_EGL_LOCK_USAGE_HINT_KHR, LOCAL_EGL_READ_SURFACE_BIT_KHR | LOCAL_EGL_WRITE_SURFACE_BIT_KHR, - LOCAL_EGL_NONE - }; - - sEGLLibrary.fLockSurface(EGL_DISPLAY(), mSurface, lock_attribs); - - mIsLocked = true; - - unsigned char *data = nullptr; - int pitch = 0; - int pixsize = 0; - - sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_POINTER_KHR, (EGLint*)&data); - sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_PITCH_KHR, &pitch); - sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR, &pixsize); - - nsRefPtr sharedImage = - new gfxImageSurface(data, - mBackingSurface->GetSize(), - pitch, - mUpdateFormat); - - return sharedImage.forget(); - } - - virtual void UnlockSurface() - { - if (!mIsLocked) { - NS_WARNING("UnlockSurface called, surface not locked!"); - return; - } - - mIsLocked = false; - -#ifdef MOZ_WIDGET_GONK - if (mGraphicBuffer != nullptr) { - mGraphicBuffer->unlock(); - - return; - } -#endif - - sEGLLibrary.fUnlockSurface(EGL_DISPLAY(), mSurface); - } - - virtual already_AddRefed GetBackingSurface() - { - nsRefPtr copy = mBackingSurface; - return copy.forget(); - } - - virtual bool CreateEGLSurface(gfxASurface* aSurface) - { -#ifdef MOZ_X11 - if (!aSurface) { - NS_WARNING("no surface"); - return false; - } - - if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) { - NS_WARNING("wrong surface type, must be xlib"); - return false; - } - - if (mSurface) { - return true; - } - - EGLSurface surface = CreateEGLSurfaceForXSurface(aSurface, &mConfig); - - if (!surface) { - NS_WARNING("couldn't find X config for surface"); - return false; - } - - mSurface = surface; - return true; -#else - return false; -#endif - } - - virtual void DestroyEGLSurface(void) - { -#ifdef MOZ_WIDGET_GONK - mGraphicBuffer.clear(); - - if (mEGLImage) { - sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage); - mEGLImage = nullptr; - } -#endif - - if (!mSurface) - return; - - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); - mSurface = nullptr; - } - - virtual bool CreateBackingSurface(const gfxIntSize& aSize) - { - ReleaseTexImage(); - DestroyEGLSurface(); - mBackingSurface = nullptr; - -#ifdef MOZ_X11 - Display* dpy = DefaultXDisplay(); - XRenderPictFormat* renderFMT = - gfxXlibSurface::FindRenderFormat(dpy, mUpdateFormat); - - nsRefPtr xsurface = - gfxXlibSurface::Create(DefaultScreenOfDisplay(dpy), - renderFMT, - gfxIntSize(aSize.width, aSize.height)); - - XSync(dpy, False); - mConfig = nullptr; - - if (sEGLLibrary.HasKHRImagePixmap() && - mGLContext->IsExtensionSupported(GLContext::OES_EGL_image)) - { - mEGLImage = - sEGLLibrary.fCreateImage(EGL_DISPLAY(), - EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_PIXMAP, - (EGLClientBuffer)xsurface->XDrawable(), - nullptr); - - if (!mEGLImage) { - printf_stderr("couldn't create EGL image: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); - return false; - } - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - mGLContext->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage); - sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage); - mEGLImage = nullptr; - } else { - if (!CreateEGLSurface(xsurface)) { - printf_stderr("ProviderEGL Failed create EGL surface: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); - return false; - } - - if (!BindTexImage()) { - printf_stderr("ProviderEGL Failed to bind teximage: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); - return false; - } - } - - mBackingSurface = xsurface; - - return mBackingSurface != nullptr; -#endif - -#ifdef MOZ_WIDGET_GONK - if (gUseBackingSurface && aSize.width >= 64) { - mGLContext->MakeCurrent(true); - PixelFormat format = PixelFormatForImage(mUpdateFormat); - uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN; - mGraphicBuffer = new GraphicBuffer(aSize.width, aSize.height, format, usage); - if (mGraphicBuffer->initCheck() == OK) { - const int eglImageAttributes[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, - LOCAL_EGL_NONE, LOCAL_EGL_NONE }; - mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), - EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer) mGraphicBuffer->getNativeBuffer(), - eglImageAttributes); - if (!mEGLImage) { - mGraphicBuffer = nullptr; - LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError()); - return false; - } - - return true; - } - - mGraphicBuffer = nullptr; - LOG("GraphicBufferAllocator::alloc failed"); - return false; - } -#endif - return mBackingSurface != nullptr; - } - -protected: - typedef gfxASurface::gfxImageFormat ImageFormat; - - GLContext* mGLContext; - - nsIntRect mUpdateRect; - ImageFormat mUpdateFormat; - bool mUsingDirectTexture; - nsRefPtr mBackingSurface; - nsRefPtr mUpdateSurface; -#ifdef MOZ_WIDGET_GONK - sp mGraphicBuffer; -#endif - EGLImage mEGLImage; - GLuint mTexture; - EGLSurface mSurface; - EGLConfig mConfig; - TextureState mTextureState; - - bool mBound; - bool mIsLocked; - - virtual void ApplyFilter() - { - mGLContext->ApplyFilterToBoundTexture(mFilter); - } -}; - -#ifdef MOZ_WIDGET_GONK - -class DirectTextureImageEGL - : public TextureImageEGL -{ -public: - DirectTextureImageEGL(GLuint aTexture, - sp aGraphicBuffer, - GLenum aWrapMode, - GLContext* aContext) - : TextureImageEGL(aTexture, - nsIntSize(aGraphicBuffer->getWidth(), aGraphicBuffer->getHeight()), - aWrapMode, - ContentTypeForPixelFormat(aGraphicBuffer->getPixelFormat()), - aContext, - ForceSingleTile, - Valid) - { - mGraphicBuffer = aGraphicBuffer; - - const int eglImageAttributes[] = - { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, - LOCAL_EGL_NONE, LOCAL_EGL_NONE }; - - mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), - EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, - mGraphicBuffer->getNativeBuffer(), - eglImageAttributes); - if (!mEGLImage) { - LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError()); - } - } -}; - -#endif // MOZ_WIDGET_GONK - -already_AddRefed -GLContextEGL::CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags) -{ - nsRefPtr t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags); - return t.forget(); -} - -#ifdef MOZ_WIDGET_GONK -already_AddRefed -GLContextEGL::CreateDirectTextureImage(GraphicBuffer* aBuffer, - GLenum aWrapMode) -{ - MakeCurrent(); - - GLuint texture; - fGenTextures(1, &texture); - - nsRefPtr texImage( - new DirectTextureImageEGL(texture, aBuffer, aWrapMode, this)); - texImage->BindTexture(LOCAL_GL_TEXTURE0); - - GLint texfilter = LOCAL_GL_LINEAR; - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode); - - return texImage.forget(); -} -#endif // MOZ_WIDGET_GONK - -already_AddRefed -GLContextEGL::TileGenFunc(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - TextureImage::Flags aFlags) -{ - MakeCurrent(); - - GLuint texture; - fGenTextures(1, &texture); - - nsRefPtr teximage = - new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this, aFlags); - - teximage->BindTexture(LOCAL_GL_TEXTURE0); - - GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); - - return teximage.forget(); -} - -static nsRefPtr gGlobalContext; - -static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_NONE -}; - -static const EGLint kEGLConfigAttribsRGB16[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 5, - LOCAL_EGL_GREEN_SIZE, 6, - LOCAL_EGL_BLUE_SIZE, 5, - LOCAL_EGL_ALPHA_SIZE, 0, - LOCAL_EGL_NONE -}; - -static const EGLint kEGLConfigAttribsRGB24[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 8, - LOCAL_EGL_GREEN_SIZE, 8, - LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 0, - LOCAL_EGL_NONE -}; - -static const EGLint kEGLConfigAttribsRGBA32[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_RED_SIZE, 8, - LOCAL_EGL_GREEN_SIZE, 8, - LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 8, - LOCAL_EGL_NONE -}; - -static bool -CreateConfig(EGLConfig* aConfig, int32_t depth) -{ - EGLConfig configs[64]; - const EGLint* attribs; - EGLint ncfg = ArrayLength(configs); - - switch (depth) { - case 16: - attribs = kEGLConfigAttribsRGB16; - break; - case 24: - attribs = kEGLConfigAttribsRGB24; - break; - case 32: - attribs = kEGLConfigAttribsRGBA32; - break; - default: - NS_ERROR("Unknown pixel depth"); - return false; - } - - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs, - configs, ncfg, &ncfg) || - ncfg < 1) { - return false; - } - - for (int j = 0; j < ncfg; ++j) { - EGLConfig config = configs[j]; - EGLint r, g, b, a; - - if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, - LOCAL_EGL_RED_SIZE, &r) && - sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, - LOCAL_EGL_GREEN_SIZE, &g) && - sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, - LOCAL_EGL_BLUE_SIZE, &b) && - sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, - LOCAL_EGL_ALPHA_SIZE, &a) && - ((depth == 16 && r == 5 && g == 6 && b == 5) || - (depth == 24 && r == 8 && g == 8 && b == 8) || - (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) - { - *aConfig = config; - return true; - } - } - return false; -} - -// Return true if a suitable EGLConfig was found and pass it out -// through aConfig. Return false otherwise. -// -// NB: It's entirely legal for the returned EGLConfig to be valid yet -// have the value null. -static bool -CreateConfig(EGLConfig* aConfig) -{ - int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth(); - if (!CreateConfig(aConfig, depth)) { -#ifdef MOZ_WIDGET_ANDROID - // Bug 736005 - // Android doesn't always support 16 bit so also try 24 bit - if (depth == 16) { - return CreateConfig(aConfig, 24); - } -#endif - return false; - } else { - return true; - } -} - -// When MOZ_ANDROID_OMTC is defined, -// use mozilla::AndroidBridge::Bridge()->ProvideEGLSurface() instead. -#ifndef MOZ_ANDROID_OMTC -static EGLSurface -CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config) -{ - EGLSurface surface; - -#ifdef DEBUG - sEGLLibrary.DumpEGLConfig(config); -#endif - -#if !defined(MOZ_WIDGET_ANDROID) - surface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(aWidget), 0); -#endif - -#ifdef MOZ_WIDGET_GONK - gScreenBounds.x = 0; - gScreenBounds.y = 0; - sEGLLibrary.fQuerySurface(EGL_DISPLAY(), surface, LOCAL_EGL_WIDTH, &gScreenBounds.width); - sEGLLibrary.fQuerySurface(EGL_DISPLAY(), surface, LOCAL_EGL_HEIGHT, &gScreenBounds.height); -#endif - - return surface; -} -#endif - -already_AddRefed -GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) -{ - if (!sEGLLibrary.EnsureInitialized()) { - return nullptr; - } - - bool doubleBuffered = true; - - bool hasNativeContext = aWidget->HasGLContext(); - EGLContext eglContext = sEGLLibrary.fGetCurrentContext(); - if (hasNativeContext && eglContext) { - void* platformContext = eglContext; - SurfaceCaps caps = SurfaceCaps::Any(); -#ifdef MOZ_WIDGET_QT - int depth = gfxPlatform::GetPlatform()->GetScreenDepth(); - QGLContext* context = const_cast(QGLContext::currentContext()); - if (context && context->device()) { - depth = context->device()->depth(); - } - const QGLFormat& format = context->format(); - doubleBuffered = format.doubleBuffer(); - platformContext = context; - caps.bpp16 = depth == 16 ? true : false; - caps.alpha = format.rgba(); - caps.depth = format.depth(); - caps.stencil = format.stencil(); -#endif - EGLConfig config = EGL_NO_CONFIG; - EGLSurface surface = sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW); - nsRefPtr glContext = - new GLContextEGL(caps, - gGlobalContext, false, - config, surface, eglContext); - - if (!glContext->Init()) - return nullptr; - - glContext->MakeCurrent(); - glContext->SetIsDoubleBuffered(doubleBuffered); - glContext->SetPlatformContext(platformContext); - - if (!gGlobalContext) { - gGlobalContext = glContext; - } - - return glContext.forget(); - } - - EGLConfig config; - if (!CreateConfig(&config)) { - printf_stderr("Failed to create EGL config!\n"); - return nullptr; - } - -#ifdef MOZ_ANDROID_OMTC - mozilla::AndroidBridge::Bridge()->RegisterCompositor(); - EGLSurface surface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface(); -#else - EGLSurface surface = CreateSurfaceForWindow(aWidget, config); -#endif - - if (!surface) { - printf_stderr("Failed to create EGLSurface!\n"); - return nullptr; - } - - GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps caps = SurfaceCaps::Any(); - nsRefPtr glContext = - GLContextEGL::CreateGLContext(caps, - shareContext, false, - config, surface); - - if (!glContext) { - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); - return nullptr; - } - - glContext->MakeCurrent(); - glContext->SetIsDoubleBuffered(doubleBuffered); - - return glContext.forget(); -} - -already_AddRefed -GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size) -{ - EGLConfig config; - EGLSurface surface; - - const EGLint numConfigs = 1; // We only need one. - EGLConfig configs[numConfigs]; - EGLint foundConfigs = 0; - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), - kEGLConfigAttribsOffscreenPBuffer, - configs, numConfigs, - &foundConfigs) - || foundConfigs == 0) - { - NS_WARNING("No EGL Config for minimal PBuffer!"); - return nullptr; - } - - // We absolutely don't care, so just pick the first one. - config = configs[0]; - if (GLContext::DebugMode()) - sEGLLibrary.DumpEGLConfig(config); - - gfxIntSize pbSize(size); - surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, - LOCAL_EGL_NONE, - pbSize); - if (!surface) { - NS_WARNING("Failed to create PBuffer for context!"); - return nullptr; - } - - GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = - GLContextEGL::CreateGLContext(dummyCaps, - shareContext, true, - config, surface); - if (!glContext) { - NS_WARNING("Failed to create GLContext from PBuffer"); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); - return nullptr; - } - - if (!glContext->Init()) { - NS_WARNING("Failed to initialize GLContext!"); - // GLContextEGL::dtor will destroy |surface| for us. - return nullptr; - } - - return glContext.forget(); -} - -#ifdef MOZ_X11 -EGLSurface -CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig) -{ - gfxXlibSurface* xsurface = static_cast(aSurface); - bool opaque = - aSurface->GetContentType() == gfxASurface::CONTENT_COLOR; - - static EGLint pixmap_config_rgb[] = { - LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D, - LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGB, - LOCAL_EGL_NONE - }; - - static EGLint pixmap_config_rgba[] = { - LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D, - LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGBA, - LOCAL_EGL_NONE - }; - - EGLSurface surface = nullptr; - if (aConfig && *aConfig) { - if (opaque) - surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig, - (EGLNativePixmapType)xsurface->XDrawable(), - pixmap_config_rgb); - else - surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig, - (EGLNativePixmapType)xsurface->XDrawable(), - pixmap_config_rgba); - - if (surface != EGL_NO_SURFACE) - return surface; - } - - EGLConfig configs[32]; - int numConfigs = 32; - - static EGLint pixmap_config[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_DEPTH_SIZE, 0, - LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE, - LOCAL_EGL_NONE - }; - - static EGLint pixmap_lock_config[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT | LOCAL_EGL_LOCK_SURFACE_BIT_KHR, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_DEPTH_SIZE, 0, - LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE, - LOCAL_EGL_NONE - }; - - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), - sEGLLibrary.HasKHRLockSurface() ? - pixmap_lock_config : pixmap_config, - configs, numConfigs, &numConfigs) - || numConfigs == 0) - { - NS_WARNING("No EGL Config for pixmap!"); - return nullptr; - } - - int i = 0; - for (i = 0; i < numConfigs; ++i) { - if (opaque) - surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i], - (EGLNativePixmapType)xsurface->XDrawable(), - pixmap_config_rgb); - else - surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i], - (EGLNativePixmapType)xsurface->XDrawable(), - pixmap_config_rgba); - - if (surface != EGL_NO_SURFACE) - break; - } - - if (!surface) { - NS_WARNING("Failed to CreatePixmapSurface!"); - return nullptr; - } - - if (aConfig) - *aConfig = configs[i]; - - return surface; -} -#endif - -already_AddRefed -GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size) -{ - gfxASurface *thebesSurface = nullptr; - EGLNativePixmapType pixmap = 0; - -#ifdef MOZ_X11 - nsRefPtr xsurface = - gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), - gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), - gfxASurface::ImageFormatRGB24), - size); - - // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error - XSync(DefaultXDisplay(), False); - if (xsurface->CairoStatus() != 0) - return nullptr; - - thebesSurface = xsurface; - pixmap = (EGLNativePixmapType)xsurface->XDrawable(); -#endif - - if (!pixmap) { - return nullptr; - } - - EGLSurface surface = 0; - EGLConfig config = 0; - -#ifdef MOZ_X11 - surface = CreateEGLSurfaceForXSurface(thebesSurface, &config); -#endif - if (!config) { - return nullptr; - } - MOZ_ASSERT(surface); - - GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = - GLContextEGL::CreateGLContext(dummyCaps, - shareContext, true, - config, surface); - if (!glContext) { - NS_WARNING("Failed to create GLContext from XSurface"); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); - return nullptr; - } - - if (!glContext->Init()) { - NS_WARNING("Failed to initialize GLContext!"); - // GLContextEGL::dtor will destroy |surface| for us. - return nullptr; - } - - glContext->HoldSurface(thebesSurface); - - return glContext.forget(); -} - -// Under EGL, if we're under X11, then we have to create a Pixmap -// because Maemo's EGL implementation doesn't support pbuffers at all -// for some reason. On Android, pbuffers are supported fine, though -// often without the ability to texture from them directly. -already_AddRefed -GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) -{ - if (!sEGLLibrary.EnsureInitialized()) { - return nullptr; - } - - gfxIntSize dummySize = gfxIntSize(16, 16); - nsRefPtr glContext; -#if defined(MOZ_X11) - glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(dummySize); -#else - glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); -#endif - - if (!glContext) - return nullptr; - - if (flags & GLContext::ContextFlagsGlobal) - return glContext.forget(); - - if (!glContext->InitOffscreen(size, caps)) - return nullptr; - - return glContext.forget(); -} - -// Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) -// and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) -// and 3) each EGL context eats 750k on B2G (bug 813783) -GLContext * -GLContextProviderEGL::GetGlobalContext(const ContextFlags) -{ - return nullptr; -} - -void -GLContextProviderEGL::Shutdown() -{ - gGlobalContext = nullptr; -} - -} /* namespace gl */ -} /* namespace mozilla */ - diff --git a/libazure/src/gfx/gl/GLContextProviderGLX.cpp b/libazure/src/gfx/gl/GLContextProviderGLX.cpp deleted file mode 100644 index 5aee0af..0000000 --- a/libazure/src/gfx/gl/GLContextProviderGLX.cpp +++ /dev/null @@ -1,1433 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifdef MOZ_WIDGET_GTK -#include -#include -#define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#elif defined(MOZ_WIDGET_QT) -#include -#define GET_NATIVE_WINDOW(aWidget) static_cast(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->winId() -#endif - -#include -#include - -#include "mozilla/X11Util.h" - -#include "prenv.h" -#include "GLContextProvider.h" -#include "GLLibraryLoader.h" -#include "nsDebug.h" -#include "nsIWidget.h" -#include "GLXLibrary.h" -#include "gfxXlibSurface.h" -#include "gfxContext.h" -#include "gfxImageSurface.h" -#include "gfxPlatform.h" -#include "GLContext.h" -#include "gfxUtils.h" - -#include "gfxCrashReporterUtils.h" - -#ifdef MOZ_WIDGET_GTK -#include "gfxPlatformGtk.h" -#endif - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -GLXLibrary sGLXLibrary[GLXLibrary::LIBS_MAX]; -GLXLibrary& sDefGLXLib = sGLXLibrary[GLXLibrary::OPENGL_LIB]; - -typedef GLXLibrary::LibraryType LibType; - -static LibType gCurrLib = GLXLibrary::OPENGL_LIB; - -LibType -GLXLibrary::SelectLibrary(const GLContext::ContextFlags& aFlags) -{ - return (aFlags & GLContext::ContextFlagsMesaLLVMPipe) - ? GLXLibrary::MESA_LLVMPIPE_LIB - : GLXLibrary::OPENGL_LIB; -} - -// Check that we have at least version aMajor.aMinor . -bool -GLXLibrary::GLXVersionCheck(int aMajor, int aMinor) -{ - return aMajor < mGLXMajorVersion || - (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion); -} - -static inline bool -HasExtension(const char* aExtensions, const char* aRequiredExtension) -{ - return GLContext::ListHasExtension( - reinterpret_cast(aExtensions), aRequiredExtension); -} - -bool -GLXLibrary::EnsureInitialized(LibType libType) -{ - if (mInitialized) { - return true; - } - - // Don't repeatedly try to initialize. - if (mTriedInitializing) { - return false; - } - mTriedInitializing = true; - - // Force enabling s3 texture compression. (Bug 774134) - PR_SetEnv("force_s3tc_enable=true"); - - if (!mOGLLibrary) { - const char* libGLfilename = nullptr; - bool forceFeatureReport = false; - switch (libType) { - case MESA_LLVMPIPE_LIB: - libGLfilename = "mesallvmpipe.so"; - forceFeatureReport = true; - break; - case OPENGL_LIB: - // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 - // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, - // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 -#ifdef __OpenBSD__ - libGLfilename = "libGL.so"; -#else - libGLfilename = "libGL.so.1"; -#endif - break; - default: - MOZ_NOT_REACHED("Invalid GLX library type."); - return false; - } - - ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); - mOGLLibrary = PR_LoadLibrary(libGLfilename); - if (!mOGLLibrary) { - NS_WARNING("Couldn't load OpenGL shared library."); - return false; - } - reporter.SetSuccessful(); - } - - if (PR_GetEnv("MOZ_GLX_DEBUG")) { - mDebug = true; - } - - GLLibraryLoader::SymLoadStruct symbols[] = { - /* functions that were in GLX 1.0 */ - { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", NULL } }, - { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", NULL } }, - { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", NULL } }, - { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", NULL } }, - { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", NULL } }, - { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", NULL } }, - { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", NULL } }, - /* functions introduced in GLX 1.1 */ - { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", NULL } }, - { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", NULL } }, - { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols13[] = { - /* functions introduced in GLX 1.3 */ - { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", NULL } }, - { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", NULL } }, - // WARNING: xGetFBConfigs not set in symbols13_ext - { (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", NULL } }, - // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead - { (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", NULL } }, - { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", NULL } }, - { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols13_ext[] = { - /* extension equivalents for functions introduced in GLX 1.3 */ - // GLX_SGIX_fbconfig extension - { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", NULL } }, - { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", NULL } }, - // WARNING: no xGetFBConfigs equivalent in extensions - // WARNING: different from symbols13: - { (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", NULL } }, - { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", NULL } }, // not from ext - { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols14[] = { - /* functions introduced in GLX 1.4 */ - { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols14_ext[] = { - /* extension equivalents for functions introduced in GLX 1.4 */ - // GLX_ARB_get_proc_address extension - { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = { - { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", NULL } }, - { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct symbols_robustness[] = { - { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", NULL } }, - { NULL, { NULL } } - }; - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) { - NS_WARNING("Couldn't find required entry point in OpenGL shared library"); - return false; - } - - Display *display = DefaultXDisplay(); - int screen = DefaultScreen(display); - - if (!xQueryVersion(display, &mGLXMajorVersion, &mGLXMinorVersion)) { - mGLXMajorVersion = 0; - mGLXMinorVersion = 0; - return false; - } - - if (!GLXVersionCheck(1, 1)) - // Not possible to query for extensions. - return false; - - const char *clientVendor = xGetClientString(display, GLX_VENDOR); - const char *serverVendor = xQueryServerString(display, screen, GLX_VENDOR); - const char *extensionsStr = xQueryExtensionsString(display, screen); - - GLLibraryLoader::SymLoadStruct *sym13; - if (!GLXVersionCheck(1, 3)) { - // Even if we don't have 1.3, we might have equivalent extensions - // (as on the Intel X server). - if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) { - return false; - } - sym13 = symbols13_ext; - } else { - sym13 = symbols13; - } - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym13)) { - NS_WARNING("Couldn't find required entry point in OpenGL shared library"); - return false; - } - - GLLibraryLoader::SymLoadStruct *sym14; - if (!GLXVersionCheck(1, 4)) { - // Even if we don't have 1.4, we might have equivalent extensions - // (as on the Intel X server). - if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) { - return false; - } - sym14 = symbols14_ext; - } else { - sym14 = symbols14; - } - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym14)) { - NS_WARNING("Couldn't find required entry point in OpenGL shared library"); - return false; - } - - if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") && - GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap, - (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress)) - { -#ifdef MOZ_WIDGET_GTK - mUseTextureFromPixmap = gfxPlatformGtk::GetPlatform()->UseXRender(); -#else - mUseTextureFromPixmap = true; -#endif - } else { - mUseTextureFromPixmap = false; - NS_WARNING("Texture from pixmap disabled"); - } - - if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") && - GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { - mHasRobustness = true; - } - - mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); - mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); - - mInitialized = true; - mLibType = libType; - - return true; -} - -bool -GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface) -{ - if (!EnsureInitialized(mLibType)) { - return false; - } - - if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib || !mUseTextureFromPixmap) { - return false; - } - - return true; -} - -GLXPixmap -GLXLibrary::CreatePixmap(gfxASurface* aSurface) -{ - if (!SupportsTextureFromPixmap(aSurface)) { - return None; - } - - gfxXlibSurface *xs = static_cast(aSurface); - const XRenderPictFormat *format = xs->XRenderFormat(); - if (!format || format->type != PictTypeDirect) { - return None; - } - const XRenderDirectFormat& direct = format->direct; - int alphaSize; - PR_FLOOR_LOG2(alphaSize, direct.alphaMask + 1); - NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask, - "Unexpected render format with non-adjacent alpha bits"); - - int attribs[] = { GLX_DOUBLEBUFFER, False, - GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, - GLX_ALPHA_SIZE, alphaSize, - (alphaSize ? GLX_BIND_TO_TEXTURE_RGBA_EXT - : GLX_BIND_TO_TEXTURE_RGB_EXT), True, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - None }; - - int numConfigs = 0; - Display *display = xs->XDisplay(); - int xscreen = DefaultScreen(display); - - ScopedXFree cfgs(xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs)); - - // Find an fbconfig that matches the pixel format used on the Pixmap. - int matchIndex = -1; - unsigned long redMask = - static_cast(direct.redMask) << direct.red; - unsigned long greenMask = - static_cast(direct.greenMask) << direct.green; - unsigned long blueMask = - static_cast(direct.blueMask) << direct.blue; - // This is true if the Pixmap has bits for alpha or unused bits. - bool haveNonColorBits = - ~(redMask | greenMask | blueMask) != -1UL << format->depth; - - for (int i = 0; i < numConfigs; i++) { - int id = None; - sGLXLibrary[mLibType].xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &id); - Visual *visual; - int depth; - FindVisualAndDepth(display, id, &visual, &depth); - if (!visual || - visual->c_class != TrueColor || - visual->red_mask != redMask || - visual->green_mask != greenMask || - visual->blue_mask != blueMask ) { - continue; - } - - // Historically Xlib Visuals did not try to represent an alpha channel - // and there was no means to use an alpha channel on a Pixmap. The - // Xlib Visual from the fbconfig was not intended to have any - // information about alpha bits. - // - // Since then, RENDER has added formats for 32 bit depth Pixmaps. - // Some of these formats have bits for alpha and some have unused - // bits. - // - // Then the Composite extension added a 32 bit depth Visual intended - // for Windows with an alpha channel, so bits not in the visual color - // masks were expected to be treated as alpha bits. - // - // Usually GLX counts only color bits in the Visual depth, but the - // depth of Composite's ARGB Visual includes alpha bits. However, - // bits not in the color masks are not necessarily alpha bits because - // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32 - // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA - // again). - // - // This checks that the depth matches in one of the two ways. - if (depth != format->depth && depth != format->depth - alphaSize) { - continue; - } - - // If all bits of the Pixmap are color bits and the Pixmap depth - // matches the depth of the fbconfig visual, then we can assume that - // the driver will do whatever is necessary to ensure that any - // GLXPixmap alpha bits are treated as set. We can skip the - // ALPHA_SIZE check in this situation. We need to skip this check for - // situations (ATI) where there are no fbconfigs without alpha bits. - // - // glXChooseFBConfig should prefer configs with smaller - // GLX_BUFFER_SIZE, so we should still get zero alpha bits if - // available, except perhaps with NVIDIA drivers where buffer size is - // not the specified sum of the component sizes. - if (haveNonColorBits) { - // There are bits in the Pixmap format that haven't been matched - // against the fbconfig visual. These bits could either represent - // alpha or be unused, so just check that the number of alpha bits - // matches. - int size = 0; - sGLXLibrary[mLibType].xGetFBConfigAttrib(display, cfgs[i], - GLX_ALPHA_SIZE, &size); - if (size != alphaSize) { - continue; - } - } - - matchIndex = i; - break; - } - if (matchIndex == -1) { - NS_WARNING("[GLX] Couldn't find a FBConfig matching Pixmap format"); - return None; - } - - int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, - GLX_TEXTURE_FORMAT_EXT, - (alphaSize ? GLX_TEXTURE_FORMAT_RGBA_EXT - : GLX_TEXTURE_FORMAT_RGB_EXT), - None}; - - GLXPixmap glxpixmap = xCreatePixmap(display, - cfgs[matchIndex], - xs->XDrawable(), - pixmapAttribs); - - return glxpixmap; -} - -void -GLXLibrary::DestroyPixmap(GLXPixmap aPixmap) -{ - if (!mUseTextureFromPixmap) { - return; - } - - Display *display = DefaultXDisplay(); - xDestroyPixmap(display, aPixmap); -} - -void -GLXLibrary::BindTexImage(GLXPixmap aPixmap) -{ - if (!mUseTextureFromPixmap) { - return; - } - - Display *display = DefaultXDisplay(); - // Make sure all X drawing to the surface has finished before binding to a texture. - if (mClientIsMesa) { - // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a - // noop when direct rendering unless the current drawable is a - // single-buffer window. - FinishX(display); - } else { - xWaitX(); - } - xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL); -} - -void -GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap) -{ - if (!mUseTextureFromPixmap) { - return; - } - - Display *display = DefaultXDisplay(); - xReleaseTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT); -} - -#ifdef DEBUG - -static int (*sOldErrorHandler)(Display *, XErrorEvent *); -ScopedXErrorHandler::ErrorEvent sErrorEvent; -static int GLXErrorHandler(Display *display, XErrorEvent *ev) -{ - if (!sErrorEvent.mError.error_code) { - sErrorEvent.mError = *ev; - } - return 0; -} - -void -GLXLibrary::BeforeGLXCall() -{ - if (mDebug) { - sOldErrorHandler = XSetErrorHandler(GLXErrorHandler); - } -} - -void -GLXLibrary::AfterGLXCall() -{ - if (mDebug) { - FinishX(DefaultXDisplay()); - if (sErrorEvent.mError.error_code) { - char buffer[2048]; - XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer)); - printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i", - buffer, - sErrorEvent.mError.error_code, - sErrorEvent.mError.request_code, - sErrorEvent.mError.minor_code, - sErrorEvent.mError.serial); - NS_ABORT(); - } - XSetErrorHandler(sOldErrorHandler); - } -} - -#define BEFORE_GLX_CALL do { \ - sGLXLibrary[gCurrLib].BeforeGLXCall(); \ -} while (0) - -#define AFTER_GLX_CALL do { \ - sGLXLibrary[gCurrLib].AfterGLXCall(); \ -} while (0) - -#else - -#define BEFORE_GLX_CALL do { } while(0) -#define AFTER_GLX_CALL do { } while(0) - -#endif - -void -GLXLibrary::xDestroyContext(Display* display, GLXContext context) -{ - BEFORE_GLX_CALL; - xDestroyContextInternal(display, context); - AFTER_GLX_CALL; -} - -Bool -GLXLibrary::xMakeCurrent(Display* display, - GLXDrawable drawable, - GLXContext context) -{ - BEFORE_GLX_CALL; - Bool result = xMakeCurrentInternal(display, drawable, context); - AFTER_GLX_CALL; - return result; -} - -GLXContext -GLXLibrary::xGetCurrentContext() -{ - BEFORE_GLX_CALL; - GLXContext result = xGetCurrentContextInternal(); - AFTER_GLX_CALL; - return result; -} - -/* static */ void* -GLXLibrary::xGetProcAddress(const char *procName) -{ - BEFORE_GLX_CALL; - void* result = sGLXLibrary[gCurrLib].xGetProcAddressInternal(procName); - AFTER_GLX_CALL; - return result; -} - -GLXFBConfig* -GLXLibrary::xChooseFBConfig(Display* display, - int screen, - const int *attrib_list, - int *nelements) -{ - BEFORE_GLX_CALL; - GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements); - AFTER_GLX_CALL; - return result; -} - -GLXFBConfig* -GLXLibrary::xGetFBConfigs(Display* display, - int screen, - int *nelements) -{ - BEFORE_GLX_CALL; - GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements); - AFTER_GLX_CALL; - return result; -} - -GLXContext -GLXLibrary::xCreateNewContext(Display* display, - GLXFBConfig config, - int render_type, - GLXContext share_list, - Bool direct) -{ - BEFORE_GLX_CALL; - GLXContext result = xCreateNewContextInternal(display, config, - render_type, - share_list, direct); - AFTER_GLX_CALL; - return result; -} - -int -GLXLibrary::xGetFBConfigAttrib(Display *display, - GLXFBConfig config, - int attribute, - int *value) -{ - BEFORE_GLX_CALL; - int result = xGetFBConfigAttribInternal(display, config, - attribute, value); - AFTER_GLX_CALL; - return result; -} - -void -GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable) -{ - BEFORE_GLX_CALL; - xSwapBuffersInternal(display, drawable); - AFTER_GLX_CALL; -} - -const char * -GLXLibrary::xQueryExtensionsString(Display *display, - int screen) -{ - BEFORE_GLX_CALL; - const char *result = xQueryExtensionsStringInternal(display, screen); - AFTER_GLX_CALL; - return result; -} - -const char * -GLXLibrary::xGetClientString(Display *display, - int screen) -{ - BEFORE_GLX_CALL; - const char *result = xGetClientStringInternal(display, screen); - AFTER_GLX_CALL; - return result; -} - -const char * -GLXLibrary::xQueryServerString(Display *display, - int screen, int name) -{ - BEFORE_GLX_CALL; - const char *result = xQueryServerStringInternal(display, screen, name); - AFTER_GLX_CALL; - return result; -} - -GLXPixmap -GLXLibrary::xCreatePixmap(Display *display, - GLXFBConfig config, - Pixmap pixmap, - const int *attrib_list) -{ - BEFORE_GLX_CALL; - GLXPixmap result = xCreatePixmapInternal(display, config, - pixmap, attrib_list); - AFTER_GLX_CALL; - return result; -} - -GLXPixmap -GLXLibrary::xCreateGLXPixmapWithConfig(Display *display, - GLXFBConfig config, - Pixmap pixmap) -{ - BEFORE_GLX_CALL; - GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap); - AFTER_GLX_CALL; - return result; -} - -void -GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap) -{ - BEFORE_GLX_CALL; - xDestroyPixmapInternal(display, pixmap); - AFTER_GLX_CALL; -} - -Bool -GLXLibrary::xQueryVersion(Display *display, - int *major, - int *minor) -{ - BEFORE_GLX_CALL; - Bool result = xQueryVersionInternal(display, major, minor); - AFTER_GLX_CALL; - return result; -} - -void -GLXLibrary::xBindTexImage(Display *display, - GLXDrawable drawable, - int buffer, - const int *attrib_list) -{ - BEFORE_GLX_CALL; - xBindTexImageInternal(display, drawable, buffer, attrib_list); - AFTER_GLX_CALL; -} - -void -GLXLibrary::xReleaseTexImage(Display *display, - GLXDrawable drawable, - int buffer) -{ - BEFORE_GLX_CALL; - xReleaseTexImageInternal(display, drawable, buffer); - AFTER_GLX_CALL; -} - -void -GLXLibrary::xWaitGL() -{ - BEFORE_GLX_CALL; - xWaitGLInternal(); - AFTER_GLX_CALL; -} - -void -GLXLibrary::xWaitX() -{ - BEFORE_GLX_CALL; - xWaitXInternal(); - AFTER_GLX_CALL; -} - -GLXContext -GLXLibrary::xCreateContextAttribs(Display* display, - GLXFBConfig config, - GLXContext share_list, - Bool direct, - const int* attrib_list) -{ - BEFORE_GLX_CALL; - GLXContext result = xCreateContextAttribsInternal(display, - config, - share_list, - direct, - attrib_list); - AFTER_GLX_CALL; - return result; -} - -class GLContextGLX : public GLContext -{ -public: - static already_AddRefed - CreateGLContext(const SurfaceCaps& caps, - GLContextGLX* shareContext, - bool isOffscreen, - Display* display, - GLXDrawable drawable, - GLXFBConfig cfg, - bool deleteDrawable, - LibType libType = GLXLibrary::OPENGL_LIB, - gfxXlibSurface* pixmap = nullptr) - { - GLXLibrary& glx = sGLXLibrary[libType]; - - int db = 0; - int err = glx.xGetFBConfigAttrib(display, cfg, - GLX_DOUBLEBUFFER, &db); - if (GLX_BAD_ATTRIBUTE != err) { -#ifdef DEBUG - if (DebugMode()) { - printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not "); - } -#endif - } - - GLXContext context; - nsRefPtr glContext; - bool error; - - ScopedXErrorHandler xErrorHandler; - -TRY_AGAIN_NO_SHARING: - - error = false; - - GLXContext glxContext = shareContext ? shareContext->mContext : NULL; - if (glx.HasRobustness()) { - int attrib_list[] = { - LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB, - 0, - }; - - context = glx.xCreateContextAttribs( - display, - cfg, - glxContext, - True, - attrib_list); - } else { - context = glx.xCreateNewContext( - display, - cfg, - GLX_RGBA_TYPE, - glxContext, - True); - } - - if (context) { - glContext = new GLContextGLX(caps, - shareContext, - isOffscreen, - display, - drawable, - context, - deleteDrawable, - db, - pixmap, - libType); - if (!glContext->Init()) - error = true; - } else { - error = true; - } - - error |= xErrorHandler.SyncAndGetError(display); - - if (error) { - if (shareContext) { - shareContext = nullptr; - goto TRY_AGAIN_NO_SHARING; - } - - NS_WARNING("Failed to create GLXContext!"); - glContext = nullptr; // note: this must be done while the graceful X error handler is set, - // because glxMakeCurrent can give a GLXBadDrawable error - } - - return glContext.forget(); - } - - ~GLContextGLX() - { - MarkDestroyed(); - - // see bug 659842 comment 76 -#ifdef DEBUG - bool success = -#endif - mGLX->xMakeCurrent(mDisplay, None, nullptr); - NS_ABORT_IF_FALSE(success, - "glXMakeCurrent failed to release GL context before we call glXDestroyContext!"); - - mGLX->xDestroyContext(mDisplay, mContext); - - if (mDeleteDrawable) { - mGLX->xDestroyPixmap(mDisplay, mDrawable); - } - } - - GLContextType GetContextType() { - return ContextTypeGLX; - } - - bool Init() - { - MakeCurrent(); - SetupLookupFunction(); - if (!InitWithPrefix("gl", true)) { - return false; - } - - if (!IsExtensionSupported(EXT_framebuffer_object)) - return false; - - return true; - } - - bool MakeCurrentImpl(bool aForce = false) - { - bool succeeded = true; - - // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change. - // (This is not the case with other drivers such as NVIDIA). - // So avoid calling it more than necessary. Since GLX documentation says that: - // "glXGetCurrentContext returns client-side information. - // It does not make a round trip to the server." - // I assume that it's not worth using our own TLS slot here. - if (aForce || mGLX->xGetCurrentContext() != mContext) { - succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext); - NS_ASSERTION(succeeded, "Failed to make GL context current!"); - } - - return succeeded; - } - - virtual bool IsCurrent() { - return mGLX->xGetCurrentContext() == mContext; - } - - bool SetupLookupFunction() - { - mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress; - return true; - } - - void *GetNativeData(NativeDataType aType) - { - switch(aType) { - case NativeGLContext: - return mContext; - - case NativeThebesSurface: - return mPixmap; - - default: - return nullptr; - } - } - - bool IsDoubleBuffered() - { - return mDoubleBuffered; - } - - bool SupportsRobustness() - { - return mGLX->HasRobustness(); - } - - bool SwapBuffers() - { - if (!mDoubleBuffered) - return false; - mGLX->xSwapBuffers(mDisplay, mDrawable); - mGLX->xWaitGL(); - return true; - } - - bool TextureImageSupportsGetBackingSurface() - { - return mGLX->UseTextureFromPixmap(); - } - - virtual already_AddRefed - CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags = TextureImage::NoFlags); - -private: - friend class GLContextProviderGLX; - - GLContextGLX(const SurfaceCaps& caps, - GLContext* shareContext, - bool isOffscreen, - Display *aDisplay, - GLXDrawable aDrawable, - GLXContext aContext, - bool aDeleteDrawable, - bool aDoubleBuffered, - gfxXlibSurface *aPixmap, - LibType libType) - : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ), - mContext(aContext), - mDisplay(aDisplay), - mDrawable(aDrawable), - mDeleteDrawable(aDeleteDrawable), - mDoubleBuffered(aDoubleBuffered), - mLibType(libType), - mGLX(&sGLXLibrary[libType]), - mPixmap(aPixmap) - { - MOZ_ASSERT(mGLX); - } - - GLXContext mContext; - Display *mDisplay; - GLXDrawable mDrawable; - bool mDeleteDrawable; - bool mDoubleBuffered; - - LibType mLibType; - GLXLibrary* mGLX; - - nsRefPtr mPixmap; -}; - -class TextureImageGLX : public TextureImage -{ - friend already_AddRefed - GLContextGLX::CreateTextureImage(const nsIntSize&, - ContentType, - GLenum, - TextureImage::Flags); - -public: - virtual ~TextureImageGLX() - { - mGLContext->MakeCurrent(); - mGLContext->fDeleteTextures(1, &mTexture); - sGLXLib.DestroyPixmap(mPixmap); - } - - virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) - { - mInUpdate = true; - return mUpdateSurface; - } - - virtual void EndUpdate() - { - mInUpdate = false; - } - - - virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom) - { - nsRefPtr ctx = new gfxContext(mUpdateSurface); - gfxUtils::ClipToRegion(ctx, aRegion); - ctx->SetSource(aSurface, aFrom); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->Paint(); - return true; - } - - virtual void BindTexture(GLenum aTextureUnit) - { - mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - sGLXLib.BindTexImage(mPixmap); - mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); - } - - virtual void ReleaseTexture() - { - sGLXLib.ReleaseTexImage(mPixmap); - } - - virtual already_AddRefed GetBackingSurface() - { - nsRefPtr copy = mUpdateSurface; - return copy.forget(); - } - - virtual bool InUpdate() const { return mInUpdate; } - - virtual GLuint GetTextureID() { - return mTexture; - } - -private: - TextureImageGLX(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - ContentType aContentType, - GLContext* aContext, - gfxASurface* aSurface, - GLXPixmap aPixmap, - TextureImage::Flags aFlags, - LibType aLibType) - : TextureImage(aSize, aWrapMode, aContentType, aFlags) - , mGLContext(aContext) - , mUpdateSurface(aSurface) - , mPixmap(aPixmap) - , mInUpdate(false) - , mTexture(aTexture) - , sGLXLib(sGLXLibrary[aLibType]) - { - if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { - mShaderType = gl::RGBALayerProgramType; - } else { - mShaderType = gl::RGBXLayerProgramType; - } - } - - GLContext* mGLContext; - nsRefPtr mUpdateSurface; - GLXPixmap mPixmap; - bool mInUpdate; - GLuint mTexture; - GLXLibrary& sGLXLib; - - virtual void ApplyFilter() - { - mGLContext->ApplyFilterToBoundTexture(mFilter); - } -}; - -already_AddRefed -GLContextGLX::CreateTextureImage(const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags) -{ - if (!TextureImageSupportsGetBackingSurface()) { - return GLContext::CreateTextureImage(aSize, - aContentType, - aWrapMode, - aFlags); - } - - Display *display = DefaultXDisplay(); - int xscreen = DefaultScreen(display); - gfxASurface::gfxImageFormat imageFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType); - - XRenderPictFormat* xrenderFormat = - gfxXlibSurface::FindRenderFormat(display, imageFormat); - NS_ASSERTION(xrenderFormat, "Could not find a render format for our display!"); - - - nsRefPtr surface = - gfxXlibSurface::Create(ScreenOfDisplay(display, xscreen), - xrenderFormat, - gfxIntSize(aSize.width, aSize.height)); - NS_ASSERTION(surface, "Failed to create xlib surface!"); - - if (aContentType == gfxASurface::CONTENT_COLOR_ALPHA) { - nsRefPtr ctx = new gfxContext(surface); - ctx->SetOperator(gfxContext::OPERATOR_CLEAR); - ctx->Paint(); - } - - MakeCurrent(); - GLXPixmap pixmap = mGLX->CreatePixmap(surface); - NS_ASSERTION(pixmap, "Failed to create pixmap!"); - - GLuint texture; - fGenTextures(1, &texture); - - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, texture); - - nsRefPtr teximage = - new TextureImageGLX(texture, aSize, aWrapMode, aContentType, - this, surface, pixmap, aFlags, mLibType); - - GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode); - - return teximage.forget(); -} - -static GLContextGLX * -GetGlobalContextGLX(const GLContext::ContextFlags aFlags = GLContext::ContextFlagsNone) -{ - return static_cast(GLContextProviderGLX::GetGlobalContext(aFlags)); -} - -static bool -AreCompatibleVisuals(Visual *one, Visual *two) -{ - if (one->c_class != two->c_class) { - return false; - } - - if (one->red_mask != two->red_mask || - one->green_mask != two->green_mask || - one->blue_mask != two->blue_mask) { - return false; - } - - if (one->bits_per_rgb != two->bits_per_rgb) { - return false; - } - - return true; -} - -already_AddRefed -GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget) -{ - const LibType libType = GLXLibrary::OPENGL_LIB; - if (!sDefGLXLib.EnsureInitialized(libType)) { - return nullptr; - } - - // Currently, we take whatever Visual the window already has, and - // try to create an fbconfig for that visual. This isn't - // necessarily what we want in the long run; an fbconfig may not - // be available for the existing visual, or if it is, the GL - // performance might be suboptimal. But using the existing visual - // is a relatively safe intermediate step. - - Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY); - int xscreen = DefaultScreen(display); - Window window = GET_NATIVE_WINDOW(aWidget); - - int numConfigs; - ScopedXFree cfgs; - if (sDefGLXLib.IsATI() || - !sDefGLXLib.GLXVersionCheck(1, 3)) { - const int attribs[] = { - GLX_DOUBLEBUFFER, False, - 0 - }; - cfgs = sDefGLXLib.xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs); - } else { - cfgs = sDefGLXLib.xGetFBConfigs(display, - xscreen, - &numConfigs); - } - - if (!cfgs) { - NS_WARNING("[GLX] glXGetFBConfigs() failed"); - return nullptr; - } - NS_ASSERTION(numConfigs > 0, "No FBConfigs found!"); - - // XXX the visual ID is almost certainly the GLX_FBCONFIG_ID, so - // we could probably do this first and replace the glXGetFBConfigs - // with glXChooseConfigs. Docs are sparklingly clear as always. - XWindowAttributes widgetAttrs; - if (!XGetWindowAttributes(display, window, &widgetAttrs)) { - NS_WARNING("[GLX] XGetWindowAttributes() failed"); - return nullptr; - } - const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual); -#ifdef DEBUG - printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID); -#endif - - int matchIndex = -1; - - for (int i = 0; i < numConfigs; i++) { - int visid = None; - sDefGLXLib.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid); - if (!visid) { - continue; - } - if (sDefGLXLib.IsATI()) { - int depth; - Visual *visual; - FindVisualAndDepth(display, visid, &visual, &depth); - if (depth == widgetAttrs.depth && - AreCompatibleVisuals(widgetAttrs.visual, visual)) { - matchIndex = i; - break; - } - } else { - if (widgetVisualID == static_cast(visid)) { - matchIndex = i; - break; - } - } - } - - if (matchIndex == -1) { - NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual"); - return nullptr; - } - - GLContextGLX *shareContext = GetGlobalContextGLX(); - - SurfaceCaps caps = SurfaceCaps::Any(); - nsRefPtr glContext = GLContextGLX::CreateGLContext(caps, - shareContext, - false, - display, - window, - cfgs[matchIndex], - false, - libType); - - return glContext.forget(); -} - -static already_AddRefed -CreateOffscreenPixmapContext(const gfxIntSize& size, LibType libToUse) -{ - GLXLibrary& glx = sGLXLibrary[libToUse]; - if (!glx.EnsureInitialized(libToUse)) { - return nullptr; - } - - Display *display = DefaultXDisplay(); - int xscreen = DefaultScreen(display); - - int attribs[] = { - GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, - GLX_X_RENDERABLE, True, - 0 - }; - int numConfigs = 0; - - ScopedXFree cfgs; - cfgs = glx.xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs); - if (!cfgs) { - return nullptr; - } - - MOZ_ASSERT(numConfigs > 0, - "glXChooseFBConfig() failed to match our requested format and violated its spec!"); - - int visid = None; - int chosenIndex = 0; - - for (int i = 0; i < numConfigs; ++i) { - int dtype; - - if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success - || !(dtype & GLX_PIXMAP_BIT)) - { - continue; - } - if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success - || visid == 0) - { - continue; - } - - chosenIndex = i; - break; - } - - if (!visid) { - NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!"); - return nullptr; - } - - Visual *visual; - int depth; - FindVisualAndDepth(display, visid, &visual, &depth); - ScopedXErrorHandler xErrorHandler; - GLXPixmap glxpixmap = 0; - bool error = false; - - gfxIntSize dummySize(16, 16); - nsRefPtr xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), - visual, - dummySize); - if (xsurface->CairoStatus() != 0) { - error = true; - goto DONE_CREATING_PIXMAP; - } - - // Handle slightly different signature between glXCreatePixmap and - // its pre-GLX-1.3 extension equivalent (though given the ABI, we - // might not need to). - if (glx.GLXVersionCheck(1, 3)) { - glxpixmap = glx.xCreatePixmap(display, - cfgs[chosenIndex], - xsurface->XDrawable(), - NULL); - } else { - glxpixmap = glx.xCreateGLXPixmapWithConfig(display, - cfgs[chosenIndex], - xsurface-> - XDrawable()); - } - if (glxpixmap == 0) { - error = true; - } - -DONE_CREATING_PIXMAP: - - nsRefPtr glContext; - bool serverError = xErrorHandler.SyncAndGetError(display); - - if (!error && // earlier recorded error - !serverError) - { - GLContext::ContextFlags flag = libToUse == GLXLibrary::MESA_LLVMPIPE_LIB - ? GLContext::ContextFlagsMesaLLVMPipe - : GLContext::ContextFlagsNone; - // We might have an alpha channel, but it doesn't matter. - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - GLContextGLX* shareContext = GetGlobalContextGLX(flag); - - glContext = GLContextGLX::CreateGLContext(dummyCaps, - shareContext, - true, - display, - glxpixmap, - cfgs[chosenIndex], - false, - libToUse, - xsurface); - } - - return glContext.forget(); -} - -already_AddRefed -GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) -{ - LibType libType = GLXLibrary::SelectLibrary(flags); - gCurrLib = libType; - - gfxIntSize dummySize = gfxIntSize(16, 16); - nsRefPtr glContext = - CreateOffscreenPixmapContext(dummySize, libType); - - if (!glContext) - return nullptr; - - if (!glContext->InitOffscreen(size, caps)) - return nullptr; - - return glContext.forget(); -} - -static nsRefPtr gGlobalContext[GLXLibrary::LIBS_MAX]; - -GLContext* -GLContextProviderGLX::GetGlobalContext(const ContextFlags aFlag) -{ - LibType libType = GLXLibrary::SelectLibrary(aFlag); - static bool triedToCreateContext[GLXLibrary::LIBS_MAX] = {false, false}; - if (!triedToCreateContext[libType] && !gGlobalContext[libType]) { - triedToCreateContext[libType] = true; - - gfxIntSize dummySize = gfxIntSize(16, 16); - gGlobalContext[libType] = CreateOffscreenPixmapContext(dummySize, libType); - if (gGlobalContext[libType]) - gGlobalContext[libType]->SetIsGlobalSharedContext(true); - } - - return gGlobalContext[libType]; -} - -void -GLContextProviderGLX::Shutdown() -{ - for (int i = 0; i < GLXLibrary::LIBS_MAX; ++i) - gGlobalContext[i] = nullptr; -} - -} /* namespace gl */ -} /* namespace mozilla */ - diff --git a/libazure/src/gfx/gl/GLContextProviderImpl.h b/libazure/src/gfx/gl/GLContextProviderImpl.h deleted file mode 100644 index 52657ca..0000000 --- a/libazure/src/gfx/gl/GLContextProviderImpl.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef IN_GL_CONTEXT_PROVIDER_H -#error GLContextProviderImpl.h must only be included from GLContextProvider.h -#endif - -#ifndef GL_CONTEXT_PROVIDER_NAME -#error GL_CONTEXT_PROVIDER_NAME not defined -#endif - -class THEBES_API GL_CONTEXT_PROVIDER_NAME -{ -public: - typedef GLContext::ContextFlags ContextFlags; - typedef gfx::SurfaceCaps SurfaceCaps; - /** - * Create a context that renders to the surface of the widget that is - * passed in. The context is always created with an RGB pixel format, - * with no alpha, depth or stencil. If any of those features are needed, - * either use a framebuffer, or use CreateOffscreen. - * - * This context will attempt to share resources with all other window - * contexts. As such, it's critical that resources allocated that are not - * needed by other contexts be deleted before the context is destroyed. - * - * The GetSharedContext() method will return non-null if sharing - * was successful. - * - * Note: a context created for a widget /must not/ hold a strong - * reference to the widget; otherwise a cycle can be created through - * a GL layer manager. - * - * @param aWidget Widget whose surface to create a context for - * - * @return Context to use for the window - */ - static already_AddRefed - CreateForWindow(nsIWidget* widget); - - /** - * Create a context for offscreen rendering. The target of this - * context should be treated as opaque -- it might be a FBO, or a - * pbuffer, or some other construct. Users of this GLContext - * should bind framebuffer 0 directly to use this offscreen buffer. - * - * The offscreen context returned by this method will always have - * the ability to be rendered into a context created by a window. - * It might or might not share resources with the global context; - * query GetSharedContext() for a non-null result to check. If - * resource sharing can be avoided on the target platform, it will - * be, in order to isolate the offscreen context. - * - * @param aSize The initial size of this offscreen context. - * @param aFormat The ContextFormat for this offscreen context. - * - * @return Context to use for offscreen rendering - */ - static already_AddRefed - CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags = GLContext::ContextFlagsNone); - - /** - * Get a pointer to the global context, creating it if it doesn't exist. - */ - static GLContext* - GetGlobalContext(ContextFlags flags = GLContext::ContextFlagsNone); - - /** - * Free any resources held by this Context Provider. - */ - static void - Shutdown(); -}; diff --git a/libazure/src/gfx/gl/GLContextProviderNull.cpp b/libazure/src/gfx/gl/GLContextProviderNull.cpp deleted file mode 100644 index 1d8f8e3..0000000 --- a/libazure/src/gfx/gl/GLContextProviderNull.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContextProvider.h" - -namespace mozilla { -namespace gl { - -already_AddRefed -GLContextProviderNull::CreateForWindow(nsIWidget*) -{ - return nullptr; -} - -already_AddRefed -GLContextProviderNull::CreateOffscreen(const gfxIntSize&, - const SurfaceCaps&, - ContextFlags) -{ - return nullptr; -} - -GLContext* -GLContextProviderNull::GetGlobalContext(ContextFlags) -{ - return nullptr; -} - -void -GLContextProviderNull::Shutdown() -{ -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLContextProviderWGL.cpp b/libazure/src/gfx/gl/GLContextProviderWGL.cpp deleted file mode 100644 index 34c5187..0000000 --- a/libazure/src/gfx/gl/GLContextProviderWGL.cpp +++ /dev/null @@ -1,733 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContextProvider.h" -#include "GLContext.h" -#include "GLLibraryLoader.h" -#include "nsDebug.h" -#include "nsIWidget.h" -#include "WGLLibrary.h" -#include "gfxASurface.h" -#include "gfxImageSurface.h" -#include "gfxPlatform.h" -#include "gfxWindowsSurface.h" - -#include "gfxCrashReporterUtils.h" - -#include "prenv.h" - -#include "mozilla/Preferences.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -typedef WGLLibrary::LibraryType LibType; - -WGLLibrary sWGLLib[WGLLibrary::LIBS_MAX]; - -LibType -WGLLibrary::SelectLibrary(const GLContext::ContextFlags& aFlags) -{ - return (aFlags & GLContext::ContextFlagsMesaLLVMPipe) - ? WGLLibrary::MESA_LLVMPIPE_LIB - : WGLLibrary::OPENGL_LIB; -} - -HWND -WGLLibrary::CreateDummyWindow(HDC *aWindowDC) -{ - WNDCLASSW wc; - if (!GetClassInfoW(GetModuleHandle(NULL), L"GLContextWGLClass", &wc)) { - ZeroMemory(&wc, sizeof(WNDCLASSW)); - wc.style = CS_OWNDC; - wc.hInstance = GetModuleHandle(NULL); - wc.lpfnWndProc = DefWindowProc; - wc.lpszClassName = L"GLContextWGLClass"; - if (!RegisterClassW(&wc)) { - NS_WARNING("Failed to register GLContextWGLClass?!"); - // er. failed to register our class? - return NULL; - } - } - - HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, - 0, 0, 16, 16, - NULL, NULL, GetModuleHandle(NULL), NULL); - NS_ENSURE_TRUE(win, NULL); - - HDC dc = GetDC(win); - NS_ENSURE_TRUE(dc, NULL); - - if (mWindowPixelFormat == 0) { - PIXELFORMATDESCRIPTOR pfd; - ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - if (mUseDoubleBufferedWindows) - pfd.dwFlags |= PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cRedBits = 8; - pfd.cGreenBits = 8; - pfd.cBlueBits = 8; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 0; - pfd.iLayerType = PFD_MAIN_PLANE; - - mWindowPixelFormat = ChoosePixelFormat(dc, &pfd); - } - - if (!mWindowPixelFormat || - !SetPixelFormat(dc, mWindowPixelFormat, NULL)) - { - NS_WARNING("SetPixelFormat failed!"); - DestroyWindow(win); - return NULL; - } - - if (aWindowDC) { - *aWindowDC = dc; - } - - return win; -} - -static inline bool -HasExtension(const char* aExtensions, const char* aRequiredExtension) -{ - return GLContext::ListHasExtension( - reinterpret_cast(aExtensions), aRequiredExtension); -} - -bool -WGLLibrary::EnsureInitialized(bool aUseMesaLlvmPipe) -{ - if (mInitialized) - return true; - - mozilla::ScopedGfxFeatureReporter reporter("WGL", aUseMesaLlvmPipe); - - const char* libGLFilename = aUseMesaLlvmPipe - ? "mesallvmpipe.dll" - : "Opengl32.dll"; - if (!mOGLLibrary) { - mOGLLibrary = PR_LoadLibrary(libGLFilename); - if (!mOGLLibrary) { - NS_WARNING("Couldn't load OpenGL library."); - return false; - } - } - - mUseDoubleBufferedWindows = PR_GetEnv("MOZ_WGL_DB") != nullptr; - - GLLibraryLoader::SymLoadStruct earlySymbols[] = { - { (PRFuncPtr*) &fCreateContext, { "wglCreateContext", NULL } }, - { (PRFuncPtr*) &fMakeCurrent, { "wglMakeCurrent", NULL } }, - { (PRFuncPtr*) &fGetProcAddress, { "wglGetProcAddress", NULL } }, - { (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", NULL } }, - { (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", NULL } }, - { (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", NULL } }, - { (PRFuncPtr*) &fShareLists, { "wglShareLists", NULL } }, - { NULL, { NULL } } - }; - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &earlySymbols[0])) { - NS_WARNING("Couldn't find required entry points in OpenGL DLL (early init)"); - return false; - } - - // This is ridiculous -- we have to actually create a context to - // get the OpenGL ICD to load. - mWindow = CreateDummyWindow(&mWindowDC); - NS_ENSURE_TRUE(mWindow, false); - - // create rendering context - mWindowGLContext = fCreateContext(mWindowDC); - NS_ENSURE_TRUE(mWindowGLContext, false); - - HGLRC curCtx = fGetCurrentContext(); - HDC curDC = fGetCurrentDC(); - - if (!fMakeCurrent((HDC)mWindowDC, (HGLRC)mWindowGLContext)) { - NS_WARNING("wglMakeCurrent failed"); - return false; - } - - // Now we can grab all the other symbols that we couldn't without having - // a context current. - - GLLibraryLoader::SymLoadStruct pbufferSymbols[] = { - { (PRFuncPtr*) &fCreatePbuffer, { "wglCreatePbufferARB", "wglCreatePbufferEXT", NULL } }, - { (PRFuncPtr*) &fDestroyPbuffer, { "wglDestroyPbufferARB", "wglDestroyPbufferEXT", NULL } }, - { (PRFuncPtr*) &fGetPbufferDC, { "wglGetPbufferDCARB", "wglGetPbufferDCEXT", NULL } }, - { (PRFuncPtr*) &fBindTexImage, { "wglBindTexImageARB", "wglBindTexImageEXT", NULL } }, - { (PRFuncPtr*) &fReleaseTexImage, { "wglReleaseTexImageARB", "wglReleaseTexImageEXT", NULL } }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct pixFmtSymbols[] = { - { (PRFuncPtr*) &fChoosePixelFormat, { "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT", NULL } }, - { (PRFuncPtr*) &fGetPixelFormatAttribiv, { "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT", NULL } }, - { NULL, { NULL } } - }; - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pbufferSymbols[0], - (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) - { - // this isn't an error, just means that pbuffers aren't supported - fCreatePbuffer = nullptr; - } - - if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0], - (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) - { - // this isn't an error, just means that we don't have the pixel format extension - fChoosePixelFormat = nullptr; - } - - GLLibraryLoader::SymLoadStruct extensionsSymbols[] = { - { (PRFuncPtr *) &fGetExtensionsString, { "wglGetExtensionsStringARB", NULL} }, - { NULL, { NULL } } - }; - - GLLibraryLoader::SymLoadStruct robustnessSymbols[] = { - { (PRFuncPtr *) &fCreateContextAttribs, { "wglCreateContextAttribsARB", NULL} }, - { NULL, { NULL } } - }; - - if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0], - (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) { - const char *wglExts = fGetExtensionsString(mWindowDC); - if (wglExts && HasExtension(wglExts, "WGL_ARB_create_context")) { - GLLibraryLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0], - (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress); - if (HasExtension(wglExts, "WGL_ARB_create_context_robustness")) { - mHasRobustness = true; - } - } - } - - // reset back to the previous context, just in case - fMakeCurrent(curDC, curCtx); - - if (mHasRobustness) { - fDeleteContext(mWindowGLContext); - - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - - mWindowGLContext = fCreateContextAttribs(mWindowDC, NULL, attribs); - if (!mWindowGLContext) { - mHasRobustness = false; - mWindowGLContext = fCreateContext(mWindowDC); - } - } - - mInitialized = true; - - GLContext::ContextFlags flag = GLContext::ContextFlagsNone; - if (aUseMesaLlvmPipe) { - mLibType = WGLLibrary::MESA_LLVMPIPE_LIB; - flag = GLContext::ContextFlagsMesaLLVMPipe; - } - - // Call this to create the global GLContext instance, - // and to check for errors. Note that this must happen /after/ - // setting mInitialized to TRUE, or an infinite loop results. - if (GLContextProviderWGL::GetGlobalContext(flag) == nullptr) { - mInitialized = false; - return false; - } - - reporter.SetSuccessful(); - return true; -} - -class GLContextWGL : public GLContext -{ -public: - // From Window: (possibly for offscreen!) - GLContextWGL(const SurfaceCaps& caps, - GLContext* sharedContext, - bool isOffscreen, - HDC aDC, - HGLRC aContext, - LibType aLibUsed, - HWND aWindow = nullptr) - : GLContext(caps, sharedContext, isOffscreen), - mDC(aDC), - mContext(aContext), - mWnd(aWindow), - mPBuffer(NULL), - mPixelFormat(0), - mLibType(aLibUsed), - mIsDoubleBuffered(false) - { - } - - // From PBuffer - GLContextWGL(const SurfaceCaps& caps, - GLContext* sharedContext, - bool isOffscreen, - HANDLE aPbuffer, - HDC aDC, - HGLRC aContext, - int aPixelFormat, - LibType aLibUsed) - : GLContext(caps, sharedContext, isOffscreen), - mDC(aDC), - mContext(aContext), - mWnd(NULL), - mPBuffer(aPbuffer), - mPixelFormat(aPixelFormat), - mLibType(aLibUsed), - mIsDoubleBuffered(false) - { - } - - ~GLContextWGL() - { - MarkDestroyed(); - - sWGLLib[mLibType].fDeleteContext(mContext); - - if (mPBuffer) - sWGLLib[mLibType].fDestroyPbuffer(mPBuffer); - if (mWnd) - DestroyWindow(mWnd); - } - - GLContextType GetContextType() { - return ContextTypeWGL; - } - - bool Init() - { - if (!mDC || !mContext) - return false; - - MakeCurrent(); - SetupLookupFunction(); - if (!InitWithPrefix("gl", true)) - return false; - - return true; - } - - bool MakeCurrentImpl(bool aForce = false) - { - BOOL succeeded = true; - - // wglGetCurrentContext seems to just pull the HGLRC out - // of its TLS slot, so no need to do our own tls slot. - // You would think that wglMakeCurrent would avoid doing - // work if mContext was already current, but not so much.. - if (aForce || sWGLLib[mLibType].fGetCurrentContext() != mContext) { - succeeded = sWGLLib[mLibType].fMakeCurrent(mDC, mContext); - NS_ASSERTION(succeeded, "Failed to make GL context current!"); - } - - return succeeded; - } - - virtual bool IsCurrent() { - return sWGLLib[mLibType].fGetCurrentContext() == mContext; - } - - void SetIsDoubleBuffered(bool aIsDB) { - mIsDoubleBuffered = aIsDB; - } - - virtual bool IsDoubleBuffered() { - return mIsDoubleBuffered; - } - - bool SupportsRobustness() - { - return sWGLLib[mLibType].HasRobustness(); - } - - virtual bool SwapBuffers() { - if (!mIsDoubleBuffered) - return false; - return ::SwapBuffers(mDC); - } - - bool SetupLookupFunction() - { - mLookupFunc = (PlatformLookupFunction)sWGLLib[mLibType].fGetProcAddress; - return true; - } - - void *GetNativeData(NativeDataType aType) - { - switch (aType) { - case NativeGLContext: - return mContext; - - default: - return nullptr; - } - } - - bool ResizeOffscreen(const gfxIntSize& aNewSize); - - HGLRC Context() { return mContext; } - -protected: - friend class GLContextProviderWGL; - - HDC mDC; - HGLRC mContext; - HWND mWnd; - HANDLE mPBuffer; - int mPixelFormat; - LibType mLibType; - bool mIsDoubleBuffered; -}; - - -static bool -GetMaxSize(HDC hDC, int format, gfxIntSize& size, LibType aLibToUse) -{ - int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB}; - int result[2]; - - // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues) - if (!sWGLLib[aLibToUse].fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result)) - return false; - - size.width = result[0]; - size.height = result[1]; - return true; -} - -static bool -IsValidSizeForFormat(HDC hDC, int format, - const gfxIntSize& requested, - LibType aLibUsed) -{ - gfxIntSize max; - if (!GetMaxSize(hDC, format, max, aLibUsed)) - return true; - - if (requested.width > max.width) - return false; - if (requested.height > max.height) - return false; - - return true; -} - -bool -GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) -{ - return ResizeScreenBuffer(aNewSize); -} - -static GLContextWGL * -GetGlobalContextWGL(const GLContext::ContextFlags aFlags = GLContext::ContextFlagsNone) -{ - return static_cast(GLContextProviderWGL::GetGlobalContext(aFlags)); -} - -already_AddRefed -GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget) -{ - LibType libToUse = WGLLibrary::OPENGL_LIB; - - if (!sWGLLib[libToUse].EnsureInitialized(false)) { - return nullptr; - } - - /** - * We need to make sure we call SetPixelFormat -after- calling - * EnsureInitialized, otherwise it can load/unload the dll and - * wglCreateContext will fail. - */ - - HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC); - - SetPixelFormat(dc, sWGLLib[libToUse].GetWindowPixelFormat(), NULL); - HGLRC context; - - GLContextWGL *shareContext = GetGlobalContextWGL(); - - if (sWGLLib[libToUse].HasRobustness()) { - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - - context = sWGLLib[libToUse].fCreateContextAttribs(dc, - shareContext ? shareContext->Context() : nullptr, - attribs); - if (!context && shareContext) { - context = sWGLLib[libToUse].fCreateContextAttribs(dc, nullptr, attribs); - if (context) { - shareContext = nullptr; - } - } else { - context = sWGLLib[libToUse].fCreateContext(dc); - if (context && shareContext && !sWGLLib[libToUse].fShareLists(shareContext->Context(), context)) { - shareContext = nullptr; - } - } - } else { - context = sWGLLib[libToUse].fCreateContext(dc); - if (context && - shareContext && - !sWGLLib[libToUse].fShareLists(shareContext->Context(), context)) - { - shareContext = nullptr; - } - } - - if (!context) { - return nullptr; - } - - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr glContext = new GLContextWGL(caps, - shareContext, - false, - dc, - context, - libToUse); - if (!glContext->Init()) { - return nullptr; - } - - glContext->SetIsDoubleBuffered(sWGLLib[libToUse].UseDoubleBufferedWindows()); - - return glContext.forget(); -} - -static already_AddRefed -CreatePBufferOffscreenContext(const gfxIntSize& aSize, - LibType aLibToUse) -{ - WGLLibrary& wgl = sWGLLib[aLibToUse]; - -#define A1(_a,_x) do { _a.AppendElement(_x); } while(0) -#define A2(_a,_x,_y) do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0) - - nsTArray attrs; - - A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE); - A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE); - A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); - - A2(attrs, LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB); - - A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); - A2(attrs, LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE); - - A1(attrs, 0); - - nsTArray pbattrs; - A1(pbattrs, 0); - -#undef A1 -#undef A2 - - // We only need one! - UINT numFormats = 1; - int formats[1]; - HDC windowDC = wgl.GetWindowDC(); - if (!wgl.fChoosePixelFormat(windowDC, - attrs.Elements(), NULL, - numFormats, formats, &numFormats) - || numFormats == 0) - { - return nullptr; - } - - // We don't care; just pick the first one. - int chosenFormat = formats[0]; - if (!IsValidSizeForFormat(windowDC, chosenFormat, aSize, aLibToUse)) - return nullptr; - - HANDLE pbuffer = wgl.fCreatePbuffer(windowDC, chosenFormat, - aSize.width, aSize.height, - pbattrs.Elements()); - if (!pbuffer) { - return nullptr; - } - - HDC pbdc = wgl.fGetPbufferDC(pbuffer); - NS_ASSERTION(pbdc, "expected a dc"); - - HGLRC context; - if (wgl.HasRobustness()) { - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - - context = wgl.fCreateContextAttribs(pbdc, nullptr, attribs); - } else { - context = wgl.fCreateContext(pbdc); - } - - if (!context) { - wgl.fDestroyPbuffer(pbuffer); - return nullptr; - } - - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = new GLContextWGL(dummyCaps, - nullptr, true, - pbuffer, - pbdc, - context, - chosenFormat, - aLibToUse); - - return glContext.forget(); -} - -static already_AddRefed -CreateWindowOffscreenContext(GLContext::ContextFlags aFlags) -{ - // CreateWindowOffscreenContext must return a global-shared context - GLContextWGL *shareContext = GetGlobalContextWGL(aFlags); - if (!shareContext) { - return nullptr; - } - - LibType libToUse = WGLLibrary::SelectLibrary(aFlags); - HDC dc; - HWND win = sWGLLib[libToUse].CreateDummyWindow(&dc); - if (!win) { - return nullptr; - } - - HGLRC context = sWGLLib[libToUse].fCreateContext(dc); - if (sWGLLib[libToUse].HasRobustness()) { - int attribs[] = { - LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, - LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, - 0 - }; - - context = sWGLLib[libToUse].fCreateContextAttribs(dc, shareContext->Context(), attribs); - } else { - context = sWGLLib[libToUse].fCreateContext(dc); - if (context && shareContext && - !sWGLLib[libToUse].fShareLists(shareContext->Context(), context)) - { - NS_WARNING("wglShareLists failed!"); - - sWGLLib[libToUse].fDeleteContext(context); - DestroyWindow(win); - return nullptr; - } - } - - if (!context) { - return nullptr; - } - - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr glContext = new GLContextWGL(caps, - shareContext, true, - dc, context, - libToUse, win); - - return glContext.forget(); -} - -already_AddRefed -GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) -{ - LibType libToUse = WGLLibrary::SelectLibrary(flags); - - if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) { - return nullptr; - } - - nsRefPtr glContext; - - // Always try to create a pbuffer context first, because we - // want the context isolation. - if (sWGLLib[libToUse].fCreatePbuffer && - sWGLLib[libToUse].fChoosePixelFormat) - { - gfxIntSize dummySize = gfxIntSize(16, 16); - glContext = CreatePBufferOffscreenContext(dummySize, libToUse); - } - - // If it failed, then create a window context and use a FBO. - if (!glContext) { - glContext = CreateWindowOffscreenContext(flags); - } - - if (!glContext || - !glContext->Init()) - { - return nullptr; - } - - if (!glContext->InitOffscreen(size, caps)) - return nullptr; - - return glContext.forget(); -} - -static nsRefPtr gGlobalContext[WGLLibrary::LIBS_MAX]; - -GLContext * -GLContextProviderWGL::GetGlobalContext(const ContextFlags flags) -{ - LibType libToUse = WGLLibrary::SelectLibrary(flags); - - if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) { - return nullptr; - } - - static bool triedToCreateContext[WGLLibrary::LIBS_MAX] = {false, false}; - - if (!triedToCreateContext[libToUse] && !gGlobalContext[libToUse]) { - triedToCreateContext[libToUse] = true; - - // conveniently, we already have what we need... - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - gGlobalContext[libToUse] = new GLContextWGL(dummyCaps, - nullptr, true, - sWGLLib[libToUse].GetWindowDC(), - sWGLLib[libToUse].GetWindowGLContext(), - libToUse); - if (!gGlobalContext[libToUse]->Init()) { - NS_WARNING("Global context GLContext initialization failed?"); - gGlobalContext[libToUse] = nullptr; - return nullptr; - } - - gGlobalContext[libToUse]->SetIsGlobalSharedContext(true); - } - - return static_cast(gGlobalContext[libToUse]); -} - -void -GLContextProviderWGL::Shutdown() -{ - for (int i = 0; i < WGLLibrary::LIBS_MAX; ++i) - gGlobalContext[i] = nullptr; -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLContextSkia.cpp b/libazure/src/gfx/gl/GLContextSkia.cpp deleted file mode 100644 index 4e35778..0000000 --- a/libazure/src/gfx/gl/GLContextSkia.cpp +++ /dev/null @@ -1,801 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "skia/GrGLInterface.h" - -/* SkPostConfig.h includes windows.h, which includes windef.h - * which redefines min/max. We don't want that. */ -#ifdef _WIN32 -#undef min -#undef max -#endif - -#include "GLContext.h" - -using mozilla::gl::GLContext; - -static GLContext* sGLContext; - -extern "C" { - -void EnsureGLContext(const GrGLInterface* interface) -{ - sGLContext = (GLContext*)(interface->fCallbackData); - sGLContext->MakeCurrent(); -} - -// Core GL functions required by Ganesh - -GrGLvoid glActiveTexture_mozilla(GrGLenum texture) -{ - return sGLContext->fActiveTexture(texture); -} - -GrGLvoid glAttachShader_mozilla(GrGLuint program, GrGLuint shader) -{ - return sGLContext->fAttachShader(program, shader); -} - -GrGLvoid glBindAttribLocation_mozilla(GrGLuint program, GrGLuint index, const GLchar* name) -{ - return sGLContext->fBindAttribLocation(program, index, name); -} - -GrGLvoid glBindBuffer_mozilla(GrGLenum target, GrGLuint buffer) -{ - return sGLContext->fBindBuffer(target, buffer); -} - -GrGLvoid glBindFramebuffer_mozilla(GrGLenum target, GrGLuint framebuffer) -{ - return sGLContext->fBindFramebuffer(target, framebuffer); -} - -GrGLvoid glBindRenderbuffer_mozilla(GrGLenum target, GrGLuint renderbuffer) -{ - return sGLContext->fBindRenderbuffer(target, renderbuffer); -} - -GrGLvoid glBindTexture_mozilla(GrGLenum target, GrGLuint texture) -{ - return sGLContext->fBindTexture(target, texture); -} - -GrGLvoid glBlendColor_mozilla(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha) -{ - return sGLContext->fBlendColor(red, green, blue, alpha); -} - -GrGLvoid glBlendFunc_mozilla(GrGLenum sfactor, GrGLenum dfactor) -{ - return sGLContext->fBlendFunc(sfactor, dfactor); -} - -GrGLvoid glBufferData_mozilla(GrGLenum target, GrGLsizeiptr size, const void* data, GrGLenum usage) -{ - return sGLContext->fBufferData(target, size, data, usage); -} - -GrGLvoid glBufferSubData_mozilla(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const void* data) -{ - return sGLContext->fBufferSubData(target, offset, size, data); -} - -GrGLenum glCheckFramebufferStatus_mozilla(GrGLenum target) -{ - return sGLContext->fCheckFramebufferStatus(target); -} - -GrGLvoid glClear_mozilla(GrGLbitfield mask) -{ - return sGLContext->fClear(mask); -} - -GrGLvoid glClearColor_mozilla(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha) -{ - return sGLContext->fClearColor(red, green, blue, alpha); -} - -GrGLvoid glClearStencil_mozilla(GrGLint s) -{ - return sGLContext->fClearStencil(s); -} - -GrGLvoid glColorMask_mozilla(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha) -{ - return sGLContext->fColorMask(red, green, blue, alpha); -} - -GrGLvoid glCompileShader_mozilla(GrGLuint shader) -{ - return sGLContext->fCompileShader(shader); -} - -GrGLuint glCreateProgram_mozilla(void) -{ - return sGLContext->fCreateProgram(); -} - -GrGLuint glCreateShader_mozilla(GrGLenum type) -{ - return sGLContext->fCreateShader(type); -} - -GrGLvoid glCullFace_mozilla(GrGLenum mode) -{ - return sGLContext->fCullFace(mode); -} - -GrGLvoid glDeleteBuffers_mozilla(GrGLsizei n, const GrGLuint* buffers) -{ - return sGLContext->fDeleteBuffers(n, const_cast(buffers)); -} - -GrGLvoid glDeleteFramebuffers_mozilla(GrGLsizei n, const GrGLuint* framebuffers) -{ - return sGLContext->fDeleteFramebuffers(n, const_cast(framebuffers)); -} - -GrGLvoid glDeleteProgram_mozilla(GrGLuint program) -{ - return sGLContext->fDeleteProgram(program); -} - -GrGLvoid glDeleteRenderbuffers_mozilla(GrGLsizei n, const GrGLuint* renderbuffers) -{ - return sGLContext->fDeleteRenderbuffers(n, const_cast(renderbuffers)); -} - -GrGLvoid glDeleteShader_mozilla(GrGLuint shader) -{ - return sGLContext->fDeleteShader(shader); -} - -GrGLvoid glDeleteTextures_mozilla(GrGLsizei n, const GrGLuint* textures) -{ - return sGLContext->fDeleteTextures(n, const_cast(textures)); -} - -GrGLvoid glDepthMask_mozilla(GrGLboolean flag) -{ - return sGLContext->fDepthMask(flag); -} - -GrGLvoid glDisable_mozilla(GrGLenum cap) -{ - return sGLContext->fDisable(cap); -} - -GrGLvoid glDisableVertexAttribArray_mozilla(GrGLuint index) -{ - return sGLContext->fDisableVertexAttribArray(index); -} - -GrGLvoid glDrawArrays_mozilla(GrGLenum mode, GrGLint first, GrGLsizei count) -{ - return sGLContext->fDrawArrays(mode, first, count); -} - -GrGLvoid glDrawElements_mozilla(GrGLenum mode, GrGLsizei count, GrGLenum type, const void* indices) -{ - return sGLContext->fDrawElements(mode, count, type, indices); -} - -GrGLvoid glEnable_mozilla(GrGLenum cap) -{ - return sGLContext->fEnable(cap); -} - -GrGLvoid glEnableVertexAttribArray_mozilla(GrGLuint index) -{ - return sGLContext->fEnableVertexAttribArray(index); -} - -GrGLvoid glFinish_mozilla() -{ - return sGLContext->fFinish(); -} - -GrGLvoid glFlush_mozilla() -{ - return sGLContext->fFlush(); -} - -GrGLvoid glFramebufferRenderbuffer_mozilla(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer) -{ - return sGLContext->fFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); -} - -GrGLvoid glFramebufferTexture2D_mozilla(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) -{ - return sGLContext->fFramebufferTexture2D(target, attachment, textarget, texture, level); -} - -GrGLvoid glFrontFace_mozilla(GrGLenum mode) -{ - return sGLContext->fFrontFace(mode); -} - -GrGLvoid glGenBuffers_mozilla(GrGLsizei n, GrGLuint* buffers) -{ - return sGLContext->fGenBuffers(n, buffers); -} - -GrGLvoid glGenFramebuffers_mozilla(GrGLsizei n, GrGLuint* framebuffers) -{ - return sGLContext->fGenFramebuffers(n, framebuffers); -} - -GrGLvoid glGenRenderbuffers_mozilla(GrGLsizei n, GrGLuint* renderbuffers) -{ - return sGLContext->fGenRenderbuffers(n, renderbuffers); -} - -GrGLvoid glGenTextures_mozilla(GrGLsizei n, GrGLuint* textures) -{ - return sGLContext->fGenTextures(n, textures); -} - -GrGLvoid glGetBufferParameteriv_mozilla(GrGLenum target, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetBufferParameteriv(target, pname, params); -} - -GrGLvoid glGetFramebufferAttachmentParameteriv_mozilla(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetFramebufferAttachmentParameteriv(target, attachment, pname, params); -} - -GrGLenum glGetError_mozilla() -{ - return sGLContext->fGetError(); -} - -GrGLvoid glGetIntegerv_mozilla(GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetIntegerv(pname, params); -} - -GrGLvoid glGetProgramInfoLog_mozilla(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog) -{ - return sGLContext->fGetProgramInfoLog(program, bufsize, length, infolog); -} - -GrGLvoid glGetProgramiv_mozilla(GrGLuint program, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetProgramiv(program, pname, params); -} - -GrGLvoid glGetRenderbufferParameteriv_mozilla(GrGLenum target, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetRenderbufferParameteriv(target, pname, params); -} - -GrGLvoid glGetShaderInfoLog_mozilla(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, char* infolog) -{ - return sGLContext->fGetShaderInfoLog(shader, bufsize, length, infolog); -} - -GrGLvoid glGetShaderiv_mozilla(GrGLuint shader, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetShaderiv(shader, pname, params); -} - -const GLubyte* glGetString_mozilla(GrGLenum name) -{ - // GLContext only exposes a OpenGL 2.0 style API, so we have to intercept a bunch - // of checks that Ganesh makes to determine which capabilities are present - // on the GL implementation and change them to match what GLContext actually exposes. - - if (name == LOCAL_GL_VERSION) { - if (sGLContext->IsGLES2()) { - return reinterpret_cast("OpenGL ES 2.0"); - } else { - return reinterpret_cast("2.0"); - } - } else if (name == LOCAL_GL_EXTENSIONS) { - // Only expose the bare minimum extensions we want to support to ensure a functional Ganesh - // as GLContext only exposes certain extensions - static bool extensionsStringBuilt = false; - static char extensionsString[120]; - - if (!extensionsStringBuilt) { - if (sGLContext->IsExtensionSupported(GLContext::EXT_texture_format_BGRA8888)) { - strcpy(extensionsString, "GL_EXT_texture_format_BGRA8888 "); - } - - if (sGLContext->IsExtensionSupported(GLContext::OES_packed_depth_stencil)) { - strcat(extensionsString, "GL_OES_packed_depth_stencil "); - } - - if (sGLContext->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) { - strcat(extensionsString, "GL_EXT_packed_depth_stencil "); - } - - extensionsStringBuilt = true; - } - - return reinterpret_cast(extensionsString); - - } else if (name == LOCAL_GL_SHADING_LANGUAGE_VERSION) { - if (sGLContext->IsGLES2()) { - return reinterpret_cast("OpenGL ES GLSL ES 1.0"); - } else { - return reinterpret_cast("1.10"); - } - } - - return sGLContext->fGetString(name); -} - -GrGLint glGetUniformLocation_mozilla(GrGLuint program, const char* name) -{ - return sGLContext->fGetUniformLocation(program, name); -} - -GrGLvoid glLineWidth_mozilla(GrGLfloat width) -{ - return sGLContext->fLineWidth(width); -} - -GrGLvoid glLinkProgram_mozilla(GrGLuint program) -{ - return sGLContext->fLinkProgram(program); -} - -GrGLvoid glPixelStorei_mozilla(GrGLenum pname, GrGLint param) -{ - return sGLContext->fPixelStorei(pname, param); -} - -GrGLvoid glReadPixels_mozilla(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, - GrGLenum format, GrGLenum type, void* pixels) -{ - return sGLContext->fReadPixels(x, y, width, height, - format, type, pixels); -} - -GrGLvoid glRenderbufferStorage_mozilla(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height) -{ - return sGLContext->fRenderbufferStorage(target, internalformat, width, height); -} - -GrGLvoid glScissor_mozilla(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) -{ - return sGLContext->fScissor(x, y, width, height); -} - -GrGLvoid glShaderSource_mozilla(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length) -{ - return sGLContext->fShaderSource(shader, count, str, length); -} - -GrGLvoid glStencilFunc_mozilla(GrGLenum func, GrGLint ref, GrGLuint mask) -{ - return sGLContext->fStencilFunc(func, ref, mask); -} - -GrGLvoid glStencilMask_mozilla(GrGLuint mask) -{ - return sGLContext->fStencilMask(mask); -} - -GrGLvoid glStencilOp_mozilla(GrGLenum fail, GrGLenum zfail, GrGLenum zpass) -{ - return sGLContext->fStencilOp(fail, zfail, zpass); -} - -GrGLvoid glTexImage2D_mozilla(GrGLenum target, GrGLint level, GrGLint internalformat, - GrGLsizei width, GrGLsizei height, GrGLint border, - GrGLenum format, GrGLenum type, const void* pixels) -{ - return sGLContext->fTexImage2D(target, level, internalformat, - width, height, border, - format, type, pixels); -} - -GrGLvoid glTexParameteri_mozilla(GrGLenum target, GrGLenum pname, GrGLint param) -{ - return sGLContext->fTexParameteri(target, pname, param); -} - -GrGLvoid glTexParameteriv_mozilla(GrGLenum target, GrGLenum pname, const GrGLint* params) -{ - return sGLContext->fTexParameteriv(target, pname, const_cast(params)); -} - -GrGLvoid glTexSubImage2D_mozilla(GrGLenum target, GrGLint level, - GrGLint xoffset, GrGLint yoffset, - GrGLsizei width, GrGLsizei height, - GrGLenum format, GrGLenum type, const void* pixels) -{ - return sGLContext->fTexSubImage2D(target, level, - xoffset, yoffset, - width, height, - format, type, pixels); -} - -GrGLvoid glUniform1f_mozilla(GrGLint location, GrGLfloat v) -{ - return sGLContext->fUniform1f(location, v); -} - -GrGLvoid glUniform1i_mozilla(GrGLint location, GrGLint v) -{ - return sGLContext->fUniform1i(location, v); -} - -GrGLvoid glUniform1fv_mozilla(GrGLint location, GrGLsizei count, const GrGLfloat* v) -{ - return sGLContext->fUniform1fv(location, count, v); -} - -GrGLvoid glUniform1iv_mozilla(GrGLint location, GrGLsizei count, const GrGLint* v) -{ - return sGLContext->fUniform1iv(location, count, v); -} - -GrGLvoid glUniform2f_mozilla(GrGLint location, GrGLfloat v0, GrGLfloat v1) -{ - return sGLContext->fUniform2f(location, v0, v1); -} - -GrGLvoid glUniform2i_mozilla(GrGLint location, GrGLint v0, GrGLint v1) -{ - return sGLContext->fUniform2i(location, v0, v1); -} - -GrGLvoid glUniform2fv_mozilla(GrGLint location, GrGLsizei count, const GrGLfloat* v) -{ - return sGLContext->fUniform2fv(location, count, v); -} - -GrGLvoid glUniform2iv_mozilla(GrGLint location, GrGLsizei count, const GrGLint* v) -{ - return sGLContext->fUniform2iv(location, count, v); -} - -GrGLvoid glUniform3f_mozilla(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2) -{ - return sGLContext->fUniform3f(location, v0, v1, v2); -} - -GrGLvoid glUniform3i_mozilla(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2) -{ - return sGLContext->fUniform3i(location, v0, v1, v2); -} - -GrGLvoid glUniform3fv_mozilla(GrGLint location, GrGLsizei count, const GrGLfloat* v) -{ - return sGLContext->fUniform3fv(location, count, v); -} - -GrGLvoid glUniform3iv_mozilla(GrGLint location, GrGLsizei count, const GrGLint* v) -{ - return sGLContext->fUniform3iv(location, count, v); -} - -GrGLvoid glUniform4f_mozilla(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3) -{ - return sGLContext->fUniform4f(location, v0, v1, v2, v3); -} - -GrGLvoid glUniform4i_mozilla(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3) -{ - return sGLContext->fUniform4i(location, v0, v1, v2, v3); -} - -GrGLvoid glUniform4fv_mozilla(GrGLint location, GrGLsizei count, const GrGLfloat* v) -{ - return sGLContext->fUniform4fv(location, count, v); -} - -GrGLvoid glUniform4iv_mozilla(GrGLint location, GrGLsizei count, const GrGLint* v) -{ - return sGLContext->fUniform4iv(location, count, v); -} - -GrGLvoid glUniformMatrix2fv_mozilla(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) -{ - return sGLContext->fUniformMatrix2fv(location, count, transpose, value); -} - -GrGLvoid glUniformMatrix3fv_mozilla(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) -{ - return sGLContext->fUniformMatrix3fv(location, count, transpose, value); -} - -GrGLvoid glUniformMatrix4fv_mozilla(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) -{ - return sGLContext->fUniformMatrix4fv(location, count, transpose, value); -} - -GrGLvoid glUseProgram_mozilla(GrGLuint program) -{ - return sGLContext->fUseProgram(program); -} - -GrGLvoid glVertexAttrib4fv_mozilla(GrGLuint index, const GrGLfloat* values) -{ - return sGLContext->fVertexAttrib4fv(index, values); -} - -GrGLvoid glVertexAttribPointer_mozilla(GrGLuint index, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const void* ptr) -{ - return sGLContext->fVertexAttribPointer(index, size, type, normalized, stride, ptr); -} - -GrGLvoid glViewport_mozilla(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) -{ - return sGLContext->fViewport(x, y, width, height); -} - -// Required if the bindings are GLES2 or desktop OpenGL 2.0 - -GrGLvoid glStencilFuncSeparate_mozilla(GrGLenum frontfunc, GrGLenum backfunc, GrGLint ref, GrGLuint mask) -{ - return sGLContext->fStencilFuncSeparate(frontfunc, backfunc, ref, mask); -} - -GrGLvoid glStencilMaskSeparate_mozilla(GrGLenum face, GrGLuint mask) -{ - return sGLContext->fStencilMaskSeparate(face, mask); -} - -GrGLvoid glStencilOpSeparate_mozilla(GrGLenum face, GrGLenum sfail, GrGLenum dpfail, GrGLenum dppass) -{ - return sGLContext->fStencilOpSeparate(face, sfail, dpfail, dppass); -} - -// Not in GLES2 - -GrGLvoid glGetTexLevelParameteriv_mozilla(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint *params) -{ - return sGLContext->fGetTexLevelParameteriv(target, level, pname, params); -} - -GrGLvoid glDrawBuffer_mozilla(GrGLenum mode) -{ - return sGLContext->fDrawBuffer(mode); -} - -GrGLvoid glReadBuffer_mozilla(GrGLenum mode) -{ - return sGLContext->fReadBuffer(mode); -} - -// Desktop OpenGL version >= 1.5 - -GrGLvoid glGenQueries_mozilla(GrGLsizei n, GrGLuint* ids) -{ - return sGLContext->fGenQueries(n, ids); -} - -GrGLvoid glDeleteQueries_mozilla(GrGLsizei n, const GrGLuint* ids) -{ - return sGLContext->fDeleteQueries(n, const_cast(ids)); -} - -GrGLvoid glBeginQuery_mozilla(GrGLenum target, GrGLuint id) -{ - return sGLContext->fBeginQuery(target, id); -} - -GrGLvoid glEndQuery_mozilla(GrGLenum target) -{ - return sGLContext->fEndQuery(target); -} - -GrGLvoid glGetQueryiv_mozilla(GrGLenum target, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetQueryiv(target, pname, params); -} - -GrGLvoid glGetQueryObjectiv_mozilla(GrGLuint id, GrGLenum pname, GrGLint* params) -{ - return sGLContext->fGetQueryObjectiv(id, pname, params); -} - -GrGLvoid glGetQueryObjectuiv_mozilla(GrGLuint id, GrGLenum pname, GrGLuint* params) -{ - return sGLContext->fGetQueryObjectuiv(id, pname, params); -} - -// Desktop OpenGL version >= 2.0 - -GrGLvoid glDrawBuffers_mozilla(GrGLsizei n, const GrGLenum* bufs) -{ - return sGLContext->fDrawBuffers(n, const_cast(bufs)); -} - -// GLContext supports glMapBuffer on everything (GL_OES_mapbuffer) - -GrGLvoid* glMapBuffer_mozilla(GrGLenum target, GrGLenum access) -{ - return sGLContext->fMapBuffer(target, access); -} - -GrGLboolean glUnmapBuffer_mozilla(GrGLenum target) -{ - return sGLContext->fUnmapBuffer(target); -} - -// GLContext supports glCompressedTexImage2D (GL_ARB_texture_compression) - -GrGLvoid glCompressedTexImage2D_mozilla(GrGLenum target, GrGLint level, GrGLenum internalformat, - GrGLsizei width, GrGLsizei height, GrGLint border, - GrGLsizei imageSize, const GrGLvoid* pixels) -{ - return sGLContext->fCompressedTexImage2D(target, level, internalformat, - width, height, border, - imageSize, pixels); -} - -// GLContext supports glBlitFramebuffer/glRenderbufferStorageMultisample (GL_ARB_framebuffer_object) - -GrGLvoid glRenderbufferStorageMultisample_mozilla(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, - GrGLsizei width, GrGLsizei height) -{ - return sGLContext->fRenderbufferStorageMultisample(target, samples, internalformat, - width, height); -} - -GrGLvoid glBlitFramebuffer_mozilla(GrGLint srcX0, GrGLint srcY0, - GrGLint srcX1, GrGLint srcY1, - GrGLint dstX0, GrGLint dstY0, - GrGLint dstX1, GrGLint dstY1, - GrGLbitfield mask, GrGLenum filter) { - return sGLContext->fBlitFramebuffer(srcX0, srcY0, - srcX1, srcY1, - dstX0, dstY0, - dstX1, dstY1, - mask, filter); -} - -} // extern "C" - -GrGLInterface* CreateGrInterfaceFromGLContext(GLContext* context) -{ - sGLContext = context; - - GrGLInterface* interface = new GrGLInterface(); - interface->fCallbackData = reinterpret_cast(context); - interface->fCallback = EnsureGLContext; - - // Core GL functions required by Ganesh - interface->fActiveTexture = glActiveTexture_mozilla; - interface->fAttachShader = glAttachShader_mozilla; - interface->fBindAttribLocation = glBindAttribLocation_mozilla; - interface->fBindBuffer = glBindBuffer_mozilla; - interface->fBindFramebuffer = glBindFramebuffer_mozilla; - interface->fBindRenderbuffer = glBindRenderbuffer_mozilla; - interface->fBindTexture = glBindTexture_mozilla; - interface->fBlendFunc = glBlendFunc_mozilla; - interface->fBlendColor = glBlendColor_mozilla; - interface->fBufferData = glBufferData_mozilla; - interface->fBufferSubData = glBufferSubData_mozilla; - interface->fCheckFramebufferStatus = glCheckFramebufferStatus_mozilla; - interface->fClear = glClear_mozilla; - interface->fClearColor = glClearColor_mozilla; - interface->fClearStencil = glClearStencil_mozilla; - interface->fColorMask = glColorMask_mozilla; - interface->fCompileShader = glCompileShader_mozilla; - interface->fCreateProgram = glCreateProgram_mozilla; - interface->fCreateShader = glCreateShader_mozilla; - interface->fCullFace = glCullFace_mozilla; - interface->fDeleteBuffers = glDeleteBuffers_mozilla; - interface->fDeleteFramebuffers = glDeleteFramebuffers_mozilla; - interface->fDeleteProgram = glDeleteProgram_mozilla; - interface->fDeleteRenderbuffers = glDeleteRenderbuffers_mozilla; - interface->fDeleteShader = glDeleteShader_mozilla; - interface->fDeleteTextures = glDeleteTextures_mozilla; - interface->fDepthMask = glDepthMask_mozilla; - interface->fDisable = glDisable_mozilla; - interface->fDisableVertexAttribArray = glDisableVertexAttribArray_mozilla; - interface->fDrawArrays = glDrawArrays_mozilla; - interface->fDrawElements = glDrawElements_mozilla; - interface->fEnable = glEnable_mozilla; - interface->fEnableVertexAttribArray = glEnableVertexAttribArray_mozilla; - interface->fFinish = glFinish_mozilla; - interface->fFlush = glFlush_mozilla; - interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer_mozilla; - interface->fFramebufferTexture2D = glFramebufferTexture2D_mozilla; - interface->fFrontFace = glFrontFace_mozilla; - interface->fGenBuffers = glGenBuffers_mozilla; - interface->fGenFramebuffers = glGenFramebuffers_mozilla; - interface->fGenRenderbuffers = glGenRenderbuffers_mozilla; - interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv_mozilla; - interface->fGenTextures = glGenTextures_mozilla; - interface->fGetBufferParameteriv = glGetBufferParameteriv_mozilla; - interface->fGetError = glGetError_mozilla; - interface->fGetIntegerv = glGetIntegerv_mozilla; - interface->fGetProgramInfoLog = glGetProgramInfoLog_mozilla; - interface->fGetProgramiv = glGetProgramiv_mozilla; - interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv_mozilla; - interface->fGetShaderInfoLog = glGetShaderInfoLog_mozilla; - interface->fGetShaderiv = glGetShaderiv_mozilla; - interface->fGetString = glGetString_mozilla; - interface->fGetUniformLocation = glGetUniformLocation_mozilla; - interface->fLineWidth = glLineWidth_mozilla; - interface->fLinkProgram = glLinkProgram_mozilla; - interface->fPixelStorei = glPixelStorei_mozilla; - interface->fReadPixels = glReadPixels_mozilla; - interface->fRenderbufferStorage = glRenderbufferStorage_mozilla; - interface->fScissor = glScissor_mozilla; - interface->fShaderSource = glShaderSource_mozilla; - interface->fStencilFunc = glStencilFunc_mozilla; - interface->fStencilMask = glStencilMask_mozilla; - interface->fStencilOp = glStencilOp_mozilla; - interface->fTexImage2D = glTexImage2D_mozilla; - interface->fTexParameteri = glTexParameteri_mozilla; - interface->fTexParameteriv = glTexParameteriv_mozilla; - interface->fTexSubImage2D = glTexSubImage2D_mozilla; - interface->fUniform1f = glUniform1f_mozilla; - interface->fUniform1i = glUniform1i_mozilla; - interface->fUniform1fv = glUniform1fv_mozilla; - interface->fUniform1iv = glUniform1iv_mozilla; - interface->fUniform2f = glUniform2f_mozilla; - interface->fUniform2i = glUniform2i_mozilla; - interface->fUniform2fv = glUniform2fv_mozilla; - interface->fUniform2iv = glUniform2iv_mozilla; - interface->fUniform3f = glUniform3f_mozilla; - interface->fUniform3i = glUniform3i_mozilla; - interface->fUniform3fv = glUniform3fv_mozilla; - interface->fUniform3iv = glUniform3iv_mozilla; - interface->fUniform4f = glUniform4f_mozilla; - interface->fUniform4i = glUniform4i_mozilla; - interface->fUniform4fv = glUniform4fv_mozilla; - interface->fUniform4iv = glUniform4iv_mozilla; - interface->fUniformMatrix2fv = glUniformMatrix2fv_mozilla; - interface->fUniformMatrix3fv = glUniformMatrix3fv_mozilla; - interface->fUniformMatrix4fv = glUniformMatrix4fv_mozilla; - interface->fUseProgram = glUseProgram_mozilla; - interface->fVertexAttrib4fv = glVertexAttrib4fv_mozilla; - interface->fVertexAttribPointer = glVertexAttribPointer_mozilla; - interface->fViewport = glViewport_mozilla; - - // Required for either desktop OpenGL 2.0 or OpenGL ES 2.0 - interface->fStencilFuncSeparate = glStencilFuncSeparate_mozilla; - interface->fStencilMaskSeparate = glStencilMaskSeparate_mozilla; - interface->fStencilOpSeparate = glStencilOpSeparate_mozilla; - - // GLContext supports glMapBuffer - interface->fMapBuffer = glMapBuffer_mozilla; - interface->fUnmapBuffer = glUnmapBuffer_mozilla; - - // GLContext supports glRenderbufferStorageMultisample/glBlitFramebuffer - interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample_mozilla; - interface->fBlitFramebuffer = glBlitFramebuffer_mozilla; - - // GLContext supports glCompressedTexImage2D - interface->fCompressedTexImage2D = glCompressedTexImage2D_mozilla; - - // Desktop GL - interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv_mozilla; - interface->fDrawBuffer = glDrawBuffer_mozilla; - interface->fReadBuffer = glReadBuffer_mozilla; - - // Desktop OpenGL > 1.5 - interface->fGenQueries = glGenQueries_mozilla; - interface->fDeleteQueries = glDeleteQueries_mozilla; - interface->fBeginQuery = glBeginQuery_mozilla; - interface->fEndQuery = glEndQuery_mozilla; - interface->fGetQueryiv = glGetQueryiv_mozilla; - interface->fGetQueryObjectiv = glGetQueryObjectiv_mozilla; - interface->fGetQueryObjectuiv = glGetQueryObjectuiv_mozilla; - - // Desktop OpenGL > 2.0 - interface->fDrawBuffers = glDrawBuffers_mozilla; - - // We support both desktop GL and GLES2 - if (context->IsGLES2()) { - interface->fBindingsExported = kES2_GrGLBinding; - } else { - interface->fBindingsExported = kDesktop_GrGLBinding; - } - - return interface; -} - diff --git a/libazure/src/gfx/gl/GLContextSkia.h b/libazure/src/gfx/gl/GLContextSkia.h deleted file mode 100644 index 20905c9..0000000 --- a/libazure/src/gfx/gl/GLContextSkia.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "skia/GrGLInterface.h" - -namespace mozilla { -namespace gl { -class GLContext; -} -} - -GrGLInterface* CreateGrInterfaceFromGLContext(mozilla::gl::GLContext* context); diff --git a/libazure/src/gfx/gl/GLContextSymbols.h b/libazure/src/gfx/gl/GLContextSymbols.h deleted file mode 100644 index a7568c0..0000000 --- a/libazure/src/gfx/gl/GLContextSymbols.h +++ /dev/null @@ -1,407 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLCONTEXTSYMBOLS_H_ -#define GLCONTEXTSYMBOLS_H_ - -#include "GLDefs.h" - -/* - * This file should only be included by GLContext.h, and should be - * autogenerated in the future. - */ - -#ifndef GLAPIENTRY -#ifdef XP_WIN -#define GLAPIENTRY __stdcall -#else -#define GLAPIENTRY -#endif -#define GLAPI -#endif - -namespace mozilla { -namespace gl { - -struct GLContextSymbols -{ - GLContextSymbols() { - Zero(); - } - - void Zero() { - memset(this, 0, sizeof(GLContextSymbols)); - } - - typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture); - PFNGLACTIVETEXTUREPROC fActiveTexture; - typedef void (GLAPIENTRY * PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); - PFNGLATTACHSHADERPROC fAttachShader; - typedef void (GLAPIENTRY * PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); - PFNGLBEGINQUERYPROC fBeginQuery; - typedef void (GLAPIENTRY * PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name); - PFNGLBINDATTRIBLOCATIONPROC fBindAttribLocation; - typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); - PFNGLBINDBUFFERPROC fBindBuffer; - typedef void (GLAPIENTRY * PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); - PFNGLBINDTEXTUREPROC fBindTexture; - typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - PFNGLBLENDCOLORPROC fBlendColor; - typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode); - PFNGLBLENDEQUATIONPROC fBlendEquation; - typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum, GLenum); - PFNGLBLENDEQUATIONSEPARATEPROC fBlendEquationSeparate; - typedef void (GLAPIENTRY * PFNGLBLENDFUNCPROC) (GLenum, GLenum); - PFNGLBLENDFUNCPROC fBlendFunc; - typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); - PFNGLBLENDFUNCSEPARATEPROC fBlendFuncSeparate; - typedef void (GLAPIENTRY * PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); - PFNGLBUFFERDATAPROC fBufferData; - typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); - PFNGLBUFFERSUBDATAPROC fBufferSubData; - typedef void (GLAPIENTRY * PFNGLCLEARPROC) (GLbitfield); - PFNGLCLEARPROC fClear; - typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf); - PFNGLCLEARCOLORPROC fClearColor; - typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint); - PFNGLCLEARSTENCILPROC fClearStencil; - typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha); - PFNGLCOLORMASKPROC fColorMask; - typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels); - PFNGLCOMPRESSEDTEXIMAGE2D fCompressedTexImage2D; - typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels); - PFNGLCOMPRESSEDTEXSUBIMAGE2D fCompressedTexSubImage2D; - typedef void (GLAPIENTRY * PFNGLCULLFACEPROC) (GLenum mode); - PFNGLCULLFACEPROC fCullFace; - typedef void (GLAPIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); - PFNGLDETACHSHADERPROC fDetachShader; - typedef void (GLAPIENTRY * PFNGLDEPTHFUNCPROC) (GLenum); - PFNGLDEPTHFUNCPROC fDepthFunc; - typedef void (GLAPIENTRY * PFNGLDEPTHMASKPROC) (realGLboolean); - PFNGLDEPTHMASKPROC fDepthMask; - typedef void (GLAPIENTRY * PFNGLDISABLEPROC) (GLenum); - PFNGLDISABLEPROC fDisable; - typedef void (GLAPIENTRY * PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint); - PFNGLDISABLEVERTEXATTRIBARRAYPROC fDisableVertexAttribArray; - typedef void (GLAPIENTRY * PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); - PFNGLDRAWARRAYSPROC fDrawArrays; - typedef void (GLAPIENTRY * PFNGLDRAWBUFFERPROC) (GLenum mode); - PFNGLDRAWBUFFERPROC fDrawBuffer; - typedef void (GLAPIENTRY * PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum* bufs); - PFNGLDRAWBUFFERSPROC fDrawBuffers; - typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); - PFNGLDRAWELEMENTSPROC fDrawElements; - typedef void (GLAPIENTRY * PFNGLENABLEPROC) (GLenum); - PFNGLENABLEPROC fEnable; - typedef void (GLAPIENTRY * PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint); - PFNGLENABLEVERTEXATTRIBARRAYPROC fEnableVertexAttribArray; - typedef void (GLAPIENTRY * PFNGLFINISHPROC) (void); - PFNGLFINISHPROC fFinish; - typedef void (GLAPIENTRY * PFNGLENDQUERYPROC) (GLenum target); - PFNGLENDQUERYPROC fEndQuery; - typedef void (GLAPIENTRY * PFNGLFLUSHPROC) (void); - PFNGLFLUSHPROC fFlush; - typedef void (GLAPIENTRY * PFNGLFRONTFACEPROC) (GLenum); - PFNGLFRONTFACEPROC fFrontFace; - typedef void (GLAPIENTRY * PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name); - PFNGLGETACTIVEATTRIBPROC fGetActiveAttrib; - typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name); - PFNGLGETACTIVEUNIFORMPROC fGetActiveUniform; - typedef void (GLAPIENTRY * PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders); - PFNGLGETATTACHEDSHADERSPROC fGetAttachedShaders; - typedef GLint (GLAPIENTRY * PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar* name); - PFNGLGETATTRIBLOCATIONPROC fGetAttribLocation; - typedef void (GLAPIENTRY * PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); - PFNGLGETINTEGERVPROC fGetIntegerv; - typedef void (GLAPIENTRY * PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *params); - PFNGLGETFLOATVPROC fGetFloatv; - typedef void (GLAPIENTRY * PFNGLGETBOOLEANBPROC) (GLenum pname, realGLboolean *params); - PFNGLGETBOOLEANBPROC fGetBooleanv; - typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint* params); - PFNGLGETBUFFERPARAMETERIVPROC fGetBufferParameteriv; - typedef void (GLAPIENTRY * PFNGLGENERATEMIPMAPPROC) (GLenum target); - PFNGLGENERATEMIPMAPPROC fGenerateMipmap; - typedef GLenum (GLAPIENTRY * PFNGLGETERRORPROC) (void); - PFNGLGETERRORPROC fGetError; - typedef void (GLAPIENTRY * PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param); - PFNGLGETPROGRAMIVPROC fGetProgramiv; - typedef void (GLAPIENTRY * PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); - PFNGLGETPROGRAMINFOLOGPROC fGetProgramInfoLog; - typedef void (GLAPIENTRY * PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint* params); - PFNGLGETQUERYIVPROC fGetQueryiv; - typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint* params); - PFNGLGETQUERYOBJECTIVPROC fGetQueryObjectiv; - typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint* params); - PFNGLGETQUERYOBJECTUIVPROC fGetQueryObjectuiv; - typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); - PFNGLTEXPARAMETERIPROC fTexParameteri; - typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint* param); - PFNGLTEXPARAMETERIVPROC fTexParameteriv; - typedef void (GLAPIENTRY * PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); - PFNGLTEXPARAMETERFPROC fTexParameterf; - typedef GLubyte* (GLAPIENTRY * PFNGLGETSTRINGPROC) (GLenum); - PFNGLGETSTRINGPROC fGetString; - typedef void (GLAPIENTRY * PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid* image); - PFNGLGETTEXIMAGEPROC fGetTexImage; - typedef void (GLAPIENTRY * PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); - PFNGLGETTEXLEVELPARAMETERIVPROC fGetTexLevelParameteriv; - typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); - PFNGLGETTEXPARAMETERFVPROC fGetTexParameterfv; - typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); - PFNGLGETTEXPARAMETERIVPROC fGetTexParameteriv; - typedef void (GLAPIENTRY * PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat* params); - PFNGLGETUNIFORMFVPROC fGetUniformfv; - typedef void (GLAPIENTRY * PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint* params); - PFNGLGETUNIFORMIVPROC fGetUniformiv; - typedef GLint (GLAPIENTRY * PFNGLGETUNIFORMLOCATIONPROC) (GLint programObj, const GLchar* name); - PFNGLGETUNIFORMLOCATIONPROC fGetUniformLocation; - typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBFVPROC) (GLuint, GLenum, GLfloat*); - PFNGLGETVERTEXATTRIBFVPROC fGetVertexAttribfv; - typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIVPROC) (GLuint, GLenum, GLint*); - PFNGLGETVERTEXATTRIBIVPROC fGetVertexAttribiv; - typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint, GLenum, GLvoid**); - PFNGLGETVERTEXATTRIBPOINTERVPROC fGetVertexAttribPointerv; - typedef void (GLAPIENTRY * PFNGLHINTPROC) (GLenum target, GLenum mode); - PFNGLHINTPROC fHint; - typedef realGLboolean (GLAPIENTRY * PFNGLISBUFFERPROC) (GLuint buffer); - PFNGLISBUFFERPROC fIsBuffer; - typedef realGLboolean (GLAPIENTRY * PFNGLISENABLEDPROC) (GLenum cap); - PFNGLISENABLEDPROC fIsEnabled; - typedef realGLboolean (GLAPIENTRY * PFNGLISPROGRAMPROC) (GLuint program); - PFNGLISPROGRAMPROC fIsProgram; - typedef realGLboolean (GLAPIENTRY * PFNGLISSHADERPROC) (GLuint shader); - PFNGLISSHADERPROC fIsShader; - typedef realGLboolean (GLAPIENTRY * PFNGLISTEXTUREPROC) (GLuint texture); - PFNGLISTEXTUREPROC fIsTexture; - typedef void (GLAPIENTRY * PFNGLLINEWIDTHPROC) (GLfloat width); - PFNGLLINEWIDTHPROC fLineWidth; - typedef void (GLAPIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program); - PFNGLLINKPROGRAMPROC fLinkProgram; - typedef void (GLAPIENTRY * PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); - PFNGLPIXELSTOREIPROC fPixelStorei; - typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); - PFNGLPOINTPARAMETERFPROC fPointParameterf; - typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat bias); - PFNGLPOLYGONOFFSETPROC fPolygonOffset; - typedef void (GLAPIENTRY * PFNGLREADBUFFERPROC) (GLenum); - PFNGLREADBUFFERPROC fReadBuffer; - typedef void (GLAPIENTRY * PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); - PFNGLREADPIXELSPROC fReadPixels; - typedef void (GLAPIENTRY * PFNGLSAMPLECOVERAGEPROC) (GLclampf value, realGLboolean invert); - PFNGLSAMPLECOVERAGEPROC fSampleCoverage; - typedef void (GLAPIENTRY * PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); - PFNGLSTENCILFUNCPROC fStencilFunc; - typedef void (GLAPIENTRY * PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); - PFNGLSTENCILFUNCSEPARATEPROC fStencilFuncSeparate; - typedef void (GLAPIENTRY * PFNGLSTENCILMASKPROC) (GLuint mask); - PFNGLSTENCILMASKPROC fStencilMask; - typedef void (GLAPIENTRY * PFNGLSTENCILMASKSEPARATEPROC) (GLenum, GLuint); - PFNGLSTENCILMASKSEPARATEPROC fStencilMaskSeparate; - typedef void (GLAPIENTRY * PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); - PFNGLSTENCILOPPROC fStencilOp; - typedef void (GLAPIENTRY * PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); - PFNGLSTENCILOPSEPARATEPROC fStencilOpSeparate; - typedef void (GLAPIENTRY * PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - PFNGLTEXIMAGE2DPROC fTexImage2D; - typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); - PFNGLTEXSUBIMAGE2DPROC fTexSubImage2D; - typedef void (GLAPIENTRY * PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); - PFNGLUNIFORM1FPROC fUniform1f; - typedef void (GLAPIENTRY * PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat* value); - PFNGLUNIFORM1FVPROC fUniform1fv; - typedef void (GLAPIENTRY * PFNGLUNIFORM1IPROC) (GLint location, GLint v0); - PFNGLUNIFORM1IPROC fUniform1i; - typedef void (GLAPIENTRY * PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint* value); - PFNGLUNIFORM1IVPROC fUniform1iv; - typedef void (GLAPIENTRY * PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); - PFNGLUNIFORM2FPROC fUniform2f; - typedef void (GLAPIENTRY * PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat* value); - PFNGLUNIFORM2FVPROC fUniform2fv; - typedef void (GLAPIENTRY * PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); - PFNGLUNIFORM2IPROC fUniform2i; - typedef void (GLAPIENTRY * PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint* value); - PFNGLUNIFORM2IVPROC fUniform2iv; - typedef void (GLAPIENTRY * PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); - PFNGLUNIFORM3FPROC fUniform3f; - typedef void (GLAPIENTRY * PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat* value); - PFNGLUNIFORM3FVPROC fUniform3fv; - typedef void (GLAPIENTRY * PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); - PFNGLUNIFORM3IPROC fUniform3i; - typedef void (GLAPIENTRY * PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint* value); - PFNGLUNIFORM3IVPROC fUniform3iv; - typedef void (GLAPIENTRY * PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); - PFNGLUNIFORM4FPROC fUniform4f; - typedef void (GLAPIENTRY * PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat* value); - PFNGLUNIFORM4FVPROC fUniform4fv; - typedef void (GLAPIENTRY * PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); - PFNGLUNIFORM4IPROC fUniform4i; - typedef void (GLAPIENTRY * PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint* value); - PFNGLUNIFORM4IVPROC fUniform4iv; - typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value); - PFNGLUNIFORMMATRIX2FVPROC fUniformMatrix2fv; - typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value); - PFNGLUNIFORMMATRIX3FVPROC fUniformMatrix3fv; - typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, realGLboolean transpose, const GLfloat* value); - PFNGLUNIFORMMATRIX4FVPROC fUniformMatrix4fv; - typedef void (GLAPIENTRY * PFNGLUSEPROGRAMPROC) (GLuint program); - PFNGLUSEPROGRAMPROC fUseProgram; - typedef void (GLAPIENTRY * PFNGLVALIDATEPROGRAMPROC) (GLuint program); - PFNGLVALIDATEPROGRAMPROC fValidateProgram; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, realGLboolean normalized, GLsizei stride, const GLvoid* pointer); - PFNGLVERTEXATTRIBPOINTERPROC fVertexAttribPointer; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); - PFNGLVERTEXATTRIB1FPROC fVertexAttrib1f; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); - PFNGLVERTEXATTRIB2FPROC fVertexAttrib2f; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); - PFNGLVERTEXATTRIB3FPROC fVertexAttrib3f; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - PFNGLVERTEXATTRIB4FPROC fVertexAttrib4f; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat* v); - PFNGLVERTEXATTRIB1FVPROC fVertexAttrib1fv; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat* v); - PFNGLVERTEXATTRIB2FVPROC fVertexAttrib2fv; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat* v); - PFNGLVERTEXATTRIB3FVPROC fVertexAttrib3fv; - typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat* v); - PFNGLVERTEXATTRIB4FVPROC fVertexAttrib4fv; - typedef void (GLAPIENTRY * PFNGLCOMPILESHADERPROC) (GLuint shader); - PFNGLCOMPILESHADERPROC fCompileShader; - typedef void (GLAPIENTRY * PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); - PFNGLCOPYTEXIMAGE2DPROC fCopyTexImage2D; - typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); - PFNGLCOPYTEXSUBIMAGE2DPROC fCopyTexSubImage2D; - typedef void (GLAPIENTRY * PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param); - PFNGLGETSHADERIVPROC fGetShaderiv; - typedef void (GLAPIENTRY * PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); - PFNGLGETSHADERINFOLOGPROC fGetShaderInfoLog; - typedef void (GLAPIENTRY * PFNGETSHADERPRECISIONFORMAT) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); - PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat; - typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source); - PFNGLGETSHADERSOURCEPROC fGetShaderSource; - typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths); - PFNGLSHADERSOURCEPROC fShaderSource; - - typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer); - PFNGLBINDFRAMEBUFFER fBindFramebuffer; - typedef void (GLAPIENTRY * PFNGLBINDRENDERBUFFER) (GLenum target, GLuint renderbuffer); - PFNGLBINDRENDERBUFFER fBindRenderbuffer; - typedef GLenum (GLAPIENTRY * PFNGLCHECKFRAMEBUFFERSTATUS) (GLenum target); - PFNGLCHECKFRAMEBUFFERSTATUS fCheckFramebufferStatus; - typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERRENDERBUFFER) (GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer); - PFNGLFRAMEBUFFERRENDERBUFFER fFramebufferRenderbuffer; - typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURE2D) (GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level); - PFNGLFRAMEBUFFERTEXTURE2D fFramebufferTexture2D; - typedef void (GLAPIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV) (GLenum target, GLenum attachment, GLenum pname, GLint* value); - PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV fGetFramebufferAttachmentParameteriv; - typedef void (GLAPIENTRY * PFNGLGETRENDERBUFFERPARAMETERIV) (GLenum target, GLenum pname, GLint* value); - PFNGLGETRENDERBUFFERPARAMETERIV fGetRenderbufferParameteriv; - typedef realGLboolean (GLAPIENTRY * PFNGLISFRAMEBUFFER) (GLuint framebuffer); - PFNGLISFRAMEBUFFER fIsFramebuffer; - typedef realGLboolean (GLAPIENTRY * PFNGLISRENDERBUFFER) (GLuint renderbuffer); - PFNGLISRENDERBUFFER fIsRenderbuffer; - typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height); - PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage; - - typedef void (GLAPIENTRY * PFNGLBLITFRAMEBUFFER) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); - PFNGLBLITFRAMEBUFFER fBlitFramebuffer; - typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLE) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height); - PFNGLRENDERBUFFERSTORAGEMULTISAMPLE fRenderbufferStorageMultisample; - - - /* These are different between GLES2 and desktop GL; we hide those differences, use the GL - * names, but the most limited data type. - */ - typedef void (GLAPIENTRY * PFNGLDEPTHRANGEFPROC) (GLclampf, GLclampf); - PFNGLDEPTHRANGEFPROC fDepthRangef; - typedef void (GLAPIENTRY * PFNGLCLEARDEPTHFPROC) (GLclampf); - PFNGLCLEARDEPTHFPROC fClearDepthf; - - typedef void (GLAPIENTRY * PFNGLDEPTHRANGEPROC) (GLclampd, GLclampd); - PFNGLDEPTHRANGEPROC fDepthRange; - typedef void (GLAPIENTRY * PFNGLCLEARDEPTHPROC) (GLclampd); - PFNGLCLEARDEPTHPROC fClearDepth; - - /* These are special because we end up tracking these so that we don't - * have to query the values from GL. - */ - - typedef void (GLAPIENTRY * PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); - PFNGLVIEWPORTPROC fViewport; - typedef void (GLAPIENTRY * PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); - PFNGLSCISSORPROC fScissor; - - - /* These are special -- they create or delete GL resources that can live - * in a shared namespace. In DEBUG, we wrap these calls so that we can - * check when we have something that failed to do cleanup at the time the - * final context is destroyed. - */ - - typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void); - PFNGLCREATEPROGRAMPROC fCreateProgram; - typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type); - PFNGLCREATESHADERPROC fCreateShader; - typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers); - PFNGLGENBUFFERSPROC fGenBuffers; - typedef void (GLAPIENTRY * PFNGLGENQUERIESPROC) (GLsizei n, GLuint* queries); - PFNGLGENQUERIESPROC fGenQueries; - typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); - PFNGLGENTEXTURESPROC fGenTextures; - typedef void (GLAPIENTRY * PFNGLGENFRAMEBUFFERS) (GLsizei n, GLuint* ids); - PFNGLGENFRAMEBUFFERS fGenFramebuffers; - typedef void (GLAPIENTRY * PFNGLGENRENDERBUFFERS) (GLsizei n, GLuint* ids); - PFNGLGENRENDERBUFFERS fGenRenderbuffers; - - typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program); - PFNGLDELETEPROGRAMPROC fDeleteProgram; - typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader); - PFNGLDELETESHADERPROC fDeleteShader; - typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers); - PFNGLDELETEBUFFERSPROC fDeleteBuffers; - typedef void (GLAPIENTRY * PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint* queries); - PFNGLDELETEQUERIESPROC fDeleteQueries; - typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint* textures); - PFNGLDELETETEXTURESPROC fDeleteTextures; - typedef void (GLAPIENTRY * PFNGLDELETEFRAMEBUFFERS) (GLsizei n, const GLuint* ids); - PFNGLDELETEFRAMEBUFFERS fDeleteFramebuffers; - typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids); - PFNGLDELETERENDERBUFFERS fDeleteRenderbuffers; - - typedef void* (GLAPIENTRY * PFNGLMAPBUFFER) (GLenum target, GLenum access); - PFNGLMAPBUFFER fMapBuffer; - typedef realGLboolean (GLAPIENTRY * PFNGLUNMAPBUFFER) (GLenum target); - PFNGLUNMAPBUFFER fUnmapBuffer; - - typedef GLenum (GLAPIENTRY * PFNGLGETGRAPHICSRESETSTATUS) (void); - PFNGLGETGRAPHICSRESETSTATUS fGetGraphicsResetStatus; - - // ARB_sync - typedef GLsync (GLAPIENTRY * PFNGLFENCESYNC) (GLenum condition, GLbitfield flags); - PFNGLFENCESYNC fFenceSync; - typedef realGLboolean (GLAPIENTRY * PFNGLISSYNC) (GLsync sync); - PFNGLISSYNC fIsSync; - typedef void (GLAPIENTRY * PFNGLDELETESYNC) (GLsync sync); - PFNGLDELETESYNC fDeleteSync; - typedef GLenum (GLAPIENTRY * PFNGLCLIENTWAITSYNC) (GLsync sync, GLbitfield flags, GLuint64 timeout); - PFNGLCLIENTWAITSYNC fClientWaitSync; - typedef void (GLAPIENTRY * PFNGLWAITSYNC) (GLsync sync, GLbitfield flags, GLuint64 timeout); - PFNGLWAITSYNC fWaitSync; - typedef void (GLAPIENTRY * PFNGLGETINTEGER64V) (GLenum pname, GLint64 *params); - PFNGLGETINTEGER64V fGetInteger64v; - typedef void (GLAPIENTRY * PFNGLGETSYNCIV) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); - PFNGLGETSYNCIV fGetSynciv; - - // OES_egl_image - typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETTEXTURE2D)(GLenum target, GLeglImage image); - PFNGLEGLIMAGETARGETTEXTURE2D fEGLImageTargetTexture2D; - typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE)(GLenum target, GLeglImage image); - PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE fEGLImageTargetRenderbufferStorage; -}; - -} -} - -#endif /* GLCONTEXTSYMBOLS_H_ */ diff --git a/libazure/src/gfx/gl/GLContextTypes.cpp b/libazure/src/gfx/gl/GLContextTypes.cpp deleted file mode 100644 index b11c990..0000000 --- a/libazure/src/gfx/gl/GLContextTypes.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContextTypes.h" -#include - -using namespace mozilla::gl; - -GLFormats::GLFormats() -{ - std::memset(this, 0, sizeof(GLFormats)); -} - -PixelBufferFormat::PixelBufferFormat() -{ - std::memset(this, 0, sizeof(PixelBufferFormat)); -} diff --git a/libazure/src/gfx/gl/GLContextTypes.h b/libazure/src/gfx/gl/GLContextTypes.h deleted file mode 100644 index 8b1b6f6..0000000 --- a/libazure/src/gfx/gl/GLContextTypes.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLCONTEXT_TYPES_H_ -#define GLCONTEXT_TYPES_H_ - -typedef unsigned int GLenum; -typedef unsigned int GLbitfield; -typedef unsigned int GLuint; -typedef int GLint; -typedef int GLsizei; - -namespace mozilla { -namespace gl { - -enum ShaderProgramType { - RGBALayerProgramType, - RGBALayerExternalProgramType, - BGRALayerProgramType, - RGBXLayerProgramType, - BGRXLayerProgramType, - RGBARectLayerProgramType, - RGBAExternalLayerProgramType, - ColorLayerProgramType, - YCbCrLayerProgramType, - ComponentAlphaPass1ProgramType, - ComponentAlphaPass2ProgramType, - Copy2DProgramType, - Copy2DRectProgramType, - NumProgramTypes -}; - -struct GLFormats -{ - // Constructs a zeroed object: - GLFormats(); - - GLenum color_texInternalFormat; - GLenum color_texFormat; - GLenum color_texType; - GLenum color_rbFormat; - - GLenum depthStencil; - GLenum depth; - GLenum stencil; - - GLsizei samples; -}; - - -struct PixelBufferFormat -{ - // Constructs a zeroed object: - PixelBufferFormat(); - - int red, green, blue; - int alpha; - int depth, stencil; - int samples; - - int ColorBits() const { return red + green + blue; } -}; - - -} /* namespace gl */ -} /* namespace mozilla */ - -#endif /* GLCONTEXT_TYPES_H_ */ diff --git a/libazure/src/gfx/gl/GLContextUtils.cpp b/libazure/src/gfx/gl/GLContextUtils.cpp deleted file mode 100644 index 552b057..0000000 --- a/libazure/src/gfx/gl/GLContextUtils.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContext.h" - -#include "mozilla/Preferences.h" -#include "mozilla/Assertions.h" -#include "mozilla/StandardInteger.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -static const char kTexBlit_VertShaderSource[] = "\ -attribute vec2 aPosition; \n\ - \n\ -varying vec2 vTexCoord; \n\ - \n\ -void main(void) { \n\ - vTexCoord = aPosition; \n\ - vec2 vertPos = aPosition * 2.0 - 1.0; \n\ - gl_Position = vec4(vertPos, 0.0, 1.0); \n\ -} \n\ -"; - -static const char kTexBlit_FragShaderSource[] = "\ -#ifdef GL_FRAGMENT_PRECISION_HIGH \n\ - precision highp float; \n\ -#else \n\ - precision mediump float; \n\ -#endif \n\ - \n\ -uniform sampler2D uTexUnit; \n\ - \n\ -varying vec2 vTexCoord; \n\ - \n\ -void main(void) { \n\ - gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\ -} \n\ -"; - -// Allowed to be destructive of state we restore in functions below. -bool -GLContext::UseTexQuadProgram() -{ - bool success = false; - - // Use do-while(false) to let us break on failure - do { - if (mTexBlit_Program) { - // Already have it... - success = true; - break; - } - - /* CCW tri-strip: - * 2---3 - * | \ | - * 0---1 - */ - GLfloat verts[] = { - 0.0f, 0.0f, - 1.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 1.0f - }; - - MOZ_ASSERT(!mTexBlit_Buffer); - fGenBuffers(1, &mTexBlit_Buffer); - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer); - - const size_t vertsSize = sizeof(verts); - MOZ_ASSERT(vertsSize >= 3 * sizeof(GLfloat)); // Make sure we have a sane size. - fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsSize, verts, LOCAL_GL_STATIC_DRAW); - - fEnableVertexAttribArray(0); - fVertexAttribPointer(0, - 2, - LOCAL_GL_FLOAT, - false, - 0, - nullptr); - - MOZ_ASSERT(!mTexBlit_VertShader); - MOZ_ASSERT(!mTexBlit_FragShader); - - const char* vertShaderSource = kTexBlit_VertShaderSource; - const char* fragShaderSource = kTexBlit_FragShaderSource; - - mTexBlit_VertShader = fCreateShader(LOCAL_GL_VERTEX_SHADER); - fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr); - fCompileShader(mTexBlit_VertShader); - - mTexBlit_FragShader = fCreateShader(LOCAL_GL_FRAGMENT_SHADER); - fShaderSource(mTexBlit_FragShader, 1, &fragShaderSource, nullptr); - fCompileShader(mTexBlit_FragShader); - - mTexBlit_Program = fCreateProgram(); - fAttachShader(mTexBlit_Program, mTexBlit_VertShader); - fAttachShader(mTexBlit_Program, mTexBlit_FragShader); - fBindAttribLocation(mTexBlit_Program, 0, "aPosition"); - fLinkProgram(mTexBlit_Program); - - if (DebugMode()) { - GLint status = 0; - fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status); - if (status != LOCAL_GL_TRUE) { - NS_ERROR("Vert shader compilation failed."); - - GLint length = 0; - fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length); - if (!length) { - printf_stderr("No shader info log available.\n"); - break; - } - - nsAutoArrayPtr buffer(new char[length]); - fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer); - - printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); - break; - } - - status = 0; - fGetShaderiv(mTexBlit_FragShader, LOCAL_GL_COMPILE_STATUS, &status); - if (status != LOCAL_GL_TRUE) { - NS_ERROR("Frag shader compilation failed."); - - GLint length = 0; - fGetShaderiv(mTexBlit_FragShader, LOCAL_GL_INFO_LOG_LENGTH, &length); - if (!length) { - printf_stderr("No shader info log available.\n"); - break; - } - - nsAutoArrayPtr buffer(new char[length]); - fGetShaderInfoLog(mTexBlit_FragShader, length, nullptr, buffer); - - printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); - break; - } - } - - GLint status = 0; - fGetProgramiv(mTexBlit_Program, LOCAL_GL_LINK_STATUS, &status); - if (status != LOCAL_GL_TRUE) { - if (DebugMode()) { - NS_ERROR("Linking blit program failed."); - GLint length = 0; - fGetProgramiv(mTexBlit_Program, LOCAL_GL_INFO_LOG_LENGTH, &length); - if (!length) { - printf_stderr("No program info log available.\n"); - break; - } - - nsAutoArrayPtr buffer(new char[length]); - fGetProgramInfoLog(mTexBlit_Program, length, nullptr, buffer); - - printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get()); - } - break; - } - - MOZ_ASSERT(fGetAttribLocation(mTexBlit_Program, "aPosition") == 0); - GLuint texUnitLoc = fGetUniformLocation(mTexBlit_Program, "uTexUnit"); - - // Set uniforms here: - fUseProgram(mTexBlit_Program); - fUniform1i(texUnitLoc, 0); - - success = true; - } while (false); - - if (!success) { - NS_ERROR("Creating program for texture blit failed!"); - - // Clean up: - DeleteTexBlitProgram(); - return false; - } - - fUseProgram(mTexBlit_Program); - fEnableVertexAttribArray(0); - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer); - fVertexAttribPointer(0, - 2, - LOCAL_GL_FLOAT, - false, - 0, - nullptr); - return true; -} - -void -GLContext::DeleteTexBlitProgram() -{ - if (mTexBlit_Buffer) { - fDeleteBuffers(1, &mTexBlit_Buffer); - mTexBlit_Buffer = 0; - } - if (mTexBlit_VertShader) { - fDeleteShader(mTexBlit_VertShader); - mTexBlit_VertShader = 0; - } - if (mTexBlit_FragShader) { - fDeleteShader(mTexBlit_FragShader); - mTexBlit_FragShader = 0; - } - if (mTexBlit_Program) { - fDeleteProgram(mTexBlit_Program); - mTexBlit_Program = 0; - } -} - -void -GLContext::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize) -{ - MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); - MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); - - MOZ_ASSERT(IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit)); - - ScopedBindFramebuffer boundFB(this); - ScopedGLState scissor(this, LOCAL_GL_SCISSOR_TEST, false); - - BindReadFB(srcFB); - BindDrawFB(destFB); - - fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, - 0, 0, destSize.width, destSize.height, - LOCAL_GL_COLOR_BUFFER_BIT, - LOCAL_GL_NEAREST); -} - -void -GLContext::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, - const GLFormats& srcFormats) -{ - MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); - MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); - - if (IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit)) - { - BlitFramebufferToFramebuffer(srcFB, destFB, - srcSize, destSize); - return; - } - - GLuint tex = CreateTextureForOffscreen(srcFormats, srcSize); - MOZ_ASSERT(tex); - - BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize); - BlitTextureToFramebuffer(tex, destFB, srcSize, destSize); - - fDeleteTextures(1, &tex); -} - -void -GLContext::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize) -{ - MOZ_ASSERT(fIsTexture(srcTex)); - MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); - - if (IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit)) - { - ScopedFramebufferForTexture srcWrapper(this, srcTex); - MOZ_ASSERT(srcWrapper.IsComplete()); - - BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, - srcSize, destSize); - return; - } - - - ScopedBindFramebuffer boundFB(this, destFB); - - GLuint boundTexUnit = 0; - GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &boundTexUnit); - fActiveTexture(LOCAL_GL_TEXTURE0); - - GLuint boundTex = 0; - GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &boundTex); - fBindTexture(LOCAL_GL_TEXTURE_2D, srcTex); - - GLuint boundProgram = 0; - GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram); - - GLuint boundBuffer = 0; - GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer); - - /* - * fGetVertexAttribiv takes: - * VERTEX_ATTRIB_ARRAY_ENABLED - * VERTEX_ATTRIB_ARRAY_SIZE, - * VERTEX_ATTRIB_ARRAY_STRIDE, - * VERTEX_ATTRIB_ARRAY_TYPE, - * VERTEX_ATTRIB_ARRAY_NORMALIZED, - * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, - * CURRENT_VERTEX_ATTRIB - * - * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/ - * Others appear to be vertex array state, - * or alternatively in the internal vertex array state - * for a buffer object. - */ - - GLint attrib0_enabled = 0; - GLint attrib0_size = 0; - GLint attrib0_stride = 0; - GLint attrib0_type = 0; - GLint attrib0_normalized = 0; - GLint attrib0_bufferBinding = 0; - void* attrib0_pointer = nullptr; - - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib0_enabled); - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size); - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride); - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type); - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized); - fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding); - fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer); - // Note that uniform values are program state, so we don't need to rebind those. - - ScopedGLState blend (this, LOCAL_GL_BLEND, false); - ScopedGLState cullFace (this, LOCAL_GL_CULL_FACE, false); - ScopedGLState depthTest (this, LOCAL_GL_DEPTH_TEST, false); - ScopedGLState dither (this, LOCAL_GL_DITHER, false); - ScopedGLState polyOffsFill(this, LOCAL_GL_POLYGON_OFFSET_FILL, false); - ScopedGLState sampleAToC (this, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false); - ScopedGLState sampleCover (this, LOCAL_GL_SAMPLE_COVERAGE, false); - ScopedGLState scissor (this, LOCAL_GL_SCISSOR_TEST, false); - ScopedGLState stencil (this, LOCAL_GL_STENCIL_TEST, false); - - realGLboolean colorMask[4]; - fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask); - fColorMask(LOCAL_GL_TRUE, - LOCAL_GL_TRUE, - LOCAL_GL_TRUE, - LOCAL_GL_TRUE); - - GLint viewport[4]; - fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); - fViewport(0, 0, destSize.width, destSize.height); - - // Does destructive things to (only!) what we just saved above. - bool good = UseTexQuadProgram(); - if (!good) { - // We're up against the wall, so bail. - // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good). - printf_stderr("[%s:%d] Fatal Error: Failed to prepare to blit texture->framebuffer.\n", - __FILE__, __LINE__); - MOZ_CRASH(); - } - fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); - - fViewport(viewport[0], viewport[1], - viewport[2], viewport[3]); - - fColorMask(colorMask[0], - colorMask[1], - colorMask[2], - colorMask[3]); - - if (attrib0_enabled) - fEnableVertexAttribArray(0); - - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding); - fVertexAttribPointer(0, - attrib0_size, - attrib0_type, - attrib0_normalized, - attrib0_stride, - attrib0_pointer); - - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer); - - fUseProgram(boundProgram); - fBindTexture(LOCAL_GL_TEXTURE_2D, boundTex); - fActiveTexture(boundTexUnit); -} - -void -GLContext::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize) -{ - MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); - MOZ_ASSERT(fIsTexture(destTex)); - - if (IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit)) - { - ScopedFramebufferForTexture destWrapper(this, destTex); - - BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(), - srcSize, destSize); - return; - } - - ScopedBindTexture autoTex(this, destTex); - ScopedBindFramebuffer boundFB(this, srcFB); - ScopedGLState scissor(this, LOCAL_GL_SCISSOR_TEST, false); - - fCopyTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, - 0, 0, - 0, 0, - srcSize.width, srcSize.height); -} - -void -GLContext::BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize) -{ - MOZ_ASSERT(fIsTexture(srcTex)); - MOZ_ASSERT(fIsTexture(destTex)); - - if (mTexBlit_UseDrawNotCopy) { - // Draw is texture->framebuffer - ScopedFramebufferForTexture destWrapper(this, destTex); - - BlitTextureToFramebuffer(srcTex, destWrapper.FB(), - srcSize, destSize); - return; - } - - // Generally, just use the CopyTexSubImage path - ScopedFramebufferForTexture srcWrapper(this, srcTex); - - BlitFramebufferToTexture(srcWrapper.FB(), destTex, - srcSize, destSize); -} - -uint32_t GetBitsPerTexel(GLenum format, GLenum type) -{ - // If there is no defined format or type, we're not taking up any memory - if (!format || !type) { - return 0; - } - - if (format == LOCAL_GL_DEPTH_COMPONENT) { - if (type == LOCAL_GL_UNSIGNED_SHORT) - return 2; - else if (type == LOCAL_GL_UNSIGNED_INT) - return 4; - } else if (format == LOCAL_GL_DEPTH_STENCIL) { - if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT) - return 4; - } - - if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) { - int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8; - switch (format) { - case LOCAL_GL_ALPHA: - case LOCAL_GL_LUMINANCE: - return 1 * multiplier; - case LOCAL_GL_LUMINANCE_ALPHA: - return 2 * multiplier; - case LOCAL_GL_RGB: - return 3 * multiplier; - case LOCAL_GL_RGBA: - return 4 * multiplier; - case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1: - case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1: - return 2; - case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case LOCAL_GL_ATC_RGB: - case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1: - case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1: - return 4; - case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA: - case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA: - return 8; - default: - break; - } - } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 || - type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 || - type == LOCAL_GL_UNSIGNED_SHORT_5_6_5) - { - return 16; - } - - MOZ_ASSERT(false); - return 0; -} - - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLLibraryEGL.cpp b/libazure/src/gfx/gl/GLLibraryEGL.cpp deleted file mode 100644 index 59177ff..0000000 --- a/libazure/src/gfx/gl/GLLibraryEGL.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLLibraryEGL.h" - -#include "gfxCrashReporterUtils.h" -#include "mozilla/Preferences.h" -#include "nsDirectoryServiceDefs.h" -#include "nsDirectoryServiceUtils.h" -#include "nsPrintfCString.h" -#include "prenv.h" -#include "GLContext.h" - -namespace mozilla { -namespace gl { - -// should match the order of EGLExtensions, and be null-terminated. -static const char *sExtensionNames[] = { - "EGL_KHR_image_base", - "EGL_KHR_image_pixmap", - "EGL_KHR_gl_texture_2D_image", - "EGL_KHR_lock_surface", - "EGL_ANGLE_surface_d3d_texture_2d_share_handle", - "EGL_EXT_create_context_robustness", - "EGL_KHR_image", - "EGL_KHR_fence_sync", - nullptr -}; - -#if defined(ANDROID) - -static PRLibrary* LoadApitraceLibrary() -{ - static PRLibrary* sApitraceLibrary = NULL; - - if (sApitraceLibrary) - return sApitraceLibrary; - - nsCString logFile = Preferences::GetCString("gfx.apitrace.logfile"); - - if (logFile.IsEmpty()) { - logFile = "firefox.trace"; - } - - // The firefox process can't write to /data/local, but it can write - // to $GRE_HOME/ - nsAutoCString logPath; - logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get()); - - // apitrace uses the TRACE_FILE environment variable to determine where - // to log trace output to - printf_stderr("Logging GL tracing output to %s", logPath.get()); - setenv("TRACE_FILE", logPath.get(), false); - - printf_stderr("Attempting load of %s\n", APITRACE_LIB); - - sApitraceLibrary = PR_LoadLibrary(APITRACE_LIB); - - return sApitraceLibrary; -} - -#endif // ANDROID - -#ifdef XP_WIN -// see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here. -static PRLibrary* -LoadLibraryForEGLOnWindows(const nsAString& filename) -{ - nsCOMPtr file; - nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); - if (NS_FAILED(rv)) - return nullptr; - - file->Append(filename); - PRLibrary* lib = nullptr; - rv = file->Load(&lib); - if (NS_FAILED(rv)) { - nsPrintfCString msg("Failed to load %s - Expect EGL initialization to fail", - NS_LossyConvertUTF16toASCII(filename).get()); - NS_WARNING(msg.get()); - } - return lib; -} -#endif // XP_WIN - -bool -GLLibraryEGL::EnsureInitialized() -{ - if (mInitialized) { - return true; - } - - mozilla::ScopedGfxFeatureReporter reporter("EGL"); - -#ifdef XP_WIN -#ifdef MOZ_WEBGL - if (!mEGLLibrary) { - // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and - // we should look for them there. We have to load the libs in this - // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK - // libraries. This matters especially for WebRT apps which are in a different directory. - // See bug 760323 and bug 749459 - -#ifndef MOZ_D3DCOMPILER_DLL -#error MOZ_D3DCOMPILER_DLL should have been defined by the Makefile -#endif - LoadLibraryForEGLOnWindows(NS_LITERAL_STRING(NS_STRINGIFY(MOZ_D3DCOMPILER_DLL))); - // intentionally leak the D3DCOMPILER_DLL library - - LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libGLESv2.dll")); - // intentionally leak the libGLESv2.dll library - - mEGLLibrary = LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libEGL.dll")); - - if (!mEGLLibrary) - return false; - } -#endif // MOZ_WEBGL -#else // !Windows - - // On non-Windows (Android) we use system copies of libEGL. We look for - // the APITrace lib, libEGL.so, and libEGL.so.1 in that order. - -#if defined(ANDROID) - if (!mEGLLibrary) - mEGLLibrary = LoadApitraceLibrary(); -#endif - - if (!mEGLLibrary) { - printf_stderr("Attempting load of libEGL.so\n"); - mEGLLibrary = PR_LoadLibrary("libEGL.so"); - } -#if defined(XP_UNIX) - if (!mEGLLibrary) { - mEGLLibrary = PR_LoadLibrary("libEGL.so.1"); - } -#endif - - if (!mEGLLibrary) { - NS_WARNING("Couldn't load EGL LIB."); - return false; - } - -#endif // !Windows - -#define SYMBOL(name) \ -{ (PRFuncPtr*) &mSymbols.f##name, { "egl" #name, NULL } } - - GLLibraryLoader::SymLoadStruct earlySymbols[] = { - SYMBOL(GetDisplay), - SYMBOL(GetCurrentSurface), - SYMBOL(GetCurrentContext), - SYMBOL(MakeCurrent), - SYMBOL(DestroyContext), - SYMBOL(CreateContext), - SYMBOL(DestroySurface), - SYMBOL(CreateWindowSurface), - SYMBOL(CreatePbufferSurface), - SYMBOL(CreatePixmapSurface), - SYMBOL(BindAPI), - SYMBOL(Initialize), - SYMBOL(ChooseConfig), - SYMBOL(GetError), - SYMBOL(GetConfigs), - SYMBOL(GetConfigAttrib), - SYMBOL(WaitNative), - SYMBOL(GetProcAddress), - SYMBOL(SwapBuffers), - SYMBOL(CopyBuffers), - SYMBOL(QueryString), - SYMBOL(QueryContext), - SYMBOL(BindTexImage), - SYMBOL(ReleaseTexImage), - SYMBOL(QuerySurface), - { NULL, { NULL } } - }; - - if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) { - NS_WARNING("Couldn't find required entry points in EGL library (early init)"); - return false; - } - - mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY); - if (!fInitialize(mEGLDisplay, NULL, NULL)) - return false; - - const char *vendor = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR); - if (vendor && (strstr(vendor, "TransGaming") != 0 || strstr(vendor, "Google Inc.") != 0)) { - mIsANGLE = true; - } - - InitExtensions(); - - GLLibraryLoader::PlatformLookupFunction lookupFunction = - (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress; - - if (IsExtensionSupported(KHR_lock_surface)) { - GLLibraryLoader::SymLoadStruct lockSymbols[] = { - { (PRFuncPtr*) &mSymbols.fLockSurface, { "eglLockSurfaceKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fUnlockSurface, { "eglUnlockSurfaceKHR", nullptr } }, - { nullptr, { nullptr } } - }; - - bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, - &lockSymbols[0], - lookupFunction); - if (!success) { - NS_ERROR("EGL supports KHR_lock_surface without exposing its functions!"); - - MarkExtensionUnsupported(KHR_lock_surface); - - mSymbols.fLockSurface = nullptr; - mSymbols.fUnlockSurface = nullptr; - } - } - - if (IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle)) { - GLLibraryLoader::SymLoadStruct d3dSymbols[] = { - { (PRFuncPtr*) &mSymbols.fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", nullptr } }, - { nullptr, { nullptr } } - }; - - bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, - &d3dSymbols[0], - lookupFunction); - if (!success) { - NS_ERROR("EGL supports ANGLE_surface_d3d_texture_2d_share_handle without exposing its functions!"); - - MarkExtensionUnsupported(ANGLE_surface_d3d_texture_2d_share_handle); - - mSymbols.fQuerySurfacePointerANGLE = nullptr; - } - } - - if (IsExtensionSupported(KHR_fence_sync)) { - GLLibraryLoader::SymLoadStruct syncSymbols[] = { - { (PRFuncPtr*) &mSymbols.fCreateSync, { "eglCreateSyncKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDestroySync, { "eglDestroySyncKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "eglClientWaitSyncKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fGetSyncAttrib, { "eglGetSyncAttribKHR", nullptr } }, - { nullptr, { nullptr } } - }; - - bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, - &syncSymbols[0], - lookupFunction); - if (!success) { - NS_ERROR("EGL supports KHR_fence_sync without exposing its functions!"); - - MarkExtensionUnsupported(KHR_fence_sync); - - mSymbols.fCreateSync = nullptr; - mSymbols.fDestroySync = nullptr; - mSymbols.fClientWaitSync = nullptr; - mSymbols.fGetSyncAttrib = nullptr; - } - } - - if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) { - GLLibraryLoader::SymLoadStruct imageSymbols[] = { - { (PRFuncPtr*) &mSymbols.fCreateImage, { "eglCreateImageKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDestroyImage, { "eglDestroyImageKHR", nullptr } }, - { nullptr, { nullptr } } - }; - - bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, - &imageSymbols[0], - lookupFunction); - if (!success) { - NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!"); - - MarkExtensionUnsupported(KHR_image); - MarkExtensionUnsupported(KHR_image_base); - MarkExtensionUnsupported(KHR_image_pixmap); - - mSymbols.fCreateImage = nullptr; - mSymbols.fDestroyImage = nullptr; - } - } else { - MarkExtensionUnsupported(KHR_image_pixmap); - } - - mInitialized = true; - reporter.SetSuccessful(); - return true; -} - -void -GLLibraryEGL::InitExtensions() -{ - const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); - - if (!extensions) { - NS_WARNING("Failed to load EGL extension list!"); - return; - } - - bool debugMode = false; -#ifdef DEBUG - if (PR_GetEnv("MOZ_GL_DEBUG")) - debugMode = true; - - static bool firstRun = true; -#else - // Non-DEBUG, so never spew. - const bool firstRun = false; -#endif - - mAvailableExtensions.Load(extensions, sExtensionNames, firstRun && debugMode); - -#ifdef DEBUG - firstRun = false; -#endif -} - -void -GLLibraryEGL::DumpEGLConfig(EGLConfig cfg) -{ - int attrval; - int err; - -#define ATTR(_x) do { \ - fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval); \ - if ((err = fGetError()) != 0x3000) { \ - printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \ - } else { \ - printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \ - } \ - } while(0) - - printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg); - - ATTR(BUFFER_SIZE); - ATTR(ALPHA_SIZE); - ATTR(BLUE_SIZE); - ATTR(GREEN_SIZE); - ATTR(RED_SIZE); - ATTR(DEPTH_SIZE); - ATTR(STENCIL_SIZE); - ATTR(CONFIG_CAVEAT); - ATTR(CONFIG_ID); - ATTR(LEVEL); - ATTR(MAX_PBUFFER_HEIGHT); - ATTR(MAX_PBUFFER_PIXELS); - ATTR(MAX_PBUFFER_WIDTH); - ATTR(NATIVE_RENDERABLE); - ATTR(NATIVE_VISUAL_ID); - ATTR(NATIVE_VISUAL_TYPE); - ATTR(PRESERVED_RESOURCES); - ATTR(SAMPLES); - ATTR(SAMPLE_BUFFERS); - ATTR(SURFACE_TYPE); - ATTR(TRANSPARENT_TYPE); - ATTR(TRANSPARENT_RED_VALUE); - ATTR(TRANSPARENT_GREEN_VALUE); - ATTR(TRANSPARENT_BLUE_VALUE); - ATTR(BIND_TO_TEXTURE_RGB); - ATTR(BIND_TO_TEXTURE_RGBA); - ATTR(MIN_SWAP_INTERVAL); - ATTR(MAX_SWAP_INTERVAL); - ATTR(LUMINANCE_SIZE); - ATTR(ALPHA_MASK_SIZE); - ATTR(COLOR_BUFFER_TYPE); - ATTR(RENDERABLE_TYPE); - ATTR(CONFORMANT); - -#undef ATTR -} - -void -GLLibraryEGL::DumpEGLConfigs() -{ - int nc = 0; - fGetConfigs(mEGLDisplay, NULL, 0, &nc); - EGLConfig *ec = new EGLConfig[nc]; - fGetConfigs(mEGLDisplay, ec, nc, &nc); - - for (int i = 0; i < nc; ++i) { - printf_stderr ("========= EGL Config %d ========\n", i); - DumpEGLConfig(ec[i]); - } - - delete [] ec; -} - -} /* namespace gl */ -} /* namespace mozilla */ - diff --git a/libazure/src/gfx/gl/GLLibraryEGL.h b/libazure/src/gfx/gl/GLLibraryEGL.h deleted file mode 100644 index 3cdf2d8..0000000 --- a/libazure/src/gfx/gl/GLLibraryEGL.h +++ /dev/null @@ -1,537 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLLIBRARYEGL_H_ -#define GLLIBRARYEGL_H_ - -#if defined(MOZ_X11) -#include "mozilla/X11Util.h" -#endif - -#include "GLContext.h" -#include "GLLibraryLoader.h" - -#include "nsIFile.h" - - -#if defined(XP_WIN) - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#include - -typedef HDC EGLNativeDisplayType; -typedef HBITMAP EGLNativePixmapType; -typedef HWND EGLNativeWindowType; - -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) - -#else -typedef void *EGLNativeDisplayType; -typedef void *EGLNativePixmapType; -typedef void *EGLNativeWindowType; - -#ifdef ANDROID -// We only need to explicitly dlopen egltrace -// on android as we can use LD_PRELOAD or other tricks -// on other platforms. We look for it in /data/local -// as that's writeable by all users -// -// This should really go in GLLibraryEGL.cpp but we currently reference -// APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring -// will come in subsequent patches on Bug 732865 -#define APITRACE_LIB "/data/local/egltrace.so" - -#ifdef MOZ_WIDGET_ANDROID - -#endif // MOZ_WIDGET_ANDROID -#endif // ANDROID -#endif - -#if defined(MOZ_X11) -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) -#else -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) -#endif - -namespace mozilla { -namespace gl { - -#ifdef DEBUG -#undef BEFORE_GL_CALL -#undef AFTER_GL_CALL - -#define BEFORE_GL_CALL do { \ - BeforeGLCall(MOZ_FUNCTION_NAME); \ -} while (0) - -#define AFTER_GL_CALL do { \ - AfterGLCall(MOZ_FUNCTION_NAME); \ -} while (0) -// We rely on the fact that GLLibraryEGL.h #defines BEFORE_GL_CALL and -// AFTER_GL_CALL to nothing if !defined(DEBUG). -#endif - -static inline void BeforeGLCall(const char* glFunction) -{ - if (GLContext::DebugMode()) { - if (GLContext::DebugMode() & GLContext::DebugTrace) - printf_stderr("[egl] > %s\n", glFunction); - } -} - -static inline void AfterGLCall(const char* glFunction) -{ - if (GLContext::DebugMode() & GLContext::DebugTrace) { - printf_stderr("[egl] < %s\n", glFunction); - } -} - -class GLLibraryEGL -{ -public: - GLLibraryEGL() - : mInitialized(false), - mEGLLibrary(nullptr), - mIsANGLE(false) - { - } - - void InitExtensions(); - - /** - * Known GL extensions that can be queried by - * IsExtensionSupported. The results of this are cached, and as - * such it's safe to use this even in performance critical code. - * If you add to this array, remember to add to the string names - * in GLContext.cpp. - */ - enum EGLExtensions { - KHR_image_base, - KHR_image_pixmap, - KHR_gl_texture_2D_image, - KHR_lock_surface, - ANGLE_surface_d3d_texture_2d_share_handle, - EXT_create_context_robustness, - KHR_image, - KHR_fence_sync, - Extensions_Max - }; - - bool IsExtensionSupported(EGLExtensions aKnownExtension) { - return mAvailableExtensions[aKnownExtension]; - } - - void MarkExtensionUnsupported(EGLExtensions aKnownExtension) { - mAvailableExtensions[aKnownExtension] = 0; - } - -protected: - GLContext::ExtensionBitset mAvailableExtensions; - -public: - - EGLDisplay fGetDisplay(void* display_id) - { - BEFORE_GL_CALL; - EGLDisplay disp = mSymbols.fGetDisplay(display_id); - AFTER_GL_CALL; - return disp; - } - - EGLSurface fGetCurrentSurface(EGLint id) - { - BEFORE_GL_CALL; - EGLSurface surf = mSymbols.fGetCurrentSurface(id); - AFTER_GL_CALL; - return surf; - } - - EGLContext fGetCurrentContext() - { - BEFORE_GL_CALL; - EGLContext context = mSymbols.fGetCurrentContext(); - AFTER_GL_CALL; - return context; - } - - EGLBoolean fMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fMakeCurrent(dpy, draw, read, ctx); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fDestroyContext(EGLDisplay dpy, EGLContext ctx) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fDestroyContext(dpy, ctx); - AFTER_GL_CALL; - return b; - } - - EGLContext fCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLContext ctx = mSymbols.fCreateContext(dpy, config, share_context, attrib_list); - AFTER_GL_CALL; - return ctx; - } - - EGLBoolean fDestroySurface(EGLDisplay dpy, EGLSurface surface) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fDestroySurface(dpy, surface); - AFTER_GL_CALL; - return b; - } - - EGLSurface fCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLSurface surf = mSymbols.fCreateWindowSurface(dpy, config, win, attrib_list); - AFTER_GL_CALL; - return surf; - } - - EGLSurface fCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLSurface surf = mSymbols.fCreatePbufferSurface(dpy, config, attrib_list); - AFTER_GL_CALL; - return surf; - } - - EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLSurface surf = mSymbols.fCreatePixmapSurface(dpy, config, pixmap, attrib_list); - AFTER_GL_CALL; - return surf; - } - - EGLBoolean fBindAPI(EGLenum api) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fBindAPI(api); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fInitialize(dpy, major, minor); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fChooseConfig(dpy, attrib_list, configs, config_size, num_config); - AFTER_GL_CALL; - return b; - } - - EGLint fGetError() - { - BEFORE_GL_CALL; - EGLint i = mSymbols.fGetError(); - AFTER_GL_CALL; - return i; - } - - EGLBoolean fGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fGetConfigAttrib(dpy, config, attribute, value); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fGetConfigs(dpy, configs, config_size, num_config); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fWaitNative(EGLint engine) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fWaitNative(engine); - AFTER_GL_CALL; - return b; - } - - EGLCastToRelevantPtr fGetProcAddress(const char *procname) - { - BEFORE_GL_CALL; - EGLCastToRelevantPtr p = mSymbols.fGetProcAddress(procname); - AFTER_GL_CALL; - return p; - } - - EGLBoolean fSwapBuffers(EGLDisplay dpy, EGLSurface surface) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fSwapBuffers(dpy, surface); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fCopyBuffers(dpy, surface, target); - AFTER_GL_CALL; - return b; - } - - const GLubyte* fQueryString(EGLDisplay dpy, EGLint name) - { - BEFORE_GL_CALL; - const GLubyte* b = mSymbols.fQueryString(dpy, name); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fQueryContext(dpy, ctx, attribute, value); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fBindTexImage(dpy, surface, buffer); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fReleaseTexImage(dpy, surface, buffer); - AFTER_GL_CALL; - return b; - } - - EGLImage fCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLImage i = mSymbols.fCreateImage(dpy, ctx, target, buffer, attrib_list); - AFTER_GL_CALL; - return i; - } - - EGLBoolean fDestroyImage(EGLDisplay dpy, EGLImage image) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fDestroyImage(dpy, image); - AFTER_GL_CALL; - return b; - } - - // New extension which allow us to lock texture and get raw image pointer - EGLBoolean fLockSurface(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fLockSurface(dpy, surface, attrib_list); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fUnlockSurface(EGLDisplay dpy, EGLSurface surface) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fUnlockSurface(dpy, surface); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fQuerySurface(dpy, surface, attribute, value); - AFTER_GL_CALL; - return b; - } - - EGLBoolean fQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fQuerySurfacePointerANGLE(dpy, surface, attribute, value); - AFTER_GL_CALL; - return b; - } - - EGLSync fCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) - { - BEFORE_GL_CALL; - EGLSync ret = mSymbols.fCreateSync(dpy, type, attrib_list); - AFTER_GL_CALL; - return ret; - } - - EGLBoolean fDestroySync(EGLDisplay dpy, EGLSync sync) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fDestroySync(dpy, sync); - AFTER_GL_CALL; - return b; - } - - EGLint fClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) - { - BEFORE_GL_CALL; - EGLint ret = mSymbols.fClientWaitSync(dpy, sync, flags, timeout); - AFTER_GL_CALL; - return ret; - } - - EGLBoolean fGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value) - { - BEFORE_GL_CALL; - EGLBoolean b = mSymbols.fGetSyncAttrib(dpy, sync, attribute, value); - AFTER_GL_CALL; - return b; - } - - - EGLDisplay Display() { - return mEGLDisplay; - } - - bool IsANGLE() { - return mIsANGLE; - } - - bool HasKHRImageBase() { - return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base); - } - - bool HasKHRImagePixmap() { - return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_pixmap); - } - - bool HasKHRImageTexture2D() { - return IsExtensionSupported(KHR_gl_texture_2D_image); - } - - bool HasKHRLockSurface() { - return IsExtensionSupported(KHR_lock_surface); - } - - bool HasANGLESurfaceD3DTexture2DShareHandle() { - return IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle); - } - - bool HasRobustness() { - return IsExtensionSupported(EXT_create_context_robustness); - } - - bool EnsureInitialized(); - - void DumpEGLConfig(EGLConfig cfg); - void DumpEGLConfigs(); - - struct { - typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id); - pfnGetDisplay fGetDisplay; - typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint); - pfnGetCurrentSurface fGetCurrentSurface; - typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void); - pfnGetCurrentContext fGetCurrentContext; - typedef EGLBoolean (GLAPIENTRY * pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); - pfnMakeCurrent fMakeCurrent; - typedef EGLBoolean (GLAPIENTRY * pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx); - pfnDestroyContext fDestroyContext; - typedef EGLContext (GLAPIENTRY * pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); - pfnCreateContext fCreateContext; - typedef EGLBoolean (GLAPIENTRY * pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface); - pfnDestroySurface fDestroySurface; - typedef EGLSurface (GLAPIENTRY * pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); - pfnCreateWindowSurface fCreateWindowSurface; - typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); - pfnCreatePbufferSurface fCreatePbufferSurface; - typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); - pfnCreatePixmapSurface fCreatePixmapSurface; - typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api); - pfnBindAPI fBindAPI; - typedef EGLBoolean (GLAPIENTRY * pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); - pfnInitialize fInitialize; - typedef EGLBoolean (GLAPIENTRY * pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); - pfnChooseConfig fChooseConfig; - typedef EGLint (GLAPIENTRY * pfnGetError)(void); - pfnGetError fGetError; - typedef EGLBoolean (GLAPIENTRY * pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); - pfnGetConfigAttrib fGetConfigAttrib; - typedef EGLBoolean (GLAPIENTRY * pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); - pfnGetConfigs fGetConfigs; - typedef EGLBoolean (GLAPIENTRY * pfnWaitNative)(EGLint engine); - pfnWaitNative fWaitNative; - typedef EGLCastToRelevantPtr (GLAPIENTRY * pfnGetProcAddress)(const char *procname); - pfnGetProcAddress fGetProcAddress; - typedef EGLBoolean (GLAPIENTRY * pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface); - pfnSwapBuffers fSwapBuffers; - typedef EGLBoolean (GLAPIENTRY * pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface, - EGLNativePixmapType target); - pfnCopyBuffers fCopyBuffers; - typedef const GLubyte* (GLAPIENTRY * pfnQueryString)(EGLDisplay, EGLint name); - pfnQueryString fQueryString; - typedef EGLBoolean (GLAPIENTRY * pfnQueryContext)(EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value); - pfnQueryContext fQueryContext; - typedef EGLBoolean (GLAPIENTRY * pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer); - pfnBindTexImage fBindTexImage; - typedef EGLBoolean (GLAPIENTRY * pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer); - pfnReleaseTexImage fReleaseTexImage; - typedef EGLImage (GLAPIENTRY * pfnCreateImage)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); - pfnCreateImage fCreateImage; - typedef EGLBoolean (GLAPIENTRY * pfnDestroyImage)(EGLDisplay dpy, EGLImage image); - pfnDestroyImage fDestroyImage; - - // New extension which allow us to lock texture and get raw image pointer - typedef EGLBoolean (GLAPIENTRY * pfnLockSurface)(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list); - pfnLockSurface fLockSurface; - typedef EGLBoolean (GLAPIENTRY * pfnUnlockSurface)(EGLDisplay dpy, EGLSurface surface); - pfnUnlockSurface fUnlockSurface; - typedef EGLBoolean (GLAPIENTRY * pfnQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); - pfnQuerySurface fQuerySurface; - - typedef EGLBoolean (GLAPIENTRY * pfnQuerySurfacePointerANGLE)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); - pfnQuerySurfacePointerANGLE fQuerySurfacePointerANGLE; - - typedef EGLSync (GLAPIENTRY * pfnCreateSync)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); - pfnCreateSync fCreateSync; - typedef EGLBoolean (GLAPIENTRY * pfnDestroySync)(EGLDisplay dpy, EGLSync sync); - pfnDestroySync fDestroySync; - typedef EGLint (GLAPIENTRY * pfnClientWaitSync)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); - pfnClientWaitSync fClientWaitSync; - typedef EGLBoolean (GLAPIENTRY * pfnGetSyncAttrib)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value); - pfnGetSyncAttrib fGetSyncAttrib; - } mSymbols; - -private: - bool mInitialized; - PRLibrary* mEGLLibrary; - EGLDisplay mEGLDisplay; - - bool mIsANGLE; -}; - -} /* namespace gl */ -} /* namespace mozilla */ - -#endif /* GLLIBRARYEGL_H_ */ - diff --git a/libazure/src/gfx/gl/GLLibraryLoader.cpp b/libazure/src/gfx/gl/GLLibraryLoader.cpp deleted file mode 100644 index a66bd37..0000000 --- a/libazure/src/gfx/gl/GLLibraryLoader.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLLibraryLoader.h" - -#include "nsDebug.h" - -namespace mozilla { -namespace gl { - -bool -GLLibraryLoader::OpenLibrary(const char *library) -{ - PRLibSpec lspec; - lspec.type = PR_LibSpec_Pathname; - lspec.value.pathname = library; - - mLibrary = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL); - if (!mLibrary) - return false; - - return true; -} - -bool -GLLibraryLoader::LoadSymbols(SymLoadStruct *firstStruct, - bool tryplatform, - const char *prefix, - bool warnOnFailure) -{ - return LoadSymbols(mLibrary, - firstStruct, - tryplatform ? mLookupFunc : nullptr, - prefix, - warnOnFailure); -} - -PRFuncPtr -GLLibraryLoader::LookupSymbol(PRLibrary *lib, - const char *sym, - PlatformLookupFunction lookupFunction) -{ - PRFuncPtr res = 0; - - // try finding it in the library directly, if we have one - if (lib) { - res = PR_FindFunctionSymbol(lib, sym); - } - - // then try looking it up via the lookup symbol - if (!res && lookupFunction) { - res = lookupFunction(sym); - } - - // finally just try finding it in the process - if (!res) { - PRLibrary *leakedLibRef; - res = PR_FindFunctionSymbolAndLibrary(sym, &leakedLibRef); - } - - return res; -} - -bool -GLLibraryLoader::LoadSymbols(PRLibrary *lib, - SymLoadStruct *firstStruct, - PlatformLookupFunction lookupFunction, - const char *prefix, - bool warnOnFailure) -{ - char sbuf[MAX_SYMBOL_LENGTH * 2]; - int failCount = 0; - - SymLoadStruct *ss = firstStruct; - while (ss->symPointer) { - *ss->symPointer = 0; - - for (int i = 0; i < MAX_SYMBOL_NAMES; i++) { - if (ss->symNames[i] == nullptr) - break; - - const char *s = ss->symNames[i]; - if (prefix && *prefix != 0) { - strcpy(sbuf, prefix); - strcat(sbuf, ss->symNames[i]); - s = sbuf; - } - - PRFuncPtr p = LookupSymbol(lib, s, lookupFunction); - if (p) { - *ss->symPointer = p; - break; - } - } - - if (*ss->symPointer == 0) { - if (warnOnFailure) - printf_stderr("Can't find symbol '%s'.\n", ss->symNames[0]); - - failCount++; - } - - ss++; - } - - return failCount == 0 ? true : false; -} - -} /* namespace gl */ -} /* namespace mozilla */ - diff --git a/libazure/src/gfx/gl/GLLibraryLoader.h b/libazure/src/gfx/gl/GLLibraryLoader.h deleted file mode 100644 index 5991200..0000000 --- a/libazure/src/gfx/gl/GLLibraryLoader.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLLIBRARYLOADER_H_ -#define GLLIBRARYLOADER_H_ - -#include - -#ifdef WIN32 -#include -#endif - -#include "GLDefs.h" -#include "mozilla/Util.h" -#include "nscore.h" -#include "prlink.h" - -namespace mozilla { -namespace gl { - -class GLLibraryLoader -{ -public: - bool OpenLibrary(const char *library); - - typedef PRFuncPtr (GLAPIENTRY * PlatformLookupFunction) (const char *); - - enum { - MAX_SYMBOL_NAMES = 5, - MAX_SYMBOL_LENGTH = 128 - }; - - typedef struct { - PRFuncPtr *symPointer; - const char *symNames[MAX_SYMBOL_NAMES]; - } SymLoadStruct; - - bool LoadSymbols(SymLoadStruct *firstStruct, - bool tryplatform = false, - const char *prefix = nullptr, - bool warnOnFailure = true); - - /* - * Static version of the functions in this class - */ - static PRFuncPtr LookupSymbol(PRLibrary *lib, - const char *symname, - PlatformLookupFunction lookupFunction = nullptr); - static bool LoadSymbols(PRLibrary *lib, - SymLoadStruct *firstStruct, - PlatformLookupFunction lookupFunction = nullptr, - const char *prefix = nullptr, - bool warnOnFailure = true); -protected: - GLLibraryLoader() { - mLibrary = nullptr; - mLookupFunc = nullptr; - } - - PRLibrary *mLibrary; - PlatformLookupFunction mLookupFunc; -}; - -} /* namespace gl */ -} /* namespace mozilla */ - -#endif /* GLLIBRARYLOADER_H_ */ diff --git a/libazure/src/gfx/gl/GLScreenBuffer.cpp b/libazure/src/gfx/gl/GLScreenBuffer.cpp deleted file mode 100644 index aa6247e..0000000 --- a/libazure/src/gfx/gl/GLScreenBuffer.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLScreenBuffer.h" - -#include -#include "gfxImageSurface.h" -#include "GLContext.h" -#include "SharedSurfaceGL.h" -#include "SurfaceStream.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -GLScreenBuffer* -GLScreenBuffer::Create(GLContext* gl, - const gfxIntSize& size, - const SurfaceCaps& caps) -{ - if (caps.antialias && - !gl->SupportsFramebufferMultisample()) - { - return nullptr; - } - - SurfaceFactory_GL* factory = new SurfaceFactory_Basic(gl, caps); - SurfaceStream* stream = SurfaceStream::CreateForType( - SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, - caps.preserve), - nullptr); - - return new GLScreenBuffer(gl, caps, factory, stream); -} - -GLScreenBuffer::~GLScreenBuffer() -{ - delete mFactory; - delete mStream; - delete mDraw; - delete mRead; -} - - -void -GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const -{ - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - if (!gl->HasExt_FramebufferBlit()) { - MOZ_ASSERT(drawFB == readFB); - gl->raw_fBindFramebuffer(target, readFB); - return; - } - - switch (target) { - case LOCAL_GL_FRAMEBUFFER: - gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); - gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); - break; - - case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: - if (!gl->HasExt_FramebufferBlit()) - NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable."); - - gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); - break; - - case LOCAL_GL_READ_FRAMEBUFFER_EXT: - if (!gl->HasExt_FramebufferBlit()) - NS_WARNING("READ_FRAMEBUFFER requested but unavailable."); - - gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); - break; - - default: - // In case we got a bad target. - MOZ_NOT_REACHED("Bad `target` for BindFramebuffer."); - gl->raw_fBindFramebuffer(target, 0); - break; - } -} - -void -GLScreenBuffer::BindFB(GLuint fb) -{ - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - mUserDrawFB = fb; - mUserReadFB = fb; - mInternalDrawFB = (fb == 0) ? drawFB : fb; - mInternalReadFB = (fb == 0) ? readFB : fb; - - if (mInternalDrawFB == mInternalReadFB) { - mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB); - } else { - MOZ_ASSERT(mGL->SupportsSplitFramebuffer()); - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - } - -#ifdef DEBUG - mInInternalMode_DrawFB = false; - mInInternalMode_ReadFB = false; -#endif -} - -void -GLScreenBuffer::BindDrawFB(GLuint fb) -{ - if (!mGL->SupportsSplitFramebuffer()) { - NS_WARNING("DRAW_FRAMEBUFFER requested, but unsupported."); - - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); - } else { - GLuint drawFB = DrawFB(); - mUserDrawFB = fb; - mInternalDrawFB = (fb == 0) ? drawFB : fb; - - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - } - -#ifdef DEBUG - mInInternalMode_DrawFB = false; -#endif -} - -void -GLScreenBuffer::BindReadFB(GLuint fb) -{ - if (!mGL->SupportsSplitFramebuffer()) { - NS_WARNING("READ_FRAMEBUFFER requested, but unsupported."); - - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); - } else { - GLuint readFB = ReadFB(); - mUserReadFB = fb; - mInternalReadFB = (fb == 0) ? readFB : fb; - - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - } - -#ifdef DEBUG - mInInternalMode_ReadFB = false; -#endif -} - -void -GLScreenBuffer::BindDrawFB_Internal(GLuint fb) -{ - mInternalDrawFB = mUserDrawFB = fb; - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - -#ifdef DEBUG - mInInternalMode_DrawFB = true; -#endif -} - -void -GLScreenBuffer::BindReadFB_Internal(GLuint fb) -{ - mInternalReadFB = mUserReadFB = fb; - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - -#ifdef DEBUG - mInInternalMode_ReadFB = true; -#endif -} - - -GLuint -GLScreenBuffer::GetDrawFB() const -{ -#ifdef DEBUG - MOZ_ASSERT(mGL->IsCurrent()); - MOZ_ASSERT(!mInInternalMode_DrawFB); - - // Don't need a branch here, because: - // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6 - // We use raw_ here because this is debug code and we need to see what - // the driver thinks. - GLuint actual = 0; - mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); - - GLuint predicted = mInternalDrawFB; - if (predicted != actual) { - printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n", - predicted, actual); - MOZ_ASSERT(false, "Draw FB binding misprediction!"); - } -#endif - - return mUserDrawFB; -} - -GLuint -GLScreenBuffer::GetReadFB() const -{ -#ifdef DEBUG - MOZ_ASSERT(mGL->IsCurrent()); - MOZ_ASSERT(!mInInternalMode_ReadFB); - - // We use raw_ here because this is debug code and we need to see what - // the driver thinks. - GLuint actual = 0; - if (mGL->SupportsSplitFramebuffer()) - mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); - else - mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual); - - GLuint predicted = mInternalReadFB; - if (predicted != actual) { - printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n", - predicted, actual); - MOZ_ASSERT(false, "Read FB binding misprediction!"); - } -#endif - - return mUserReadFB; -} - -GLuint -GLScreenBuffer::GetFB() const -{ - MOZ_ASSERT(GetDrawFB() == GetReadFB()); - return GetDrawFB(); -} - - -void -GLScreenBuffer::DeletingFB(GLuint fb) -{ - if (fb == mInternalDrawFB) { - mInternalDrawFB = 0; - mUserDrawFB = 0; - } - if (fb == mInternalReadFB) { - mInternalReadFB = 0; - mUserReadFB = 0; - } -} - - -void -GLScreenBuffer::AfterDrawCall() -{ - if (mUserDrawFB != 0) - return; - - RequireBlit(); -} - -void -GLScreenBuffer::BeforeReadCall() -{ - if (mUserReadFB != 0) - return; - - AssureBlitted(); -} - -void -GLScreenBuffer::RequireBlit() -{ - mNeedsBlit = true; -} - -void -GLScreenBuffer::AssureBlitted() -{ - if (!mNeedsBlit) - return; - - if (mDraw) { - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - MOZ_ASSERT(drawFB != 0); - MOZ_ASSERT(drawFB != readFB); - MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::EXT_framebuffer_blit) || - mGL->IsExtensionSupported(GLContext::ANGLE_framebuffer_blit)); - MOZ_ASSERT(mDraw->Size() == mRead->Size()); - - ScopedBindFramebuffer boundFB(mGL); - ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); - - BindReadFB_Internal(drawFB); - BindDrawFB_Internal(readFB); - - const gfxIntSize& srcSize = mDraw->Size(); - const gfxIntSize& destSize = mRead->Size(); - - mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, - 0, 0, destSize.width, destSize.height, - LOCAL_GL_COLOR_BUFFER_BIT, - LOCAL_GL_NEAREST); - // Done! - } - - mNeedsBlit = false; -} - -void -GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType) -{ - MOZ_ASSERT(mStream); - - if (newFactory) { - delete mFactory; - mFactory = newFactory; - } - - if (mStream->mType == streamType) - return; - - SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mStream); - MOZ_ASSERT(newStream); - - delete mStream; - mStream = newStream; -} - -void -GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) -{ - ScopedBindFramebuffer autoFB(mGL); - - SharedSurface_GL* surf = SharedSurface_GL::Cast(surface); - if (mRead && SharedSurf()) - SharedSurf()->UnlockProd(); - - surf->LockProd(); - - if (mRead && - surf->AttachType() == SharedSurf()->AttachType() && - size == Size()) - { - // Same size, same type, ready for reuse! - mRead->Attach(surf); - } else { - // Else something changed, so resize: - DrawBuffer* draw = CreateDraw(size); // Can be null. - ReadBuffer* read = CreateRead(surf); - MOZ_ASSERT(read); // Should never fail if SwapProd succeeded. - - delete mDraw; - delete mRead; - - mDraw = draw; - mRead = read; - } - - // Check that we're all set up. - MOZ_ASSERT(SharedSurf() == surf); - - if (!PreserveBuffer()) { - // DiscardFramebuffer here could help perf on some mobile platforms. - } -} - -bool -GLScreenBuffer::Swap(const gfxIntSize& size) -{ - SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size); - if (!nextSurf) { - SurfaceFactory_GL* basicFactory = - new SurfaceFactory_Basic(mGL, mFactory->Caps()); - nextSurf = mStream->SwapProducer(basicFactory, size); - if (!nextSurf) { - delete basicFactory; - return false; - } - - // Swap out the apparently defective old factory. - delete mFactory; - mFactory = basicFactory; - } - - Attach(nextSurf, size); - - return true; -} - -bool -GLScreenBuffer::PublishFrame(const gfxIntSize& size) -{ - AssureBlitted(); - - bool good = Swap(size); - return good; -} - -bool -GLScreenBuffer::Resize(const gfxIntSize& size) -{ - SharedSurface* surface = mStream->Resize(mFactory, size); - if (!surface) - return false; - - Attach(surface, size); - return true; -} - -DrawBuffer* -GLScreenBuffer::CreateDraw(const gfxIntSize& size) -{ - GLContext* gl = mFactory->GL(); - const GLFormats& formats = mFactory->Formats(); - const SurfaceCaps& caps = mFactory->DrawCaps(); - - return DrawBuffer::Create(gl, caps, formats, size); -} - -ReadBuffer* -GLScreenBuffer::CreateRead(SharedSurface_GL* surf) -{ - GLContext* gl = mFactory->GL(); - const GLFormats& formats = mFactory->Formats(); - const SurfaceCaps& caps = mFactory->ReadCaps(); - - return ReadBuffer::Create(gl, caps, formats, surf); -} - - -void -GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) -{ - MOZ_ASSERT(src && dest); - MOZ_ASSERT(dest->GetSize() == src->Size()); - MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageSurface::ImageFormatARGB32 - : gfxImageSurface::ImageFormatRGB24)); - - mGL->MakeCurrent(); - - bool needsSwap = src != SharedSurf(); - if (needsSwap) { - SharedSurf()->UnlockProd(); - src->LockProd(); - } - - ReadBuffer* buffer = CreateRead(src); - MOZ_ASSERT(buffer); - - ScopedBindFramebuffer autoFB(mGL, buffer->FB()); - mGL->ReadPixelsIntoImageSurface(dest); - - delete buffer; - - if (needsSwap) { - src->UnlockProd(); - SharedSurf()->LockProd(); - } -} - - - -DrawBuffer* -DrawBuffer::Create(GLContext* const gl, - const SurfaceCaps& caps, - const GLFormats& formats, - const gfxIntSize& size) -{ - if (!caps.color) { - MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil); - - // Nothing is needed. - return nullptr; - } - - GLuint colorMSRB = 0; - GLuint depthRB = 0; - GLuint stencilRB = 0; - - GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr; - GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; - GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; - - if (!formats.color_rbFormat) - pColorMSRB = nullptr; - - if (pDepthRB && pStencilRB) { - if (!formats.depth && !formats.depthStencil) - pDepthRB = nullptr; - - if (!formats.stencil && !formats.depthStencil) - pStencilRB = nullptr; - } else { - if (!formats.depth) - pDepthRB = nullptr; - - if (!formats.stencil) - pStencilRB = nullptr; - } - - gl->CreateRenderbuffersForOffscreen(formats, size, caps.antialias, - pColorMSRB, pDepthRB, pStencilRB); - - GLuint fb = 0; - gl->fGenFramebuffers(1, &fb); - gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb); - MOZ_ASSERT(gl->IsFramebufferComplete(fb)); - - return new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB); -} - -DrawBuffer::~DrawBuffer() -{ - mGL->MakeCurrent(); - - GLuint fb = mFB; - GLuint rbs[] = { - mColorMSRB, - mDepthRB, - mStencilRB - }; - - mGL->fDeleteFramebuffers(1, &fb); - mGL->fDeleteRenderbuffers(3, rbs); -} - - - - - - -ReadBuffer* -ReadBuffer::Create(GLContext* gl, - const SurfaceCaps& caps, - const GLFormats& formats, - SharedSurface_GL* surf) -{ - MOZ_ASSERT(surf); - - if (surf->AttachType() == AttachmentType::Screen) { - // Don't need anything. Our read buffer will be the 'screen'. - - return new ReadBuffer(gl, - 0, 0, 0, - surf); - } - - GLuint depthRB = 0; - GLuint stencilRB = 0; - - GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; - GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; - - gl->CreateRenderbuffersForOffscreen(formats, surf->Size(), caps.antialias, - nullptr, pDepthRB, pStencilRB); - - GLuint colorTex = 0; - GLuint colorRB = 0; - - switch (surf->AttachType()) { - case AttachmentType::GLTexture: - colorTex = surf->Texture(); - break; - case AttachmentType::GLRenderbuffer: - colorRB = surf->Renderbuffer(); - break; - default: - MOZ_NOT_REACHED("Unknown attachment type?"); - return nullptr; - } - MOZ_ASSERT(colorTex || colorRB); - - GLuint fb = 0; - gl->fGenFramebuffers(1, &fb); - gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb); - - MOZ_ASSERT(gl->IsFramebufferComplete(fb)); - - return new ReadBuffer(gl, - fb, depthRB, stencilRB, - surf); -} - -ReadBuffer::~ReadBuffer() -{ - mGL->MakeCurrent(); - - GLuint fb = mFB; - GLuint rbs[] = { - mDepthRB, - mStencilRB - }; - - mGL->fDeleteFramebuffers(1, &fb); - mGL->fDeleteRenderbuffers(2, rbs); -} - -void -ReadBuffer::Attach(SharedSurface_GL* surf) -{ - MOZ_ASSERT(surf && mSurf); - MOZ_ASSERT(surf->AttachType() == mSurf->AttachType()); - MOZ_ASSERT(surf->Size() == mSurf->Size()); - - // Nothing else is needed for AttachType Screen. - if (surf->AttachType() != AttachmentType::Screen) { - GLuint colorTex = 0; - GLuint colorRB = 0; - - switch (surf->AttachType()) { - case AttachmentType::GLTexture: - colorTex = surf->Texture(); - break; - case AttachmentType::GLRenderbuffer: - colorRB = surf->Renderbuffer(); - break; - default: - MOZ_NOT_REACHED("Unknown attachment type?"); - return; - } - - mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB); - MOZ_ASSERT(mGL->IsFramebufferComplete(mFB)); - } - - mSurf = surf; -} - -const gfxIntSize& -ReadBuffer::Size() const -{ - return mSurf->Size(); -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/GLScreenBuffer.h b/libazure/src/gfx/gl/GLScreenBuffer.h deleted file mode 100644 index 0fd6f27..0000000 --- a/libazure/src/gfx/gl/GLScreenBuffer.h +++ /dev/null @@ -1,300 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* GLScreenBuffer is the abstraction for the "default framebuffer" used - * by an offscreen GLContext. Since it's only for offscreen GLContext's, - * it's only useful for things like WebGL, and is NOT used by the - * compositor's GLContext. Remember that GLContext provides an abstraction - * so that even if you want to draw to the 'screen', even if that's not - * actually the screen, just draw to 0. This GLScreenBuffer class takes the - * logic handling out of GLContext. -*/ - -#ifndef SCREEN_BUFFER_H_ -#define SCREEN_BUFFER_H_ - -#include "SurfaceTypes.h" -#include "GLContextTypes.h" -#include "GLDefs.h" -#include "gfxPoint.h" - -// Forwards: -class gfxImageSurface; - -namespace mozilla { - namespace gfx { - class SurfaceStream; - class SharedSurface; - } - namespace gl { - class GLContext; - class SharedSurface_GL; - class SurfaceFactory_GL; - } -} - -namespace mozilla { -namespace gl { - -class DrawBuffer -{ -protected: - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible, may return null if unneeded. - static DrawBuffer* Create(GLContext* const gl, - const SurfaceCaps& caps, - const GLFormats& formats, - const gfxIntSize& size); - -protected: - GLContext* const mGL; - const gfxIntSize mSize; - const GLuint mFB; - const GLuint mColorMSRB; - const GLuint mDepthRB; - const GLuint mStencilRB; - - DrawBuffer(GLContext* gl, - const gfxIntSize& size, - GLuint fb, - GLuint colorMSRB, - GLuint depthRB, - GLuint stencilRB) - : mGL(gl) - , mSize(size) - , mFB(fb) - , mColorMSRB(colorMSRB) - , mDepthRB(depthRB) - , mStencilRB(stencilRB) - {} - -public: - virtual ~DrawBuffer(); - - const gfxIntSize& Size() const { - return mSize; - } - - GLuint FB() const { - return mFB; - } -}; - -class ReadBuffer -{ -protected: - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible, always non-null. - static ReadBuffer* Create(GLContext* gl, - const SurfaceCaps& caps, - const GLFormats& formats, - SharedSurface_GL* surf); - -protected: - GLContext* const mGL; - - const GLuint mFB; - // mFB has the following attachments: - const GLuint mDepthRB; - const GLuint mStencilRB; - // note no mColorRB here: this is provided by mSurf. - SharedSurface_GL* mSurf; // Owned by GLScreenBuffer's SurfaceStream. - - ReadBuffer(GLContext* gl, - GLuint fb, - GLuint depthRB, - GLuint stencilRB, - SharedSurface_GL* surf) - : mGL(gl) - , mFB(fb) - , mDepthRB(depthRB) - , mStencilRB(stencilRB) - , mSurf(surf) - {} - -public: - virtual ~ReadBuffer(); - - // Cannot attach a surf of a different AttachType or Size than before. - void Attach(SharedSurface_GL* surf); - - const gfxIntSize& Size() const; - - GLuint FB() const { - return mFB; - } - - SharedSurface_GL* SharedSurf() const { - return mSurf; - } -}; - - -class GLScreenBuffer -{ -protected: - typedef class gfx::SurfaceStream SurfaceStream; - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SurfaceStreamType SurfaceStreamType; - typedef gfx::SharedSurfaceType SharedSurfaceType; - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible. - static GLScreenBuffer* Create(GLContext* gl, - const gfxIntSize& size, - const SurfaceCaps& caps); - -protected: - GLContext* const mGL; // Owns us. - SurfaceCaps mCaps; - SurfaceFactory_GL* mFactory; // Owned by us. - SurfaceStream* mStream; // Owned by us. - - DrawBuffer* mDraw; // Owned by us. - ReadBuffer* mRead; // Owned by us. - - bool mNeedsBlit; - - // Below are the parts that help us pretend to be framebuffer 0: - GLuint mUserDrawFB; - GLuint mUserReadFB; - GLuint mInternalDrawFB; - GLuint mInternalReadFB; - -#ifdef DEBUG - bool mInInternalMode_DrawFB; - bool mInInternalMode_ReadFB; -#endif - - GLScreenBuffer(GLContext* gl, - const SurfaceCaps& caps, - SurfaceFactory_GL* factory, - SurfaceStream* stream) - : mGL(gl) - , mCaps(caps) - , mFactory(factory) - , mStream(stream) - , mDraw(nullptr) - , mRead(nullptr) - , mNeedsBlit(true) - , mUserDrawFB(0) - , mUserReadFB(0) - , mInternalDrawFB(0) - , mInternalReadFB(0) -#ifdef DEBUG - , mInInternalMode_DrawFB(true) - , mInInternalMode_ReadFB(true) -#endif - {} - -public: - virtual ~GLScreenBuffer(); - - SurfaceStream* Stream() const { - return mStream; - } - - SurfaceFactory_GL* Factory() const { - return mFactory; - } - - SharedSurface_GL* SharedSurf() const { - MOZ_ASSERT(mRead); - return mRead->SharedSurf(); - } - - bool PreserveBuffer() const { - return mCaps.preserve; - } - - const SurfaceCaps& Caps() const { - return mCaps; - } - - GLuint DrawFB() const { - if (!mDraw) - return ReadFB(); - - return mDraw->FB(); - } - - GLuint ReadFB() const { - return mRead->FB(); - } - - void DeletingFB(GLuint fb); - - const gfxIntSize& Size() const { - MOZ_ASSERT(mRead); - MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); - return mRead->Size(); - } - - void BindAsFramebuffer(GLContext* const gl, GLenum target) const; - - void RequireBlit(); - void AssureBlitted(); - void AfterDrawCall(); - void BeforeReadCall(); - - /* Morph swaps out our SurfaceStream mechanism and replaces it with - * one best suited to our platform and compositor configuration. - * - * Must be called on the producing thread. - * We haven't made any guarantee that rendering is actually - * done when Morph is run, just that it can't run concurrently - * with rendering. This means that we can't just drop the contents - * of the buffer, since we may only be partially done rendering. - * - * Once you pass newFactory into Morph, newFactory will be owned by - * GLScreenBuffer, so `forget` any references to it that still exist. - */ - void Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType); - -protected: - // Returns false on error or inability to resize. - bool Swap(const gfxIntSize& size); - -public: - bool PublishFrame(const gfxIntSize& size); - - bool Resize(const gfxIntSize& size); - - void Readback(SharedSurface_GL* src, gfxImageSurface* dest); - -protected: - void Attach(SharedSurface* surface, const gfxIntSize& size); - - DrawBuffer* CreateDraw(const gfxIntSize& size); - ReadBuffer* CreateRead(SharedSurface_GL* surf); - -public: - /* `fb` in these functions is the framebuffer the GLContext is hoping to - * bind. When this is 0, we intercept the call and bind our own - * framebuffers. As a client of these functions, just bind 0 when you want - * to draw to the default framebuffer/'screen'. - */ - void BindFB(GLuint fb); - void BindDrawFB(GLuint fb); - void BindReadFB(GLuint fb); - GLuint GetFB() const; - GLuint GetDrawFB() const; - GLuint GetReadFB() const; - - // Here `fb` is the actual framebuffer you want bound. Binding 0 will - // bind the (generally useless) default framebuffer. - void BindDrawFB_Internal(GLuint fb); - void BindReadFB_Internal(GLuint fb); -}; - -} // namespace gl -} // namespace mozilla - -#endif // SCREEN_BUFFER_H_ diff --git a/libazure/src/gfx/gl/GLTextureImage.cpp b/libazure/src/gfx/gl/GLTextureImage.cpp deleted file mode 100644 index f622d55..0000000 --- a/libazure/src/gfx/gl/GLTextureImage.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLTextureImage.h" -#include "GLContext.h" -#include "gfxContext.h" -#include "gfxPlatform.h" -#include "gfxUtils.h" - -using namespace mozilla::gl; - -already_AddRefed -TextureImage::Create(GLContext* gl, - const nsIntSize& size, - TextureImage::ContentType contentType, - GLenum wrapMode, - TextureImage::Flags flags) -{ - return gl->CreateTextureImage(size, contentType, wrapMode, flags); -} - -BasicTextureImage::~BasicTextureImage() -{ - GLContext *ctx = mGLContext; - if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) { - ctx = ctx->GetSharedContext(); - } - - // If we have a context, then we need to delete the texture; - // if we don't have a context (either real or shared), - // then they went away when the contex was deleted, because it - // was the only one that had access to it. - if (ctx && !ctx->IsDestroyed()) { - mGLContext->MakeCurrent(); - mGLContext->fDeleteTextures(1, &mTexture); - } -} - -gfxASurface* -BasicTextureImage::BeginUpdate(nsIntRegion& aRegion) -{ - NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?"); - - // determine the region the client will need to repaint - if (mGLContext->CanUploadSubTextures()) { - GetUpdateRegion(aRegion); - } else { - aRegion = nsIntRect(nsIntPoint(0, 0), mSize); - } - - mUpdateRegion = aRegion; - - nsIntRect rgnSize = mUpdateRegion.GetBounds(); - if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) { - NS_ERROR("update outside of image"); - return NULL; - } - - ImageFormat format = - (GetContentType() == gfxASurface::CONTENT_COLOR) ? - gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; - mUpdateSurface = - GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format); - - if (!mUpdateSurface || mUpdateSurface->CairoStatus()) { - mUpdateSurface = NULL; - return NULL; - } - - mUpdateSurface->SetDeviceOffset(gfxPoint(-rgnSize.x, -rgnSize.y)); - - return mUpdateSurface; -} - -void -BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion) -{ - // if the texture hasn't been initialized yet, or something important - // changed, we need to recreate our backing surface and force the - // client to paint everything - if (mTextureState != Valid) - aForRegion = nsIntRect(nsIntPoint(0, 0), mSize); -} - -void -BasicTextureImage::EndUpdate() -{ - NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?"); - - // FIXME: this is the slow boat. Make me fast (with GLXPixmap?). - - // Undo the device offset that BeginUpdate set; doesn't much matter for us here, - // but important if we ever do anything directly with the surface. - mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0)); - - bool relative = FinishedSurfaceUpdate(); - - mShaderType = - mGLContext->UploadSurfaceToTexture(mUpdateSurface, - mUpdateRegion, - mTexture, - mTextureState == Created, - mUpdateOffset, - relative); - FinishedSurfaceUpload(); - - mUpdateSurface = nullptr; - mTextureState = Valid; -} - -void -BasicTextureImage::BindTexture(GLenum aTextureUnit) -{ - mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); -} - -void -BasicTextureImage::ApplyFilter() -{ - mGLContext->ApplyFilterToBoundTexture(mFilter); -} - - -already_AddRefed -BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt) -{ - return gfxPlatform::GetPlatform()-> - CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt)); -} - -bool -BasicTextureImage::FinishedSurfaceUpdate() -{ - return false; -} - -void -BasicTextureImage::FinishedSurfaceUpload() -{ -} - -bool -BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) -{ - nsIntRect bounds = aRegion.GetBounds(); - nsIntRegion region; - if (mTextureState != Valid) { - bounds = nsIntRect(0, 0, mSize.width, mSize.height); - region = nsIntRegion(bounds); - } else { - region = aRegion; - } - - mShaderType = - mGLContext->UploadSurfaceToTexture(aSurf, - region, - mTexture, - mTextureState == Created, - bounds.TopLeft() + aFrom, - false); - mTextureState = Valid; - return true; -} - -void -BasicTextureImage::Resize(const nsIntSize& aSize) -{ - NS_ASSERTION(!mUpdateSurface, "Resize() while in update?"); - - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); - - mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - aSize.width, - aSize.height, - 0, - LOCAL_GL_RGBA, - LOCAL_GL_UNSIGNED_BYTE, - NULL); - - mTextureState = Allocated; - mSize = aSize; -} - -TiledTextureImage::TiledTextureImage(GLContext* aGL, - nsIntSize aSize, - TextureImage::ContentType aContentType, - TextureImage::Flags aFlags) - : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags) - , mCurrentImage(0) - , mIterationCallback(nullptr) - , mInUpdate(false) - , mRows(0) - , mColumns(0) - , mGL(aGL) - , mTextureState(Created) -{ - if (!(aFlags & TextureImage::ForceSingleTile) && mGL->WantsSmallTiles()) { - mTileSize = 256; - } else { - mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize); - } - if (aSize.width != 0 && aSize.height != 0) { - Resize(aSize); - } -} - -TiledTextureImage::~TiledTextureImage() -{ -} - -bool -TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) -{ - if (mSize.width == 0 || mSize.height == 0) { - return true; - } - - nsIntRegion region; - - if (mTextureState != Valid) { - nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height); - region = nsIntRegion(bounds); - } else { - region = aRegion; - } - - bool result = true; - int oldCurrentImage = mCurrentImage; - BeginTileIteration(); - do { - nsIntRect tileRect = GetSrcTileRect(); - int xPos = tileRect.x; - int yPos = tileRect.y; - - nsIntRegion tileRegion; - tileRegion.And(region, tileRect); // intersect with tile - - if (tileRegion.IsEmpty()) - continue; - - if (mGL->CanUploadSubTextures()) { - tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space - } else { - // If sub-textures are unsupported, expand to tile boundaries - tileRect.x = tileRect.y = 0; - tileRegion = nsIntRegion(tileRect); - } - - result &= mImages[mCurrentImage]-> - DirectUpdate(aSurf, tileRegion, aFrom + nsIntPoint(xPos, yPos)); - - if (mCurrentImage == mImages.Length() - 1) { - // We know we're done, but we still need to ensure that the callback - // gets called (e.g. to update the uploaded region). - NextTile(); - break; - } - // Override a callback cancelling iteration if the texture wasn't valid. - // We need to force the update in that situation, or we may end up - // showing invalid/out-of-date texture data. - } while (NextTile() || (mTextureState != Valid)); - mCurrentImage = oldCurrentImage; - - mShaderType = mImages[0]->GetShaderProgramType(); - mTextureState = Valid; - return result; -} - -void -TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion) -{ - if (mTextureState != Valid) { - // if the texture hasn't been initialized yet, or something important - // changed, we need to recreate our backing surface and force the - // client to paint everything - aForRegion = nsIntRect(nsIntPoint(0, 0), mSize); - return; - } - - nsIntRegion newRegion; - - // We need to query each texture with the region it will be drawing and - // set aForRegion to be the combination of all of these regions - for (unsigned i = 0; i < mImages.Length(); i++) { - int xPos = (i % mColumns) * mTileSize; - int yPos = (i / mColumns) * mTileSize; - nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); - - if (aForRegion.Intersects(imageRect)) { - // Make a copy of the region - nsIntRegion subRegion; - subRegion.And(aForRegion, imageRect); - // Translate it into tile-space - subRegion.MoveBy(-xPos, -yPos); - // Query region - mImages[i]->GetUpdateRegion(subRegion); - // Translate back - subRegion.MoveBy(xPos, yPos); - // Add to the accumulated region - newRegion.Or(newRegion, subRegion); - } - } - - aForRegion = newRegion; -} - -gfxASurface* -TiledTextureImage::BeginUpdate(nsIntRegion& aRegion) -{ - NS_ASSERTION(!mInUpdate, "nested update"); - mInUpdate = true; - - // Note, we don't call GetUpdateRegion here as if the updated region is - // fully contained in a single tile, we get to avoid iterating through - // the tiles again (and a little copying). - if (mTextureState != Valid) - { - // if the texture hasn't been initialized yet, or something important - // changed, we need to recreate our backing surface and force the - // client to paint everything - aRegion = nsIntRect(nsIntPoint(0, 0), mSize); - } - - nsIntRect bounds = aRegion.GetBounds(); - - for (unsigned i = 0; i < mImages.Length(); i++) { - int xPos = (i % mColumns) * mTileSize; - int yPos = (i / mColumns) * mTileSize; - nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); - - // a single Image can handle this update request - if (imageRegion.Contains(aRegion)) { - // adjust for tile offset - aRegion.MoveBy(-xPos, -yPos); - // forward the actual call - nsRefPtr surface = mImages[i]->BeginUpdate(aRegion); - // caller expects container space - aRegion.MoveBy(xPos, yPos); - // Correct the device offset - gfxPoint offset = surface->GetDeviceOffset(); - surface->SetDeviceOffset(gfxPoint(offset.x - xPos, - offset.y - yPos)); - // we don't have a temp surface - mUpdateSurface = nullptr; - // remember which image to EndUpdate - mCurrentImage = i; - return surface.get(); - } - } - - // Get the real updated region, taking into account the capabilities of - // each TextureImage tile - GetUpdateRegion(aRegion); - mUpdateRegion = aRegion; - bounds = aRegion.GetBounds(); - - // update covers multiple Images - create a temp surface to paint in - gfxASurface::gfxImageFormat format = - (GetContentType() == gfxASurface::CONTENT_COLOR) ? - gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; - mUpdateSurface = gfxPlatform::GetPlatform()-> - CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format)); - mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y)); - - return mUpdateSurface; -} - -void -TiledTextureImage::EndUpdate() -{ - NS_ASSERTION(mInUpdate, "EndUpdate not in update"); - if (!mUpdateSurface) { // update was to a single TextureImage - mImages[mCurrentImage]->EndUpdate(); - mInUpdate = false; - mTextureState = Valid; - mShaderType = mImages[mCurrentImage]->GetShaderProgramType(); - return; - } - - // upload tiles from temp surface - for (unsigned i = 0; i < mImages.Length(); i++) { - int xPos = (i % mColumns) * mTileSize; - int yPos = (i / mColumns) * mTileSize; - nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()); - - nsIntRegion subregion; - subregion.And(mUpdateRegion, imageRect); - if (subregion.IsEmpty()) - continue; - subregion.MoveBy(-xPos, -yPos); // Tile-local space - // copy tile from temp surface - gfxASurface* surf = mImages[i]->BeginUpdate(subregion); - nsRefPtr ctx = new gfxContext(surf); - gfxUtils::ClipToRegion(ctx, subregion); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos)); - ctx->Paint(); - mImages[i]->EndUpdate(); - } - - mUpdateSurface = nullptr; - mInUpdate = false; - mShaderType = mImages[0]->GetShaderProgramType(); - mTextureState = Valid; -} - -void TiledTextureImage::BeginTileIteration() -{ - mCurrentImage = 0; -} - -bool TiledTextureImage::NextTile() -{ - bool continueIteration = true; - - if (mIterationCallback) - continueIteration = mIterationCallback(this, mCurrentImage, - mIterationCallbackData); - - if (mCurrentImage + 1 < mImages.Length()) { - mCurrentImage++; - return continueIteration; - } - return false; -} - -void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback, - void* aCallbackData) -{ - mIterationCallback = aCallback; - mIterationCallbackData = aCallbackData; -} - -nsIntRect TiledTextureImage::GetTileRect() -{ - if (!GetTileCount()) { - return nsIntRect(); - } - nsIntRect rect = mImages[mCurrentImage]->GetTileRect(); - unsigned int xPos = (mCurrentImage % mColumns) * mTileSize; - unsigned int yPos = (mCurrentImage / mColumns) * mTileSize; - rect.MoveBy(xPos, yPos); - return rect; -} - -nsIntRect TiledTextureImage::GetSrcTileRect() -{ - nsIntRect rect = GetTileRect(); - unsigned int srcY = mFlags & NeedsYFlip - ? mSize.height - rect.height - rect.y - : rect.y; - return nsIntRect(rect.x, srcY, rect.width, rect.height); -} - -void -TiledTextureImage::BindTexture(GLenum aTextureUnit) -{ - if (!GetTileCount()) { - return; - } - mImages[mCurrentImage]->BindTexture(aTextureUnit); -} - -void -TiledTextureImage::ApplyFilter() -{ - mGL->ApplyFilterToBoundTexture(mFilter); -} - -/* - * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per - * column. A tile on a column is reused if it hasn't changed size, otherwise it - * is discarded/replaced. Extra tiles on a column are pruned after iterating - * each column, and extra rows are pruned after iteration over the entire image - * finishes. - */ -void TiledTextureImage::Resize(const nsIntSize& aSize) -{ - if (mSize == aSize && mTextureState != Created) { - return; - } - - // calculate rows and columns, rounding up - unsigned int columns = (aSize.width + mTileSize - 1) / mTileSize; - unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize; - - // Iterate over old tile-store and insert/remove tiles as necessary - int row; - unsigned int i = 0; - for (row = 0; row < (int)rows; row++) { - // If we've gone beyond how many rows there were before, set mColumns to - // zero so that we only create new tiles. - if (row >= (int)mRows) - mColumns = 0; - - // Similarly, if we're on the last row of old tiles and the height has - // changed, discard all tiles in that row. - // This will cause the pruning of columns not to work, but we don't need - // to worry about that, as no more tiles will be reused past this point - // anyway. - if ((row == (int)mRows - 1) && (aSize.height != mSize.height)) - mColumns = 0; - - int col; - for (col = 0; col < (int)columns; col++) { - nsIntSize size( // use tilesize first, then the remainder - (col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize, - (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize); - - bool replace = false; - - // Check if we can re-use old tiles. - if (col < (int)mColumns) { - // Reuse an existing tile. If the tile is an end-tile and the - // width differs, replace it instead. - if (mSize.width != aSize.width) { - if (col == (int)mColumns - 1) { - // Tile at the end of the old column, replace it with - // a new one. - replace = true; - } else if (col == (int)columns - 1) { - // Tile at the end of the new column, create a new one. - } else { - // Before the last column on both the old and new sizes, - // reuse existing tile. - i++; - continue; - } - } else { - // Width hasn't changed, reuse existing tile. - i++; - continue; - } - } - - // Create a new tile. - nsRefPtr teximg = - mGL->TileGenFunc(size, mContentType, mFlags); - if (replace) - mImages.ReplaceElementAt(i, teximg.forget()); - else - mImages.InsertElementAt(i, teximg.forget()); - i++; - } - - // Prune any unused tiles on the end of the column. - if (row < (int)mRows) { - for (col = (int)mColumns - col; col > 0; col--) { - mImages.RemoveElementAt(i); - } - } - } - - // Prune any unused tiles at the end of the store. - unsigned int length = mImages.Length(); - for (; i < length; i++) - mImages.RemoveElementAt(mImages.Length()-1); - - // Reset tile-store properties. - mRows = rows; - mColumns = columns; - mSize = aSize; - mTextureState = Allocated; - mCurrentImage = 0; -} - -uint32_t TiledTextureImage::GetTileCount() -{ - return mImages.Length(); -} - -TextureImage::ScopedBindTexture::ScopedBindTexture(TextureImage* aTexture, - GLenum aTextureUnit) - : mTexture(aTexture) -{ - if (mTexture) { - MOZ_ASSERT(aTextureUnit >= LOCAL_GL_TEXTURE0); - mTexture->BindTexture(aTextureUnit); - } -} diff --git a/libazure/src/gfx/gl/GLTextureImage.h b/libazure/src/gfx/gl/GLTextureImage.h deleted file mode 100644 index c53dc97..0000000 --- a/libazure/src/gfx/gl/GLTextureImage.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GLTEXTUREIMAGE_H_ -#define GLTEXTUREIMAGE_H_ - -#include "nsAutoPtr.h" -#include "nsRegion.h" -#include "nsTArray.h" -#include "gfxASurface.h" -#include "GLContextTypes.h" -#include "gfxPattern.h" - -namespace mozilla { -namespace gl { -class GLContext; - -/** - * A TextureImage encapsulates a surface that can be drawn to by a - * Thebes gfxContext and (hopefully efficiently!) synchronized to a - * texture in the server. TextureImages are associated with one and - * only one GLContext. - * - * Implementation note: TextureImages attempt to unify two categories - * of backends - * - * (1) proxy to server-side object that can be bound to a texture; - * e.g. Pixmap on X11. - * - * (2) efficient manager of texture memory; e.g. by having clients draw - * into a scratch buffer which is then uploaded with - * glTexSubImage2D(). - */ -class TextureImage -{ - NS_INLINE_DECL_REFCOUNTING(TextureImage) -public: - enum TextureState - { - Created, // Texture created, but has not had glTexImage called to initialize it. - Allocated, // Texture memory exists, but contents are invalid. - Valid // Texture fully ready to use. - }; - - enum Flags { - NoFlags = 0x0, - UseNearestFilter = 0x1, - NeedsYFlip = 0x2, - ForceSingleTile = 0x4 - }; - - typedef gfxASurface::gfxContentType ContentType; - - static already_AddRefed Create( - GLContext* gl, - const nsIntSize& aSize, - TextureImage::ContentType aContentType, - GLenum aWrapMode, - TextureImage::Flags aFlags = TextureImage::NoFlags); - - virtual ~TextureImage() {} - - /** - * Returns a gfxASurface for updating |aRegion| of the client's - * image if successul, NULL if not. |aRegion|'s bounds must fit - * within Size(); its coordinate space (if any) is ignored. If - * the update begins successfully, the returned gfxASurface is - * owned by this. Otherwise, NULL is returned. - * - * |aRegion| is an inout param: the returned region is what the - * client must repaint. Category (1) regions above can - * efficiently handle repaints to "scattered" regions, while (2) - * can only efficiently handle repaints to rects. - * - * Painting the returned surface outside of |aRegion| results - * in undefined behavior. - * - * BeginUpdate() calls cannot be "nested", and each successful - * BeginUpdate() must be followed by exactly one EndUpdate() (see - * below). Failure to do so can leave this in a possibly - * inconsistent state. Unsuccessful BeginUpdate()s must not be - * followed by EndUpdate(). - */ - virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) = 0; - /** - * Retrieves the region that will require updating, given a - * region that needs to be updated. This can be used for - * making decisions about updating before calling BeginUpdate(). - * - * |aRegion| is an inout param. - */ - virtual void GetUpdateRegion(nsIntRegion& aForRegion) { - } - /** - * Finish the active update and synchronize with the server, if - * necessary. - * - * BeginUpdate() must have been called exactly once before - * EndUpdate(). - */ - virtual void EndUpdate() = 0; - - /** - * The Image may contain several textures for different regions (tiles). - * These functions iterate over each sub texture image tile. - */ - virtual void BeginTileIteration() { - } - - virtual bool NextTile() { - return false; - } - - // Function prototype for a tile iteration callback. Returning false will - // cause iteration to be interrupted (i.e. the corresponding NextTile call - // will return false). - typedef bool (* TileIterationCallback)(TextureImage* aImage, - int aTileNumber, - void* aCallbackData); - - // Sets a callback to be called every time NextTile is called. - virtual void SetIterationCallback(TileIterationCallback aCallback, - void* aCallbackData) { - } - - virtual nsIntRect GetTileRect() { - return nsIntRect(nsIntPoint(0,0), mSize); - } - - virtual GLuint GetTextureID() = 0; - - virtual uint32_t GetTileCount() { - return 1; - } - - /** - * Set this TextureImage's size, and ensure a texture has been - * allocated. Must not be called between BeginUpdate and EndUpdate. - * After a resize, the contents are undefined. - * - * If this isn't implemented by a subclass, it will just perform - * a dummy BeginUpdate/EndUpdate pair. - */ - virtual void Resize(const nsIntSize& aSize) { - mSize = aSize; - nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height)); - BeginUpdate(r); - EndUpdate(); - } - - /** - * Mark this texture as having valid contents. Call this after modifying - * the texture contents externally. - */ - virtual void MarkValid() {} - - /** - * aSurf - the source surface to update from - * aRegion - the region in this image to update - * aFrom - offset in the source to update from - */ - virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)) = 0; - - virtual void BindTexture(GLenum aTextureUnit) = 0; - virtual void ReleaseTexture() {} - - void BindTextureAndApplyFilter(GLenum aTextureUnit) { - BindTexture(aTextureUnit); - ApplyFilter(); - } - - class ScopedBindTexture - { - public: - ScopedBindTexture(TextureImage *aTexture, GLenum aTextureUnit); - - ~ScopedBindTexture() - { - if (mTexture) { - mTexture->ReleaseTexture(); - } - } - - protected: - TextureImage *mTexture; - }; - - class ScopedBindTextureAndApplyFilter - : public ScopedBindTexture - { - public: - ScopedBindTextureAndApplyFilter(TextureImage *aTexture, GLenum aTextureUnit) : - ScopedBindTexture(aTexture, aTextureUnit) - { - if (mTexture) { - mTexture->ApplyFilter(); - } - } - }; - - /** - * Returns the shader program type that should be used to render - * this texture. Only valid after a matching BeginUpdate/EndUpdate - * pair have been called. - */ - virtual ShaderProgramType GetShaderProgramType() - { - return mShaderType; - } - - /** Can be called safely at any time. */ - - /** - * If this TextureImage has a permanent gfxASurface backing, - * return it. Otherwise return NULL. - */ - virtual already_AddRefed GetBackingSurface() - { return NULL; } - - const nsIntSize& GetSize() const { return mSize; } - ContentType GetContentType() const { return mContentType; } - virtual bool InUpdate() const = 0; - GLenum GetWrapMode() const { return mWrapMode; } - - void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; } - - /** - * Applies this TextureImage's filter, assuming that its texture is - * the currently bound texture. - */ - virtual void ApplyFilter() = 0; - -protected: - friend class GLContext; - - /** - * After the ctor, the TextureImage is invalid. Implementations - * must allocate resources successfully before returning the new - * TextureImage from GLContext::CreateTextureImage(). That is, - * clients must not be given partially-constructed TextureImages. - */ - TextureImage(const nsIntSize& aSize, - GLenum aWrapMode, ContentType aContentType, - Flags aFlags = NoFlags) - : mSize(aSize) - , mWrapMode(aWrapMode) - , mContentType(aContentType) - , mFilter(gfxPattern::FILTER_GOOD) - , mFlags(aFlags) - {} - - virtual nsIntRect GetSrcTileRect() { - return nsIntRect(nsIntPoint(0,0), mSize); - } - - nsIntSize mSize; - GLenum mWrapMode; - ContentType mContentType; - ShaderProgramType mShaderType; - gfxPattern::GraphicsFilter mFilter; - Flags mFlags; -}; - -/** - * BasicTextureImage is the baseline TextureImage implementation --- - * it updates its texture by allocating a scratch buffer for the - * client to draw into, then using glTexSubImage2D() to upload the new - * pixels. Platforms must provide the code to create a new surface - * into which the updated pixels will be drawn, and the code to - * convert the update surface's pixels into an image on which we can - * glTexSubImage2D(). - */ -class BasicTextureImage - : public TextureImage -{ -public: - typedef gfxASurface::gfxImageFormat ImageFormat; - virtual ~BasicTextureImage(); - - BasicTextureImage(GLuint aTexture, - const nsIntSize& aSize, - GLenum aWrapMode, - ContentType aContentType, - GLContext* aContext, - TextureImage::Flags aFlags = TextureImage::NoFlags) - : TextureImage(aSize, aWrapMode, aContentType, aFlags) - , mTexture(aTexture) - , mTextureState(Created) - , mGLContext(aContext) - , mUpdateOffset(0, 0) - {} - - virtual void BindTexture(GLenum aTextureUnit); - - virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion); - virtual void GetUpdateRegion(nsIntRegion& aForRegion); - virtual void EndUpdate(); - virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)); - virtual GLuint GetTextureID() { return mTexture; } - // Returns a surface to draw into - virtual already_AddRefed - GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt); - - virtual void MarkValid() { mTextureState = Valid; } - - // Call when drawing into the update surface is complete. - // Returns true if textures should be upload with a relative - // offset - See UploadSurfaceToTexture. - virtual bool FinishedSurfaceUpdate(); - - // Call after surface data has been uploaded to a texture. - virtual void FinishedSurfaceUpload(); - - virtual bool InUpdate() const { return !!mUpdateSurface; } - - virtual void Resize(const nsIntSize& aSize); - - virtual void ApplyFilter(); -protected: - - GLuint mTexture; - TextureState mTextureState; - GLContext* mGLContext; - nsRefPtr mUpdateSurface; - nsIntRegion mUpdateRegion; - - // The offset into the update surface at which the update rect is located. - nsIntPoint mUpdateOffset; -}; - -/** - * A container class that complements many sub TextureImages into a big TextureImage. - * Aims to behave just like the real thing. - */ - -class TiledTextureImage - : public TextureImage -{ -public: - TiledTextureImage(GLContext* aGL, nsIntSize aSize, - TextureImage::ContentType, TextureImage::Flags aFlags = TextureImage::NoFlags); - ~TiledTextureImage(); - void DumpDiv(); - virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion); - virtual void GetUpdateRegion(nsIntRegion& aForRegion); - virtual void EndUpdate(); - virtual void Resize(const nsIntSize& aSize); - virtual uint32_t GetTileCount(); - virtual void BeginTileIteration(); - virtual bool NextTile(); - virtual void SetIterationCallback(TileIterationCallback aCallback, - void* aCallbackData); - virtual nsIntRect GetTileRect(); - virtual GLuint GetTextureID() { - return mImages[mCurrentImage]->GetTextureID(); - } - virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)); - virtual bool InUpdate() const { return mInUpdate; } - virtual void BindTexture(GLenum); - virtual void ApplyFilter(); - -protected: - virtual nsIntRect GetSrcTileRect(); - - unsigned int mCurrentImage; - TileIterationCallback mIterationCallback; - void* mIterationCallbackData; - nsTArray< nsRefPtr > mImages; - bool mInUpdate; - nsIntSize mSize; - unsigned int mTileSize; - unsigned int mRows, mColumns; - GLContext* mGL; - // A temporary surface to faciliate cross-tile updates. - nsRefPtr mUpdateSurface; - // The region of update requested - nsIntRegion mUpdateRegion; - TextureState mTextureState; -}; - -} // namespace gl -} // namespace mozilla - -#endif /* GLTEXTUREIMAGE_H_ */ diff --git a/libazure/src/gfx/gl/GLXLibrary.h b/libazure/src/gfx/gl/GLXLibrary.h deleted file mode 100644 index 43ee600..0000000 --- a/libazure/src/gfx/gl/GLXLibrary.h +++ /dev/null @@ -1,219 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_GLXLIBRARY_H -#define GFX_GLXLIBRARY_H - -#include "GLContext.h" -typedef realGLboolean GLboolean; -#include - -namespace mozilla { -namespace gl { - -class GLXLibrary -{ -public: - GLXLibrary() : mInitialized(false), mTriedInitializing(false), - mUseTextureFromPixmap(false), mDebug(false), - mHasRobustness(false), mIsATI(false), - mClientIsMesa(false), mGLXMajorVersion(0), - mGLXMinorVersion(0), mLibType(OPENGL_LIB), - mOGLLibrary(nullptr) {} - - void xDestroyContext(Display* display, GLXContext context); - Bool xMakeCurrent(Display* display, - GLXDrawable drawable, - GLXContext context); - - enum LibraryType - { - OPENGL_LIB = 0, - MESA_LLVMPIPE_LIB = 1, - LIBS_MAX - }; - - GLXContext xGetCurrentContext(); - static void* xGetProcAddress(const char *procName); - GLXFBConfig* xChooseFBConfig(Display* display, - int screen, - const int *attrib_list, - int *nelements); - GLXFBConfig* xGetFBConfigs(Display* display, - int screen, - int *nelements); - GLXContext xCreateNewContext(Display* display, - GLXFBConfig config, - int render_type, - GLXContext share_list, - Bool direct); - int xGetFBConfigAttrib(Display *display, - GLXFBConfig config, - int attribute, - int *value); - void xSwapBuffers(Display *display, GLXDrawable drawable); - const char * xQueryExtensionsString(Display *display, - int screen); - const char * xGetClientString(Display *display, - int screen); - const char * xQueryServerString(Display *display, - int screen, int name); - GLXPixmap xCreatePixmap(Display *display, - GLXFBConfig config, - Pixmap pixmap, - const int *attrib_list); - GLXPixmap xCreateGLXPixmapWithConfig(Display *display, - GLXFBConfig config, - Pixmap pixmap); - void xDestroyPixmap(Display *display, GLXPixmap pixmap); - Bool xQueryVersion(Display *display, - int *major, - int *minor); - void xBindTexImage(Display *display, - GLXDrawable drawable, - int buffer, - const int *attrib_list); - void xReleaseTexImage(Display *display, - GLXDrawable drawable, - int buffer); - void xWaitGL(); - void xWaitX(); - - GLXContext xCreateContextAttribs(Display* display, - GLXFBConfig config, - GLXContext share_list, - Bool direct, - const int* attrib_list); - - bool EnsureInitialized(LibraryType libType); - - GLXPixmap CreatePixmap(gfxASurface* aSurface); - void DestroyPixmap(GLXPixmap aPixmap); - void BindTexImage(GLXPixmap aPixmap); - void ReleaseTexImage(GLXPixmap aPixmap); - - bool UseTextureFromPixmap() { return mUseTextureFromPixmap; } - bool HasRobustness() { return mHasRobustness; } - bool SupportsTextureFromPixmap(gfxASurface* aSurface); - bool IsATI() { return mIsATI; } - bool GLXVersionCheck(int aMajor, int aMinor); - static LibraryType SelectLibrary(const GLContext::ContextFlags& aFlags); - -private: - - typedef void (GLAPIENTRY * PFNGLXDESTROYCONTEXTPROC) (Display*, - GLXContext); - PFNGLXDESTROYCONTEXTPROC xDestroyContextInternal; - typedef Bool (GLAPIENTRY * PFNGLXMAKECURRENTPROC) (Display*, - GLXDrawable, - GLXContext); - PFNGLXMAKECURRENTPROC xMakeCurrentInternal; - typedef GLXContext (GLAPIENTRY * PFNGLXGETCURRENTCONTEXT) (); - PFNGLXGETCURRENTCONTEXT xGetCurrentContextInternal; - typedef void* (GLAPIENTRY * PFNGLXGETPROCADDRESSPROC) (const char *); - PFNGLXGETPROCADDRESSPROC xGetProcAddressInternal; - typedef GLXFBConfig* (GLAPIENTRY * PFNGLXCHOOSEFBCONFIG) (Display *, - int, - const int *, - int *); - PFNGLXCHOOSEFBCONFIG xChooseFBConfigInternal; - typedef GLXFBConfig* (GLAPIENTRY * PFNGLXGETFBCONFIGS) (Display *, - int, - int *); - PFNGLXGETFBCONFIGS xGetFBConfigsInternal; - typedef GLXContext (GLAPIENTRY * PFNGLXCREATENEWCONTEXT) (Display *, - GLXFBConfig, - int, - GLXContext, - Bool); - PFNGLXCREATENEWCONTEXT xCreateNewContextInternal; - typedef int (GLAPIENTRY * PFNGLXGETFBCONFIGATTRIB) (Display *, - GLXFBConfig, - int, - int *); - PFNGLXGETFBCONFIGATTRIB xGetFBConfigAttribInternal; - - typedef void (GLAPIENTRY * PFNGLXSWAPBUFFERS) (Display *, - GLXDrawable); - PFNGLXSWAPBUFFERS xSwapBuffersInternal; - typedef const char * (GLAPIENTRY * PFNGLXQUERYEXTENSIONSSTRING) (Display *, - int); - PFNGLXQUERYEXTENSIONSSTRING xQueryExtensionsStringInternal; - typedef const char * (GLAPIENTRY * PFNGLXGETCLIENTSTRING) (Display *, - int); - PFNGLXGETCLIENTSTRING xGetClientStringInternal; - typedef const char * (GLAPIENTRY * PFNGLXQUERYSERVERSTRING) (Display *, - int, - int); - PFNGLXQUERYSERVERSTRING xQueryServerStringInternal; - - typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEPIXMAP) (Display *, - GLXFBConfig, - Pixmap, - const int *); - PFNGLXCREATEPIXMAP xCreatePixmapInternal; - typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEGLXPIXMAPWITHCONFIG) - (Display *, - GLXFBConfig, - Pixmap); - PFNGLXCREATEGLXPIXMAPWITHCONFIG xCreateGLXPixmapWithConfigInternal; - typedef void (GLAPIENTRY * PFNGLXDESTROYPIXMAP) (Display *, - GLXPixmap); - PFNGLXDESTROYPIXMAP xDestroyPixmapInternal; - typedef Bool (GLAPIENTRY * PFNGLXQUERYVERSION) (Display *, - int *, - int *); - PFNGLXQUERYVERSION xQueryVersionInternal; - - typedef void (GLAPIENTRY * PFNGLXBINDTEXIMAGE) (Display *, - GLXDrawable, - int, - const int *); - PFNGLXBINDTEXIMAGE xBindTexImageInternal; - - typedef void (GLAPIENTRY * PFNGLXRELEASETEXIMAGE) (Display *, - GLXDrawable, - int); - PFNGLXRELEASETEXIMAGE xReleaseTexImageInternal; - - typedef void (GLAPIENTRY * PFNGLXWAITGL) (); - PFNGLXWAITGL xWaitGLInternal; - - typedef void (GLAPIENTRY * PFNGLXWAITX) (); - PFNGLXWAITGL xWaitXInternal; - - typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXTATTRIBS) (Display *, - GLXFBConfig, - GLXContext, - Bool, - const int *); - PFNGLXCREATECONTEXTATTRIBS xCreateContextAttribsInternal; - -#ifdef DEBUG - void BeforeGLXCall(); - void AfterGLXCall(); -#endif - - bool mInitialized; - bool mTriedInitializing; - bool mUseTextureFromPixmap; - bool mDebug; - bool mHasRobustness; - bool mIsATI; - bool mClientIsMesa; - int mGLXMajorVersion; - int mGLXMinorVersion; - LibraryType mLibType; - PRLibrary *mOGLLibrary; -}; - -// a global GLXLibrary instance -extern GLXLibrary sGLXLibrary[GLXLibrary::LIBS_MAX]; -extern GLXLibrary& sDefGLXLib; - -} /* namespace gl */ -} /* namespace mozilla */ -#endif /* GFX_GLXLIBRARY_H */ - diff --git a/libazure/src/gfx/gl/Makefile.in b/libazure/src/gfx/gl/Makefile.in deleted file mode 100644 index fad293c..0000000 --- a/libazure/src/gfx/gl/Makefile.in +++ /dev/null @@ -1,149 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -LIBRARY_NAME = gl -LIBXUL_LIBRARY = 1 -EXPORT_LIBRARY = 1 -FAIL_ON_WARNINGS = 1 - -EXPORTS = \ - ForceDiscreteGPUHelperCGL.h \ - GLContext.h \ - GLContextProvider.h \ - GLContextProviderImpl.h \ - GLContextSymbols.h \ - GLContextTypes.h \ - GLDefs.h \ - GLLibraryLoader.h \ - GLLibraryEGL.h \ - GLScreenBuffer.h \ - GLTextureImage.h \ - SharedSurface.h \ - SharedSurfaceEGL.h \ - SharedSurfaceGL.h \ - SurfaceFactory.h \ - SurfaceStream.h \ - SurfaceTypes.h \ - $(NULL) - -ifdef MOZ_X11 -EXPORTS += \ - GLXLibrary.h \ - $(NULL) -endif - - -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -EXPORTS += \ - WGLLibrary.h \ - $(NULL) -ifdef MOZ_WEBGL -DEFINES += -DMOZ_WEBGL -DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL) -endif -endif - -CPPSRCS = \ - GLContext.cpp \ - GLContextTypes.cpp \ - GLContextUtils.cpp \ - GLLibraryLoader.cpp \ - GLScreenBuffer.cpp \ - GLTextureImage.cpp \ - SharedSurface.cpp \ - SharedSurfaceEGL.cpp \ - SharedSurfaceGL.cpp \ - SurfaceFactory.cpp \ - SurfaceStream.cpp \ - $(NULL) - -GL_PROVIDER = Null - -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -GL_PROVIDER = WGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) -GL_PROVIDER = CGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) -ifdef MOZ_PLATFORM_MAEMO -GL_PROVIDER = EGL -else -ifdef MOZ_EGL_XRENDER_COMPOSITE -GL_PROVIDER = EGL -else -GL_PROVIDER = GLX -endif -endif -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),qt) -ifdef MOZ_PLATFORM_MAEMO -GL_PROVIDER = EGL -else -GL_PROVIDER = GLX -endif -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),android) -GL_PROVIDER = EGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),gonk) -GL_PROVIDER = EGL -LOCAL_INCLUDES = -I$(topsrcdir)/widget/gonk -endif - -ifdef MOZ_GL_PROVIDER -GL_PROVIDER = $(MOZ_GL_PROVIDER) -endif - -# Mac is a special snowflake -ifeq ($(GL_PROVIDER),CGL) -CMMSRCS += GLContextProvider$(GL_PROVIDER).mm -else -CPPSRCS += GLContextProvider$(GL_PROVIDER).cpp -endif - -ifeq ($(GL_PROVIDER),EGL) -CPPSRCS += GLLibraryEGL.cpp -endif - -# Win32 is a special snowflake, for ANGLE -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -EXPORTS += \ - SharedSurfaceANGLE.h \ - $(NULL) - -CPPSRCS += \ - GLContextProviderEGL.cpp \ - GLLibraryEGL.cpp \ - SharedSurfaceANGLE.cpp \ - $(NULL) -endif - -ifdef MOZ_ANDROID_OMTC -DEFINES += -DMOZ_ANDROID_OMTC -endif - -ifdef MOZ_ENABLE_SKIA_GPU -CPPSRCS += GLContextSkia.cpp -EXPORTS += GLContextSkia.h -endif - -include $(topsrcdir)/config/rules.mk - -DEFINES := $(filter-out -DUNICODE,$(DEFINES)) - -CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS) -CFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS) diff --git a/libazure/src/gfx/gl/SharedSurface.cpp b/libazure/src/gfx/gl/SharedSurface.cpp deleted file mode 100644 index e8f82e7..0000000 --- a/libazure/src/gfx/gl/SharedSurface.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurface.h" -#include "SharedSurfaceGL.h" - -using namespace mozilla::gl; - -namespace mozilla { -namespace gfx { - -// |src| must begin and end locked, though it -// can be temporarily unlocked if needed. -void -SharedSurface::Copy(SharedSurface* src, SharedSurface* dest, SurfaceFactory* factory) -{ - MOZ_ASSERT( src->APIType() == APITypeT::OpenGL); - MOZ_ASSERT(dest->APIType() == APITypeT::OpenGL); - - SharedSurface_GL* srcGL = (SharedSurface_GL*)src; - SharedSurface_GL* destGL = (SharedSurface_GL*)dest; - - SharedSurface_GL::Copy(srcGL, destGL, (SurfaceFactory_GL*)factory); -} - -} /* namespace gfx */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SharedSurface.h b/libazure/src/gfx/gl/SharedSurface.h deleted file mode 100644 index 91c0f5b..0000000 --- a/libazure/src/gfx/gl/SharedSurface.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* SharedSurface abstracts an actual surface (can be a GL texture, but - * not necessarily) that handles sharing. - * Its specializations are: - * SharedSurface_Basic (client-side bitmap, does readback) - * SharedSurface_GLTexture - * SharedSurface_EGLImage - * SharedSurface_ANGLEShareHandle - */ - -#ifndef SHARED_SURFACE_H_ -#define SHARED_SURFACE_H_ - -#include "mozilla/StandardInteger.h" -#include "mozilla/Attributes.h" -#include "GLDefs.h" -#include "gfxPoint.h" -#include "SurfaceTypes.h" - -namespace mozilla { -namespace gfx { - -class SurfaceFactory; - -class SharedSurface -{ -protected: - const SharedSurfaceType mType; - const APITypeT mAPI; - const AttachmentType mAttachType; - const gfxIntSize mSize; - const bool mHasAlpha; - bool mIsLocked; - - SharedSurface(SharedSurfaceType type, - APITypeT api, - AttachmentType attachType, - const gfxIntSize& size, - bool hasAlpha) - : mType(type) - , mAPI(api) - , mAttachType(attachType) - , mSize(size) - , mHasAlpha(hasAlpha) - , mIsLocked(false) - { - } - -public: - virtual ~SharedSurface() { - } - - static void Copy(SharedSurface* src, SharedSurface* dest, - SurfaceFactory* factory); - - // This locks the SharedSurface as the production buffer for the context. - // This is needed by backends which use PBuffers and/or EGLSurfaces. - virtual void LockProd() { - MOZ_ASSERT(!mIsLocked); - LockProdImpl(); - mIsLocked = true; - } - - // Unlocking is harmless if we're already unlocked. - virtual void UnlockProd() { - if (!mIsLocked) - return; - - UnlockProdImpl(); - mIsLocked = false; - } - - virtual void LockProdImpl() = 0; - virtual void UnlockProdImpl() = 0; - - virtual void Fence() = 0; - virtual bool WaitSync() = 0; - - - SharedSurfaceType Type() const { - return mType; - } - - APITypeT APIType() const { - return mAPI; - } - - AttachmentType AttachType() const { - return mAttachType; - } - - const gfxIntSize& Size() const { - return mSize; - } - - bool HasAlpha() const { - return mHasAlpha; - } - - - // For use when AttachType is correct. - virtual GLuint Texture() const { - MOZ_ASSERT(AttachType() == AttachmentType::GLTexture); - MOZ_NOT_REACHED("Did you forget to override this function?"); - return 0; - } - - virtual GLuint Renderbuffer() const { - MOZ_ASSERT(AttachType() == AttachmentType::GLRenderbuffer); - MOZ_NOT_REACHED("Did you forget to override this function?"); - return 0; - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_H_ */ diff --git a/libazure/src/gfx/gl/SharedSurfaceANGLE.cpp b/libazure/src/gfx/gl/SharedSurfaceANGLE.cpp deleted file mode 100644 index eea5bce..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceANGLE.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceANGLE.h" - -#include "GLContext.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -SurfaceFactory_ANGLEShareHandle* -SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, - ID3D10Device1* d3d, - const SurfaceCaps& caps) -{ - GLLibraryEGL* egl = gl->GetLibraryEGL(); - if (!egl) - return nullptr; - - if (!egl->IsExtensionSupported( - GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)) - { - return nullptr; - } - - return new SurfaceFactory_ANGLEShareHandle(gl, egl, d3d, caps); -} - -EGLDisplay -SharedSurface_ANGLEShareHandle::Display() -{ - return mEGL->Display(); -} - - -SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() -{ - mEGL->fDestroySurface(Display(), mPBuffer); -} - -void -SharedSurface_ANGLEShareHandle::LockProdImpl() -{ - mGL->MakeCurrent_EGLSurface(mPBuffer); -} - -void -SharedSurface_ANGLEShareHandle::UnlockProdImpl() -{ -} - - -void -SharedSurface_ANGLEShareHandle::Fence() -{ - mGL->fFinish(); -} - -bool -SharedSurface_ANGLEShareHandle::WaitSync() -{ - // Since we glFinish in Fence(), we're always going to be resolved here. - return true; -} - -static void -FillPBufferAttribs_ByBits(nsTArray& aAttrs, - int redBits, int greenBits, - int blueBits, int alphaBits, - int depthBits, int stencilBits) -{ - aAttrs.Clear(); - -#if defined(A1) || defined(A2) -#error The temp-macro names we want are already defined. -#endif - -#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) -#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) - - A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); - A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); - - A2(LOCAL_EGL_RED_SIZE, redBits); - A2(LOCAL_EGL_GREEN_SIZE, greenBits); - A2(LOCAL_EGL_BLUE_SIZE, blueBits); - A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); - - A2(LOCAL_EGL_DEPTH_SIZE, depthBits); - A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); - - A1(LOCAL_EGL_NONE); -#undef A1 -#undef A2 -} - -static void -FillPBufferAttribs_BySizes(nsTArray& attribs, - bool bpp16, bool hasAlpha, - int depthBits, int stencilBits) -{ - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - if (bpp16) { - if (hasAlpha) { - red = green = blue = alpha = 4; - } else { - red = 5; - green = 6; - blue = 5; - } - } else { - red = green = blue = 8; - if (hasAlpha) - alpha = 8; - } - - FillPBufferAttribs_ByBits(attribs, - red, green, blue, alpha, - depthBits, stencilBits); -} - -static EGLConfig -ChooseConfig(GLContext* gl, - GLLibraryEGL* egl, - const SurfaceCaps& caps) -{ - MOZ_ASSERT(egl); - MOZ_ASSERT(caps.color); - - // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. - int depthBits = caps.depth ? 16 : 0; - int stencilBits = caps.stencil ? 8 : 0; - - // Ok, now we have everything. - nsTArray attribs(32); - FillPBufferAttribs_BySizes(attribs, - caps.bpp16, caps.alpha, - depthBits, stencilBits); - - // Time to try to get this config: - EGLConfig configs[64]; - int numConfigs = sizeof(configs)/sizeof(EGLConfig); - int foundConfigs = 0; - - if (!egl->fChooseConfig(egl->Display(), - attribs.Elements(), - configs, numConfigs, - &foundConfigs) || - !foundConfigs) - { - NS_WARNING("No configs found for the requested formats."); - return EGL_NO_CONFIG; - } - - // TODO: Pick a config progamatically instead of hoping that - // the first config will be minimally matching our request. - EGLConfig config = configs[0]; - - if (gl->DebugMode()) { - egl->DumpEGLConfig(config); - } - - return config; -} - - -// Returns EGL_NO_SURFACE on error. -static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, - EGLDisplay display, - EGLConfig config, - const gfxIntSize& size) -{ - EGLint attribs[] = { - LOCAL_EGL_WIDTH, size.width, - LOCAL_EGL_HEIGHT, size.height, - LOCAL_EGL_NONE - }; - - EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs); - - return surface; -} - -SharedSurface_ANGLEShareHandle* -SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, - EGLContext context, EGLConfig config, - const gfxIntSize& size, bool hasAlpha) -{ - GLLibraryEGL* egl = gl->GetLibraryEGL(); - MOZ_ASSERT(egl); - MOZ_ASSERT(egl->IsExtensionSupported( - GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); - - if (!context || !config) - return nullptr; - - EGLDisplay display = egl->Display(); - EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); - if (!pbuffer) - return nullptr; - - - // Declare everything before 'goto's. - HANDLE shareHandle = nullptr; - nsRefPtr texture; - nsRefPtr srv; - - // On failure, goto CleanUpIfFailed. - // If |failed|, CleanUpIfFailed will clean up and return null. - bool failed = true; - HRESULT hr; - - // Off to the races! - if (!egl->fQuerySurfacePointerANGLE( - display, - pbuffer, - LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - &shareHandle)) - { - NS_ERROR("Failed to grab ShareHandle for PBuffer!"); - goto CleanUpIfFailed; - } - - // Ok, we have a valid PBuffer with ShareHandle. - // Let's attach it to D3D. - hr = d3d->OpenSharedResource(shareHandle, - __uuidof(ID3D10Texture2D), - getter_AddRefs(texture)); - if (FAILED(hr)) - goto CleanUpIfFailed; - - hr = d3d->CreateShaderResourceView(texture, nullptr, getter_AddRefs(srv)); - if (FAILED(hr)) - goto CleanUpIfFailed; - - failed = false; - -CleanUpIfFailed: - if (failed) { - NS_WARNING("CleanUpIfFailed"); - egl->fDestroySurface(egl->Display(), pbuffer); - MOZ_CRASH(); - return nullptr; - } - - return new SharedSurface_ANGLEShareHandle(gl, egl, - size, hasAlpha, - context, pbuffer, - texture, srv); -} - - -SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - ID3D10Device1* d3d, - const SurfaceCaps& caps) - : SurfaceFactory_GL(gl, SharedSurfaceType::EGLSurfaceANGLE, caps) - , mProdGL(gl) - , mEGL(egl) - , mConsD3D(d3d) -{ - mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); - mContext = mProdGL->GetEGLContext(); - MOZ_ASSERT(mConfig && mContext); -} - -} /* namespace gl */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SharedSurfaceANGLE.h b/libazure/src/gfx/gl/SharedSurfaceANGLE.h deleted file mode 100644 index d6bedfd..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceANGLE.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_SURFACE_ANGLE_H_ -#define SHARED_SURFACE_ANGLE_H_ - -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" -#include "SurfaceTypes.h" - -#include -#include - -namespace mozilla { -namespace gl { - -class GLContext; - -class SharedSurface_ANGLEShareHandle - : public SharedSurface_GL -{ -public: - static SharedSurface_ANGLEShareHandle* Create(GLContext* gl, ID3D10Device1* d3d, - EGLContext context, EGLConfig config, - const gfxIntSize& size, - bool hasAlpha); - - static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLSurfaceANGLE); - - return (SharedSurface_ANGLEShareHandle*)surf; - } - -protected: - GLLibraryEGL* const mEGL; - const EGLContext mContext; - const EGLSurface mPBuffer; - nsRefPtr mTexture; - nsRefPtr mSRV; - - SharedSurface_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context, - EGLSurface pbuffer, - ID3D10Texture2D* texture, - ID3D10ShaderResourceView* srv) - : SharedSurface_GL(SharedSurfaceType::EGLSurfaceANGLE, - AttachmentType::Screen, - gl, - size, - hasAlpha) - , mEGL(egl) - , mContext(context) - , mPBuffer(pbuffer) - , mTexture(texture) - , mSRV(srv) - {} - - EGLDisplay Display(); - -public: - virtual ~SharedSurface_ANGLEShareHandle(); - - virtual void LockProdImpl(); - virtual void UnlockProdImpl(); - - virtual void Fence(); - virtual bool WaitSync(); - - // Implementation-specific functions below: - ID3D10ShaderResourceView* GetSRV() { - return mSRV; - } -}; - - - -class SurfaceFactory_ANGLEShareHandle - : public SurfaceFactory_GL -{ -protected: - GLContext* const mProdGL; - GLLibraryEGL* const mEGL; - nsRefPtr mConsD3D; - EGLContext mContext; - EGLConfig mConfig; - -public: - static SurfaceFactory_ANGLEShareHandle* Create(GLContext* gl, - ID3D10Device1* d3d, - const SurfaceCaps& caps); - -protected: - SurfaceFactory_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - ID3D10Device1* d3d, - const SurfaceCaps& caps); - - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConsD3D, - mContext, mConfig, - size, hasAlpha); - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_ANGLE_H_ */ diff --git a/libazure/src/gfx/gl/SharedSurfaceEGL.cpp b/libazure/src/gfx/gl/SharedSurfaceEGL.cpp deleted file mode 100644 index 2265715..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceEGL.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceEGL.h" - -#include "GLContext.h" -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -SharedSurface_EGLImage* -SharedSurface_EGLImage::Create(GLContext* prodGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context) -{ - GLLibraryEGL* egl = prodGL->GetLibraryEGL(); - MOZ_ASSERT(egl); - - if (!HasExtensions(egl, prodGL)) - return nullptr; - - MOZ_ALWAYS_TRUE(prodGL->MakeCurrent()); - GLuint prodTex = prodGL->CreateTextureForOffscreen(formats, size); - if (!prodTex) - return nullptr; - - return new SharedSurface_EGLImage(prodGL, egl, - size, hasAlpha, - formats, prodTex); -} - - -bool -SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) -{ - return egl->HasKHRImageBase() && - egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) && - gl->IsExtensionSupported(GLContext::OES_EGL_image); -} - -SharedSurface_EGLImage::~SharedSurface_EGLImage() -{ - mEGL->fDestroyImage(Display(), mImage); - mImage = 0; - - mGL->MakeCurrent(); - mGL->fDeleteTextures(1, &mProdTex); - mProdTex = 0; - - if (mProdTexForPipe) { - mGL->fDeleteTextures(1, &mProdTexForPipe); - mProdTexForPipe = 0; - } - - if (mConsTex) { - MOZ_ASSERT(mGarbageBin); - mGarbageBin->Trash(mConsTex); - mConsTex = 0; - } - - if (mSync) { - // We can't call this unless we have the ext, but we will always have - // the ext if we have something to destroy. - mEGL->fDestroySync(Display(), mSync); - mSync = 0; - } -} - -void -SharedSurface_EGLImage::LockProdImpl() -{ - MutexAutoLock lock(mMutex); - - if (!mPipeComplete) - return; - - if (mPipeActive) - return; - - mGL->BlitTextureToTexture(mProdTex, mProdTexForPipe, Size(), Size()); - mGL->fDeleteTextures(1, &mProdTex); - mProdTex = mProdTexForPipe; - mProdTexForPipe = 0; - mPipeActive = true; -} - -static bool -CreateTexturePipe(GLLibraryEGL* const egl, GLContext* const gl, - const GLFormats& formats, const gfxIntSize& size, - GLuint* const out_tex, EGLImage* const out_image) -{ - MOZ_ASSERT(out_tex && out_image); - *out_tex = 0; - *out_image = 0; - - GLuint tex = gl->CreateTextureForOffscreen(formats, size); - if (!tex) - return false; - - EGLContext context = gl->GetEGLContext(); - MOZ_ASSERT(context); - EGLClientBuffer buffer = reinterpret_cast(tex); - EGLImage image = egl->fCreateImage(egl->Display(), context, - LOCAL_EGL_GL_TEXTURE_2D, buffer, - nullptr); - if (!image) { - gl->fDeleteTextures(1, &tex); - return false; - } - - // Success. - *out_tex = tex; - *out_image = image; - return true; -} - -void -SharedSurface_EGLImage::Fence() -{ - MutexAutoLock lock(mMutex); - mGL->MakeCurrent(); - - if (!mPipeActive) { - MOZ_ASSERT(!mSync); - MOZ_ASSERT(!mPipeComplete); - - if (!mPipeFailed) { - if (!CreateTexturePipe(mEGL, mGL, mFormats, Size(), - &mProdTexForPipe, &mImage)) - { - mPipeFailed = true; - } - } - - if (!mPixels) { - gfxASurface::gfxImageFormat format = - HasAlpha() ? gfxASurface::ImageFormatARGB32 - : gfxASurface::ImageFormatRGB24; - mPixels = new gfxImageSurface(Size(), format); - } - - mPixels->Flush(); - mGL->ReadScreenIntoImageSurface(mPixels); - mPixels->MarkDirty(); - return; - } - MOZ_ASSERT(mPipeActive); - MOZ_ASSERT(mCurConsGL); - - if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && - mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) - { - if (mSync) { - MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); - mSync = 0; - } - - mSync = mEGL->fCreateSync(Display(), - LOCAL_EGL_SYNC_FENCE, - nullptr); - if (mSync) { - mGL->fFlush(); - return; - } - } - - MOZ_ASSERT(!mSync); - mGL->fFinish(); -} - -bool -SharedSurface_EGLImage::WaitSync() -{ - MutexAutoLock lock(mMutex); - if (!mSync) { - // We must not be needed. - return true; - } - MOZ_ASSERT(mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); - - EGLTime waitMS = 500; - const EGLTime nsPerMS = 1000 * 1000; - EGLTime waitNS = waitMS * nsPerMS; - EGLint status = mEGL->fClientWaitSync(Display(), - mSync, - 0, - waitNS); - - if (status != LOCAL_EGL_CONDITION_SATISFIED) { - return false; - } - - MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); - mSync = 0; - - return true; -} - - -EGLDisplay -SharedSurface_EGLImage::Display() const -{ - return mEGL->Display(); -} - -GLuint -SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL) -{ - MutexAutoLock lock(mMutex); - MOZ_ASSERT(!mCurConsGL || consGL == mCurConsGL); - if (mPipeFailed) - return 0; - - if (mPipeActive) { - MOZ_ASSERT(mConsTex); - - return mConsTex; - } - - if (!mConsTex) { - consGL->fGenTextures(1, &mConsTex); - ScopedBindTexture autoTex(consGL, mConsTex); - consGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mImage); - - mPipeComplete = true; - mCurConsGL = consGL; - mGarbageBin = consGL->TexGarbageBin(); - } - - MOZ_ASSERT(consGL == mCurConsGL); - return 0; -} - -gfxImageSurface* -SharedSurface_EGLImage::GetPixels() const -{ - MutexAutoLock lock(mMutex); - return mPixels; -} - - - -SurfaceFactory_EGLImage* -SurfaceFactory_EGLImage::Create(GLContext* prodGL, - const SurfaceCaps& caps) -{ - EGLContext context = prodGL->GetEGLContext(); - - return new SurfaceFactory_EGLImage(prodGL, context, caps); -} - -} /* namespace gfx */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SharedSurfaceEGL.h b/libazure/src/gfx/gl/SharedSurfaceEGL.h deleted file mode 100644 index 874bce7..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceEGL.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_SURFACE_EGL_H_ -#define SHARED_SURFACE_EGL_H_ - -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" -#include "SurfaceTypes.h" -#include "mozilla/Attributes.h" -#include "mozilla/Mutex.h" - -namespace mozilla { -namespace gl { - -class GLContext; - -class SharedSurface_EGLImage - : public SharedSurface_GL -{ -public: - static SharedSurface_EGLImage* Create(GLContext* prodGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context); - - static SharedSurface_EGLImage* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLImageShare); - - return (SharedSurface_EGLImage*)surf; - } - -protected: - mutable Mutex mMutex; - GLLibraryEGL* const mEGL; - const GLFormats mFormats; - GLuint mProdTex; - nsRefPtr mPixels; - GLuint mProdTexForPipe; // Moves to mProdTex when mPipeActive becomes true. - EGLImage mImage; - GLContext* mCurConsGL; - GLuint mConsTex; - nsRefPtr mGarbageBin; - EGLSync mSync; - bool mPipeFailed; // Pipe creation failed, and has been abandoned. - bool mPipeComplete; // Pipe connects (mPipeActive ? mProdTex : mProdTexForPipe) to mConsTex. - bool mPipeActive; // Pipe is complete and in use for production. - - SharedSurface_EGLImage(GLContext* gl, - GLLibraryEGL* egl, - const gfxIntSize& size, - bool hasAlpha, - const GLFormats& formats, - GLuint prodTex) - : SharedSurface_GL(SharedSurfaceType::EGLImageShare, - AttachmentType::GLTexture, - gl, - size, - hasAlpha) - , mMutex("SharedSurface_EGLImage mutex") - , mEGL(egl) - , mFormats(formats) - , mProdTex(prodTex) - , mProdTexForPipe(0) - , mImage(0) - , mCurConsGL(nullptr) - , mConsTex(0) - , mSync(0) - , mPipeFailed(false) - , mPipeComplete(false) - , mPipeActive(false) - {} - - EGLDisplay Display() const; - - static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl); - -public: - virtual ~SharedSurface_EGLImage(); - - virtual void LockProdImpl(); - virtual void UnlockProdImpl() {} - - - virtual void Fence(); - virtual bool WaitSync(); - - - virtual GLuint Texture() const { - return mProdTex; - } - - // Implementation-specific functions below: - // Returns 0 if the pipe isn't ready. If 0, use GetPixels below. - GLuint AcquireConsumerTexture(GLContext* consGL); - - // Will be void if AcquireConsumerTexture returns non-zero. - gfxImageSurface* GetPixels() const; -}; - - - -class SurfaceFactory_EGLImage - : public SurfaceFactory_GL -{ -public: - // Infallible: - static SurfaceFactory_EGLImage* Create(GLContext* prodGL, - const SurfaceCaps& caps); - -protected: - const EGLContext mContext; - - SurfaceFactory_EGLImage(GLContext* prodGL, - EGLContext context, - const SurfaceCaps& caps) - : SurfaceFactory_GL(prodGL, SharedSurfaceType::EGLImageShare, caps) - , mContext(context) - {} - -public: - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext); - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_EGL_H_ */ diff --git a/libazure/src/gfx/gl/SharedSurfaceGL.cpp b/libazure/src/gfx/gl/SharedSurfaceGL.cpp deleted file mode 100644 index fa9db87..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceGL.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceGL.h" - -#include "GLContext.h" -#include "gfxImageSurface.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -// |src| must begin and end locked, though we may -// temporarily unlock it if we need to. -void -SharedSurface_GL::Copy(SharedSurface_GL* src, SharedSurface_GL* dest, - SurfaceFactory_GL* factory) -{ - GLContext* gl = src->GL(); - - if (src->AttachType() == AttachmentType::Screen && - dest->AttachType() == AttachmentType::Screen) - { - // Here, we actually need to blit through a temp surface, so let's make one. - nsAutoPtr tempSurf( - SharedSurface_GLTexture::Create(gl, gl, - factory->Formats(), - src->Size(), - factory->Caps().alpha)); - - Copy(src, tempSurf, factory); - Copy(tempSurf, dest, factory); - return; - } - - if (src->AttachType() == AttachmentType::Screen) { - SharedSurface* origLocked = gl->GetLockedSurface(); - bool srcNeedsUnlock = false; - bool origNeedsRelock = false; - if (origLocked != src) { - if (origLocked) { - origLocked->UnlockProd(); - origNeedsRelock = true; - } - - src->LockProd(); - srcNeedsUnlock = true; - } - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitFramebufferToTexture(0, destTex, src->Size(), dest->Size()); - } else if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitFramebufferToFramebuffer(0, destWrapper.FB(), - src->Size(), dest->Size()); - } else { - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - if (srcNeedsUnlock) - src->UnlockProd(); - - if (origNeedsRelock) - origLocked->LockProd(); - - return; - } - - if (dest->AttachType() == AttachmentType::Screen) { - SharedSurface* origLocked = gl->GetLockedSurface(); - bool destNeedsUnlock = false; - bool origNeedsRelock = false; - if (origLocked != dest) { - if (origLocked) { - origLocked->UnlockProd(); - origNeedsRelock = true; - } - - dest->LockProd(); - destNeedsUnlock = true; - } - - if (src->AttachType() == AttachmentType::GLTexture) { - GLuint srcTex = src->Texture(); - - gl->BlitTextureToFramebuffer(srcTex, 0, src->Size(), dest->Size()); - } else if (src->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint srcRB = src->Renderbuffer(); - ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); - - gl->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0, - src->Size(), dest->Size()); - } else { - MOZ_NOT_REACHED("Unhandled src->AttachType()."); - return; - } - - if (destNeedsUnlock) - dest->UnlockProd(); - - if (origNeedsRelock) - origLocked->LockProd(); - - return; - } - - // Alright, done with cases involving Screen types. - // Only {src,dest}x{texture,renderbuffer} left. - - if (src->AttachType() == AttachmentType::GLTexture) { - GLuint srcTex = src->Texture(); - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitTextureToTexture(srcTex, destTex, - src->Size(), dest->Size()); - - return; - } - - if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitTextureToFramebuffer(srcTex, destWrapper.FB(), - src->Size(), dest->Size()); - - return; - } - - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - if (src->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint srcRB = src->Renderbuffer(); - ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitFramebufferToTexture(srcWrapper.FB(), destTex, - src->Size(), dest->Size()); - - return; - } - - if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(), - src->Size(), dest->Size()); - - return; - } - - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - MOZ_NOT_REACHED("Unhandled src->AttachType()."); - return; -} - -void -SharedSurface_GL::LockProd() -{ - MOZ_ASSERT(!mIsLocked); - - LockProdImpl(); - - mGL->LockSurface(this); - mIsLocked = true; -} - -void -SharedSurface_GL::UnlockProd() -{ - if (!mIsLocked) - return; - - UnlockProdImpl(); - - mGL->UnlockSurface(this); - mIsLocked = false; -} - - -SurfaceFactory_GL::SurfaceFactory_GL(GLContext* gl, - SharedSurfaceType type, - const SurfaceCaps& caps) - : SurfaceFactory(type, caps) - , mGL(gl) - , mFormats(gl->ChooseGLFormats(caps)) -{ - ChooseBufferBits(caps, mDrawCaps, mReadCaps); -} - -void -SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps, - SurfaceCaps& drawCaps, - SurfaceCaps& readCaps) const -{ - SurfaceCaps screenCaps; - - screenCaps.color = caps.color; - screenCaps.alpha = caps.alpha; - screenCaps.bpp16 = caps.bpp16; - - screenCaps.depth = caps.depth; - screenCaps.stencil = caps.stencil; - - screenCaps.antialias = caps.antialias; - screenCaps.preserve = caps.preserve; - - if (caps.antialias) { - drawCaps = screenCaps; - readCaps.Clear(); - - // Color caps need to be duplicated in readCaps. - readCaps.color = caps.color; - readCaps.alpha = caps.alpha; - readCaps.bpp16 = caps.bpp16; - } else { - drawCaps.Clear(); - readCaps = screenCaps; - } -} - - -SharedSurface_Basic* -SharedSurface_Basic::Create(GLContext* gl, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha) -{ - gl->MakeCurrent(); - GLuint tex = gl->CreateTexture(formats.color_texInternalFormat, - formats.color_texFormat, - formats.color_texType, - size); - - gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatRGB24; - switch (formats.color_texInternalFormat) { - case LOCAL_GL_RGB: - case LOCAL_GL_RGB8: - if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) - format = gfxASurface::ImageFormatRGB16_565; - else - format = gfxASurface::ImageFormatRGB24; - break; - case LOCAL_GL_RGBA: - case LOCAL_GL_RGBA8: - format = gfxASurface::ImageFormatARGB32; - break; - default: - MOZ_NOT_REACHED("Unhandled Tex format."); - return nullptr; - } - return new SharedSurface_Basic(gl, size, hasAlpha, format, tex); -} - -SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, - const gfxIntSize& size, - bool hasAlpha, - gfxASurface::gfxImageFormat format, - GLuint tex) - : SharedSurface_GL(SharedSurfaceType::Basic, - AttachmentType::GLTexture, - gl, - size, - hasAlpha) - , mTex(tex) -{ - mData = new gfxImageSurface(size, format); -} - -SharedSurface_Basic::~SharedSurface_Basic() -{ - if (!mGL->MakeCurrent()) - return; - - GLuint tex = mTex; - mGL->fDeleteTextures(1, &tex); -} - -void -SharedSurface_Basic::Fence() -{ - MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize()); - - mGL->MakeCurrent(); - mData->Flush(); - mGL->ReadScreenIntoImageSurface(mData); - mData->MarkDirty(); -} - - - -SharedSurface_GLTexture* -SharedSurface_GLTexture::Create(GLContext* prodGL, - GLContext* consGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha) -{ - MOZ_ASSERT(prodGL && consGL); - MOZ_ASSERT(prodGL->SharesWith(consGL)); - - prodGL->MakeCurrent(); - GLuint tex = prodGL->CreateTextureForOffscreen(formats, size); - - return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex); -} - -SharedSurface_GLTexture::~SharedSurface_GLTexture() -{ - if (!mGL->MakeCurrent()) - return; - - GLuint tex = mTex; - mGL->fDeleteTextures(1, &tex); - - if (mSync) { - mGL->fDeleteSync(mSync); - } -} - -void -SharedSurface_GLTexture::Fence() -{ - mGL->MakeCurrent(); - - if (mGL->IsExtensionSupported(GLContext::ARB_sync)) { - if (mSync) { - mGL->fDeleteSync(mSync); - mSync = 0; - } - - mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - if (mSync) { - mGL->fFlush(); - return; - } - } - MOZ_ASSERT(!mSync); - - mGL->fFinish(); -} - -bool -SharedSurface_GLTexture::WaitSync() -{ - if (!mSync) { - // We must have used glFinish instead of glFenceSync. - return true; - } - mConsGL->MakeCurrent(); - MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync)); - - mConsGL->fWaitSync(mSync, - 0, - LOCAL_GL_TIMEOUT_IGNORED); - - mConsGL->fDeleteSync(mSync); - mSync = 0; - - return true; -} - -} /* namespace gfx */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SharedSurfaceGL.h b/libazure/src/gfx/gl/SharedSurfaceGL.h deleted file mode 100644 index 7d24bea..0000000 --- a/libazure/src/gfx/gl/SharedSurfaceGL.h +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_SURFACE_GL_H_ -#define SHARED_SURFACE_GL_H_ - -#include "SharedSurface.h" -#include "SurfaceFactory.h" -#include "SurfaceTypes.h" -#include "GLContextTypes.h" -#include "nsAutoPtr.h" -#include "gfxASurface.h" - -#include - -// Forwards: -class gfxImageSurface; -namespace mozilla { - namespace gl { - class GLContext; - } -} - -namespace mozilla { -namespace gl { - -class SurfaceFactory_GL; - -class SharedSurface_GL - : public gfx::SharedSurface -{ -protected: - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SharedSurfaceType SharedSurfaceType; - typedef gfx::APITypeT APITypeT; - typedef gfx::AttachmentType AttachmentType; - - GLContext* const mGL; - - SharedSurface_GL(SharedSurfaceType type, - AttachmentType attachType, - GLContext* gl, - const gfxIntSize& size, - bool hasAlpha) - : SharedSurface(type, APITypeT::OpenGL, attachType, size, hasAlpha) - , mGL(gl) - {} - -public: - static void Copy(SharedSurface_GL* src, SharedSurface_GL* dest, - SurfaceFactory_GL* factory); - - static SharedSurface_GL* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->APIType() == APITypeT::OpenGL); - - return (SharedSurface_GL*)surf; - } - - virtual void LockProd(); - virtual void UnlockProd(); - - GLContext* GL() const { - return mGL; - } -}; - -class SurfaceFactory_GL - : public gfx::SurfaceFactory -{ -protected: - typedef struct gfx::SurfaceCaps SurfaceCaps; - typedef class gfx::SurfaceFactory SurfaceFactory; - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SharedSurfaceType SharedSurfaceType; - - GLContext* const mGL; - const GLFormats mFormats; - - SurfaceCaps mDrawCaps; - SurfaceCaps mReadCaps; - - // This uses ChooseBufferBits to pick drawBits/readBits. - SurfaceFactory_GL(GLContext* gl, - SharedSurfaceType type, - const SurfaceCaps& caps); - - virtual void ChooseBufferBits(const SurfaceCaps& caps, - SurfaceCaps& drawCaps, - SurfaceCaps& readCaps) const; - -public: - GLContext* GL() const { - return mGL; - } - - const GLFormats& Formats() const { - return mFormats; - } - - const SurfaceCaps& DrawCaps() const { - return mDrawCaps; - } - - const SurfaceCaps& ReadCaps() const { - return mReadCaps; - } -}; - -// For readback and bootstrapping: -class SharedSurface_Basic - : public SharedSurface_GL -{ -public: - static SharedSurface_Basic* Create(GLContext* gl, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha); - - static SharedSurface_Basic* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::Basic); - - return (SharedSurface_Basic*)surf; - } - -protected: - const GLuint mTex; - nsRefPtr mData; - - SharedSurface_Basic(GLContext* gl, - const gfxIntSize& size, - bool hasAlpha, - gfxASurface::gfxImageFormat format, - GLuint tex); - -public: - virtual ~SharedSurface_Basic(); - - virtual void LockProdImpl() {} - virtual void UnlockProdImpl() {} - - - virtual void Fence(); - - virtual bool WaitSync() { - // Since we already store the data in Fence, we're always done already. - return true; - } - - - virtual GLuint Texture() const { - return mTex; - } - - // Implementation-specific functions below: - gfxImageSurface* GetData() { - return mData; - } -}; - -class SurfaceFactory_Basic - : public SurfaceFactory_GL -{ -public: - SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps) - : SurfaceFactory_GL(gl, SharedSurfaceType::Basic, caps) - {} - - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha); - } -}; - - -// Using shared GL textures: -class SharedSurface_GLTexture - : public SharedSurface_GL -{ -public: - static SharedSurface_GLTexture* Create(GLContext* prodGL, - GLContext* consGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha); - - static SharedSurface_GLTexture* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::GLTextureShare); - - return (SharedSurface_GLTexture*)surf; - } - -protected: - GLContext* const mConsGL; - const GLuint mTex; - GLsync mSync; - - SharedSurface_GLTexture(GLContext* prodGL, - GLContext* consGL, - const gfxIntSize& size, - bool hasAlpha, - GLuint tex) - : SharedSurface_GL(SharedSurfaceType::GLTextureShare, - AttachmentType::GLTexture, - prodGL, - size, - hasAlpha) - , mConsGL(consGL) - , mTex(tex) - , mSync(0) - { - } - -public: - virtual ~SharedSurface_GLTexture(); - - virtual void LockProdImpl() {} - virtual void UnlockProdImpl() {} - - - virtual void Fence(); - virtual bool WaitSync(); - - - virtual GLuint Texture() const { - return mTex; - } -}; - -class SurfaceFactory_GLTexture - : public SurfaceFactory_GL -{ -protected: - GLContext* const mConsGL; - -public: - SurfaceFactory_GLTexture(GLContext* prodGL, - GLContext* consGL, - const SurfaceCaps& caps) - : SurfaceFactory_GL(prodGL, SharedSurfaceType::GLTextureShare, caps) - , mConsGL(consGL) - {} - - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha); - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_GL_H_ */ diff --git a/libazure/src/gfx/gl/SurfaceFactory.cpp b/libazure/src/gfx/gl/SurfaceFactory.cpp deleted file mode 100644 index 9a00f29..0000000 --- a/libazure/src/gfx/gl/SurfaceFactory.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SurfaceFactory.h" - -#include "SharedSurface.h" - -namespace mozilla { -namespace gfx { - -SurfaceFactory::~SurfaceFactory() -{ - while (!mScraps.empty()) { - SharedSurface* cur = mScraps.front(); - mScraps.pop(); - - delete cur; - } -} - -SharedSurface* -SurfaceFactory::NewSharedSurface(const gfxIntSize& size) -{ - // Attempt to reuse an old surface. - while (!mScraps.empty()) { - SharedSurface* cur = mScraps.front(); - mScraps.pop(); - if (cur->Size() == size) - return cur; - - // Destroy old surfaces of the wrong size. - delete cur; - } - - SharedSurface* ret = CreateShared(size); - - return ret; -} - -// Auto-deletes surfs of the wrong type. -void -SurfaceFactory::Recycle(SharedSurface*& surf) -{ - if (!surf) - return; - - if (surf->Type() == mType) { - mScraps.push(surf); - } else { - delete surf; - } - - surf = nullptr; -} - -} /* namespace gfx */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SurfaceFactory.h b/libazure/src/gfx/gl/SurfaceFactory.h deleted file mode 100644 index 56f5232..0000000 --- a/libazure/src/gfx/gl/SurfaceFactory.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SURFACE_FACTORY_H_ -#define SURFACE_FACTORY_H_ - -#include -#include "SurfaceTypes.h" -#include "gfxPoint.h" - -namespace mozilla { -namespace gfx { -// Forward: -class SharedSurface; - -class SurfaceFactory -{ -protected: - SurfaceCaps mCaps; - SharedSurfaceType mType; - - SurfaceFactory(SharedSurfaceType type, const SurfaceCaps& caps) - : mCaps(caps) - , mType(type) - {} - -public: - virtual ~SurfaceFactory(); - -protected: - virtual SharedSurface* CreateShared(const gfxIntSize& size) = 0; - - std::queue mScraps; - -public: - SharedSurface* NewSharedSurface(const gfxIntSize& size); - - // Auto-deletes surfs of the wrong type. - void Recycle(SharedSurface*& surf); - - const SurfaceCaps& Caps() const { - return mCaps; - } - - SharedSurfaceType Type() const { - return mType; - } -}; - -} // namespace gfx -} // namespace mozilla - -#endif // SURFACE_FACTORY_H_ diff --git a/libazure/src/gfx/gl/SurfaceStream.cpp b/libazure/src/gfx/gl/SurfaceStream.cpp deleted file mode 100644 index 8453a09..0000000 --- a/libazure/src/gfx/gl/SurfaceStream.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SurfaceStream.h" - -#include "gfxPoint.h" -#include "SharedSurface.h" -#include "SurfaceFactory.h" -#include "GeckoProfiler.h" - -namespace mozilla { -namespace gfx { - -SurfaceStreamType -SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc, - bool preserveBuffer) -{ - if (omtc == SurfaceStream::OffMainThread) { - if (preserveBuffer) - return SurfaceStreamType::TripleBuffer_Copy; - else - return SurfaceStreamType::TripleBuffer_Async; - } else { - if (preserveBuffer) - return SurfaceStreamType::SingleBuffer; - else - return SurfaceStreamType::TripleBuffer; - } -} - -SurfaceStream* -SurfaceStream::CreateForType(SurfaceStreamType type, SurfaceStream* prevStream) -{ - switch (type) { - case SurfaceStreamType::SingleBuffer: - return new SurfaceStream_SingleBuffer(prevStream); - case SurfaceStreamType::TripleBuffer_Copy: - return new SurfaceStream_TripleBuffer_Copy(prevStream); - case SurfaceStreamType::TripleBuffer_Async: - return new SurfaceStream_TripleBuffer_Async(prevStream); - case SurfaceStreamType::TripleBuffer: - return new SurfaceStream_TripleBuffer(prevStream); - default: - MOZ_NOT_REACHED("Invalid Type."); - return nullptr; - } -} - -void -SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& size, - SharedSurface*& surf) -{ - MOZ_ASSERT(!surf); - surf = factory->NewSharedSurface(size); - - if (surf) - mSurfaces.insert(surf); -} - -void -SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf) -{ - if (surf) { - mSurfaces.erase(surf); - factory->Recycle(surf); - } - MOZ_ASSERT(!surf); -} - -void -SurfaceStream::Delete(SharedSurface*& surf) -{ - if (surf) { - mSurfaces.erase(surf); - delete surf; - surf = nullptr; - } - MOZ_ASSERT(!surf); -} - -SharedSurface* -SurfaceStream::Surrender(SharedSurface*& surf) -{ - SharedSurface* ret = surf; - - if (surf) { - mSurfaces.erase(surf); - surf = nullptr; - } - MOZ_ASSERT(!surf); - - return ret; -} - -SharedSurface* -SurfaceStream::Absorb(SharedSurface*& surf) -{ - SharedSurface* ret = surf; - - if (surf) { - mSurfaces.insert(surf); - surf = nullptr; - } - MOZ_ASSERT(!surf); - - return ret; -} - -void -SurfaceStream::Scrap(SharedSurface*& scrap) -{ - if (scrap) { - mScraps.push(scrap); - scrap = nullptr; - } - MOZ_ASSERT(!scrap); -} - -void -SurfaceStream::RecycleScraps(SurfaceFactory* factory) -{ - while (!mScraps.empty()) { - SharedSurface* cur = mScraps.top(); - mScraps.pop(); - - Recycle(factory, cur); - } -} - - - -SurfaceStream::~SurfaceStream() -{ - Delete(mProducer); - - while (!mScraps.empty()) { - SharedSurface* cur = mScraps.top(); - mScraps.pop(); - - Delete(cur); - } - - MOZ_ASSERT(mSurfaces.empty()); -} - -SharedSurface* -SurfaceStream::SwapConsumer() -{ - MOZ_ASSERT(mIsAlive); - - SharedSurface* ret = SwapConsumer_NoWait(); - if (!ret) - return nullptr; - - if (!ret->WaitSync()) { - return nullptr; - } - - return ret; -} - -SharedSurface* -SurfaceStream::Resize(SurfaceFactory* factory, const gfxIntSize& size) -{ - MonitorAutoLock lock(mMonitor); - - if (mProducer) { - Scrap(mProducer); - } - - New(factory, size, mProducer); - return mProducer; -} - -SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream) - : SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream) - , mConsumer(nullptr) -{ - if (!prevStream) - return; - - SharedSurface* prevProducer = nullptr; - SharedSurface* prevConsumer = nullptr; - prevStream->SurrenderSurfaces(prevProducer, prevConsumer); - - if (prevConsumer == prevProducer) - prevConsumer = nullptr; - - mProducer = Absorb(prevProducer); - mConsumer = Absorb(prevConsumer); -} - -SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer() -{ - Delete(mConsumer); -} - -void -SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer, - SharedSurface*& consumer) -{ - mIsAlive = false; - - producer = Surrender(mProducer); - consumer = Surrender(mConsumer); - - if (!consumer) - consumer = producer; -} - -SharedSurface* -SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) -{ - MonitorAutoLock lock(mMonitor); - if (mConsumer) { - Recycle(factory, mConsumer); - } - - if (mProducer) { - // Fence now, before we start (maybe) juggling Prod around. - mProducer->Fence(); - - // Size mismatch means we need to squirrel the current Prod - // into Cons, and leave Prod empty, so it gets a new surface below. - bool needsNewBuffer = mProducer->Size() != size; - - // Even if we're the right size, if the type has changed, and we don't - // need to preserve, we should switch out for (presumedly) better perf. - if (mProducer->Type() != factory->Type() && - !factory->Caps().preserve) - { - needsNewBuffer = true; - } - - if (needsNewBuffer) { - Move(mProducer, mConsumer); - } - } - - // The old Prod (if there every was one) was invalid, - // so we need a new one. - if (!mProducer) { - New(factory, size, mProducer); - } - - return mProducer; -} - -SharedSurface* -SurfaceStream_SingleBuffer::SwapConsumer_NoWait() -{ - MonitorAutoLock lock(mMonitor); - - // Use Cons, if present. - // Otherwise, just use Prod directly. - SharedSurface* toConsume = mConsumer; - if (!toConsume) - toConsume = mProducer; - - return toConsume; -} - - - -SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream) - : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream) - , mStaging(nullptr) - , mConsumer(nullptr) -{ - if (!prevStream) - return; - - SharedSurface* prevProducer = nullptr; - SharedSurface* prevConsumer = nullptr; - prevStream->SurrenderSurfaces(prevProducer, prevConsumer); - - if (prevConsumer == prevProducer) - prevConsumer = nullptr; - - mProducer = Absorb(prevProducer); - mConsumer = Absorb(prevConsumer); -} - -SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy() -{ - Delete(mStaging); - Delete(mConsumer); -} - -void -SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer, - SharedSurface*& consumer) -{ - mIsAlive = false; - - producer = Surrender(mProducer); - consumer = Surrender(mConsumer); - - if (!consumer) - consumer = Surrender(mStaging); -} - -SharedSurface* -SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) -{ - MonitorAutoLock lock(mMonitor); - - RecycleScraps(factory); - if (mProducer) { - if (mStaging && mStaging->Type() != factory->Type()) - Recycle(factory, mStaging); - - if (!mStaging) - New(factory, mProducer->Size(), mStaging); - - if (!mStaging) - return nullptr; - - SharedSurface::Copy(mProducer, mStaging, factory); - // Fence now, before we start (maybe) juggling Prod around. - mStaging->Fence(); - - if (mProducer->Size() != size) - Recycle(factory, mProducer); - } - - // The old Prod (if there every was one) was invalid, - // so we need a new one. - if (!mProducer) { - New(factory, size, mProducer); - } - - return mProducer; -} - - -SharedSurface* -SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait() -{ - MonitorAutoLock lock(mMonitor); - - if (mStaging) { - Scrap(mConsumer); - Move(mStaging, mConsumer); - } - - return mConsumer; -} - -void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream) -{ - if (!prevStream) - return; - - SharedSurface* prevProducer = nullptr; - SharedSurface* prevConsumer = nullptr; - prevStream->SurrenderSurfaces(prevProducer, prevConsumer); - - if (prevConsumer == prevProducer) - prevConsumer = nullptr; - - mProducer = Absorb(prevProducer); - mConsumer = Absorb(prevConsumer); -} - - -SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream) - : SurfaceStream(type, prevStream) - , mStaging(nullptr) - , mConsumer(nullptr) -{ - SurfaceStream_TripleBuffer::Init(prevStream); -} - -SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream) - : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream) - , mStaging(nullptr) - , mConsumer(nullptr) -{ - SurfaceStream_TripleBuffer::Init(prevStream); -} - -SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer() -{ - Delete(mStaging); - Delete(mConsumer); -} - -void -SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer, - SharedSurface*& consumer) -{ - mIsAlive = false; - - producer = Surrender(mProducer); - consumer = Surrender(mConsumer); - - if (!consumer) - consumer = Surrender(mStaging); -} - -SharedSurface* -SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) -{ - PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer"); - - MonitorAutoLock lock(mMonitor); - if (mProducer) { - RecycleScraps(factory); - - // If WaitForCompositor succeeds, mStaging has moved to mConsumer. - // If it failed, we might have to scrap it. - if (mStaging && !WaitForCompositor()) - Scrap(mStaging); - - MOZ_ASSERT(!mStaging); - Move(mProducer, mStaging); - mStaging->Fence(); - } - - MOZ_ASSERT(!mProducer); - New(factory, size, mProducer); - - return mProducer; -} - -SharedSurface* -SurfaceStream_TripleBuffer::SwapConsumer_NoWait() -{ - MonitorAutoLock lock(mMonitor); - if (mStaging) { - Scrap(mConsumer); - Move(mStaging, mConsumer); - mMonitor.NotifyAll(); - } - - return mConsumer; -} - -SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream) - : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async, prevStream) -{ -} - -SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async() -{ -} - -bool -SurfaceStream_TripleBuffer_Async::WaitForCompositor() -{ - PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor"); - - // We are assumed to be locked - while (mStaging) - mMonitor.Wait(); - - return true; -} - -} /* namespace gfx */ -} /* namespace mozilla */ diff --git a/libazure/src/gfx/gl/SurfaceStream.h b/libazure/src/gfx/gl/SurfaceStream.h deleted file mode 100644 index a61ca53..0000000 --- a/libazure/src/gfx/gl/SurfaceStream.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SURFACESTREAM_H_ -#define SURFACESTREAM_H_ - -#include -#include -#include "mozilla/Monitor.h" -#include "mozilla/Attributes.h" -#include "gfxPoint.h" -#include "SurfaceTypes.h" - -namespace mozilla { -namespace gfx { -class SharedSurface; -class SurfaceFactory; - -// Owned by: ScreenBuffer -class SurfaceStream -{ -public: - typedef enum { - MainThread, - OffMainThread - } OMTC; - - static SurfaceStreamType ChooseGLStreamType(OMTC omtc, - bool preserveBuffer); - - static SurfaceStream* CreateForType(SurfaceStreamType type, - SurfaceStream* prevStream = nullptr); - - SurfaceStreamHandle GetShareHandle() { - return reinterpret_cast(this); - } - - static SurfaceStream* FromHandle(SurfaceStreamHandle handle) { - return (SurfaceStream*)handle; - } - - const SurfaceStreamType mType; -protected: - // |mProd| is owned by us, but can be ripped away when - // creating a new GLStream from this one. - SharedSurface* mProducer; - std::set mSurfaces; - std::stack mScraps; - mutable Monitor mMonitor; - bool mIsAlive; - - // |previous| can be null, indicating this is the first one. - // Otherwise, we pull in |mProd| from |previous| an our initial surface. - SurfaceStream(SurfaceStreamType type, SurfaceStream* prevStream) - : mType(type) - , mProducer(nullptr) - , mMonitor("SurfaceStream monitor") - , mIsAlive(true) - { - MOZ_ASSERT(!prevStream || mType != prevStream->mType, - "We should not need to create a SurfaceStream from another " - "of the same type."); - } - -public: - virtual ~SurfaceStream(); - -protected: - // These functions below are helpers to make trading buffers around easier. - // For instance, using Move(a,b) instead of normal assignment assures that - // we are never leaving anything hanging around, keeping things very safe. - static void Move(SharedSurface*& from, SharedSurface*& to) { - MOZ_ASSERT(!to); - to = from; - from = nullptr; - } - - void New(SurfaceFactory* factory, const gfxIntSize& size, - SharedSurface*& surf); - void Delete(SharedSurface*& surf); - void Recycle(SurfaceFactory* factory, SharedSurface*& surf); - - // Surrender control of a surface, and return it for use elsewhere. - SharedSurface* Surrender(SharedSurface*& surf); - // Absorb control of a surface from elsewhere, clears its old location. - SharedSurface* Absorb(SharedSurface*& surf); - - // For holding on to surfaces we don't need until we can return them to the - // Producer's factory via SurfaceFactory::Recycle. - // Not thread-safe. - void Scrap(SharedSurface*& scrap); - - // Not thread-safe. - void RecycleScraps(SurfaceFactory* factory); - -public: - /* Note that ownership of the returned surfaces below - * transfers to the caller. - * SwapProd returns null on failure. Returning null doesn't mean nothing - * happened, but rather that a surface allocation failed. After returning - * null, we must be able to call SwapProducer again with better args - * and have everything work again. - * One common failure is asking for a too-large |size|. - */ - virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) = 0; - - virtual SharedSurface* Resize(SurfaceFactory* factory, const gfxIntSize& size); - -protected: - // SwapCons will return the same surface more than once, - // if nothing new has been published. - virtual SharedSurface* SwapConsumer_NoWait() = 0; - -public: - virtual SharedSurface* SwapConsumer(); - - virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer) = 0; -}; - -// Not thread-safe. Don't use cross-threads. -class SurfaceStream_SingleBuffer - : public SurfaceStream -{ -protected: - SharedSurface* mConsumer; // Only present after resize-swap. - -public: - SurfaceStream_SingleBuffer(SurfaceStream* prevStream); - virtual ~SurfaceStream_SingleBuffer(); - - /* Since we're non-OMTC, we know the order of execution here: - * SwapProd gets called in UpdateSurface, followed by - * SwapCons being called in Render. - */ - virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); - - virtual SharedSurface* SwapConsumer_NoWait(); - - virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer); -}; - -// Our hero for preserveDrawingBuffer=true. -class SurfaceStream_TripleBuffer_Copy - : public SurfaceStream -{ -protected: - SharedSurface* mStaging; - SharedSurface* mConsumer; - -public: - SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream); - virtual ~SurfaceStream_TripleBuffer_Copy(); - - virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); - - virtual SharedSurface* SwapConsumer_NoWait(); - - virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer); -}; - - -class SurfaceStream_TripleBuffer - : public SurfaceStream -{ -protected: - SharedSurface* mStaging; - SharedSurface* mConsumer; - - // Returns true if we were able to wait, false if not - virtual bool WaitForCompositor() { return false; } - - // To support subclasses initializing the mType. - SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream); - -public: - SurfaceStream_TripleBuffer(SurfaceStream* prevStream); - virtual ~SurfaceStream_TripleBuffer(); - -private: - // Common constructor code. - void Init(SurfaceStream* prevStream); - -public: - // Done writing to prod, swap prod and staging - virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); - - virtual SharedSurface* SwapConsumer_NoWait(); - - virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer); -}; - -class SurfaceStream_TripleBuffer_Async - : public SurfaceStream_TripleBuffer -{ -protected: - virtual bool WaitForCompositor(); - -public: - SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream); - virtual ~SurfaceStream_TripleBuffer_Async(); -}; - - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SURFACESTREAM_H_ */ diff --git a/libazure/src/gfx/gl/SurfaceTypes.h b/libazure/src/gfx/gl/SurfaceTypes.h deleted file mode 100644 index d4f588c..0000000 --- a/libazure/src/gfx/gl/SurfaceTypes.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SURFACE_TYPES_H_ -#define SURFACE_TYPES_H_ - -#include "mozilla/TypedEnum.h" -#include "mozilla/StandardInteger.h" - -#include - -namespace mozilla { -namespace gfx { - -typedef uintptr_t SurfaceStreamHandle; - -struct SurfaceCaps -{ - bool any; - bool color, alpha; - bool bpp16; - bool depth, stencil; - bool antialias; - bool preserve; - - SurfaceCaps() { - Clear(); - } - - void Clear() { - std::memset(this, 0, sizeof(SurfaceCaps)); - } - - // We can't use just 'RGB' here, since it's an ancient Windows macro. - static SurfaceCaps ForRGB() { - SurfaceCaps caps; - - caps.color = true; - - return caps; - } - - static SurfaceCaps ForRGBA() { - SurfaceCaps caps; - - caps.color = true; - caps.alpha = true; - - return caps; - } - - static SurfaceCaps Any() { - SurfaceCaps caps; - - caps.any = true; - - return caps; - } -}; - -MOZ_BEGIN_ENUM_CLASS(SharedSurfaceType, uint8_t) - Unknown = 0, - - Basic, - GLTextureShare, - EGLImageShare, - EGLSurfaceANGLE, - DXGLInterop, - DXGLInterop2, - Gralloc, - - Max -MOZ_END_ENUM_CLASS(SharedSurfaceType) - - -MOZ_BEGIN_ENUM_CLASS(SurfaceStreamType, uint8_t) - SingleBuffer, - TripleBuffer_Copy, - TripleBuffer_Async, - TripleBuffer, - Max -MOZ_END_ENUM_CLASS(SurfaceStreamType) - - -MOZ_BEGIN_ENUM_CLASS(APITypeT, uint8_t) - Generic = 0, - - OpenGL, - - Max -MOZ_END_ENUM_CLASS(APITypeT) - - -MOZ_BEGIN_ENUM_CLASS(AttachmentType, uint8_t) - Screen = 0, - - GLTexture, - GLRenderbuffer, - - Max -MOZ_END_ENUM_CLASS(AttachmentType) - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SURFACE_TYPES_H_ */ diff --git a/libazure/src/gfx/gl/WGLLibrary.h b/libazure/src/gfx/gl/WGLLibrary.h deleted file mode 100644 index d16e453..0000000 --- a/libazure/src/gfx/gl/WGLLibrary.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContext.h" - -namespace mozilla { -namespace gl { - -class WGLLibrary -{ -public: - WGLLibrary() - : mInitialized(false), - mOGLLibrary(nullptr), - mHasRobustness(false), - mWindow (0), - mWindowDC(0), - mWindowGLContext(0), - mWindowPixelFormat (0), - mUseDoubleBufferedWindows(false), - mLibType(OPENGL_LIB) - {} - - enum LibraryType - { - OPENGL_LIB = 0, - MESA_LLVMPIPE_LIB = 1, - LIBS_MAX - }; - - typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC); - PFNWGLCREATECONTEXTPROC fCreateContext; - typedef BOOL (GLAPIENTRY * PFNWGLDELETECONTEXTPROC) (HGLRC); - PFNWGLDELETECONTEXTPROC fDeleteContext; - typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC); - PFNWGLMAKECURRENTPROC fMakeCurrent; - typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR); - PFNWGLGETPROCADDRESSPROC fGetProcAddress; - typedef HGLRC (GLAPIENTRY * PFNWGLGETCURRENTCONTEXT) (void); - PFNWGLGETCURRENTCONTEXT fGetCurrentContext; - typedef HDC (GLAPIENTRY * PFNWGLGETCURRENTDC) (void); - PFNWGLGETCURRENTDC fGetCurrentDC; - typedef BOOL (GLAPIENTRY * PFNWGLSHARELISTS) (HGLRC oldContext, HGLRC newContext); - PFNWGLSHARELISTS fShareLists; - - typedef HANDLE (WINAPI * PFNWGLCREATEPBUFFERPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList); - PFNWGLCREATEPBUFFERPROC fCreatePbuffer; - typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERPROC) (HANDLE hPbuffer); - PFNWGLDESTROYPBUFFERPROC fDestroyPbuffer; - typedef HDC (WINAPI * PFNWGLGETPBUFFERDCPROC) (HANDLE hPbuffer); - PFNWGLGETPBUFFERDCPROC fGetPbufferDC; - - typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEPROC) (HANDLE hPbuffer, int iBuffer); - PFNWGLBINDTEXIMAGEPROC fBindTexImage; - typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEPROC) (HANDLE hPbuffer, int iBuffer); - PFNWGLRELEASETEXIMAGEPROC fReleaseTexImage; - - typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); - PFNWGLCHOOSEPIXELFORMATPROC fChoosePixelFormat; - typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues); - PFNWGLGETPIXELFORMATATTRIBIVPROC fGetPixelFormatAttribiv; - - typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGPROC) (HDC hdc); - PFNWGLGETEXTENSIONSSTRINGPROC fGetExtensionsString; - - typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSPROC) (HDC hdc, HGLRC hShareContext, const int *attribList); - PFNWGLCREATECONTEXTATTRIBSPROC fCreateContextAttribs; - - bool EnsureInitialized(bool aUseMesaLlvmPipe); - HWND CreateDummyWindow(HDC *aWindowDC = nullptr); - - bool HasRobustness() const { return mHasRobustness; } - bool IsInitialized() const { return mInitialized; } - HWND GetWindow() const { return mWindow; } - HDC GetWindowDC() const {return mWindowDC; } - HGLRC GetWindowGLContext() const {return mWindowGLContext; } - int GetWindowPixelFormat() const { return mWindowPixelFormat; } - bool UseDoubleBufferedWindows() const { return mUseDoubleBufferedWindows; } - LibraryType GetLibraryType() const { return mLibType; } - static LibraryType SelectLibrary(const GLContext::ContextFlags& aFlags); - -private: - bool mInitialized; - PRLibrary *mOGLLibrary; - bool mHasRobustness; - - HWND mWindow; - HDC mWindowDC; - HGLRC mWindowGLContext; - int mWindowPixelFormat; - bool mUseDoubleBufferedWindows; - LibraryType mLibType; - -}; - -// a global WGLLibrary instance -extern WGLLibrary sWGLLibrary[WGLLibrary::LIBS_MAX]; - -} /* namespace gl */ -} /* namespace mozilla */ - diff --git a/libazure/src/gfx/gl/moz.build b/libazure/src/gfx/gl/moz.build deleted file mode 100644 index 2ff4eda..0000000 --- a/libazure/src/gfx/gl/moz.build +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MODULE = 'gl' - diff --git a/libazure/src/memory/mozalloc/Makefile.in b/libazure/src/memory/mozalloc/Makefile.in deleted file mode 100644 index 62d01c4..0000000 --- a/libazure/src/memory/mozalloc/Makefile.in +++ /dev/null @@ -1,94 +0,0 @@ -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -VISIBILITY_FLAGS= -STL_FLAGS = -ifdef _MSC_VER -STL_FLAGS = -D_HAS_EXCEPTIONS=0 -endif - -LIBRARY_NAME = mozalloc -DIST_INSTALL = 1 - -ifeq (gonk,$(MOZ_WIDGET_TOOLKIT)) -FORCE_STATIC_LIB= 1 -else -FORCE_SHARED_LIB= 1 -endif - -# TODO: we do this in crashreporter and storage/src too, should be centralized -ifeq ($(OS_ARCH),Linux) -DEFINES += -DXP_LINUX -endif - -ifeq (,$(filter-out OS2,$(OS_ARCH))) -# The strndup declaration in string.h is in an ifdef __USE_GNU section -DEFINES += -D_GNU_SOURCE -endif - -EXPORTS_NAMESPACES = mozilla -EXPORTS_mozilla = \ - fallible.h \ - mozalloc.h \ - mozalloc_abort.h \ - mozalloc_macro_wrappers.h \ - mozalloc_oom.h \ - mozalloc_undef_macro_wrappers.h \ - $(NULL) - -CPPSRCS = \ - mozalloc.cpp \ - mozalloc_abort.cpp \ - mozalloc_oom.cpp \ - $(NULL) - -ifdef WRAP_STL_INCLUDES #{ -ifdef GNU_CXX #{ -EXPORTS_mozilla += throw_gcc.h -else -ifdef _MSC_VER #{ - -ifeq ($(MOZ_MSVC_STL_WRAP__RAISE),1) #{ -BUILD_MSVC_WRAPPERS = 1 -else -ifeq ($(MOZ_MSVC_STL_WRAP__Throw),1) #{ -BUILD_MSVC_WRAPPERS = 1 -endif #} -endif #} - -ifdef BUILD_MSVC_WRAPPERS #{ -EXPORTS_mozilla += \ - msvc_raise_wrappers.h \ - msvc_throw_wrapper.h \ - throw_msvc.h \ - $(NULL) - -CPPSRCS += \ - msvc_raise_wrappers.cpp \ - msvc_throw_wrapper.cpp \ - $(NULL) -endif #} - -endif #} -endif #} - -endif #} - -ifneq (,$(filter OS2 WINNT,$(OS_ARCH))) -SDK_LIBRARY = $(IMPORT_LIBRARY) -else -SDK_LIBRARY = $(SHARED_LIBRARY) -endif - -LOCAL_INCLUDES += -I$(DEPTH)/xpcom - -include $(topsrcdir)/config/rules.mk diff --git a/libazure/src/memory/mozalloc/moz.build b/libazure/src/memory/mozalloc/moz.build deleted file mode 100644 index f96aa8c..0000000 --- a/libazure/src/memory/mozalloc/moz.build +++ /dev/null @@ -1,8 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MODULE = 'mozalloc' - diff --git a/libazure/src/memory/mozalloc/mozalloc.cpp b/libazure/src/memory/mozalloc/mozalloc.cpp deleted file mode 100644 index 5da9943..0000000 --- a/libazure/src/memory/mozalloc/mozalloc.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include // for std::bad_alloc -#include - -#include - -#if defined(MALLOC_H) -# include MALLOC_H // for memalign, valloc, malloc_size, malloc_usable_size -#endif // if defined(MALLOC_H) -#include // for size_t -#include // for malloc, free -#if defined(XP_UNIX) -# include // for valloc on *BSD -#endif //if defined(XP_UNIX) - -#if defined(XP_WIN) || (defined(XP_OS2) && defined(__declspec)) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - -// Make sure that "malloc" et al. resolve to their libc variants. -#define MOZALLOC_DONT_DEFINE_MACRO_WRAPPERS -#include "mozilla/mozalloc.h" -#include "mozilla/mozalloc_oom.h" // for mozalloc_handle_oom - -/* Windows doesn't have malloc_usable_size, but jemalloc has */ -#if defined(MOZ_MEMORY_WINDOWS) -extern "C" size_t malloc_usable_size(const void *ptr); -#endif - -#ifdef __GNUC__ -#define LIKELY(x) (__builtin_expect(!!(x), 1)) -#define UNLIKELY(x) (__builtin_expect(!!(x), 0)) -#else -#define LIKELY(x) (x) -#define UNLIKELY(x) (x) -#endif - -void -moz_free(void* ptr) -{ - free(ptr); -} - -void* -moz_xmalloc(size_t size) -{ - void* ptr = malloc(size); - if (UNLIKELY(!ptr && size)) { - mozalloc_handle_oom(size); - return moz_xmalloc(size); - } - return ptr; -} -void* -moz_malloc(size_t size) -{ - return malloc(size); -} - -void* -moz_xcalloc(size_t nmemb, size_t size) -{ - void* ptr = calloc(nmemb, size); - if (UNLIKELY(!ptr && nmemb && size)) { - mozalloc_handle_oom(size); - return moz_xcalloc(nmemb, size); - } - return ptr; -} -void* -moz_calloc(size_t nmemb, size_t size) -{ - return calloc(nmemb, size); -} - -void* -moz_xrealloc(void* ptr, size_t size) -{ - void* newptr = realloc(ptr, size); - if (UNLIKELY(!newptr && size)) { - mozalloc_handle_oom(size); - return moz_xrealloc(ptr, size); - } - return newptr; -} -void* -moz_realloc(void* ptr, size_t size) -{ - return realloc(ptr, size); -} - -char* -moz_xstrdup(const char* str) -{ - char* dup = strdup(str); - if (UNLIKELY(!dup)) { - mozalloc_handle_oom(0); - return moz_xstrdup(str); - } - return dup; -} -char* -moz_strdup(const char* str) -{ - return strdup(str); -} - -#if defined(HAVE_STRNDUP) -char* -moz_xstrndup(const char* str, size_t strsize) -{ - char* dup = strndup(str, strsize); - if (UNLIKELY(!dup)) { - mozalloc_handle_oom(strsize); - return moz_xstrndup(str, strsize); - } - return dup; -} -char* -moz_strndup(const char* str, size_t strsize) -{ - return strndup(str, strsize); -} -#endif // if defined(HAVE_STRNDUP) - -#if defined(HAVE_POSIX_MEMALIGN) -int -moz_xposix_memalign(void **ptr, size_t alignment, size_t size) -{ - int err = posix_memalign(ptr, alignment, size); - if (UNLIKELY(err && ENOMEM == err)) { - mozalloc_handle_oom(size); - return moz_xposix_memalign(ptr, alignment, size); - } - // else: (0 == err) or (EINVAL == err) - return err; -} -int -moz_posix_memalign(void **ptr, size_t alignment, size_t size) -{ - int code = posix_memalign(ptr, alignment, size); - if (code) - return code; - -#if defined(XP_MACOSX) - // Workaround faulty OSX posix_memalign, which provides memory with the - // incorrect alignment sometimes, but returns 0 as if nothing was wrong. - size_t mask = alignment - 1; - if (((size_t)(*ptr) & mask) != 0) { - void* old = *ptr; - code = moz_posix_memalign(ptr, alignment, size); - free(old); - } -#endif - - return code; - -} -#endif // if defined(HAVE_POSIX_MEMALIGN) - -#if defined(HAVE_MEMALIGN) -void* -moz_xmemalign(size_t boundary, size_t size) -{ - void* ptr = memalign(boundary, size); - if (UNLIKELY(!ptr && EINVAL != errno)) { - mozalloc_handle_oom(size); - return moz_xmemalign(boundary, size); - } - // non-NULL ptr or errno == EINVAL - return ptr; -} -void* -moz_memalign(size_t boundary, size_t size) -{ - return memalign(boundary, size); -} -#endif // if defined(HAVE_MEMALIGN) - -#if defined(HAVE_VALLOC) -void* -moz_xvalloc(size_t size) -{ - void* ptr = valloc(size); - if (UNLIKELY(!ptr)) { - mozalloc_handle_oom(size); - return moz_xvalloc(size); - } - return ptr; -} -void* -moz_valloc(size_t size) -{ - return valloc(size); -} -#endif // if defined(HAVE_VALLOC) - -size_t -moz_malloc_usable_size(void *ptr) -{ - if (!ptr) - return 0; - -#if defined(XP_MACOSX) - return malloc_size(ptr); -#elif defined(HAVE_MALLOC_USABLE_SIZE) || defined(MOZ_MEMORY) - return malloc_usable_size(ptr); -#elif defined(XP_WIN) - return _msize(ptr); -#else - return 0; -#endif -} - -size_t moz_malloc_size_of(const void *ptr) -{ - return moz_malloc_usable_size((void *)ptr); -} - -namespace mozilla { - -const fallible_t fallible = fallible_t(); - -} // namespace mozilla diff --git a/libazure/src/memory/mozalloc/mozalloc_abort.cpp b/libazure/src/memory/mozalloc/mozalloc_abort.cpp deleted file mode 100644 index e1513f0..0000000 --- a/libazure/src/memory/mozalloc/mozalloc_abort.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if defined(XP_WIN) || defined(XP_OS2) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - -#include "mozilla/mozalloc_abort.h" - -#ifdef ANDROID -# include -#endif -#include - -#include "mozilla/Assertions.h" - -void -mozalloc_abort(const char* const msg) -{ -#ifndef ANDROID - fputs(msg, stderr); - fputs("\n", stderr); -#else - __android_log_print(ANDROID_LOG_ERROR, "Gecko", "mozalloc_abort: %s", msg); -#endif - MOZ_CRASH(); -} - -#if defined(XP_UNIX) -// Define abort() here, so that it is used instead of the system abort(). This -// lets us control the behavior when aborting, in order to get better results -// on *NIX platforms. See mozalloc_abort for details. -void abort(void) -{ - mozalloc_abort("Redirecting call to abort() to mozalloc_abort\n"); -} -#endif - diff --git a/libazure/src/memory/mozalloc/mozalloc_oom.cpp b/libazure/src/memory/mozalloc/mozalloc_oom.cpp deleted file mode 100644 index 4ad2414..0000000 --- a/libazure/src/memory/mozalloc/mozalloc_oom.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if defined(XP_WIN) || defined(XP_OS2) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - -#include "mozilla/mozalloc_abort.h" -#include "mozilla/mozalloc_oom.h" -#include "mozilla/Assertions.h" - -static mozalloc_oom_abort_handler gAbortHandler; - -#define OOM_MSG_LEADER "out of memory: 0x" -#define OOM_MSG_DIGITS "0000000000000000" // large enough for 2^64 -#define OOM_MSG_TRAILER " bytes requested" -#define OOM_MSG_FIRST_DIGIT_OFFSET sizeof(OOM_MSG_LEADER) - 1 -#define OOM_MSG_LAST_DIGIT_OFFSET sizeof(OOM_MSG_LEADER) + \ - sizeof(OOM_MSG_DIGITS) - 3 - -static const char *hex = "0123456789ABCDEF"; - -void -mozalloc_handle_oom(size_t size) -{ - char oomMsg[] = OOM_MSG_LEADER OOM_MSG_DIGITS OOM_MSG_TRAILER; - size_t i; - - // NB: this is handle_oom() stage 1, which simply aborts on OOM. - // we might proceed to a stage 2 in which an attempt is made to - // reclaim memory - - if (gAbortHandler) - gAbortHandler(size); - - MOZ_STATIC_ASSERT(OOM_MSG_FIRST_DIGIT_OFFSET > 0, - "Loop below will never terminate (i can't go below 0)"); - - // Insert size into the diagnostic message using only primitive operations - for (i = OOM_MSG_LAST_DIGIT_OFFSET; - size && i >= OOM_MSG_FIRST_DIGIT_OFFSET; i--) { - oomMsg[i] = hex[size % 16]; - size /= 16; - } - - mozalloc_abort(oomMsg); -} - -void -mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler) -{ - gAbortHandler = handler; -} diff --git a/libazure/src/memory/mozalloc/mozalloc_undef_macro_wrappers.h b/libazure/src/memory/mozalloc/mozalloc_undef_macro_wrappers.h deleted file mode 100644 index 0ab5c28..0000000 --- a/libazure/src/memory/mozalloc/mozalloc_undef_macro_wrappers.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * This header is the "anti-header" for mozalloc_macro_wrappers.h. - * Including it undefines all the macros defined by - * mozalloc_macro_wrappers.h. - */ - -#ifndef mozilla_mozalloc_macro_wrappers_h -# error "mozalloc macro wrappers haven't been defined" -#endif - -/* - * This allows the wrappers to be redefined by including - * mozalloc_macro_wrappers.h again - */ -#undef mozilla_mozalloc_macro_wrappers_h - -#undef free -#undef malloc -#undef calloc -#undef realloc -#undef strdup - -#if defined(HAVE_STRNDUP) -# undef strndup -#endif - -#if defined(HAVE_POSIX_MEMALIGN) -# undef posix_memalign -#endif - -#if defined(HAVE_MEMALIGN) -# undef memalign -#endif - -#if defined(HAVE_VALLOC) -# undef valloc -#endif diff --git a/libazure/src/memory/mozalloc/msvc_raise_wrappers.cpp b/libazure/src/memory/mozalloc/msvc_raise_wrappers.cpp deleted file mode 100644 index cbdc452..0000000 --- a/libazure/src/memory/mozalloc/msvc_raise_wrappers.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include - -#if defined(XP_WIN) || defined(XP_OS2) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - -#include "mozalloc_abort.h" - -#define MOZALLOC_DONT_WRAP_RAISE_FUNCTIONS -#include "mozilla/throw_msvc.h" - -__declspec(noreturn) static void abort_from_exception(const char* const which, - const char* const what); -static void -abort_from_exception(const char* const which, const char* const what) -{ - fprintf(stderr, "fatal: STL threw %s: ", which); - mozalloc_abort(what); -} - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -void -moz_Xinvalid_argument(const char* what) -{ - abort_from_exception("invalid_argument", what); -} - -void -moz_Xlength_error(const char* what) -{ - abort_from_exception("length_error", what); -} - -void -moz_Xout_of_range(const char* what) -{ - abort_from_exception("out_of_range", what); -} - -void -moz_Xoverflow_error(const char* what) -{ - abort_from_exception("overflow_error", what); -} - -void -moz_Xruntime_error(const char* what) -{ - abort_from_exception("runtime_error", what); -} - -} // namespace std diff --git a/libazure/src/memory/mozalloc/msvc_raise_wrappers.h b/libazure/src/memory/mozalloc/msvc_raise_wrappers.h deleted file mode 100644 index 98e233b..0000000 --- a/libazure/src/memory/mozalloc/msvc_raise_wrappers.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_msvc_raise_wrappers_h -#define mozilla_msvc_raise_wrappers_h - -#ifdef _XSTDDEF_ -# error "Unable to wrap _RAISE(); CRT _RAISE() already defined" -#endif -#ifdef _XUTILITY_ -# error "Unabled to wrap _X[exception]"(); CRT versions already declared" -#endif - -#include "mozilla/mozalloc_abort.h" - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xinvalid_argument(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xlength_error(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xout_of_range(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xoverflow_error(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xruntime_error(const char*); - -} // namespace std - -#ifndef MOZALLOC_DONT_WRAP_RAISE_FUNCTIONS - -# define _Xinvalid_argument moz_Xinvalid_argument -# define _Xlength_error moz_Xlength_error -# define _Xout_of_range moz_Xout_of_range -# define _Xoverflow_error moz_Xoverflow_error -# define _Xruntime_error moz_Xruntime_error - -# include -# include - -# undef _RAISE -# define _RAISE(x) mozalloc_abort((x).what()) - -#endif // ifndef MOZALLOC_DONT_WRAP_RAISE_FUNCTIONS - -#endif // ifndef mozilla_msvc_raise_wrappers_h diff --git a/libazure/src/memory/mozalloc/msvc_throw_wrapper.cpp b/libazure/src/memory/mozalloc/msvc_throw_wrapper.cpp deleted file mode 100644 index 6e403cf..0000000 --- a/libazure/src/memory/mozalloc/msvc_throw_wrapper.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include - -#if defined(XP_WIN) || defined(XP_OS2) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - -#include "mozilla/mozalloc_abort.h" - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -__declspec(dllexport) void mozilla_Throw(const exception& e); - -void -mozilla_Throw(const exception& e) -{ - mozalloc_abort(e.what()); -} - -} // namespace std diff --git a/libazure/src/memory/mozalloc/msvc_throw_wrapper.h b/libazure/src/memory/mozalloc/msvc_throw_wrapper.h deleted file mode 100644 index 3bdfba4..0000000 --- a/libazure/src/memory/mozalloc/msvc_throw_wrapper.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_msvc_throw_wrapper_h -#define mozilla_msvc_throw_wrapper_h - -// Define our own _Throw because the Win2k CRT doesn't export it. -# ifdef _EXCEPTION_ -# error "Unable to wrap _Throw(); CRT _Throw() already declared" -# endif -# define _Throw mozilla_Throw -# include - -#endif // ifndef mozilla_msvc_throw_wrapper_h diff --git a/libazure/src/memory/mozalloc/throw_gcc.h b/libazure/src/memory/mozalloc/throw_gcc.h deleted file mode 100644 index 65a96ab..0000000 --- a/libazure/src/memory/mozalloc/throw_gcc.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_throw_gcc_h -#define mozilla_throw_gcc_h - -#include "mozilla/Attributes.h" -#include "mozilla/Util.h" - -#include // snprintf -#include // strerror - -// For gcc, we define these inline to abort so that we're absolutely -// certain that (i) no exceptions are thrown from Gecko; (ii) these -// errors are always terminal and caught by breakpad. - -#include "mozilla/mozalloc_abort.h" - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_bad_exception(void) -{ - mozalloc_abort("fatal: STL threw bad_exception"); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_bad_alloc(void) -{ - mozalloc_abort("fatal: STL threw bad_alloc"); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_bad_cast(void) -{ - mozalloc_abort("fatal: STL threw bad_cast"); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_bad_typeid(void) -{ - mozalloc_abort("fatal: STL threw bad_typeid"); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_logic_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_domain_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_invalid_argument(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_length_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_out_of_range(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_runtime_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_range_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_overflow_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_underflow_error(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_ios_failure(const char* msg) -{ - mozalloc_abort(msg); -} - -MOZ_NORETURN MOZ_ALWAYS_INLINE void -__throw_system_error(int err) -{ - char error[128]; - snprintf(error, sizeof(error)-1, - "fatal: STL threw system_error: %s (%d)", strerror(err), err); - mozalloc_abort(error); -} - -} // namespace std - -#endif // mozilla_throw_gcc_h diff --git a/libazure/src/memory/mozalloc/throw_msvc.h b/libazure/src/memory/mozalloc/throw_msvc.h deleted file mode 100644 index ef24fb0..0000000 --- a/libazure/src/memory/mozalloc/throw_msvc.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_throw_msvc_h -#define mozilla_throw_msvc_h - -#if defined(MOZ_MSVC_STL_WRAP__RAISE) -# include "msvc_raise_wrappers.h" -#elif defined(MOZ_MSVC_STL_WRAP__Throw) -# include "msvc_throw_wrapper.h" -#else -# error "Unknown STL wrapper tactic" -#endif - -#endif // mozilla_throw_msvc_h diff --git a/libazure/src/mfbt/BloomFilter.h b/libazure/src/mfbt/BloomFilter.h deleted file mode 100644 index 8680ef2..0000000 --- a/libazure/src/mfbt/BloomFilter.h +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * A counting Bloom filter implementation. This allows consumers to - * do fast probabilistic "is item X in set Y?" testing which will - * never answer "no" when the correct answer is "yes" (but might - * incorrectly answer "yes" when the correct answer is "no"). - */ - -#ifndef mozilla_BloomFilter_h_ -#define mozilla_BloomFilter_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Likely.h" -#include "mozilla/StandardInteger.h" -#include "mozilla/Util.h" - -#include - -namespace mozilla { - -/* - * This class implements a counting Bloom filter as described at - * , with - * 8-bit counters. This allows quick probabilistic answers to the - * question "is object X in set Y?" where the contents of Y might not - * be time-invariant. The probabilistic nature of the test means that - * sometimes the answer will be "yes" when it should be "no". If the - * answer is "no", then X is guaranteed not to be in Y. - * - * The filter is parametrized on KeySize, which is the size of the key - * generated by each of hash functions used by the filter, in bits, - * and the type of object T being added and removed. T must implement - * a |uint32_t hash() const| method which returns a uint32_t hash key - * that will be used to generate the two separate hash functions for - * the Bloom filter. This hash key MUST be well-distributed for good - * results! KeySize is not allowed to be larger than 16. - * - * The filter uses exactly 2**KeySize bytes of memory. From now on we - * will refer to the memory used by the filter as M. - * - * The expected rate of incorrect "yes" answers depends on M and on - * the number N of objects in set Y. As long as N is small compared - * to M, the rate of such answers is expected to be approximately - * 4*(N/M)**2 for this filter. In practice, if Y has a few hundred - * elements then using a KeySize of 12 gives a reasonably low - * incorrect answer rate. A KeySize of 12 has the additional benefit - * of using exactly one page for the filter in typical hardware - * configurations. - */ - -template -class BloomFilter -{ - /* - * A counting Bloom filter with 8-bit counters. For now we assume - * that having two hash functions is enough, but we may revisit that - * decision later. - * - * The filter uses an array with 2**KeySize entries. - * - * Assuming a well-distributed hash function, a Bloom filter with - * array size M containing N elements and - * using k hash function has expected false positive rate exactly - * - * $ (1 - (1 - 1/M)^{kN})^k $ - * - * because each array slot has a - * - * $ (1 - 1/M)^{kN} $ - * - * chance of being 0, and the expected false positive rate is the - * probability that all of the k hash functions will hit a nonzero - * slot. - * - * For reasonable assumptions (M large, kN large, which should both - * hold if we're worried about false positives) about M and kN this - * becomes approximately - * - * $$ (1 - \exp(-kN/M))^k $$ - * - * For our special case of k == 2, that's $(1 - \exp(-2N/M))^2$, - * or in other words - * - * $$ N/M = -0.5 * \ln(1 - \sqrt(r)) $$ - * - * where r is the false positive rate. This can be used to compute - * the desired KeySize for a given load N and false positive rate r. - * - * If N/M is assumed small, then the false positive rate can - * further be approximated as 4*N^2/M^2. So increasing KeySize by - * 1, which doubles M, reduces the false positive rate by about a - * factor of 4, and a false positive rate of 1% corresponds to - * about M/N == 20. - * - * What this means in practice is that for a few hundred keys using a - * KeySize of 12 gives false positive rates on the order of 0.25-4%. - * - * Similarly, using a KeySize of 10 would lead to a 4% false - * positive rate for N == 100 and to quite bad false positive - * rates for larger N. - */ - public: - BloomFilter() { - MOZ_STATIC_ASSERT(KeySize <= keyShift, "KeySize too big"); - - // Should we have a custom operator new using calloc instead and - // require that we're allocated via the operator? - clear(); - } - - /* - * Clear the filter. This should be done before reusing it, because - * just removing all items doesn't clear counters that hit the upper - * bound. - */ - void clear(); - - /* - * Add an item to the filter. - */ - void add(const T* t); - - /* - * Remove an item from the filter. - */ - void remove(const T* t); - - /* - * Check whether the filter might contain an item. This can - * sometimes return true even if the item is not in the filter, - * but will never return false for items that are actually in the - * filter. - */ - bool mightContain(const T* t) const; - - /* - * Methods for add/remove/contain when we already have a hash computed - */ - void add(uint32_t hash); - void remove(uint32_t hash); - bool mightContain(uint32_t hash) const; - - private: - static const size_t arraySize = (1 << KeySize); - static const uint32_t keyMask = (1 << KeySize) - 1; - static const uint32_t keyShift = 16; - - static uint32_t hash1(uint32_t hash) { return hash & keyMask; } - static uint32_t hash2(uint32_t hash) { return (hash >> keyShift) & keyMask; } - - uint8_t& firstSlot(uint32_t hash) { return counters[hash1(hash)]; } - uint8_t& secondSlot(uint32_t hash) { return counters[hash2(hash)]; } - const uint8_t& firstSlot(uint32_t hash) const { return counters[hash1(hash)]; } - const uint8_t& secondSlot(uint32_t hash) const { return counters[hash2(hash)]; } - - static bool full(const uint8_t& slot) { return slot == UINT8_MAX; } - - uint8_t counters[arraySize]; -}; - -template -inline void -BloomFilter::clear() -{ - memset(counters, 0, arraySize); -} - -template -inline void -BloomFilter::add(uint32_t hash) -{ - uint8_t& slot1 = firstSlot(hash); - if (MOZ_LIKELY(!full(slot1))) - ++slot1; - - uint8_t& slot2 = secondSlot(hash); - if (MOZ_LIKELY(!full(slot2))) - ++slot2; -} - -template -MOZ_ALWAYS_INLINE void -BloomFilter::add(const T* t) -{ - uint32_t hash = t->hash(); - return add(hash); -} - -template -inline void -BloomFilter::remove(uint32_t hash) -{ - // If the slots are full, we don't know whether we bumped them to be - // there when we added or not, so just leave them full. - uint8_t& slot1 = firstSlot(hash); - if (MOZ_LIKELY(!full(slot1))) - --slot1; - - uint8_t& slot2 = secondSlot(hash); - if (MOZ_LIKELY(!full(slot2))) - --slot2; -} - -template -MOZ_ALWAYS_INLINE void -BloomFilter::remove(const T* t) -{ - uint32_t hash = t->hash(); - remove(hash); -} - -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(uint32_t hash) const -{ - // Check that all the slots for this hash contain something - return firstSlot(hash) && secondSlot(hash); -} - -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(const T* t) const -{ - uint32_t hash = t->hash(); - return mightContain(hash); -} - -} // namespace mozilla - -#endif /* mozilla_BloomFilter_h_ */ diff --git a/libazure/src/mfbt/Char16.h b/libazure/src/mfbt/Char16.h deleted file mode 100644 index c6f9f87..0000000 --- a/libazure/src/mfbt/Char16.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Implements a UTF-16 character type. */ - -#ifndef mozilla_Char16_h_ -#define mozilla_Char16_h_ - -#include "mozilla/Assertions.h" - -/* - * C11 and C++11 introduce a char16_t type and support for UTF-16 string and - * character literals. C++11's char16_t is a distinct builtin type. C11's - * char16_t is a typedef for uint_least16_t. Technically, char16_t is a 16-bit - * code unit of a Unicode code point, not a "character". - * - * For now, Char16.h only supports C++ because we don't want mix different C - * and C++ definitions of char16_t in the same code base. - */ - -#ifdef _MSC_VER - /* - * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h - * typedefs char16_t as an unsigned short. We would like to alias char16_t - * to Windows's 16-bit wchar_t so we can declare UTF-16 literals as constant - * expressions (and pass char16_t pointers to Windows APIs). We #define our - * char16_t as a macro to override yval.h's typedef of the same name. - */ -# define MOZ_UTF16_HELPER(s) L##s -# include -# define char16_t wchar_t -#elif defined(__cplusplus) && \ - (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) - /* C++11 has a builtin char16_t type. */ -# define MOZ_UTF16_HELPER(s) u##s -#else -# error "Char16.h requires C++11 (or something like it) for UTF-16 support." -#endif - -/* - * Macro arguments used in concatenation or stringification won't be expanded. - * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to - * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper - * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro - * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the - * CPP manual for a more accurate and precise explanation. - */ -#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) - -MOZ_STATIC_ASSERT(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); -MOZ_STATIC_ASSERT(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); -MOZ_STATIC_ASSERT(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); - -#endif /* mozilla_Char16_h_ */ diff --git a/libazure/src/mfbt/DebugOnly.h b/libazure/src/mfbt/DebugOnly.h deleted file mode 100644 index 1f78ed7..0000000 --- a/libazure/src/mfbt/DebugOnly.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Provides DebugOnly, a type for variables used only in debug builds (i.e. by - * assertions). - */ - -#ifndef mozilla_DebugOnly_h_ -#define mozilla_DebugOnly_h_ - -namespace mozilla { - -/** - * DebugOnly contains a value of type T, but only in debug builds. In release - * builds, it does not contain a value. This helper is intended to be used with - * MOZ_ASSERT()-style macros, allowing one to write: - * - * DebugOnly check = func(); - * MOZ_ASSERT(check); - * - * more concisely than declaring |check| conditional on #ifdef DEBUG, but also - * without allocating storage space for |check| in release builds. - * - * DebugOnly instances can only be coerced to T in debug builds. In release - * builds they don't have a value, so type coercion is not well defined. - */ -template -class DebugOnly -{ - public: -#ifdef DEBUG - T value; - - DebugOnly() { } - DebugOnly(const T& other) : value(other) { } - DebugOnly(const DebugOnly& other) : value(other.value) { } - DebugOnly& operator=(const T& rhs) { - value = rhs; - return *this; - } - void operator++(int) { - value++; - } - void operator--(int) { - value--; - } - - T* operator&() { return &value; } - - operator T&() { return value; } - operator const T&() const { return value; } - - T& operator->() { return value; } - -#else - DebugOnly() { } - DebugOnly(const T&) { } - DebugOnly(const DebugOnly&) { } - DebugOnly& operator=(const T&) { return *this; } - void operator++(int) { } - void operator--(int) { } -#endif - - /* - * DebugOnly must always have a destructor or else it will - * generate "unused variable" warnings, exactly what it's intended - * to avoid! - */ - ~DebugOnly() {} -}; - -} - -#endif /* mozilla_DebugOnly_h_ */ diff --git a/libazure/src/mfbt/Endian.h b/libazure/src/mfbt/Endian.h deleted file mode 100644 index 5d2f905..0000000 --- a/libazure/src/mfbt/Endian.h +++ /dev/null @@ -1,639 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Functions for reading and writing integers in various endiannesses. */ - -/* - * The classes LittleEndian and BigEndian expose static methods for - * reading and writing 16-, 32-, and 64-bit signed and unsigned integers - * in their respective endianness. The naming scheme is: - * - * {Little,Big}Endian::{read,write}{Uint,Int} - * - * For instance, LittleEndian::readInt32 will read a 32-bit signed - * integer from memory in little endian format. Similarly, - * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory - * in big-endian format. - * - * The class NativeEndian exposes methods for conversion of existing - * data to and from the native endianness. These methods are intended - * for cases where data needs to be transferred, serialized, etc. - * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. - * Bulk conversion functions are also provided which optimize the - * no-conversion-needed case: - * - * - copyAndSwap{To,From}{Little,Big}Endian; - * - swap{To,From}{Little,Big}EndianInPlace. - * - * The *From* variants are intended to be used for reading data and the - * *To* variants for writing data. - * - * Methods on NativeEndian work with integer data of any type. - * Floating-point data is not supported. - * - * For clarity in networking code, "Network" may be used as a synonym - * for "Big" in any of the above methods or class names. - * - * As an example, reading a file format header whose fields are stored - * in big-endian format might look like: - * - * class ExampleHeader - * { - * private: - * uint32_t magic; - * uint32_t length; - * uint32_t totalRecords; - * uint64_t checksum; - * - * public: - * ExampleHeader(const void* data) { - * const uint8_t* ptr = static_cast(data); - * magic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * length = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * totalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * checksum = BigEndian::readUint64(ptr); - * } - * ... - * }; - */ - -#ifndef mozilla_Endian_h_ -#define mozilla_Endian_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Compiler.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/StandardInteger.h" -#include "mozilla/TypeTraits.h" - -#include - -#if defined(_MSC_VER) && _MSC_VER >= 1300 -# include -# pragma intrinsic(_byteswap_ushort) -# pragma intrinsic(_byteswap_ulong) -# pragma intrinsic(_byteswap_uint64) -#endif - -#if defined(_WIN64) -# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(_WIN32) -# if defined(_M_IX86) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(__APPLE__) -# if __LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# endif -#elif defined(__GNUC__) && \ - defined(__BYTE_ORDER__) && \ - defined(__ORDER_LITTLE_ENDIAN__) && \ - defined(__ORDER_BIG_ENDIAN__) - /* - * Some versions of GCC provide architecture-independent macros for - * this. Yes, there are more than two values for __BYTE_ORDER__. - */ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# else -# error "Can't handle mixed-endian architectures" -# endif -/* - * We can't include useful headers like or - * here because they're not present on all platforms. Instead we have - * this big conditional that ideally will catch all the interesting - * cases. - */ -#elif defined(__sparc) || defined(__sparc__) || \ - defined(_POWER) || defined(__powerpc__) || \ - defined(__ppc__) || defined(__hppa) || \ - defined(_MIPSEB) || defined(__ARMEB__) || \ - defined(__s390__) || \ - (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ - (defined(__ia64) && defined(__BIG_ENDIAN__)) -# define MOZ_BIG_ENDIAN 1 -#elif defined(__i386) || defined(__i386__) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_MIPSEL) || defined(__ARMEL__) || \ - defined(__alpha__) || \ - (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ - (defined(__ia64) && !defined(__BIG_ENDIAN__)) -# define MOZ_LITTLE_ENDIAN 1 -#endif - -#if MOZ_BIG_ENDIAN -# define MOZ_LITTLE_ENDIAN 0 -#elif MOZ_LITTLE_ENDIAN -# define MOZ_BIG_ENDIAN 0 -#else -# error "Cannot determine endianness" -#endif - -#if defined(__clang__) -# if __has_builtin(__builtin_bswap16) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(__GNUC__) -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(_MSC_VER) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort -#endif - -namespace mozilla { - -namespace detail { - -/* - * We need wrappers here because free functions with default template - * arguments and/or partial specialization of function templates are not - * supported by all the compilers we use. - */ -template -struct Swapper; - -template -struct Swapper -{ - static T swap(T value) - { -#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) - return MOZ_HAVE_BUILTIN_BYTESWAP16(value); -#else - return T(((value & 0x00ff) << 8) | ((value & 0xff00) >> 8)); -#endif - } -}; - -template -struct Swapper -{ - static T swap(T value) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap32(value)); -#elif defined(_MSC_VER) - return T(_byteswap_ulong(value)); -#else - return T(((value & 0x000000ffU) << 24) | - ((value & 0x0000ff00U) << 8) | - ((value & 0x00ff0000U) >> 8) | - ((value & 0xff000000U) >> 24)); -#endif - } -}; - -template -struct Swapper -{ - static inline T swap(T value) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap64(value)); -#elif defined(_MSC_VER) - return T(_byteswap_uint64(value)); -#else - return T(((value & 0x00000000000000ffULL) << 56) | - ((value & 0x000000000000ff00ULL) << 40) | - ((value & 0x0000000000ff0000ULL) << 24) | - ((value & 0x00000000ff000000ULL) << 8) | - ((value & 0x000000ff00000000ULL) >> 8) | - ((value & 0x0000ff0000000000ULL) >> 24) | - ((value & 0x00ff000000000000ULL) >> 40) | - ((value & 0xff00000000000000ULL) >> 56)); -#endif - } -}; - -enum Endianness { Little, Big }; - -#if MOZ_BIG_ENDIAN -# define MOZ_NATIVE_ENDIANNESS detail::Big -#else -# define MOZ_NATIVE_ENDIANNESS detail::Little -#endif - -class EndianUtils -{ - /** - * Assert that the memory regions [dest, dest+count) and [src, src+count] - * do not overlap. count is given in bytes. - */ - static void assertNoOverlap(const void* dest, const void* src, size_t count) - { - DebugOnly byteDestPtr = static_cast(dest); - DebugOnly byteSrcPtr = static_cast(src); - MOZ_ASSERT((byteDestPtr < byteSrcPtr && - byteDestPtr + count <= byteSrcPtr) || - (byteSrcPtr < byteDestPtr && - byteSrcPtr + count <= byteDestPtr)); - } - - template - static void assertAligned(T* ptr) - { - MOZ_ASSERT((uintptr_t(ptr) % sizeof(T)) == 0, "Unaligned pointer!"); - } - - protected: - /** - * Return |value| converted from SourceEndian encoding to DestEndian - * encoding. - */ - template - static inline T maybeSwap(T value) - { - if (SourceEndian == DestEndian) - return value; - - return Swapper::swap(value); - } - - /** - * Convert |count| elements at |ptr| from SourceEndian encoding to - * DestEndian encoding. - */ - template - static inline void maybeSwapInPlace(T* ptr, size_t count) - { - assertAligned(ptr); - - if (SourceEndian == DestEndian) - return; - - for (size_t i = 0; i < count; i++) - ptr[i] = Swapper::swap(ptr[i]); - } - - /** - * Write |count| elements to the unaligned address |dest| in DestEndian - * format, using elements found at |src| in SourceEndian format. - */ - template - static void copyAndSwapTo(void* dest, const T* src, size_t count) - { - assertNoOverlap(dest, src, count * sizeof(T)); - assertAligned(src); - - if (SourceEndian == DestEndian) { - memcpy(dest, src, count * sizeof(T)); - return; - } - - uint8_t* byteDestPtr = static_cast(dest); - for (size_t i = 0; i < count; ++i) { - union { - T val; - uint8_t buffer[sizeof(T)]; - } u; - u.val = maybeSwap(src[i]); - memcpy(byteDestPtr, u.buffer, sizeof(T)); - byteDestPtr += sizeof(T); - } - } - - /** - * Write |count| elements to |dest| in DestEndian format, using elements - * found at the unaligned address |src| in SourceEndian format. - */ - template - static void copyAndSwapFrom(T* dest, const void* src, size_t count) - { - assertNoOverlap(dest, src, count * sizeof(T)); - assertAligned(dest); - - if (SourceEndian == DestEndian) { - memcpy(dest, src, count * sizeof(T)); - return; - } - - const uint8_t* byteSrcPtr = static_cast(src); - for (size_t i = 0; i < count; ++i) { - union { - T val; - uint8_t buffer[sizeof(T)]; - } u; - memcpy(u.buffer, byteSrcPtr, sizeof(T)); - dest[i] = maybeSwap(u.val); - byteSrcPtr += sizeof(T); - } - } -}; - -template -class Endian : private EndianUtils -{ - protected: - /** Read a uint16_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* p) { - return read(p); - } - - /** Read a uint32_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* p) { - return read(p); - } - - /** Read a uint64_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* p) { - return read(p); - } - - /** Read an int16_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* p) { - return read(p); - } - - /** Read an int32_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* p) { - return read(p); - } - - /** Read an int64_t in ThisEndian endianness from |p| and return it. */ - static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* p) { - return read(p); - } - - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeUint16(void* p, uint16_t val) { - write(p, val); - } - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeUint32(void* p, uint32_t val) { - write(p, val); - } - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeUint64(void* p, uint64_t val) { - write(p, val); - } - - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeInt16(void* p, int16_t val) { - write(p, val); - } - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeInt32(void* p, int32_t val) { - write(p, val); - } - /** Write |val| to |p| using ThisEndian endianness. */ - static void writeInt64(void* p, int64_t val) { - write(p, val); - } - - /* - * Converts a value of type T to little-endian format. - * - * This function is intended for cases where you have data in your - * native-endian format and you need it to appear in little-endian - * format for transmission. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T value) { - return maybeSwap(value); - } - /* - * Copies count values of type T starting at src to dest, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, dest and src must not overlap. - */ - template - static void copyAndSwapToLittleEndian(void* dest, const T* src, - size_t count) { - copyAndSwapTo(dest, src, count); - } - /* - * Likewise, but converts values in place. - */ - template - static void swapToLittleEndianInPlace(T* p, size_t count) { - maybeSwapInPlace(p, count); - } - - /* - * Converts a value of type T to big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T value) { - return maybeSwap(value); - } - /* - * Copies count values of type T starting at src to dest, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, dest and src must not overlap. - */ - template - static void copyAndSwapToBigEndian(void* dest, const T* src, size_t count) { - copyAndSwapTo(dest, src, count); - } - /* - * Likewise, but converts values in place. - */ - template - static void swapToBigEndianInPlace(T* p, size_t count) { - maybeSwapInPlace(p, count); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T value) { - return swapToBigEndian(value); - } - template - static void - copyAndSwapToNetworkOrder(void* dest, const T* src, size_t count) { - copyAndSwapToBigEndian(dest, src, count); - } - template - static void - swapToNetworkOrderInPlace(T* p, size_t count) { - swapToBigEndianInPlace(p, count); - } - - /* - * Converts a value of type T from little-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T value) { - return maybeSwap(value); - } - /* - * Copies count values of type T starting at src to dest, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, dest and src must not overlap. - */ - template - static void copyAndSwapFromLittleEndian(T* dest, const void* src, - size_t count) { - copyAndSwapFrom(dest, src, count); - } - /* - * Likewise, but converts values in place. - */ - template - static void swapFromLittleEndianInPlace(T* p, size_t count) { - maybeSwapInPlace(p, count); - } - - /* - * Converts a value of type T from big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T value) { - return maybeSwap(value); - } - /* - * Copies count values of type T starting at src to dest, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, dest and src must not overlap. - */ - template - static void copyAndSwapFromBigEndian(T* dest, const void* src, - size_t count) { - copyAndSwapFrom(dest, src, count); - } - /* - * Likewise, but converts values in place. - */ - template - static void swapFromBigEndianInPlace(T* p, size_t count) { - maybeSwapInPlace(p, count); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T value) { - return swapFromBigEndian(value); - } - template - static void copyAndSwapFromNetworkOrder(T* dest, const void* src, - size_t count) { - copyAndSwapFromBigEndian(dest, src, count); - } - template - static void swapFromNetworkOrderInPlace(T* p, size_t count) { - swapFromBigEndianInPlace(p, count); - } - - private: - /** - * Read a value of type T, encoded in endianness ThisEndian from |p|. - * Return that value encoded in native endianness. - */ - template - static T read(const void* p) { - union { - T val; - uint8_t buffer[sizeof(T)]; - } u; - memcpy(u.buffer, p, sizeof(T)); - return maybeSwap(u.val); - } - - /** - * Write a value of type T, in native endianness, to |p|, in ThisEndian - * endianness. - */ - template - static void write(void* p, T value) { - T tmp = maybeSwap(value); - memcpy(p, &tmp, sizeof(T)); - } - - Endian() MOZ_DELETE; - Endian(const Endian& other) MOZ_DELETE; - void operator=(const Endian& other) MOZ_DELETE; -}; - -template -class EndianReadWrite : public Endian -{ - private: - typedef Endian super; - - public: - using super::readUint16; - using super::readUint32; - using super::readUint64; - using super::readInt16; - using super::readInt32; - using super::readInt64; - using super::writeUint16; - using super::writeUint32; - using super::writeUint64; - using super::writeInt16; - using super::writeInt32; - using super::writeInt64; -}; - -} /* namespace detail */ - -class LittleEndian MOZ_FINAL : public detail::EndianReadWrite -{}; - -class BigEndian MOZ_FINAL : public detail::EndianReadWrite -{}; - -typedef BigEndian NetworkEndian; - -class NativeEndian MOZ_FINAL : public detail::Endian -{ - private: - typedef detail::Endian super; - - public: - /* - * These functions are intended for cases where you have data in your - * native-endian format and you need the data to appear in the appropriate - * endianness for transmission, serialization, etc. - */ - using super::swapToLittleEndian; - using super::copyAndSwapToLittleEndian; - using super::swapToLittleEndianInPlace; - using super::swapToBigEndian; - using super::copyAndSwapToBigEndian; - using super::swapToBigEndianInPlace; - using super::swapToNetworkOrder; - using super::copyAndSwapToNetworkOrder; - using super::swapToNetworkOrderInPlace; - - /* - * These functions are intended for cases where you have data in the - * given endianness (e.g. reading from disk or a file-format) and you - * need the data to appear in native-endian format for processing. - */ - using super::swapFromLittleEndian; - using super::copyAndSwapFromLittleEndian; - using super::swapFromLittleEndianInPlace; - using super::swapFromBigEndian; - using super::copyAndSwapFromBigEndian; - using super::swapFromBigEndianInPlace; - using super::swapFromNetworkOrder; - using super::copyAndSwapFromNetworkOrder; - using super::swapFromNetworkOrderInPlace; -}; - -#undef MOZ_NATIVE_ENDIANNESS - -} /* namespace mozilla */ - -#endif /* mozilla_Endian_h_ */ diff --git a/libazure/src/mfbt/EnumSet.h b/libazure/src/mfbt/EnumSet.h deleted file mode 100644 index b18b005..0000000 --- a/libazure/src/mfbt/EnumSet.h +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* A set abstraction for enumeration values. */ - -#ifndef mozilla_EnumSet_h -#define mozilla_EnumSet_h - -#include "mozilla/Assertions.h" -#include "mozilla/StandardInteger.h" - -namespace mozilla { - -/** - * EnumSet is a set of values defined by an enumeration. It is implemented - * using a 32 bit mask for each value so it will only work for enums with an int - * representation less than 32. It works both for enum and enum class types. - */ -template -class EnumSet -{ - public: - EnumSet() - : mBitField(0) - { } - - EnumSet(T aEnum) - : mBitField(aEnum) - { } - - EnumSet(T aEnum1, T aEnum2) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2)) - { } - - EnumSet(T aEnum1, T aEnum2, T aEnum3) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3)) - { } - - EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { } - - EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { } - - /** - * Add an element - */ - void operator+=(T aEnum) { - mBitField |= bitFor(aEnum); - } - - /** - * Add an element - */ - EnumSet operator+(T aEnum) const { - EnumSet result(*this); - result += aEnum; - return result; - } - - /** - * Union - */ - void operator+=(const EnumSet aEnumSet) { - mBitField |= aEnumSet.mBitField; - } - - /** - * Union - */ - EnumSet operator+(const EnumSet aEnumSet) const { - EnumSet result(*this); - result += aEnumSet; - return result; - } - - /** - * Remove an element - */ - void operator-=(T aEnum) { - mBitField &= ~(bitFor(aEnum)); - } - - /** - * Remove an element - */ - EnumSet operator-(T aEnum) const { - EnumSet result(*this); - result -= aEnum; - return result; - } - - /** - * Remove a set of elements - */ - void operator-=(const EnumSet aEnumSet) { - mBitField &= ~(aEnumSet.mBitField); - } - - /** - * Remove a set of elements - */ - EnumSet operator-(const EnumSet aEnumSet) const { - EnumSet result(*this); - result -= aEnumSet; - return result; - } - - /** - * Intersection - */ - void operator&=(const EnumSet aEnumSet) { - mBitField &= aEnumSet.mBitField; - } - - /** - * Intersection - */ - EnumSet operator&(const EnumSet aEnumSet) const { - EnumSet result(*this); - result &= aEnumSet; - return result; - } - - /** - * Equality - */ - - bool operator==(const EnumSet aEnumSet) const { - return mBitField == aEnumSet.mBitField; - } - - /** - * Test is an element is contained in the set - */ - bool contains(T aEnum) const { - return mBitField & bitFor(aEnum); - } - - /** - * Return the number of elements in the set - */ - - uint8_t size() { - uint8_t count = 0; - for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { - if (bitField & 1) - count++; - } - return count; - } - - private: - static uint32_t bitFor(T aEnum) { - uint32_t bitNumber(aEnum); - MOZ_ASSERT(bitNumber < 32); - return 1U << bitNumber; - } - - uint32_t mBitField; -}; - -} // namespace mozilla - -#endif // mozilla_EnumSet_h_ diff --git a/libazure/src/mfbt/FloatingPoint.h b/libazure/src/mfbt/FloatingPoint.h deleted file mode 100644 index cb1394e..0000000 --- a/libazure/src/mfbt/FloatingPoint.h +++ /dev/null @@ -1,244 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Various predicates and operations on IEEE-754 floating point types. */ - -#ifndef mozilla_FloatingPoint_h_ -#define mozilla_FloatingPoint_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/StandardInteger.h" - -/* - * It's reasonable to ask why we have this header at all. Don't isnan, - * copysign, the built-in comparison operators, and the like solve these - * problems? Unfortunately, they don't. We've found that various compilers - * (MSVC, MSVC when compiling with PGO, and GCC on OS X, at least) miscompile - * the standard methods in various situations, so we can't use them. Some of - * these compilers even have problems compiling seemingly reasonable bitwise - * algorithms! But with some care we've found algorithms that seem to not - * trigger those compiler bugs. - * - * For the aforementioned reasons, be very wary of making changes to any of - * these algorithms. If you must make changes, keep a careful eye out for - * compiler bustage, particularly PGO-specific bustage. - * - * Some users require that this file be C-compatible. Unfortunately, this means - * no mozilla namespace to contain everything, no detail namespace clarifying - * MozDoublePun to be an internal data structure, and so on. - */ - -/* - * These implementations all assume |double| is a 64-bit double format number - * type, compatible with the IEEE-754 standard. C/C++ don't require this to be - * the case. But we required this in implementations of these algorithms that - * preceded this header, so we shouldn't break anything if we continue doing so. - */ -MOZ_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), "double must be 64 bits"); - -/* - * Constant expressions in C can't refer to consts, unfortunately, so #define - * these rather than use |const uint64_t|. - */ -#define MOZ_DOUBLE_SIGN_BIT 0x8000000000000000ULL -#define MOZ_DOUBLE_EXPONENT_BITS 0x7ff0000000000000ULL -#define MOZ_DOUBLE_SIGNIFICAND_BITS 0x000fffffffffffffULL - -#define MOZ_DOUBLE_EXPONENT_BIAS 1023 -#define MOZ_DOUBLE_EXPONENT_SHIFT 52 - -MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT & MOZ_DOUBLE_EXPONENT_BITS) == 0, - "sign bit doesn't overlap exponent bits"); -MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT & MOZ_DOUBLE_SIGNIFICAND_BITS) == 0, - "sign bit doesn't overlap significand bits"); -MOZ_STATIC_ASSERT((MOZ_DOUBLE_EXPONENT_BITS & MOZ_DOUBLE_SIGNIFICAND_BITS) == 0, - "exponent bits don't overlap significand bits"); - -MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT | MOZ_DOUBLE_EXPONENT_BITS | MOZ_DOUBLE_SIGNIFICAND_BITS) - == ~(uint64_t)0, - "all bits accounted for"); - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This union is NOT a public data structure, and it is not to be used outside - * this file! - */ -union MozDoublePun { - /* - * Every way to pun the bits of a double introduces an additional layer of - * complexity, across a multitude of platforms, architectures, and ABIs. - * Use *only* uint64_t to reduce complexity. Don't add new punning here - * without discussion! - */ - uint64_t u; - double d; -}; - -/** Determines whether a double is NaN. */ -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_NaN(double d) -{ - union MozDoublePun pun; - pun.d = d; - - /* - * A double is NaN if all exponent bits are 1 and the significand contains at - * least one non-zero bit. - */ - return (pun.u & MOZ_DOUBLE_EXPONENT_BITS) == MOZ_DOUBLE_EXPONENT_BITS && - (pun.u & MOZ_DOUBLE_SIGNIFICAND_BITS) != 0; -} - -/** Determines whether a double is +Infinity or -Infinity. */ -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_INFINITE(double d) -{ - union MozDoublePun pun; - pun.d = d; - - /* Infinities have all exponent bits set to 1 and an all-0 significand. */ - return (pun.u & ~MOZ_DOUBLE_SIGN_BIT) == MOZ_DOUBLE_EXPONENT_BITS; -} - -/** Determines whether a double is not NaN or infinite. */ -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_FINITE(double d) -{ - union MozDoublePun pun; - pun.d = d; - - /* - * NaN and Infinities are the only non-finite doubles, and both have all - * exponent bits set to 1. - */ - return (pun.u & MOZ_DOUBLE_EXPONENT_BITS) != MOZ_DOUBLE_EXPONENT_BITS; -} - -/** - * Determines whether a double is negative. It is an error to call this method - * on a double which is NaN. - */ -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_NEGATIVE(double d) -{ - union MozDoublePun pun; - pun.d = d; - - MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(d), "NaN does not have a sign"); - - /* The sign bit is set if the double is negative. */ - return (pun.u & MOZ_DOUBLE_SIGN_BIT) != 0; -} - -/** Determines whether a double represents -0. */ -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_NEGATIVE_ZERO(double d) -{ - union MozDoublePun pun; - pun.d = d; - - /* Only the sign bit is set if the double is -0. */ - return pun.u == MOZ_DOUBLE_SIGN_BIT; -} - -/** Returns the exponent portion of the double. */ -static MOZ_ALWAYS_INLINE int_fast16_t -MOZ_DOUBLE_EXPONENT(double d) -{ - union MozDoublePun pun; - pun.d = d; - - /* - * The exponent component of a double is an unsigned number, biased from its - * actual value. Subtract the bias to retrieve the actual exponent. - */ - return (int_fast16_t)((pun.u & MOZ_DOUBLE_EXPONENT_BITS) >> MOZ_DOUBLE_EXPONENT_SHIFT) - - MOZ_DOUBLE_EXPONENT_BIAS; -} - -/** Returns +Infinity. */ -static MOZ_ALWAYS_INLINE double -MOZ_DOUBLE_POSITIVE_INFINITY() -{ - union MozDoublePun pun; - - /* - * Positive infinity has all exponent bits set, sign bit set to 0, and no - * significand. - */ - pun.u = MOZ_DOUBLE_EXPONENT_BITS; - return pun.d; -} - -/** Returns -Infinity. */ -static MOZ_ALWAYS_INLINE double -MOZ_DOUBLE_NEGATIVE_INFINITY() -{ - union MozDoublePun pun; - - /* - * Negative infinity has all exponent bits set, sign bit set to 1, and no - * significand. - */ - pun.u = MOZ_DOUBLE_SIGN_BIT | MOZ_DOUBLE_EXPONENT_BITS; - return pun.d; -} - -/** Constructs a NaN value with the specified sign bit and significand bits. */ -static MOZ_ALWAYS_INLINE double -MOZ_DOUBLE_SPECIFIC_NaN(int signbit, uint64_t significand) -{ - union MozDoublePun pun; - - MOZ_ASSERT(signbit == 0 || signbit == 1); - MOZ_ASSERT((significand & ~MOZ_DOUBLE_SIGNIFICAND_BITS) == 0); - MOZ_ASSERT(significand & MOZ_DOUBLE_SIGNIFICAND_BITS); - - pun.u = (signbit ? MOZ_DOUBLE_SIGN_BIT : 0) | - MOZ_DOUBLE_EXPONENT_BITS | - significand; - MOZ_ASSERT(MOZ_DOUBLE_IS_NaN(pun.d)); - return pun.d; -} - -/** - * Computes a NaN value. Do not use this method if you depend upon a particular - * NaN value being returned. - */ -static MOZ_ALWAYS_INLINE double -MOZ_DOUBLE_NaN() -{ - return MOZ_DOUBLE_SPECIFIC_NaN(0, 0xfffffffffffffULL); -} - -/** Computes the smallest non-zero positive double value. */ -static MOZ_ALWAYS_INLINE double -MOZ_DOUBLE_MIN_VALUE() -{ - union MozDoublePun pun; - pun.u = 1; - return pun.d; -} - -static MOZ_ALWAYS_INLINE int -MOZ_DOUBLE_IS_INT32(double d, int32_t* i) -{ - /* - * XXX Casting a double that doesn't truncate to int32_t, to int32_t, induces - * undefined behavior. We should definitely fix this (bug 744965), but as - * apparently it "works" in practice, it's not a pressing concern now. - */ - return !MOZ_DOUBLE_IS_NEGATIVE_ZERO(d) && d == (*i = (int32_t)d); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* mozilla_FloatingPoint_h_ */ diff --git a/libazure/src/mfbt/HashFunctions.cpp b/libazure/src/mfbt/HashFunctions.cpp deleted file mode 100644 index ddbd352..0000000 --- a/libazure/src/mfbt/HashFunctions.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Implementations of hash functions. */ - -#include "mozilla/HashFunctions.h" -#include "mozilla/Types.h" - -#include - -namespace mozilla { - -uint32_t -HashBytes(const void* bytes, size_t length) -{ - uint32_t hash = 0; - const char* b = reinterpret_cast(bytes); - - /* Walk word by word. */ - size_t i = 0; - for (; i < length - (length % sizeof(size_t)); i += sizeof(size_t)) { - /* Do an explicitly unaligned load of the data. */ - size_t data; - memcpy(&data, b + i, sizeof(size_t)); - - hash = AddToHash(hash, data, sizeof(data)); - } - - /* Get the remaining bytes. */ - for (; i < length; i++) - hash = AddToHash(hash, b[i]); - - return hash; -} - -} /* namespace mozilla */ diff --git a/libazure/src/mfbt/LinkedList.h b/libazure/src/mfbt/LinkedList.h deleted file mode 100644 index 5cfd60e..0000000 --- a/libazure/src/mfbt/LinkedList.h +++ /dev/null @@ -1,429 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* A type-safe doubly-linked list class. */ - -/* - * The classes LinkedList and LinkedListElement together form a - * convenient, type-safe doubly-linked list implementation. - * - * The class T which will be inserted into the linked list must inherit from - * LinkedListElement. A given object may be in only one linked list at a - * time. - * - * A LinkedListElement automatically removes itself from the list upon - * destruction, and a LinkedList will fatally assert in debug builds if it's - * non-empty when it's destructed. - * - * For example, you might use LinkedList in a simple observer list class as - * follows. - * - * class Observer : public LinkedListElement - * { - * public: - * void observe(char* topic) { ... } - * }; - * - * class ObserverContainer - * { - * private: - * LinkedList list; - * - * public: - * void addObserver(Observer* observer) { - * // Will assert if |observer| is part of another list. - * list.insertBack(observer); - * } - * - * void removeObserver(Observer* observer) { - * // Will assert if |observer| is not part of some list. - * observer.remove(); - * // Or, will assert if |observer| is not part of |list| specifically. - * // observer.removeFrom(list); - * } - * - * void notifyObservers(char* topic) { - * for (Observer* o = list.getFirst(); o != NULL; o = o->getNext()) - * o->Observe(topic); - * } - * }; - * - */ - -#ifndef mozilla_LinkedList_h_ -#define mozilla_LinkedList_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" - -#ifdef __cplusplus - -namespace mozilla { - -template -class LinkedList; - -template -class LinkedListElement -{ - /* - * It's convenient that we return NULL when getNext() or getPrevious() hits - * the end of the list, but doing so costs an extra word of storage in each - * linked list node (to keep track of whether |this| is the sentinel node) - * and a branch on this value in getNext/getPrevious. - * - * We could get rid of the extra word of storage by shoving the "is - * sentinel" bit into one of the pointers, although this would, of course, - * have performance implications of its own. - * - * But the goal here isn't to win an award for the fastest or slimmest - * linked list; rather, we want a *convenient* linked list. So we won't - * waste time guessing which micro-optimization strategy is best. - * - * - * Speaking of unnecessary work, it's worth addressing here why we wrote - * mozilla::LinkedList in the first place, instead of using stl::list. - * - * The key difference between mozilla::LinkedList and stl::list is that - * mozilla::LinkedList stores the prev/next pointers in the object itself, - * while stl::list stores the prev/next pointers in a list element which - * itself points to the object being stored. - * - * mozilla::LinkedList's approach makes it harder to store an object in more - * than one list. But the upside is that you can call next() / prev() / - * remove() directly on the object. With stl::list, you'd need to store a - * pointer to its iterator in the object in order to accomplish this. Not - * only would this waste space, but you'd have to remember to update that - * pointer every time you added or removed the object from a list. - * - * In-place, constant-time removal is a killer feature of doubly-linked - * lists, and supporting this painlessly was a key design criterion. - */ - - private: - LinkedListElement* next; - LinkedListElement* prev; - const bool isSentinel; - - LinkedListElement* thisDuringConstruction() { return this; } - - public: - LinkedListElement() - : next(thisDuringConstruction()), - prev(thisDuringConstruction()), - isSentinel(false) - { } - - ~LinkedListElement() { - if (!isSentinel && isInList()) - remove(); - } - - /* - * Get the next element in the list, or NULL if this is the last element in - * the list. - */ - T* getNext() { - return next->asT(); - } - const T* getNext() const { - return next->asT(); - } - - /* - * Get the previous element in the list, or NULL if this is the first element - * in the list. - */ - T* getPrevious() { - return prev->asT(); - } - const T* getPrevious() const { - return prev->asT(); - } - - /* - * Insert elem after this element in the list. |this| must be part of a - * linked list when you call setNext(); otherwise, this method will assert. - */ - void setNext(T* elem) { - MOZ_ASSERT(isInList()); - setNextUnsafe(elem); - } - - /* - * Insert elem before this element in the list. |this| must be part of a - * linked list when you call setPrevious(); otherwise, this method will - * assert. - */ - void setPrevious(T* elem) { - MOZ_ASSERT(isInList()); - setPreviousUnsafe(elem); - } - - /* - * Remove this element from the list which contains it. If this element is - * not currently part of a linked list, this method asserts. - */ - void remove() { - MOZ_ASSERT(isInList()); - - prev->next = next; - next->prev = prev; - next = this; - prev = this; - } - - /* - * Identical to remove(), but also asserts in debug builds that this element - * is in list. - */ - void removeFrom(const LinkedList& list) { - list.assertContains(asT()); - remove(); - } - - /* - * Return true if |this| part is of a linked list, and false otherwise. - */ - bool isInList() const { - MOZ_ASSERT((next == this) == (prev == this)); - return next != this; - } - - private: - friend class LinkedList; - - enum NodeKind { - NODE_KIND_NORMAL, - NODE_KIND_SENTINEL - }; - - LinkedListElement(NodeKind nodeKind) - : next(thisDuringConstruction()), - prev(thisDuringConstruction()), - isSentinel(nodeKind == NODE_KIND_SENTINEL) - { } - - /* - * Return |this| cast to T* if we're a normal node, or return NULL if we're - * a sentinel node. - */ - T* asT() { - if (isSentinel) - return NULL; - - return static_cast(this); - } - const T* asT() const { - if (isSentinel) - return NULL; - - return static_cast(this); - } - - /* - * Insert elem after this element, but don't check that this element is in - * the list. This is called by LinkedList::insertFront(). - */ - void setNextUnsafe(T* elem) { - LinkedListElement *listElem = static_cast(elem); - MOZ_ASSERT(!listElem->isInList()); - - listElem->next = this->next; - listElem->prev = this; - this->next->prev = listElem; - this->next = listElem; - } - - /* - * Insert elem before this element, but don't check that this element is in - * the list. This is called by LinkedList::insertBack(). - */ - void setPreviousUnsafe(T* elem) { - LinkedListElement* listElem = static_cast*>(elem); - MOZ_ASSERT(!listElem->isInList()); - - listElem->next = this; - listElem->prev = this->prev; - this->prev->next = listElem; - this->prev = listElem; - } - - private: - LinkedListElement& operator=(const LinkedList& other) MOZ_DELETE; - LinkedListElement(const LinkedList& other) MOZ_DELETE; -}; - -template -class LinkedList -{ - private: - LinkedListElement sentinel; - - public: - LinkedList() : sentinel(LinkedListElement::NODE_KIND_SENTINEL) { } - - ~LinkedList() { - MOZ_ASSERT(isEmpty()); - } - - /* - * Add elem to the front of the list. - */ - void insertFront(T* elem) { - /* Bypass setNext()'s this->isInList() assertion. */ - sentinel.setNextUnsafe(elem); - } - - /* - * Add elem to the back of the list. - */ - void insertBack(T* elem) { - sentinel.setPreviousUnsafe(elem); - } - - /* - * Get the first element of the list, or NULL if the list is empty. - */ - T* getFirst() { - return sentinel.getNext(); - } - const T* getFirst() const { - return sentinel.getNext(); - } - - /* - * Get the last element of the list, or NULL if the list is empty. - */ - T* getLast() { - return sentinel.getPrevious(); - } - const T* getLast() const { - return sentinel.getPrevious(); - } - - /* - * Get and remove the first element of the list. If the list is empty, - * return NULL. - */ - T* popFirst() { - T* ret = sentinel.getNext(); - if (ret) - static_cast*>(ret)->remove(); - return ret; - } - - /* - * Get and remove the last element of the list. If the list is empty, - * return NULL. - */ - T* popLast() { - T* ret = sentinel.getPrevious(); - if (ret) - static_cast*>(ret)->remove(); - return ret; - } - - /* - * Return true if the list is empty, or false otherwise. - */ - bool isEmpty() const { - return !sentinel.isInList(); - } - - /* - * Remove all the elements from the list. - * - * This runs in time linear to the list's length, because we have to mark - * each element as not in the list. - */ - void clear() { - while (popFirst()) - continue; - } - - /* - * In a debug build, make sure that the list is sane (no cycles, consistent - * next/prev pointers, only one sentinel). Has no effect in release builds. - */ - void debugAssertIsSane() const { -#ifdef DEBUG - const LinkedListElement* slow; - const LinkedListElement* fast1; - const LinkedListElement* fast2; - - /* - * Check for cycles in the forward singly-linked list using the - * tortoise/hare algorithm. - */ - for (slow = sentinel.next, - fast1 = sentinel.next->next, - fast2 = sentinel.next->next->next; - slow != sentinel && fast1 != sentinel && fast2 != sentinel; - slow = slow->next, fast1 = fast2->next, fast2 = fast1->next) - { - MOZ_ASSERT(slow != fast1); - MOZ_ASSERT(slow != fast2); - } - - /* Check for cycles in the backward singly-linked list. */ - for (slow = sentinel.prev, - fast1 = sentinel.prev->prev, - fast2 = sentinel.prev->prev->prev; - slow != sentinel && fast1 != sentinel && fast2 != sentinel; - slow = slow->prev, fast1 = fast2->prev, fast2 = fast1->prev) - { - MOZ_ASSERT(slow != fast1); - MOZ_ASSERT(slow != fast2); - } - - /* - * Check that |sentinel| is the only node in the list with - * isSentinel == true. - */ - for (const LinkedListElement* elem = sentinel.next; - elem != sentinel; - elem = elem->next) - { - MOZ_ASSERT(!elem->isSentinel); - } - - /* Check that the next/prev pointers match up. */ - const LinkedListElement* prev = sentinel; - const LinkedListElement* cur = sentinel.next; - do { - MOZ_ASSERT(cur->prev == prev); - MOZ_ASSERT(prev->next == cur); - - prev = cur; - cur = cur->next; - } while (cur != sentinel); -#endif /* ifdef DEBUG */ - } - - private: - friend class LinkedListElement; - - void assertContains(const T* t) const { -#ifdef DEBUG - for (const T* elem = getFirst(); - elem; - elem = elem->getNext()) - { - if (elem == t) - return; - } - MOZ_NOT_REACHED("element wasn't found in this list!"); -#endif - } - - LinkedList& operator=(const LinkedList& other) MOZ_DELETE; - LinkedList(const LinkedList& other) MOZ_DELETE; -}; - -} /* namespace mozilla */ - -#endif /* ifdef __cplusplus */ -#endif /* ifdef mozilla_LinkedList_h_ */ diff --git a/libazure/src/mfbt/Makefile.in b/libazure/src/mfbt/Makefile.in deleted file mode 100644 index f2acb04..0000000 --- a/libazure/src/mfbt/Makefile.in +++ /dev/null @@ -1,29 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -LIBRARY_NAME = mfbt -FORCE_STATIC_LIB = 1 -STL_FLAGS = - -# exported_headers.mk defines the headers exported by mfbt. It is included by -# mfbt itself and by the JS engine, which, when built standalone, must do the -# work to install mfbt's exported headers itself. -include $(srcdir)/exported_headers.mk - -# sources.mk defines the source files built for mfbt. It is included by mfbt -# itself and by the JS engine, which, when built standalone, must do the work -# to build mfbt sources itself. -MFBT_ROOT = $(srcdir) -include $(MFBT_ROOT)/sources.mk - -DEFINES += -DIMPL_MFBT - -include $(topsrcdir)/config/rules.mk diff --git a/libazure/src/mfbt/MathAlgorithms.h b/libazure/src/mfbt/MathAlgorithms.h deleted file mode 100644 index 0a47810..0000000 --- a/libazure/src/mfbt/MathAlgorithms.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* mfbt maths algorithms. */ - -#ifndef mozilla_MathAlgorithms_h_ -#define mozilla_MathAlgorithms_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/StandardInteger.h" -#include "mozilla/TypeTraits.h" - -#include -#include - -namespace mozilla { - -// Greatest Common Divisor -template -MOZ_ALWAYS_INLINE IntegerType -EuclidGCD(IntegerType a, IntegerType b) -{ - // Euclid's algorithm; O(N) in the worst case. (There are better - // ways, but we don't need them for the current use of this algo.) - MOZ_ASSERT(a > 0); - MOZ_ASSERT(b > 0); - - while (a != b) { - if (a > b) { - a = a - b; - } else { - b = b - a; - } - } - - return a; -} - -// Least Common Multiple -template -MOZ_ALWAYS_INLINE IntegerType -EuclidLCM(IntegerType a, IntegerType b) -{ - // Divide first to reduce overflow risk. - return (a / EuclidGCD(a, b)) * b; -} - -namespace detail { - -template -struct AllowDeprecatedAbsFixed : FalseType {}; - -template<> struct AllowDeprecatedAbsFixed : TrueType {}; -template<> struct AllowDeprecatedAbsFixed : TrueType {}; - -template -struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed {}; - -template<> struct AllowDeprecatedAbs : TrueType {}; -template<> struct AllowDeprecatedAbs : TrueType {}; - -} // namespace detail - -// DO NOT USE DeprecatedAbs. It exists only until its callers can be converted -// to Abs below, and it will be removed when all callers have been changed. -template -inline typename mozilla::EnableIf::value, T>::Type -DeprecatedAbs(const T t) -{ - // The absolute value of the smallest possible value of a signed-integer type - // won't fit in that type (on twos-complement systems -- and we're blithely - // assuming we're on such systems, for the non- types listed above), - // so assert that the input isn't that value. - // - // This is the case if: the value is non-negative; or if adding one (giving a - // value in the range [-maxvalue, 0]), then negating (giving a value in the - // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, - // (minvalue + 1) == -maxvalue). - MOZ_ASSERT(t >= 0 || - -(t + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), - "You can't negate the smallest possible negative integer!"); - return t >= 0 ? t : -t; -} - -namespace detail { - -// For now mozilla::Abs only takes intN_T, the signed natural types, and -// float/double/long double. Feel free to add overloads for other standard, -// signed types if you need them. - -template -struct AbsReturnTypeFixed; - -template<> struct AbsReturnTypeFixed { typedef uint8_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint16_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint32_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint64_t Type; }; - -template -struct AbsReturnType : AbsReturnTypeFixed {}; - -template<> struct AbsReturnType : EnableIf {}; -template<> struct AbsReturnType { typedef unsigned char Type; }; -template<> struct AbsReturnType { typedef unsigned short Type; }; -template<> struct AbsReturnType { typedef unsigned int Type; }; -template<> struct AbsReturnType { typedef unsigned long Type; }; -template<> struct AbsReturnType { typedef unsigned long long Type; }; -template<> struct AbsReturnType { typedef float Type; }; -template<> struct AbsReturnType { typedef double Type; }; -template<> struct AbsReturnType { typedef long double Type; }; - -} // namespace detail - -template -inline typename detail::AbsReturnType::Type -Abs(const T t) -{ - typedef typename detail::AbsReturnType::Type ReturnType; - return t >= 0 ? ReturnType(t) : ~ReturnType(t) + 1; -} - -template<> -inline float -Abs(const float f) -{ - return std::fabs(f); -} - -template<> -inline double -Abs(const double d) -{ - return std::fabs(d); -} - -template<> -inline long double -Abs(const long double d) -{ - return std::fabs(d); -} - -} /* namespace mozilla */ - -#endif /* mozilla_MathAlgorithms_h_ */ diff --git a/libazure/src/mfbt/PodOperations.h b/libazure/src/mfbt/PodOperations.h deleted file mode 100644 index 62480d4..0000000 --- a/libazure/src/mfbt/PodOperations.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Operations for zeroing POD types, arrays, and so on. - * - * These operations are preferable to memset, memcmp, and the like because they - * don't require remembering to multiply by sizeof(T), array lengths, and so on - * everywhere. - */ - -#ifndef mozilla_PodOperations_h -#define mozilla_PodOperations_h - -#include "mozilla/Attributes.h" -#include "mozilla/Util.h" - -#include - -namespace mozilla { - -/** Set the contents of |t| to 0. */ -template -static void -PodZero(T* t) -{ - memset(t, 0, sizeof(T)); -} - -/** Set the contents of |nelem| elements starting at |t| to 0. */ -template -static void -PodZero(T* t, size_t nelem) -{ - /* - * This function is often called with 'nelem' small; we use an inline loop - * instead of calling 'memset' with a non-constant length. The compiler - * should inline the memset call with constant size, though. - */ - for (T* end = t + nelem; t < end; t++) - memset(t, 0, sizeof(T)); -} - -/* - * Arrays implicitly convert to pointers to their first element, which is - * dangerous when combined with the above PodZero definitions. Adding an - * overload for arrays is ambiguous, so we need another identifier. The - * ambiguous overload is left to catch mistaken uses of PodZero; if you get a - * compile error involving PodZero and array types, use PodArrayZero instead. - */ -template -static void PodZero(T (&t)[N]) MOZ_DELETE; -template -static void PodZero(T (&t)[N], size_t nelem) MOZ_DELETE; - -/** Set the contents of the array |t| to zero. */ -template -static void -PodArrayZero(T (&t)[N]) -{ - memset(t, 0, N * sizeof(T)); -} - -/** - * Assign |*src| to |*dst|. The locations must not be the same and must not - * overlap. - */ -template -static void -PodAssign(T* dst, const T* src) -{ - MOZ_ASSERT(dst != src); - MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast(dst)) >= 1); - MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast(dst), src) >= 1); - memcpy(reinterpret_cast(dst), reinterpret_cast(src), sizeof(T)); -} - -/** - * Copy |nelem| T elements from |src| to |dst|. The two memory ranges must not - * overlap! - */ -template -MOZ_ALWAYS_INLINE static void -PodCopy(T* dst, const T* src, size_t nelem) -{ - MOZ_ASSERT(dst != src); - MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast(dst)) >= nelem); - MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast(dst), src) >= nelem); - - if (nelem < 128) { - /* - * Avoid using operator= in this loop, as it may have been - * intentionally deleted by the POD type. - */ - for (const T* srcend = src + nelem; src < srcend; src++, dst++) - PodAssign(dst, src); - } else { - memcpy(dst, src, nelem * sizeof(T)); - } -} - -/** - * Determine whether the |len| elements at |one| are memory-identical to the - * |len| elements at |two|. - */ -template -MOZ_ALWAYS_INLINE static bool -PodEqual(const T* one, const T* two, size_t len) -{ - if (len < 128) { - const T* p1end = one + len; - const T* p1 = one; - const T* p2 = two; - for (; p1 < p1end; p1++, p2++) { - if (*p1 != *p2) - return false; - } - return true; - } - - return !memcmp(one, two, len * sizeof(T)); -} - -} // namespace mozilla - -#endif // mozilla_PodOperations_h_ diff --git a/libazure/src/mfbt/Range.h b/libazure/src/mfbt/Range.h deleted file mode 100644 index e14594d..0000000 --- a/libazure/src/mfbt/Range.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_Range_h_ -#define mozilla_Range_h_ - -#include "mozilla/NullPtr.h" -#include "mozilla/RangedPtr.h" - -#include - -namespace mozilla { - -// Range is a tuple containing a pointer and a length. -template -class Range -{ - RangedPtr mStart; - RangedPtr mEnd; - - typedef void (Range::* ConvertibleToBool)(); - void nonNull() {} - - public: - Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {} - Range(T* p, size_t len) - : mStart(p, p, p + len), - mEnd(p + len, p, p + len) - {} - - RangedPtr start() const { return mStart; } - RangedPtr end() const { return mEnd; } - size_t length() const { return mEnd - mStart; } - - T& operator[](size_t offset) { - return mStart[offset]; - } - - operator ConvertibleToBool() const { return mStart ? &Range::nonNull : 0; } -}; - -} // namespace mozilla - -#endif // mozilla_Range_h_ - diff --git a/libazure/src/mfbt/RangedPtr.h b/libazure/src/mfbt/RangedPtr.h deleted file mode 100644 index 7ce19d0..0000000 --- a/libazure/src/mfbt/RangedPtr.h +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Implements a smart pointer asserted to remain within a range specified at - * construction. - */ - -#ifndef mozilla_RangedPtr_h_ -#define mozilla_RangedPtr_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Util.h" - -namespace mozilla { - -/* - * RangedPtr is a smart pointer restricted to an address range specified at - * creation. The pointer (and any smart pointers derived from it) must remain - * within the range [start, end] (inclusive of end to facilitate use as - * sentinels). Dereferencing or indexing into the pointer (or pointers derived - * from it) must remain within the range [start, end). All the standard pointer - * operators are defined on it; in debug builds these operations assert that the - * range specified at construction is respected. - * - * In theory passing a smart pointer instance as an argument can be slightly - * slower than passing a T* (due to ABI requirements for passing structs versus - * passing pointers), if the method being called isn't inlined. If you are in - * extremely performance-critical code, you may want to be careful using this - * smart pointer as an argument type. - * - * RangedPtr intentionally does not implicitly convert to T*. Use get() to - * explicitly convert to T*. Keep in mind that the raw pointer of course won't - * implement bounds checking in debug builds. - */ -template -class RangedPtr -{ - T* ptr; - -#ifdef DEBUG - T* const rangeStart; - T* const rangeEnd; -#endif - - typedef void (RangedPtr::* ConvertibleToBool)(); - void nonNull() {} - - void checkSanity() { - MOZ_ASSERT(rangeStart <= ptr); - MOZ_ASSERT(ptr <= rangeEnd); - } - - /* Creates a new pointer for |p|, restricted to this pointer's range. */ - RangedPtr create(T *p) const { -#ifdef DEBUG - return RangedPtr(p, rangeStart, rangeEnd); -#else - return RangedPtr(p, NULL, size_t(0)); -#endif - } - - uintptr_t asUintptr() const { return uintptr_t(ptr); } - - public: - RangedPtr(T* p, T* start, T* end) - : ptr(p) -#ifdef DEBUG - , rangeStart(start), rangeEnd(end) -#endif - { - MOZ_ASSERT(rangeStart <= rangeEnd); - checkSanity(); - } - RangedPtr(T* p, T* start, size_t length) - : ptr(p) -#ifdef DEBUG - , rangeStart(start), rangeEnd(start + length) -#endif - { - MOZ_ASSERT(length <= size_t(-1) / sizeof(T)); - MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart)); - checkSanity(); - } - - /* Equivalent to RangedPtr(p, p, length). */ - RangedPtr(T* p, size_t length) - : ptr(p) -#ifdef DEBUG - , rangeStart(p), rangeEnd(p + length) -#endif - { - MOZ_ASSERT(length <= size_t(-1) / sizeof(T)); - MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart)); - checkSanity(); - } - - /* Equivalent to RangedPtr(arr, arr, N). */ - template - RangedPtr(T (&arr)[N]) - : ptr(arr) -#ifdef DEBUG - , rangeStart(arr), rangeEnd(arr + N) -#endif - { - checkSanity(); - } - - T* get() const { - return ptr; - } - - operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; } - - /* - * You can only assign one RangedPtr into another if the two pointers have - * the same valid range: - * - * char arr1[] = "hi"; - * char arr2[] = "bye"; - * RangedPtr p1(arr1, 2); - * p1 = RangedPtr(arr1 + 1, arr1, arr1 + 2); // works - * p1 = RangedPtr(arr2, 3); // asserts - */ - RangedPtr& operator=(const RangedPtr& other) { - MOZ_ASSERT(rangeStart == other.rangeStart); - MOZ_ASSERT(rangeEnd == other.rangeEnd); - ptr = other.ptr; - checkSanity(); - return *this; - } - - RangedPtr operator+(size_t inc) { - MOZ_ASSERT(inc <= size_t(-1) / sizeof(T)); - MOZ_ASSERT(asUintptr() + inc * sizeof(T) >= asUintptr()); - return create(ptr + inc); - } - - RangedPtr operator-(size_t dec) { - MOZ_ASSERT(dec <= size_t(-1) / sizeof(T)); - MOZ_ASSERT(asUintptr() - dec * sizeof(T) <= asUintptr()); - return create(ptr - dec); - } - - /* - * You can assign a raw pointer into a RangedPtr if the raw pointer is - * within the range specified at creation. - */ - template - RangedPtr& operator=(U* p) { - *this = create(p); - return *this; - } - - template - RangedPtr& operator=(const RangedPtr& p) { - MOZ_ASSERT(rangeStart <= p.ptr); - MOZ_ASSERT(p.ptr <= rangeEnd); - ptr = p.ptr; - checkSanity(); - return *this; - } - - RangedPtr& operator++() { - return (*this += 1); - } - - RangedPtr operator++(int) { - RangedPtr rcp = *this; - ++*this; - return rcp; - } - - RangedPtr& operator--() { - return (*this -= 1); - } - - RangedPtr operator--(int) { - RangedPtr rcp = *this; - --*this; - return rcp; - } - - RangedPtr& operator+=(size_t inc) { - *this = *this + inc; - return *this; - } - - RangedPtr& operator-=(size_t dec) { - *this = *this - dec; - return *this; - } - - T& operator[](int index) const { - MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T)); - return *create(ptr + index); - } - - T& operator*() const { - return *ptr; - } - - template - bool operator==(const RangedPtr& other) const { - return ptr == other.ptr; - } - template - bool operator!=(const RangedPtr& other) const { - return !(*this == other); - } - - template - bool operator==(const U* u) const { - return ptr == u; - } - template - bool operator!=(const U* u) const { - return !(*this == u); - } - - template - bool operator<(const RangedPtr& other) const { - return ptr < other.ptr; - } - template - bool operator<=(const RangedPtr& other) const { - return ptr <= other.ptr; - } - - template - bool operator>(const RangedPtr& other) const { - return ptr > other.ptr; - } - template - bool operator>=(const RangedPtr& other) const { - return ptr >= other.ptr; - } - - size_t operator-(const RangedPtr& other) const { - MOZ_ASSERT(ptr >= other.ptr); - return PointerRangeSize(other.ptr, ptr); - } - - private: - RangedPtr() MOZ_DELETE; - T* operator&() MOZ_DELETE; -}; - -} /* namespace mozilla */ - -#endif /* mozilla_RangedPtr_h_ */ diff --git a/libazure/src/mfbt/SHA1.cpp b/libazure/src/mfbt/SHA1.cpp deleted file mode 100644 index f11b064..0000000 --- a/libazure/src/mfbt/SHA1.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Assertions.h" -#include "mozilla/Endian.h" -#include "mozilla/SHA1.h" - -#include - -using mozilla::NativeEndian; -using mozilla::SHA1Sum; - -static inline uint32_t -SHA_ROTL(uint32_t t, uint32_t n) -{ - MOZ_ASSERT(n < 32); - return (t << n) | (t >> (32 - n)); -} - -static void -shaCompress(volatile unsigned* X, const uint32_t* datain); - -#define SHA_F1(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z)) -#define SHA_F2(X, Y, Z) ((X) ^ (Y) ^ (Z)) -#define SHA_F3(X, Y, Z) (((X) & (Y)) | ((Z) & ((X) | (Y)))) -#define SHA_F4(X, Y, Z) ((X) ^ (Y) ^ (Z)) - -#define SHA_MIX(n, a, b, c) XW(n) = SHA_ROTL(XW(a) ^ XW(b) ^ XW(c) ^XW(n), 1) - -SHA1Sum::SHA1Sum() - : size(0), mDone(false) -{ - // Initialize H with constants from FIPS180-1. - H[0] = 0x67452301L; - H[1] = 0xefcdab89L; - H[2] = 0x98badcfeL; - H[3] = 0x10325476L; - H[4] = 0xc3d2e1f0L; -} - -/* - * Explanation of H array and index values: - * - * The context's H array is actually the concatenation of two arrays - * defined by SHA1, the H array of state variables (5 elements), - * and the W array of intermediate values, of which there are 16 elements. - * The W array starts at H[5], that is W[0] is H[5]. - * Although these values are defined as 32-bit values, we use 64-bit - * variables to hold them because the AMD64 stores 64 bit values in - * memory MUCH faster than it stores any smaller values. - * - * Rather than passing the context structure to shaCompress, we pass - * this combined array of H and W values. We do not pass the address - * of the first element of this array, but rather pass the address of an - * element in the middle of the array, element X. Presently X[0] is H[11]. - * So we pass the address of H[11] as the address of array X to shaCompress. - * Then shaCompress accesses the members of the array using positive AND - * negative indexes. - * - * Pictorially: (each element is 8 bytes) - * H | H0 H1 H2 H3 H4 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 Wa Wb Wc Wd We Wf | - * X |-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 | - * - * The byte offset from X[0] to any member of H and W is always - * representable in a signed 8-bit value, which will be encoded - * as a single byte offset in the X86-64 instruction set. - * If we didn't pass the address of H[11], and instead passed the - * address of H[0], the offsets to elements H[16] and above would be - * greater than 127, not representable in a signed 8-bit value, and the - * x86-64 instruction set would encode every such offset as a 32-bit - * signed number in each instruction that accessed element H[16] or - * higher. This results in much bigger and slower code. - */ -#define H2X 11 /* X[0] is H[11], and H[0] is X[-11] */ -#define W2X 6 /* X[0] is W[6], and W[0] is X[-6] */ - -/* - * SHA: Add data to context. - */ -void -SHA1Sum::update(const void* dataIn, uint32_t len) -{ - MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash."); - - const uint8_t* data = static_cast(dataIn); - - if (len == 0) - return; - - /* Accumulate the byte count. */ - unsigned int lenB = static_cast(size) & 63U; - - size += len; - - /* Read the data into W and process blocks as they get full. */ - unsigned int togo; - if (lenB > 0) { - togo = 64U - lenB; - if (len < togo) - togo = len; - memcpy(u.b + lenB, data, togo); - len -= togo; - data += togo; - lenB = (lenB + togo) & 63U; - if (!lenB) - shaCompress(&H[H2X], u.w); - } - - while (len >= 64U) { - len -= 64U; - shaCompress(&H[H2X], reinterpret_cast(data)); - data += 64U; - } - - if (len > 0) - memcpy(u.b, data, len); -} - - -/* - * SHA: Generate hash value - */ -void -SHA1Sum::finish(SHA1Sum::Hash& hashOut) -{ - MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash."); - - uint64_t size2 = size; - uint32_t lenB = uint32_t(size2) & 63; - - static const uint8_t bulk_pad[64] = - { 0x80,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; - - /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length in bits. */ - update(bulk_pad, (((55 + 64) - lenB) & 63) + 1); - MOZ_ASSERT((uint32_t(size) & 63) == 56); - - /* Convert size from bytes to bits. */ - size2 <<= 3; - u.w[14] = NativeEndian::swapToBigEndian(uint32_t(size2 >> 32)); - u.w[15] = NativeEndian::swapToBigEndian(uint32_t(size2)); - shaCompress(&H[H2X], u.w); - - /* Output hash. */ - u.w[0] = NativeEndian::swapToBigEndian(H[0]); - u.w[1] = NativeEndian::swapToBigEndian(H[1]); - u.w[2] = NativeEndian::swapToBigEndian(H[2]); - u.w[3] = NativeEndian::swapToBigEndian(H[3]); - u.w[4] = NativeEndian::swapToBigEndian(H[4]); - memcpy(hashOut, u.w, 20); - mDone = true; -} - -/* - * SHA: Compression function, unrolled. - * - * Some operations in shaCompress are done as 5 groups of 16 operations. - * Others are done as 4 groups of 20 operations. - * The code below shows that structure. - * - * The functions that compute the new values of the 5 state variables - * A-E are done in 4 groups of 20 operations (or you may also think - * of them as being done in 16 groups of 5 operations). They are - * done by the SHA_RNDx macros below, in the right column. - * - * The functions that set the 16 values of the W array are done in - * 5 groups of 16 operations. The first group is done by the - * LOAD macros below, the latter 4 groups are done by SHA_MIX below, - * in the left column. - * - * gcc's optimizer observes that each member of the W array is assigned - * a value 5 times in this code. It reduces the number of store - * operations done to the W array in the context (that is, in the X array) - * by creating a W array on the stack, and storing the W values there for - * the first 4 groups of operations on W, and storing the values in the - * context's W array only in the fifth group. This is undesirable. - * It is MUCH bigger code than simply using the context's W array, because - * all the offsets to the W array in the stack are 32-bit signed offsets, - * and it is no faster than storing the values in the context's W array. - * - * The original code for sha_fast.c prevented this creation of a separate - * W array in the stack by creating a W array of 80 members, each of - * whose elements is assigned only once. It also separated the computations - * of the W array values and the computations of the values for the 5 - * state variables into two separate passes, W's, then A-E's so that the - * second pass could be done all in registers (except for accessing the W - * array) on machines with fewer registers. The method is suboptimal - * for machines with enough registers to do it all in one pass, and it - * necessitates using many instructions with 32-bit offsets. - * - * This code eliminates the separate W array on the stack by a completely - * different means: by declaring the X array volatile. This prevents - * the optimizer from trying to reduce the use of the X array by the - * creation of a MORE expensive W array on the stack. The result is - * that all instructions use signed 8-bit offsets and not 32-bit offsets. - * - * The combination of this code and the -O3 optimizer flag on GCC 3.4.3 - * results in code that is 3 times faster than the previous NSS sha_fast - * code on AMD64. - */ -static void -shaCompress(volatile unsigned *X, const uint32_t *inbuf) -{ - unsigned A, B, C, D, E; - -#define XH(n) X[n - H2X] -#define XW(n) X[n - W2X] - -#define K0 0x5a827999L -#define K1 0x6ed9eba1L -#define K2 0x8f1bbcdcL -#define K3 0xca62c1d6L - -#define SHA_RND1(a, b, c, d, e, n) \ - a = SHA_ROTL(b, 5) + SHA_F1(c, d, e) + a + XW(n) + K0; c = SHA_ROTL(c, 30) -#define SHA_RND2(a, b, c, d, e, n) \ - a = SHA_ROTL(b, 5) + SHA_F2(c, d, e) + a + XW(n) + K1; c = SHA_ROTL(c, 30) -#define SHA_RND3(a, b, c, d, e, n) \ - a = SHA_ROTL(b, 5) + SHA_F3(c, d, e) + a + XW(n) + K2; c = SHA_ROTL(c, 30) -#define SHA_RND4(a, b, c, d, e, n) \ - a = SHA_ROTL(b ,5) + SHA_F4(c, d, e) + a + XW(n) + K3; c = SHA_ROTL(c, 30) - -#define LOAD(n) XW(n) = NativeEndian::swapToBigEndian(inbuf[n]) - - A = XH(0); - B = XH(1); - C = XH(2); - D = XH(3); - E = XH(4); - - LOAD(0); SHA_RND1(E,A,B,C,D, 0); - LOAD(1); SHA_RND1(D,E,A,B,C, 1); - LOAD(2); SHA_RND1(C,D,E,A,B, 2); - LOAD(3); SHA_RND1(B,C,D,E,A, 3); - LOAD(4); SHA_RND1(A,B,C,D,E, 4); - LOAD(5); SHA_RND1(E,A,B,C,D, 5); - LOAD(6); SHA_RND1(D,E,A,B,C, 6); - LOAD(7); SHA_RND1(C,D,E,A,B, 7); - LOAD(8); SHA_RND1(B,C,D,E,A, 8); - LOAD(9); SHA_RND1(A,B,C,D,E, 9); - LOAD(10); SHA_RND1(E,A,B,C,D,10); - LOAD(11); SHA_RND1(D,E,A,B,C,11); - LOAD(12); SHA_RND1(C,D,E,A,B,12); - LOAD(13); SHA_RND1(B,C,D,E,A,13); - LOAD(14); SHA_RND1(A,B,C,D,E,14); - LOAD(15); SHA_RND1(E,A,B,C,D,15); - - SHA_MIX( 0, 13, 8, 2); SHA_RND1(D,E,A,B,C, 0); - SHA_MIX( 1, 14, 9, 3); SHA_RND1(C,D,E,A,B, 1); - SHA_MIX( 2, 15, 10, 4); SHA_RND1(B,C,D,E,A, 2); - SHA_MIX( 3, 0, 11, 5); SHA_RND1(A,B,C,D,E, 3); - - SHA_MIX( 4, 1, 12, 6); SHA_RND2(E,A,B,C,D, 4); - SHA_MIX( 5, 2, 13, 7); SHA_RND2(D,E,A,B,C, 5); - SHA_MIX( 6, 3, 14, 8); SHA_RND2(C,D,E,A,B, 6); - SHA_MIX( 7, 4, 15, 9); SHA_RND2(B,C,D,E,A, 7); - SHA_MIX( 8, 5, 0, 10); SHA_RND2(A,B,C,D,E, 8); - SHA_MIX( 9, 6, 1, 11); SHA_RND2(E,A,B,C,D, 9); - SHA_MIX(10, 7, 2, 12); SHA_RND2(D,E,A,B,C,10); - SHA_MIX(11, 8, 3, 13); SHA_RND2(C,D,E,A,B,11); - SHA_MIX(12, 9, 4, 14); SHA_RND2(B,C,D,E,A,12); - SHA_MIX(13, 10, 5, 15); SHA_RND2(A,B,C,D,E,13); - SHA_MIX(14, 11, 6, 0); SHA_RND2(E,A,B,C,D,14); - SHA_MIX(15, 12, 7, 1); SHA_RND2(D,E,A,B,C,15); - - SHA_MIX( 0, 13, 8, 2); SHA_RND2(C,D,E,A,B, 0); - SHA_MIX( 1, 14, 9, 3); SHA_RND2(B,C,D,E,A, 1); - SHA_MIX( 2, 15, 10, 4); SHA_RND2(A,B,C,D,E, 2); - SHA_MIX( 3, 0, 11, 5); SHA_RND2(E,A,B,C,D, 3); - SHA_MIX( 4, 1, 12, 6); SHA_RND2(D,E,A,B,C, 4); - SHA_MIX( 5, 2, 13, 7); SHA_RND2(C,D,E,A,B, 5); - SHA_MIX( 6, 3, 14, 8); SHA_RND2(B,C,D,E,A, 6); - SHA_MIX( 7, 4, 15, 9); SHA_RND2(A,B,C,D,E, 7); - - SHA_MIX( 8, 5, 0, 10); SHA_RND3(E,A,B,C,D, 8); - SHA_MIX( 9, 6, 1, 11); SHA_RND3(D,E,A,B,C, 9); - SHA_MIX(10, 7, 2, 12); SHA_RND3(C,D,E,A,B,10); - SHA_MIX(11, 8, 3, 13); SHA_RND3(B,C,D,E,A,11); - SHA_MIX(12, 9, 4, 14); SHA_RND3(A,B,C,D,E,12); - SHA_MIX(13, 10, 5, 15); SHA_RND3(E,A,B,C,D,13); - SHA_MIX(14, 11, 6, 0); SHA_RND3(D,E,A,B,C,14); - SHA_MIX(15, 12, 7, 1); SHA_RND3(C,D,E,A,B,15); - - SHA_MIX( 0, 13, 8, 2); SHA_RND3(B,C,D,E,A, 0); - SHA_MIX( 1, 14, 9, 3); SHA_RND3(A,B,C,D,E, 1); - SHA_MIX( 2, 15, 10, 4); SHA_RND3(E,A,B,C,D, 2); - SHA_MIX( 3, 0, 11, 5); SHA_RND3(D,E,A,B,C, 3); - SHA_MIX( 4, 1, 12, 6); SHA_RND3(C,D,E,A,B, 4); - SHA_MIX( 5, 2, 13, 7); SHA_RND3(B,C,D,E,A, 5); - SHA_MIX( 6, 3, 14, 8); SHA_RND3(A,B,C,D,E, 6); - SHA_MIX( 7, 4, 15, 9); SHA_RND3(E,A,B,C,D, 7); - SHA_MIX( 8, 5, 0, 10); SHA_RND3(D,E,A,B,C, 8); - SHA_MIX( 9, 6, 1, 11); SHA_RND3(C,D,E,A,B, 9); - SHA_MIX(10, 7, 2, 12); SHA_RND3(B,C,D,E,A,10); - SHA_MIX(11, 8, 3, 13); SHA_RND3(A,B,C,D,E,11); - - SHA_MIX(12, 9, 4, 14); SHA_RND4(E,A,B,C,D,12); - SHA_MIX(13, 10, 5, 15); SHA_RND4(D,E,A,B,C,13); - SHA_MIX(14, 11, 6, 0); SHA_RND4(C,D,E,A,B,14); - SHA_MIX(15, 12, 7, 1); SHA_RND4(B,C,D,E,A,15); - - SHA_MIX( 0, 13, 8, 2); SHA_RND4(A,B,C,D,E, 0); - SHA_MIX( 1, 14, 9, 3); SHA_RND4(E,A,B,C,D, 1); - SHA_MIX( 2, 15, 10, 4); SHA_RND4(D,E,A,B,C, 2); - SHA_MIX( 3, 0, 11, 5); SHA_RND4(C,D,E,A,B, 3); - SHA_MIX( 4, 1, 12, 6); SHA_RND4(B,C,D,E,A, 4); - SHA_MIX( 5, 2, 13, 7); SHA_RND4(A,B,C,D,E, 5); - SHA_MIX( 6, 3, 14, 8); SHA_RND4(E,A,B,C,D, 6); - SHA_MIX( 7, 4, 15, 9); SHA_RND4(D,E,A,B,C, 7); - SHA_MIX( 8, 5, 0, 10); SHA_RND4(C,D,E,A,B, 8); - SHA_MIX( 9, 6, 1, 11); SHA_RND4(B,C,D,E,A, 9); - SHA_MIX(10, 7, 2, 12); SHA_RND4(A,B,C,D,E,10); - SHA_MIX(11, 8, 3, 13); SHA_RND4(E,A,B,C,D,11); - SHA_MIX(12, 9, 4, 14); SHA_RND4(D,E,A,B,C,12); - SHA_MIX(13, 10, 5, 15); SHA_RND4(C,D,E,A,B,13); - SHA_MIX(14, 11, 6, 0); SHA_RND4(B,C,D,E,A,14); - SHA_MIX(15, 12, 7, 1); SHA_RND4(A,B,C,D,E,15); - - XH(0) += A; - XH(1) += B; - XH(2) += C; - XH(3) += D; - XH(4) += E; -} diff --git a/libazure/src/mfbt/STYLE b/libazure/src/mfbt/STYLE deleted file mode 100644 index 2d94c3a..0000000 --- a/libazure/src/mfbt/STYLE +++ /dev/null @@ -1,383 +0,0 @@ -= mfbt style rules = - -== Line length == - -The line limit is 80 characters, except that excessively long blocks of -preprocessor directives may exceed this if it makes the code more readable (e.g. -MOZ_STATIC_ASSERT in Assertions.h.), and unbreakable text in comments (e.g. -URLs) may exceed this as well. Wrap expressions after binary operators. - -== Capitalization == - -Standalone functions, classes, structs, and template parameters are named -InterCaps-style. Member functions and fields in classes and structs are named -camelCaps-style. - -== Indentation == - -Indentation is two spaces, never tabs. - - if (x == 2) - return 17; - -== Whitespace == - -Surround binary operators with a single space on either side. - - if (x == 2) - return 17; - -When describing pointer types, the * shall be adjacent to the type name. (Same -goes for references -- & goes by the type name.) - - int - Foo(int* p) - { - typedef void* VoidPtr; - int& i = *p; - } - -A corollary: don't mix declaration types by declaring a T and a T* (or a T**, -&c.) in the same declaration. - - T* foo, bar; // BAD - -== Expressions == - -Ternary expressions (a ? b : c) should use only one line if sufficiently short. -Longer ternary expressions should use multiple lines. The condition, -consequent, and alternative should each be on separate lines (each part -overflowing to additional lines as necessary), and the ? and : should be aligned -with the start of the condition: - - size_t - BinaryTree::height() - { - return isLeaf() - ? 0 - : 1 + std::max(left()->height(), - right()->height()); - } - -== Bracing == - -Don't brace single statements. - - if (y == 7) - return 3; - for (size_t i = 0; i < 5; i++) - frob(i); - -But do brace them if the statement (or condition(s) or any additional -consequents, if the braces would be associated with an if statement) occupies -multiple lines. - - if (cond1 || - cond2) - { - action(); - } - if (cond1) { - consequent(); - } else { - alternative(arg1, - arg2); - } - if (cond1 || cond2) { - callMethod(arg1, - arg2); - } - for (size_t j = 0; - j < 17; - j++) - { - action(); - } - -Braces in control flow go at the end of the line except when associated with an -|if| or loop-head where the condition covers multiple lines - -== Classes and structs == - -Inside class and structure definitions, public/private consume one level of -indentation. - - class Baz - { - public: - Baz() { } - }; - -The absence of public/private in structs in which all members are public still -consumes a level. - - struct Foo - { - int field; - }; - -Braces delimiting a class or struct go on their own lines. - -Member initialization in constructors should be formatted as follows: - - class Fnord - { - size_t s1, s2, s3, s4, s5; - - public: - Fnord(size_t s) : s1(s), s2(s), s3(s), s4(s), s5(s) { } - Fnord() - : s1(0), /* member initialization can be compressed if desired */ - s2(0), - s3(0), - s4(0), - s5(0) - { - ... - } - }; - -Fields should go first in the class so that the basic structure is all in one -place, consistently. - -Use the inline keyword to annotate functions defined inline in a header. (If -the function is defined inline in the class, don't bother adding it -redundantly.) - -Explicitly delete (using Attributes.h's MOZ_DELETE) the copy constructor and -assignment operator from classes not intended to be copied or assigned to avoid -mistakes. - - class Funky - { - public: - Funky() { } - - private: - Funky(const Funky& other) MOZ_DELETE; - void operator=(const Funky& other) MOZ_DELETE; - }; - -Include a blank line between sections of structs and classes with different -access control. - -The "get" prefix is used when a method is fallible. If it's infallible, don't -use it. - - class String - { - public: - size_t length() const; // not getLength() - }; - -== Templates == - -Capitalize template parameter names to distinguish them from fields. - - template - class BloomFilter - { - }; - -Use single-letter names if it makes sense (T for an arbitrary type, K for key -type, V for value type, &c.). Otherwise use InterCaps-style names. - -When declaring or defining a function, template<...> goes on one line, the -return type and other specifiers go on another line, and the function name and -argument list go on a third line. - - template - inline bool - Vector::add(T t) - { - } - -== Namespaces == - -All C++ code shall be in the mozilla namespace, except that functionality only -used to implement external-facing API should be in the mozilla::detail -namespace, indicating that it should not be directly used. - -Namespace opening braces go on the same line as the namespace declaration. -Namespace closing braces shall be commented. Namespace contents are not -indented. - - namespace mozilla { - ... - } // namespace mozilla - -Don't use |using| in a header unless it's confined to a class or method. -Implementation files for out-of-line functionality may use |using|. - -Name data structures and methods which must be usable in C code with a Moz* -prefix, e.g. MozCustomStructure. If the data structure is not meant to be used -outside of the header in which it is found (i.e. it would be in mozilla::detail -but for its being required to work in C code), add a corresponding comment to -highlight this. - -== #includes == - -Headers that include mfbt headers use a fully-qualified include path, even if -full qualification is not strictly necessary. - - #include "mozilla/Assertions.h" - -mfbt headers should be included first, alphabetically. Standard includes should -follow, separated from mfbt includes by a blank line. - - #include "mozilla/Assertions.h" - #include "mozilla/Attributes.h" - - #include - -If a header dependency is limited simply to the existence of a class, -forward-declare it rather than #include that header. - - namespace mozilla { - - class BloomFilter; - extern bool - Test(BloomFilter* bf); - - } // namespace mozilla - -== Preprocessor == - -Include guards should be named by determining the fully-qualified include path, -then substituting _ for / and . in it, and finally appending a trailing _. For -example, "mozilla/Assertions.h" becomes mozilla_Assertions_h_. - -Nested preprocessor directives indent the directive name (but not the #) by two -spaces. - - #ifdef __clang__ - # define FOO ... - #else - # define FOO ... - #endif - -Comments within nested preprocessor directives align with directive names at -that nesting depth. - - #if defined(__GNUC__) - /* gcc supports C++11 override syntax. */ - # define MOZ_OVERRIDE override - #else - # define MOZ_OVERRIDE /* unsupported */ - #endif - -Feature-testing macros may be defined to nothing. Macros intended to be -textually expanded should be defined to a comment indicating non-support, as -above or as appropriate to the situation. - -No particular preference is expressed between testing for a macro being defined -using defined(...) and using #ifdef. - -When defining a macro with different expansions for different compilers, the top -level of distinction should be the compiler, and the next nested level should be -the compiler version. Clang seems likely to be around for awhile, so to reduce -confusion test for it separately from gcc even when it's not strictly necessary. - - #if defined(__clang__) - #elif defined(__GNUC__) - # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) - # else - # endif - #elif defined(_MSC_VER) - #endif - -But don't distinguish clang's feature support using version checks: use the -__has_feature() and __has_extension() macros instead, because vendors may -customize clang's version numbers. - -Use a MOZ_* prefix when defining macros (e.g. MOZ_OVERRIDE, MOZ_LIKELY, and so -on) that are part of the mfbt interface. (C++ implementation files implementing -mfbt's interface but which are not directly part of that interface may ignore -this rule.) - -Prefer inline functions to macros whenever possible. - -== Comments == - -Header files shall have a short descriptive comment underneath license -boilerplate indicating what functionality the file implements, to be picked up -by MXR and displayed in directory listings. (But see bug 717196, which -currently prevents MXR from doing this if the MPL2 boilerplate is used.) - - Assertions.h: - ...license boilerplate... - - /* Implementations of runtime and static assertion macros for C and C++. */ - -Classes intended for public use shall have interface comments explaining their -functionality from the user's perspective. These comments shall include -examples of how the relevant functionality might be used. These interface -comments use /** */ doxygen/Javadoc-style comments. - - /** - * The Frobber class simplifies the process of frobbing. - */ - class Frobber - { - }; - -Comments describing implementation details (tradeoffs considered, assumptions -made, mathematical background, &c.) occur separately from interface comments so -that users need not consider them. They should go inside the class definition -or inside the appropriate method, depending on the specificity of the comment. - -Headers which are intended to be C-compatible shall use only /**/-style -comments. (Code examples nested inside documentation comments may use //-style -comments.) Headers which are C++-compatible may also use //-style comments. - -Non-interface comments that are /**/-style shall not also be doxygen-style. - -Use Python-style ** to denote exponentiation inside comments, not ^ (which can -be confused with C-style bitwise xor). If you're writing sufficiently complex -math, feel free to descend into LaTeX math mode ;-) inside implementation -comments if you need to. (But keep it out of interface comments, because most -people probably haven't seen LaTeX.) - -== Miscellaneous == - -Enclose C-compatible code in |extern "C"| blocks, and #ifdef __cplusplus the -block start/end as needed. The contents of these blocks should not be indented. - -Add new functionality to new headers unless an existing header makes sense. -Err on the side of more headers rather than fewer, as this helps to minimize -dependencies. Don't add anything to Util.h, which will be split into multiple -headers at some point (bug 713082). - -Don't use bool for argument types unless the method is a "set" or "enable"-style -method where the method name and bool value together indicate the sense of its -effect. Use well-named enums in all other places, so that the semantics of the -argument are clear at a glance and do not require knowing how the method -interprets that argument. - - void - setVisible(bool visible); // true clearly means visible, false clearly not - enum Enumerability { - Enumerable, - NonEnumerable - }; - bool - DefineProperty(JSObject* obj, const char* name, Value v, Enumerability e); - -Use NULL for the null pointer constant. - -If a consequent in an if-statement ends with a return, don't specify an else. -The else would be redundant with the return, and not using it avoids excess -indentation. If you feel the if-else alternation is important as a way to -think about the choice being made, consider a ternary expression instead. - - // BAD - if (f()) - return 2; - else - return 5; - // GOOD - if (f()) - return 2; - return 5; - // GOOD - return f() ? 2 : 5 diff --git a/libazure/src/mfbt/Scoped.h b/libazure/src/mfbt/Scoped.h deleted file mode 100644 index 677a1a3..0000000 --- a/libazure/src/mfbt/Scoped.h +++ /dev/null @@ -1,271 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* A number of structures to simplify scope-based RAII management. */ - -#ifndef mozilla_Scoped_h_ -#define mozilla_Scoped_h_ - -/* - * Resource Acquisition Is Initialization is a programming idiom used - * to write robust code that is able to deallocate resources properly, - * even in presence of execution errors or exceptions that need to be - * propagated. The Scoped* classes defined in this header perform the - * deallocation of the resource they hold once program execution - * reaches the end of the scope for which they have been defined. - * - * This header provides the following RAII classes: - * - * - |ScopedFreePtr| - a container for a pointer, that automatically calls - * |free()| at the end of the scope; - * - |ScopedDeletePtr| - a container for a pointer, that automatically calls - * |delete| at the end of the scope; - * - |ScopedDeleteArray| - a container for a pointer to an array, that - * automatically calls |delete[]| at the end of the scope. - * - * The general scenario for each of the RAII classes is the following: - * - * ScopedClass foo(create_value()); - * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| - * to access the value. - * // ... In case of |return| or |throw|, |foo| is deallocated automatically. - * // ... If |foo| needs to be returned or stored, use |foo.forget()| - * - * Note that the RAII classes defined in this header do _not_ perform any form - * of reference-counting or garbage-collection. These classes have exactly two - * behaviors: - * - * - if |forget()| has not been called, the resource is always deallocated at - * the end of the scope; - * - if |forget()| has been called, any control on the resource is unbound - * and the resource is not deallocated by the class. - * - * Extension: - * - * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| - * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition - * of RAII classes for other scenarios. These macros have been used to - * automatically close file descriptors/file handles when reaching the end of - * the scope, graphics contexts, etc. - */ - -#include "mozilla/Attributes.h" -#include "mozilla/GuardObjects.h" - -namespace mozilla { - -/* - * Scoped is a helper to create RAII wrappers - * Type argument |Traits| is expected to have the following structure: - * - * struct Traits { - * // Define the type of the value stored in the wrapper - * typedef value_type type; - * // Returns the value corresponding to the uninitialized or freed state - * const static type empty(); - * // Release resources corresponding to the wrapped value - * // This function is responsible for not releasing an |empty| value - * const static void release(type); - * } - */ -template -class Scoped -{ - public: - typedef typename Traits::type Resource; - - explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : value(Traits::empty()) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - explicit Scoped(const Resource& v - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : value(v) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - ~Scoped() { - Traits::release(value); - } - - // Constant getter - operator const Resource&() const { return value; } - const Resource& operator->() const { return value; } - const Resource& get() const { return value; } - // Non-constant getter. - Resource& rwget() { return value; } - - /* - * Forget the resource. - * - * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will - * have no effect at destruction (unless it is reset to another resource by - * |operator=|). - * - * @return The original resource. - */ - Resource forget() { - Resource tmp = value; - value = Traits::empty(); - return tmp; - } - - /* - * Perform immediate clean-up of this |Scoped|. - * - * If this |Scoped| is currently empty, this method has no effect. - */ - void dispose() { - Traits::release(value); - value = Traits::empty(); - } - - bool operator==(const Resource& other) const { - return value == other; - } - - /* - * Replace the resource with another resource. - * - * Calling |operator=| has the side-effect of triggering clean-up. If you do - * not want to trigger clean-up, you should first invoke |forget|. - * - * @return this - */ - Scoped& operator=(const Resource& other) { - return reset(other); - } - Scoped& reset(const Resource& other) { - Traits::release(value); - value = other; - return *this; - } - - private: - explicit Scoped(const Scoped& value) MOZ_DELETE; - Scoped& operator=(const Scoped& value) MOZ_DELETE; - - private: - Resource value; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -/* - * SCOPED_TEMPLATE defines a templated class derived from Scoped - * This allows to implement templates such as ScopedFreePtr. - * - * @param name The name of the class to define. - * @param Traits A struct implementing clean-up. See the implementations - * for more details. - */ -#define SCOPED_TEMPLATE(name, Traits) \ -template \ -struct name : public mozilla::Scoped > \ -{ \ - typedef mozilla::Scoped > Super; \ - typedef typename Super::Resource Resource; \ - name& operator=(Resource ptr) { \ - Super::operator=(ptr); \ - return *this; \ - } \ - explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ - : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ - {} \ - explicit name(Resource ptr \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ - : Super(ptr MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ - {} \ - private: \ - explicit name(name& source) MOZ_DELETE; \ - name& operator=(name& source) MOZ_DELETE; \ -}; - -/* - * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. - * - * struct S { ... }; - * ScopedFreePtr foo = malloc(sizeof(S)); - * ScopedFreePtr bar = strdup(str); - */ -template -struct ScopedFreePtrTraits -{ - typedef T* type; - static T* empty() { return NULL; } - static void release(T* ptr) { free(ptr); } -}; -SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) - -/* - * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. - * - * struct S { ... }; - * ScopedDeletePtr foo = new S(); - */ -template -struct ScopedDeletePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { delete ptr; } -}; -SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) - -/* - * ScopedDeleteArray is a RAII wrapper for pointers that need to be delete[]ed. - * - * struct S { ... }; - * ScopedDeleteArray foo = new S[42]; - */ -template -struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { delete [] ptr; } -}; -SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits) - -/* - * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped - * pointers for types with custom deleters; just overload - * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for - * type T. - * - * @param name The name of the class to define. - * @param Type A struct implementing clean-up. See the implementations - * for more details. - * *param Deleter The function that is used to delete/destroy/free a - * non-null value of Type*. - * - * Example: - * - * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \ - * PR_Close) - * ... - * { - * ScopedPRFileDesc file(PR_OpenFile(...)); - * ... - * } // file is closed with PR_Close here - */ -#define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ -template <> inline void TypeSpecificDelete(Type * value) { Deleter(value); } \ -typedef ::mozilla::TypeSpecificScopedPointer name; - -template void TypeSpecificDelete(T * value); - -template -struct TypeSpecificScopedPointerTraits -{ - typedef T* type; - const static type empty() { return NULL; } - const static void release(type value) - { - if (value) - TypeSpecificDelete(value); - } -}; - -SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits) - -} /* namespace mozilla */ - -#endif // mozilla_Scoped_h_ diff --git a/libazure/src/mfbt/SplayTree.h b/libazure/src/mfbt/SplayTree.h deleted file mode 100644 index f9a10d3..0000000 --- a/libazure/src/mfbt/SplayTree.h +++ /dev/null @@ -1,285 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=99 ft=cpp: - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * A sorted tree with optimal access times, where recently-accessed elements - * are faster to access again. - */ - -#ifndef mozilla_SplayTree_h_ -#define mozilla_SplayTree_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/NullPtr.h" - -namespace mozilla { - -template -class SplayTree; - -template -class SplayTreeNode -{ - public: - template - friend class SplayTree; - - SplayTreeNode() - : left(nullptr), right(nullptr), parent(nullptr) - {} - - private: - T* left; - T* right; - T* parent; -}; - - -/** - * Class which represents a splay tree. - * Splay trees are balanced binary search trees for which search, insert and - * remove are all amortized O(log n), but where accessing a node makes it - * faster to access that node in the future. - * - * T indicates the type of tree elements, Comparator must have a static - * compare(const T&, const T&) method ordering the elements. The compare - * method must be free from side effects. - */ -template -class SplayTree -{ - T* root; - T* freeList; - - public: - SplayTree() - : root(nullptr), freeList(nullptr) - {} - - bool empty() const { - return !root; - } - - bool contains(const T& v) - { - if (empty()) - return false; - - T* last = lookup(v); - splay(last); - checkCoherency(root, nullptr); - return Comparator::compare(v, *last) == 0; - } - - bool insert(T* v) - { - MOZ_ASSERT(!contains(*v), "Duplicate elements are not allowed."); - - if (!root) { - root = v; - return true; - } - T* last = lookup(*v); - int cmp = Comparator::compare(*v, *last); - - T** parentPointer = (cmp < 0) ? &last->left : &last->right; - MOZ_ASSERT(!*parentPointer); - *parentPointer = v; - v->parent = last; - - splay(v); - checkCoherency(root, nullptr); - return true; - } - - T* remove(const T& v) - { - T* last = lookup(v); - MOZ_ASSERT(last, "This tree must contain the element being removed."); - MOZ_ASSERT(Comparator::compare(v, *last) == 0); - - // Splay the tree so that the item to remove is the root. - splay(last); - MOZ_ASSERT(last == root); - - // Find another node which can be swapped in for the root: either the - // rightmost child of the root's left, or the leftmost child of the - // root's right. - T* swap; - T* swapChild; - if (root->left) { - swap = root->left; - while (swap->right) - swap = swap->right; - swapChild = swap->left; - } else if (root->right) { - swap = root->right; - while (swap->left) - swap = swap->left; - swapChild = swap->right; - } else { - T* result = root; - root = nullptr; - return result; - } - - // The selected node has at most one child, in swapChild. Detach it - // from the subtree by replacing it with that child. - if (swap == swap->parent->left) - swap->parent->left = swapChild; - else - swap->parent->right = swapChild; - if (swapChild) - swapChild->parent = swap->parent; - - // Make the selected node the new root. - root = swap; - root->parent = nullptr; - root->left = last->left; - root->right = last->right; - if (root->left) { - root->left->parent = root; - } - if (root->right) { - root->right->parent = root; - } - - checkCoherency(root, nullptr); - return last; - } - - T* removeMin() - { - MOZ_ASSERT(root, "No min to remove!"); - - T* min = root; - while (min->left) - min = min->left; - return remove(*min); - } - - private: - /** - * Returns the node in this comparing equal to |v|, or a node just greater or - * just less than |v| if there is no such node. - */ - T* lookup(const T& v) - { - MOZ_ASSERT(!empty()); - - T* node = root; - T* parent; - do { - parent = node; - int c = Comparator::compare(v, *node); - if (c == 0) - return node; - else if (c < 0) - node = node->left; - else - node = node->right; - } while (node); - return parent; - } - - /** - * Rotate the tree until |node| is at the root of the tree. Performing - * the rotations in this fashion preserves the amortized balancing of - * the tree. - */ - void splay(T* node) - { - MOZ_ASSERT(node); - - while (node != root) { - T* parent = node->parent; - if (parent == root) { - // Zig rotation. - rotate(node); - MOZ_ASSERT(node == root); - return; - } - T* grandparent = parent->parent; - if ((parent->left == node) == (grandparent->left == parent)) { - // Zig-zig rotation. - rotate(parent); - rotate(node); - } else { - // Zig-zag rotation. - rotate(node); - rotate(node); - } - } - } - - void rotate(T* node) - { - // Rearrange nodes so that node becomes the parent of its current - // parent, while preserving the sortedness of the tree. - T* parent = node->parent; - if (parent->left == node) { - // x y - // y c ==> a x - // a b b c - parent->left = node->right; - if (node->right) - node->right->parent = parent; - node->right = parent; - } else { - MOZ_ASSERT(parent->right == node); - // x y - // a y ==> x c - // b c a b - parent->right = node->left; - if (node->left) - node->left->parent = parent; - node->left = parent; - } - node->parent = parent->parent; - parent->parent = node; - if (T* grandparent = node->parent) { - if (grandparent->left == parent) - grandparent->left = node; - else - grandparent->right = node; - } else { - root = node; - } - } - - T* checkCoherency(T* node, T* minimum) - { -#ifdef DEBUG - MOZ_ASSERT_IF(root, !root->parent); - if (!node) { - MOZ_ASSERT(!root); - return nullptr; - } - MOZ_ASSERT_IF(!node->parent, node == root); - MOZ_ASSERT_IF(minimum, Comparator::compare(*minimum, *node) < 0); - if (node->left) { - MOZ_ASSERT(node->left->parent == node); - T* leftMaximum = checkCoherency(node->left, minimum); - MOZ_ASSERT(Comparator::compare(*leftMaximum, *node) < 0); - } - if (node->right) { - MOZ_ASSERT(node->right->parent == node); - return checkCoherency(node->right, node); - } - return node; -#else - return nullptr; -#endif - } - - SplayTree(const SplayTree&) MOZ_DELETE; - void operator=(const SplayTree&) MOZ_DELETE; -}; - -} /* namespace mozilla */ - -#endif /* mozilla_SplayTree_h_ */ diff --git a/libazure/src/mfbt/TypeTraits.h b/libazure/src/mfbt/TypeTraits.h deleted file mode 100644 index 0c1a9a6..0000000 --- a/libazure/src/mfbt/TypeTraits.h +++ /dev/null @@ -1,384 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Template-based metaprogramming and type-testing facilities. */ - -#ifndef mozilla_TypeTraits_h_ -#define mozilla_TypeTraits_h_ - -/* - * These traits are approximate copies of the traits and semantics from C++11's - * header. Don't add traits not in that header! When all - * platforms provide that header, we can convert all users and remove this one. - */ - -#include - -namespace mozilla { - -/* Forward declarations. */ - -template struct RemoveCV; - -/* 20.9.3 Helper classes [meta.help] */ - -/** - * Helper class used as a base for various type traits, exposed publicly - * because exposes it as well. - */ -template -struct IntegralConstant -{ - static const T value = Value; - typedef T ValueType; - typedef IntegralConstant Type; -}; - -/** Convenient aliases. */ -typedef IntegralConstant TrueType; -typedef IntegralConstant FalseType; - -/* 20.9.4 Unary type traits [meta.unary] */ - -/* 20.9.4.1 Primary type categories [meta.unary.cat] */ - -namespace detail { - -template -struct IsIntegralHelper : FalseType {}; - -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; - -} /* namespace detail */ - -/** - * IsIntegral determines whether a type is an integral type. - * - * mozilla::IsIntegral::value is true; - * mozilla::IsIntegral::value is true; - * mozilla::IsIntegral::value is true; - * mozilla::IsIntegral::value is false; - * mozilla::IsIntegral::value is false; - * - * Note that the behavior of IsIntegral on char16_t and char32_t is - * unspecified. - */ -template -struct IsIntegral : detail::IsIntegralHelper::Type> -{}; - -/** - * IsPointer determines whether a type is a pointer type (but not a pointer-to- - * member type). - * - * mozilla::IsPointer::value is true; - * mozilla::IsPointer::value is true; - * mozilla::IsPointer::value is true; - * mozilla::IsPointer::value is false; - * mozilla::IsPointer::value is false. - */ -template -struct IsPointer : FalseType {}; - -template -struct IsPointer : TrueType {}; - -/* 20.9.4.2 Composite type traits [meta.unary.comp] */ - -/* 20.9.4.3 Type properties [meta.unary.prop] */ - -/** - * Traits class for identifying POD types. Until C++11 there's no automatic - * way to detect PODs, so for the moment this is done manually. Users may - * define specializations of this class that inherit from mozilla::TrueType and - * mozilla::FalseType (or equivalently mozilla::IntegralConstant, or conveniently from mozilla::IsPod for composite types) as needed to - * ensure correct IsPod behavior. - */ -template -struct IsPod : public FalseType {}; - -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template struct IsPod : TrueType {}; - -/* 20.9.5 Type property queries [meta.unary.prop.query] */ - -/* 20.9.6 Relationships between types [meta.rel] */ - -/** - * IsSame tests whether two types are the same type. - * - * mozilla::IsSame::value is true; - * mozilla::IsSame::value is true; - * mozilla::IsSame::value is false; - * mozilla::IsSame::value is true; - * mozilla::IsSame::value is false; - * mozilla::IsSame::value is true. - */ -template -struct IsSame : FalseType {}; - -template -struct IsSame : TrueType {}; - -namespace detail { - -// The trickery used to implement IsBaseOf here makes it possible to use it for -// the cases of private and multiple inheritance. This code was inspired by the -// sample code here: -// -// http://stackoverflow.com/questions/2910979/how-is-base-of-works -template -struct BaseOfHelper -{ - public: - operator Base*() const; - operator Derived*(); -}; - -template -struct BaseOfTester -{ - private: - template - static char test(Derived*, T); - static int test(Base*, int); - - public: - static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); -}; - -template -struct BaseOfTester -{ - private: - template - static char test(Derived*, T); - static int test(Base*, int); - - public: - static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); -}; - -template -struct BaseOfTester : FalseType {}; - -template -struct BaseOfTester : TrueType {}; - -template -struct BaseOfTester : TrueType {}; - -} /* namespace detail */ - -/* - * IsBaseOf allows to know whether a given class is derived from another. - * - * Consider the following class definitions: - * - * class A {}; - * class B : public A {}; - * class C {}; - * - * mozilla::IsBaseOf::value is true; - * mozilla::IsBaseOf::value is false; - */ -template -struct IsBaseOf - : IntegralConstant::value> -{}; - -namespace detail { - -template -struct ConvertibleTester -{ - private: - static From create(); - - template - static char test(To to); - - template - static int test(...); - - public: - static const bool value = - sizeof(test(create())) == sizeof(char); -}; - -} // namespace detail - -/** - * IsConvertible determines whether a value of type From will implicitly convert - * to a value of type To. For example: - * - * struct A {}; - * struct B : public A {}; - * struct C {}; - * - * mozilla::IsConvertible::value is true; - * mozilla::IsConvertible::value is true; - * mozilla::IsConvertible::value is true; - * mozilla::IsConvertible::value is true; - * mozilla::IsConvertible::value is false; - * mozilla::IsConvertible::value is false; - * mozilla::IsConvertible::value is false; - * mozilla::IsConvertible::value is false. - * - * For obscure reasons, you can't use IsConvertible when the types being tested - * are related through private inheritance, and you'll get a compile error if - * you try. Just don't do it! - */ -template -struct IsConvertible - : IntegralConstant::value> -{}; - -/* 20.9.7 Transformations between types [meta.trans] */ - -/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */ - -/** - * RemoveConst removes top-level const qualifications on a type. - * - * mozilla::RemoveConst::Type is int; - * mozilla::RemoveConst::Type is int; - * mozilla::RemoveConst::Type is const int*; - * mozilla::RemoveConst::Type is int*. - */ -template -struct RemoveConst -{ - typedef T Type; -}; - -template -struct RemoveConst -{ - typedef T Type; -}; - -/** - * RemoveVolatile removes top-level volatile qualifications on a type. - * - * mozilla::RemoveVolatile::Type is int; - * mozilla::RemoveVolatile::Type is int; - * mozilla::RemoveVolatile::Type is volatile int*; - * mozilla::RemoveVolatile::Type is int*. - */ -template -struct RemoveVolatile -{ - typedef T Type; -}; - -template -struct RemoveVolatile -{ - typedef T Type; -}; - -/** - * RemoveCV removes top-level const and volatile qualifications on a type. - * - * mozilla::RemoveCV::Type is int; - * mozilla::RemoveCV::Type is int; - * mozilla::RemoveCV::Type is int; - * mozilla::RemoveCV::Type is int*. - */ -template -struct RemoveCV -{ - typedef typename RemoveConst::Type>::Type Type; -}; - -/* 20.9.7.2 Reference modifications [meta.trans.ref] */ - -/* 20.9.7.3 Sign modifications [meta.trans.sign] */ - -/* 20.9.7.4 Array modifications [meta.trans.arr] */ - -/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ - -/* 20.9.7.6 Other transformations [meta.trans.other] */ - -/** - * EnableIf is a struct containing a typedef of T if and only if B is true. - * - * mozilla::EnableIf::Type is int; - * mozilla::EnableIf::Type is a compile-time error. - * - * Use this template to implement SFINAE-style (Substitution Failure Is not An - * Error) requirements. For example, you might use it to impose a restriction - * on a template parameter: - * - * template - * class PodVector // vector optimized to store POD (memcpy-able) types - * { - * EnableIf::value, T>::Type* vector; - * size_t length; - * ... - * }; - */ -template -struct EnableIf -{}; - -template -struct EnableIf -{ - typedef T Type; -}; - -/** - * Conditional selects a class between two, depending on a given boolean value. - * - * mozilla::Conditional::Type is A; - * mozilla::Conditional::Type is B; - */ -template -struct Conditional -{ - typedef A Type; -}; - -template -struct Conditional -{ - typedef B Type; -}; - -} /* namespace mozilla */ - -#endif /* mozilla_TypeTraits_h_ */ diff --git a/libazure/src/mfbt/WeakPtr.h b/libazure/src/mfbt/WeakPtr.h deleted file mode 100644 index b8437f5..0000000 --- a/libazure/src/mfbt/WeakPtr.h +++ /dev/null @@ -1,144 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Weak pointer functionality, implemented as a mixin for use with any class. */ - -/** - * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting - * its lifetime. It works by creating a single shared reference counted object - * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo' - * clear the pointer in the WeakReference without having to know about all of - * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime - * of 'Foo'. - * - * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional - * dereference, and an additional heap allocated pointer sized object shared - * between all of the WeakPtrs. - * - * Example of usage: - * - * // To have a class C support weak pointers, inherit from SupportsWeakPtr. - * class C : public SupportsWeakPtr - * { - * public: - * int num; - * void act(); - * }; - * - * C* ptr = new C(); - * - * // Get weak pointers to ptr. The first time asWeakPtr is called - * // a reference counted WeakReference object is created that - * // can live beyond the lifetime of 'ptr'. The WeakReference - * // object will be notified of 'ptr's destruction. - * WeakPtr weak = ptr->asWeakPtr(); - * WeakPtr other = ptr->asWeakPtr(); - * - * // Test a weak pointer for validity before using it. - * if (weak) { - * weak->num = 17; - * weak->act(); - * } - * - * // Destroying the underlying object clears weak pointers to it. - * delete ptr; - * - * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); - * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); - * - * WeakPtr is typesafe and may be used with any class. It is not required that - * the class be reference-counted or allocated in any particular way. - * - * The API was loosely inspired by Chromium's weak_ptr.h: - * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h - */ - -#ifndef mozilla_WeakPtr_h_ -#define mozilla_WeakPtr_h_ - -#include "mozilla/Assertions.h" -#include "mozilla/NullPtr.h" -#include "mozilla/RefPtr.h" -#include "mozilla/TypeTraits.h" - -namespace mozilla { - -template class WeakPtr; - -template -class SupportsWeakPtr -{ - public: - WeakPtr asWeakPtr() { - if (!weakRef) - weakRef = new WeakReference(static_cast(this)); - return WeakPtr(weakRef); - } - - protected: - ~SupportsWeakPtr() { - MOZ_STATIC_ASSERT((IsBaseOf, T>::value), "T must derive from SupportsWeakPtr"); - if (weakRef) - weakRef->detach(); - } - - private: - friend class WeakPtr; - - // This can live beyond the lifetime of the class derived from SupportsWeakPtr. - class WeakReference : public RefCounted - { - public: - explicit WeakReference(T* p) : ptr(p) {} - T* get() const { - return ptr; - } - - private: - friend class WeakPtr; - friend class SupportsWeakPtr; - void detach() { - ptr = nullptr; - } - T* ptr; - }; - - RefPtr weakRef; -}; - -template -class WeakPtr -{ - public: - WeakPtr(const WeakPtr& o) : ref(o.ref) {} - // Ensure that ref is dereferenceable in the uninitialized state - WeakPtr() : ref(new typename SupportsWeakPtr::WeakReference(nullptr)) {} - - operator T*() const { - return ref->get(); - } - T& operator*() const { - return *ref->get(); - } - - T* operator->() const { - return ref->get(); - } - - T* get() const { - return ref->get(); - } - - private: - friend class SupportsWeakPtr; - - explicit WeakPtr(const RefPtr::WeakReference> &o) : ref(o) {} - - RefPtr::WeakReference> ref; -}; - -} // namespace mozilla - -#endif /* ifdef mozilla_WeakPtr_h_ */ diff --git a/libazure/src/mfbt/double-conversion/LICENSE b/libazure/src/mfbt/double-conversion/LICENSE deleted file mode 100644 index 933718a..0000000 --- a/libazure/src/mfbt/double-conversion/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2006-2011, the V8 project authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libazure/src/mfbt/double-conversion/README b/libazure/src/mfbt/double-conversion/README deleted file mode 100644 index f186b42..0000000 --- a/libazure/src/mfbt/double-conversion/README +++ /dev/null @@ -1,11 +0,0 @@ -http://code.google.com/p/double-conversion - -This project (double-conversion) provides binary-decimal and decimal-binary -routines for IEEE doubles. - -The library consists of efficient conversion routines that have been extracted -from the V8 JavaScript engine. The code has been refactored and improved so that -it can be used more easily in other projects. - -There is extensive documentation in src/double-conversion.h. Other examples can -be found in test/cctest/test-conversions.cc. diff --git a/libazure/src/mfbt/double-conversion/add-mfbt-api-markers.patch b/libazure/src/mfbt/double-conversion/add-mfbt-api-markers.patch deleted file mode 100644 index bbb50f6..0000000 --- a/libazure/src/mfbt/double-conversion/add-mfbt-api-markers.patch +++ /dev/null @@ -1,94 +0,0 @@ -diff --git a/mfbt/double-conversion/double-conversion.h b/mfbt/double-conversion/double-conversion.h -index f98edae..c62b16b 100644 ---- a/mfbt/double-conversion/double-conversion.h -+++ b/mfbt/double-conversion/double-conversion.h -@@ -28,6 +28,7 @@ - #ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ - #define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ - -+#include "mozilla/Types.h" - #include "utils.h" - - namespace double_conversion { -@@ -129,7 +130,7 @@ class DoubleToStringConverter { - } - - // Returns a converter following the EcmaScript specification. -- static const DoubleToStringConverter& EcmaScriptConverter(); -+ static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); - - // Computes the shortest string of digits that correctly represent the input - // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high -@@ -197,7 +198,7 @@ class DoubleToStringConverter { - // The last two conditions imply that the result will never contain more than - // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters - // (one additional character for the sign, and one for the decimal point). -- bool ToFixed(double value, -+ MFBT_API bool ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const; - -@@ -229,7 +230,7 @@ class DoubleToStringConverter { - // kMaxExponentialDigits + 8 characters (the sign, the digit before the - // decimal point, the decimal point, the exponent character, the - // exponent's sign, and at most 3 exponent digits). -- bool ToExponential(double value, -+ MFBT_API bool ToExponential(double value, - int requested_digits, - StringBuilder* result_builder) const; - -@@ -267,7 +268,7 @@ class DoubleToStringConverter { - // The last condition implies that the result will never contain more than - // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the - // exponent character, the exponent's sign, and at most 3 exponent digits). -- bool ToPrecision(double value, -+ MFBT_API bool ToPrecision(double value, - int precision, - StringBuilder* result_builder) const; - -@@ -292,7 +293,7 @@ class DoubleToStringConverter { - // kBase10MaximalLength. - // Note that DoubleToAscii null-terminates its input. So the given buffer - // should be at least kBase10MaximalLength + 1 characters long. -- static const int kBase10MaximalLength = 17; -+ static const MFBT_DATA int kBase10MaximalLength = 17; - - // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or - // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' -@@ -332,7 +333,7 @@ class DoubleToStringConverter { - // terminating null-character when computing the maximal output size. - // The given length is only used in debug mode to ensure the buffer is big - // enough. -- static void DoubleToAscii(double v, -+ static MFBT_API void DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, -@@ -343,7 +344,7 @@ class DoubleToStringConverter { - - private: - // Implementation for ToShortest and ToShortestSingle. -- bool ToShortestIeeeNumber(double value, -+ MFBT_API bool ToShortestIeeeNumber(double value, - StringBuilder* result_builder, - DtoaMode mode) const; - -@@ -351,15 +352,15 @@ class DoubleToStringConverter { - // corresponding string using the configured infinity/nan-symbol. - // If either of them is NULL or the value is not special then the - // function returns false. -- bool HandleSpecialValues(double value, StringBuilder* result_builder) const; -+ MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; - // Constructs an exponential representation (i.e. 1.234e56). - // The given exponent assumes a decimal point after the first decimal digit. -- void CreateExponentialRepresentation(const char* decimal_digits, -+ MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const; - // Creates a decimal representation (i.e 1234.5678). -- void CreateDecimalRepresentation(const char* decimal_digits, -+ MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, diff --git a/libazure/src/mfbt/double-conversion/bignum-dtoa.cc b/libazure/src/mfbt/double-conversion/bignum-dtoa.cc deleted file mode 100644 index b6c2e85..0000000 --- a/libazure/src/mfbt/double-conversion/bignum-dtoa.cc +++ /dev/null @@ -1,640 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include - -#include "bignum-dtoa.h" - -#include "bignum.h" -#include "ieee.h" - -namespace double_conversion { - -static int NormalizedExponent(uint64_t significand, int exponent) { - ASSERT(significand != 0); - while ((significand & Double::kHiddenBit) == 0) { - significand = significand << 1; - exponent = exponent - 1; - } - return exponent; -} - - -// Forward declarations: -// Returns an estimation of k such that 10^(k-1) <= v < 10^k. -static int EstimatePower(int exponent); -// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator -// and denominator. -static void InitialScaledStartValues(uint64_t significand, - int exponent, - bool lower_boundary_is_closer, - int estimated_power, - bool need_boundary_deltas, - Bignum* numerator, - Bignum* denominator, - Bignum* delta_minus, - Bignum* delta_plus); -// Multiplies numerator/denominator so that its values lies in the range 1-10. -// Returns decimal_point s.t. -// v = numerator'/denominator' * 10^(decimal_point-1) -// where numerator' and denominator' are the values of numerator and -// denominator after the call to this function. -static void FixupMultiply10(int estimated_power, bool is_even, - int* decimal_point, - Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus); -// Generates digits from the left to the right and stops when the generated -// digits yield the shortest decimal representation of v. -static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus, - bool is_even, - Vector buffer, int* length); -// Generates 'requested_digits' after the decimal point. -static void BignumToFixed(int requested_digits, int* decimal_point, - Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length); -// Generates 'count' digits of numerator/denominator. -// Once 'count' digits have been produced rounds the result depending on the -// remainder (remainders of exactly .5 round upwards). Might update the -// decimal_point when rounding up (for example for 0.9999). -static void GenerateCountedDigits(int count, int* decimal_point, - Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length); - - -void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, - Vector buffer, int* length, int* decimal_point) { - ASSERT(v > 0); - ASSERT(!Double(v).IsSpecial()); - uint64_t significand; - int exponent; - bool lower_boundary_is_closer; - if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) { - float f = static_cast(v); - ASSERT(f == v); - significand = Single(f).Significand(); - exponent = Single(f).Exponent(); - lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser(); - } else { - significand = Double(v).Significand(); - exponent = Double(v).Exponent(); - lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser(); - } - bool need_boundary_deltas = - (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE); - - bool is_even = (significand & 1) == 0; - int normalized_exponent = NormalizedExponent(significand, exponent); - // estimated_power might be too low by 1. - int estimated_power = EstimatePower(normalized_exponent); - - // Shortcut for Fixed. - // The requested digits correspond to the digits after the point. If the - // number is much too small, then there is no need in trying to get any - // digits. - if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) { - buffer[0] = '\0'; - *length = 0; - // Set decimal-point to -requested_digits. This is what Gay does. - // Note that it should not have any effect anyways since the string is - // empty. - *decimal_point = -requested_digits; - return; - } - - Bignum numerator; - Bignum denominator; - Bignum delta_minus; - Bignum delta_plus; - // Make sure the bignum can grow large enough. The smallest double equals - // 4e-324. In this case the denominator needs fewer than 324*4 binary digits. - // The maximum double is 1.7976931348623157e308 which needs fewer than - // 308*4 binary digits. - ASSERT(Bignum::kMaxSignificantBits >= 324*4); - InitialScaledStartValues(significand, exponent, lower_boundary_is_closer, - estimated_power, need_boundary_deltas, - &numerator, &denominator, - &delta_minus, &delta_plus); - // We now have v = (numerator / denominator) * 10^estimated_power. - FixupMultiply10(estimated_power, is_even, decimal_point, - &numerator, &denominator, - &delta_minus, &delta_plus); - // We now have v = (numerator / denominator) * 10^(decimal_point-1), and - // 1 <= (numerator + delta_plus) / denominator < 10 - switch (mode) { - case BIGNUM_DTOA_SHORTEST: - case BIGNUM_DTOA_SHORTEST_SINGLE: - GenerateShortestDigits(&numerator, &denominator, - &delta_minus, &delta_plus, - is_even, buffer, length); - break; - case BIGNUM_DTOA_FIXED: - BignumToFixed(requested_digits, decimal_point, - &numerator, &denominator, - buffer, length); - break; - case BIGNUM_DTOA_PRECISION: - GenerateCountedDigits(requested_digits, decimal_point, - &numerator, &denominator, - buffer, length); - break; - default: - UNREACHABLE(); - } - buffer[*length] = '\0'; -} - - -// The procedure starts generating digits from the left to the right and stops -// when the generated digits yield the shortest decimal representation of v. A -// decimal representation of v is a number lying closer to v than to any other -// double, so it converts to v when read. -// -// This is true if d, the decimal representation, is between m- and m+, the -// upper and lower boundaries. d must be strictly between them if !is_even. -// m- := (numerator - delta_minus) / denominator -// m+ := (numerator + delta_plus) / denominator -// -// Precondition: 0 <= (numerator+delta_plus) / denominator < 10. -// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit -// will be produced. This should be the standard precondition. -static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus, - bool is_even, - Vector buffer, int* length) { - // Small optimization: if delta_minus and delta_plus are the same just reuse - // one of the two bignums. - if (Bignum::Equal(*delta_minus, *delta_plus)) { - delta_plus = delta_minus; - } - *length = 0; - while (true) { - uint16_t digit; - digit = numerator->DivideModuloIntBignum(*denominator); - ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. - // digit = numerator / denominator (integer division). - // numerator = numerator % denominator. - buffer[(*length)++] = digit + '0'; - - // Can we stop already? - // If the remainder of the division is less than the distance to the lower - // boundary we can stop. In this case we simply round down (discarding the - // remainder). - // Similarly we test if we can round up (using the upper boundary). - bool in_delta_room_minus; - bool in_delta_room_plus; - if (is_even) { - in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus); - } else { - in_delta_room_minus = Bignum::Less(*numerator, *delta_minus); - } - if (is_even) { - in_delta_room_plus = - Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; - } else { - in_delta_room_plus = - Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; - } - if (!in_delta_room_minus && !in_delta_room_plus) { - // Prepare for next iteration. - numerator->Times10(); - delta_minus->Times10(); - // We optimized delta_plus to be equal to delta_minus (if they share the - // same value). So don't multiply delta_plus if they point to the same - // object. - if (delta_minus != delta_plus) { - delta_plus->Times10(); - } - } else if (in_delta_room_minus && in_delta_room_plus) { - // Let's see if 2*numerator < denominator. - // If yes, then the next digit would be < 5 and we can round down. - int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator); - if (compare < 0) { - // Remaining digits are less than .5. -> Round down (== do nothing). - } else if (compare > 0) { - // Remaining digits are more than .5 of denominator. -> Round up. - // Note that the last digit could not be a '9' as otherwise the whole - // loop would have stopped earlier. - // We still have an assert here in case the preconditions were not - // satisfied. - ASSERT(buffer[(*length) - 1] != '9'); - buffer[(*length) - 1]++; - } else { - // Halfway case. - // TODO(floitsch): need a way to solve half-way cases. - // For now let's round towards even (since this is what Gay seems to - // do). - - if ((buffer[(*length) - 1] - '0') % 2 == 0) { - // Round down => Do nothing. - } else { - ASSERT(buffer[(*length) - 1] != '9'); - buffer[(*length) - 1]++; - } - } - return; - } else if (in_delta_room_minus) { - // Round down (== do nothing). - return; - } else { // in_delta_room_plus - // Round up. - // Note again that the last digit could not be '9' since this would have - // stopped the loop earlier. - // We still have an ASSERT here, in case the preconditions were not - // satisfied. - ASSERT(buffer[(*length) -1] != '9'); - buffer[(*length) - 1]++; - return; - } - } -} - - -// Let v = numerator / denominator < 10. -// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point) -// from left to right. Once 'count' digits have been produced we decide wether -// to round up or down. Remainders of exactly .5 round upwards. Numbers such -// as 9.999999 propagate a carry all the way, and change the -// exponent (decimal_point), when rounding upwards. -static void GenerateCountedDigits(int count, int* decimal_point, - Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length) { - ASSERT(count >= 0); - for (int i = 0; i < count - 1; ++i) { - uint16_t digit; - digit = numerator->DivideModuloIntBignum(*denominator); - ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. - // digit = numerator / denominator (integer division). - // numerator = numerator % denominator. - buffer[i] = digit + '0'; - // Prepare for next iteration. - numerator->Times10(); - } - // Generate the last digit. - uint16_t digit; - digit = numerator->DivideModuloIntBignum(*denominator); - if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { - digit++; - } - buffer[count - 1] = digit + '0'; - // Correct bad digits (in case we had a sequence of '9's). Propagate the - // carry until we hat a non-'9' or til we reach the first digit. - for (int i = count - 1; i > 0; --i) { - if (buffer[i] != '0' + 10) break; - buffer[i] = '0'; - buffer[i - 1]++; - } - if (buffer[0] == '0' + 10) { - // Propagate a carry past the top place. - buffer[0] = '1'; - (*decimal_point)++; - } - *length = count; -} - - -// Generates 'requested_digits' after the decimal point. It might omit -// trailing '0's. If the input number is too small then no digits at all are -// generated (ex.: 2 fixed digits for 0.00001). -// -// Input verifies: 1 <= (numerator + delta) / denominator < 10. -static void BignumToFixed(int requested_digits, int* decimal_point, - Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length) { - // Note that we have to look at more than just the requested_digits, since - // a number could be rounded up. Example: v=0.5 with requested_digits=0. - // Even though the power of v equals 0 we can't just stop here. - if (-(*decimal_point) > requested_digits) { - // The number is definitively too small. - // Ex: 0.001 with requested_digits == 1. - // Set decimal-point to -requested_digits. This is what Gay does. - // Note that it should not have any effect anyways since the string is - // empty. - *decimal_point = -requested_digits; - *length = 0; - return; - } else if (-(*decimal_point) == requested_digits) { - // We only need to verify if the number rounds down or up. - // Ex: 0.04 and 0.06 with requested_digits == 1. - ASSERT(*decimal_point == -requested_digits); - // Initially the fraction lies in range (1, 10]. Multiply the denominator - // by 10 so that we can compare more easily. - denominator->Times10(); - if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { - // If the fraction is >= 0.5 then we have to include the rounded - // digit. - buffer[0] = '1'; - *length = 1; - (*decimal_point)++; - } else { - // Note that we caught most of similar cases earlier. - *length = 0; - } - return; - } else { - // The requested digits correspond to the digits after the point. - // The variable 'needed_digits' includes the digits before the point. - int needed_digits = (*decimal_point) + requested_digits; - GenerateCountedDigits(needed_digits, decimal_point, - numerator, denominator, - buffer, length); - } -} - - -// Returns an estimation of k such that 10^(k-1) <= v < 10^k where -// v = f * 2^exponent and 2^52 <= f < 2^53. -// v is hence a normalized double with the given exponent. The output is an -// approximation for the exponent of the decimal approimation .digits * 10^k. -// -// The result might undershoot by 1 in which case 10^k <= v < 10^k+1. -// Note: this property holds for v's upper boundary m+ too. -// 10^k <= m+ < 10^k+1. -// (see explanation below). -// -// Examples: -// EstimatePower(0) => 16 -// EstimatePower(-52) => 0 -// -// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0. -static int EstimatePower(int exponent) { - // This function estimates log10 of v where v = f*2^e (with e == exponent). - // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)). - // Note that f is bounded by its container size. Let p = 53 (the double's - // significand size). Then 2^(p-1) <= f < 2^p. - // - // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close - // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)). - // The computed number undershoots by less than 0.631 (when we compute log3 - // and not log10). - // - // Optimization: since we only need an approximated result this computation - // can be performed on 64 bit integers. On x86/x64 architecture the speedup is - // not really measurable, though. - // - // Since we want to avoid overshooting we decrement by 1e10 so that - // floating-point imprecisions don't affect us. - // - // Explanation for v's boundary m+: the computation takes advantage of - // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement - // (even for denormals where the delta can be much more important). - - const double k1Log10 = 0.30102999566398114; // 1/lg(10) - - // For doubles len(f) == 53 (don't forget the hidden bit). - const int kSignificandSize = Double::kSignificandSize; - double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10); - return static_cast(estimate); -} - - -// See comments for InitialScaledStartValues. -static void InitialScaledStartValuesPositiveExponent( - uint64_t significand, int exponent, - int estimated_power, bool need_boundary_deltas, - Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus) { - // A positive exponent implies a positive power. - ASSERT(estimated_power >= 0); - // Since the estimated_power is positive we simply multiply the denominator - // by 10^estimated_power. - - // numerator = v. - numerator->AssignUInt64(significand); - numerator->ShiftLeft(exponent); - // denominator = 10^estimated_power. - denominator->AssignPowerUInt16(10, estimated_power); - - if (need_boundary_deltas) { - // Introduce a common denominator so that the deltas to the boundaries are - // integers. - denominator->ShiftLeft(1); - numerator->ShiftLeft(1); - // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common - // denominator (of 2) delta_plus equals 2^e. - delta_plus->AssignUInt16(1); - delta_plus->ShiftLeft(exponent); - // Same for delta_minus. The adjustments if f == 2^p-1 are done later. - delta_minus->AssignUInt16(1); - delta_minus->ShiftLeft(exponent); - } -} - - -// See comments for InitialScaledStartValues -static void InitialScaledStartValuesNegativeExponentPositivePower( - uint64_t significand, int exponent, - int estimated_power, bool need_boundary_deltas, - Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus) { - // v = f * 2^e with e < 0, and with estimated_power >= 0. - // This means that e is close to 0 (have a look at how estimated_power is - // computed). - - // numerator = significand - // since v = significand * 2^exponent this is equivalent to - // numerator = v * / 2^-exponent - numerator->AssignUInt64(significand); - // denominator = 10^estimated_power * 2^-exponent (with exponent < 0) - denominator->AssignPowerUInt16(10, estimated_power); - denominator->ShiftLeft(-exponent); - - if (need_boundary_deltas) { - // Introduce a common denominator so that the deltas to the boundaries are - // integers. - denominator->ShiftLeft(1); - numerator->ShiftLeft(1); - // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common - // denominator (of 2) delta_plus equals 2^e. - // Given that the denominator already includes v's exponent the distance - // to the boundaries is simply 1. - delta_plus->AssignUInt16(1); - // Same for delta_minus. The adjustments if f == 2^p-1 are done later. - delta_minus->AssignUInt16(1); - } -} - - -// See comments for InitialScaledStartValues -static void InitialScaledStartValuesNegativeExponentNegativePower( - uint64_t significand, int exponent, - int estimated_power, bool need_boundary_deltas, - Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus) { - // Instead of multiplying the denominator with 10^estimated_power we - // multiply all values (numerator and deltas) by 10^-estimated_power. - - // Use numerator as temporary container for power_ten. - Bignum* power_ten = numerator; - power_ten->AssignPowerUInt16(10, -estimated_power); - - if (need_boundary_deltas) { - // Since power_ten == numerator we must make a copy of 10^estimated_power - // before we complete the computation of the numerator. - // delta_plus = delta_minus = 10^estimated_power - delta_plus->AssignBignum(*power_ten); - delta_minus->AssignBignum(*power_ten); - } - - // numerator = significand * 2 * 10^-estimated_power - // since v = significand * 2^exponent this is equivalent to - // numerator = v * 10^-estimated_power * 2 * 2^-exponent. - // Remember: numerator has been abused as power_ten. So no need to assign it - // to itself. - ASSERT(numerator == power_ten); - numerator->MultiplyByUInt64(significand); - - // denominator = 2 * 2^-exponent with exponent < 0. - denominator->AssignUInt16(1); - denominator->ShiftLeft(-exponent); - - if (need_boundary_deltas) { - // Introduce a common denominator so that the deltas to the boundaries are - // integers. - numerator->ShiftLeft(1); - denominator->ShiftLeft(1); - // With this shift the boundaries have their correct value, since - // delta_plus = 10^-estimated_power, and - // delta_minus = 10^-estimated_power. - // These assignments have been done earlier. - // The adjustments if f == 2^p-1 (lower boundary is closer) are done later. - } -} - - -// Let v = significand * 2^exponent. -// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator -// and denominator. The functions GenerateShortestDigits and -// GenerateCountedDigits will then convert this ratio to its decimal -// representation d, with the required accuracy. -// Then d * 10^estimated_power is the representation of v. -// (Note: the fraction and the estimated_power might get adjusted before -// generating the decimal representation.) -// -// The initial start values consist of: -// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power. -// - a scaled (common) denominator. -// optionally (used by GenerateShortestDigits to decide if it has the shortest -// decimal converting back to v): -// - v - m-: the distance to the lower boundary. -// - m+ - v: the distance to the upper boundary. -// -// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator. -// -// Let ep == estimated_power, then the returned values will satisfy: -// v / 10^ep = numerator / denominator. -// v's boundarys m- and m+: -// m- / 10^ep == v / 10^ep - delta_minus / denominator -// m+ / 10^ep == v / 10^ep + delta_plus / denominator -// Or in other words: -// m- == v - delta_minus * 10^ep / denominator; -// m+ == v + delta_plus * 10^ep / denominator; -// -// Since 10^(k-1) <= v < 10^k (with k == estimated_power) -// or 10^k <= v < 10^(k+1) -// we then have 0.1 <= numerator/denominator < 1 -// or 1 <= numerator/denominator < 10 -// -// It is then easy to kickstart the digit-generation routine. -// -// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST -// or BIGNUM_DTOA_SHORTEST_SINGLE. - -static void InitialScaledStartValues(uint64_t significand, - int exponent, - bool lower_boundary_is_closer, - int estimated_power, - bool need_boundary_deltas, - Bignum* numerator, - Bignum* denominator, - Bignum* delta_minus, - Bignum* delta_plus) { - if (exponent >= 0) { - InitialScaledStartValuesPositiveExponent( - significand, exponent, estimated_power, need_boundary_deltas, - numerator, denominator, delta_minus, delta_plus); - } else if (estimated_power >= 0) { - InitialScaledStartValuesNegativeExponentPositivePower( - significand, exponent, estimated_power, need_boundary_deltas, - numerator, denominator, delta_minus, delta_plus); - } else { - InitialScaledStartValuesNegativeExponentNegativePower( - significand, exponent, estimated_power, need_boundary_deltas, - numerator, denominator, delta_minus, delta_plus); - } - - if (need_boundary_deltas && lower_boundary_is_closer) { - // The lower boundary is closer at half the distance of "normal" numbers. - // Increase the common denominator and adapt all but the delta_minus. - denominator->ShiftLeft(1); // *2 - numerator->ShiftLeft(1); // *2 - delta_plus->ShiftLeft(1); // *2 - } -} - - -// This routine multiplies numerator/denominator so that its values lies in the -// range 1-10. That is after a call to this function we have: -// 1 <= (numerator + delta_plus) /denominator < 10. -// Let numerator the input before modification and numerator' the argument -// after modification, then the output-parameter decimal_point is such that -// numerator / denominator * 10^estimated_power == -// numerator' / denominator' * 10^(decimal_point - 1) -// In some cases estimated_power was too low, and this is already the case. We -// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k == -// estimated_power) but do not touch the numerator or denominator. -// Otherwise the routine multiplies the numerator and the deltas by 10. -static void FixupMultiply10(int estimated_power, bool is_even, - int* decimal_point, - Bignum* numerator, Bignum* denominator, - Bignum* delta_minus, Bignum* delta_plus) { - bool in_range; - if (is_even) { - // For IEEE doubles half-way cases (in decimal system numbers ending with 5) - // are rounded to the closest floating-point number with even significand. - in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; - } else { - in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; - } - if (in_range) { - // Since numerator + delta_plus >= denominator we already have - // 1 <= numerator/denominator < 10. Simply update the estimated_power. - *decimal_point = estimated_power + 1; - } else { - *decimal_point = estimated_power; - numerator->Times10(); - if (Bignum::Equal(*delta_minus, *delta_plus)) { - delta_minus->Times10(); - delta_plus->AssignBignum(*delta_minus); - } else { - delta_minus->Times10(); - delta_plus->Times10(); - } - } -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/bignum-dtoa.h b/libazure/src/mfbt/double-conversion/bignum-dtoa.h deleted file mode 100644 index 34b9619..0000000 --- a/libazure/src/mfbt/double-conversion/bignum-dtoa.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_ -#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_ - -#include "utils.h" - -namespace double_conversion { - -enum BignumDtoaMode { - // Return the shortest correct representation. - // For example the output of 0.299999999999999988897 is (the less accurate but - // correct) 0.3. - BIGNUM_DTOA_SHORTEST, - // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats. - BIGNUM_DTOA_SHORTEST_SINGLE, - // Return a fixed number of digits after the decimal point. - // For instance fixed(0.1, 4) becomes 0.1000 - // If the input number is big, the output will be big. - BIGNUM_DTOA_FIXED, - // Return a fixed number of digits, no matter what the exponent is. - BIGNUM_DTOA_PRECISION -}; - -// Converts the given double 'v' to ascii. -// The result should be interpreted as buffer * 10^(point-length). -// The buffer will be null-terminated. -// -// The input v must be > 0 and different from NaN, and Infinity. -// -// The output depends on the given mode: -// - SHORTEST: produce the least amount of digits for which the internal -// identity requirement is still satisfied. If the digits are printed -// (together with the correct exponent) then reading this number will give -// 'v' again. The buffer will choose the representation that is closest to -// 'v'. If there are two at the same distance, than the number is round up. -// In this mode the 'requested_digits' parameter is ignored. -// - FIXED: produces digits necessary to print a given number with -// 'requested_digits' digits after the decimal point. The produced digits -// might be too short in which case the caller has to fill the gaps with '0's. -// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. -// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns -// buffer="2", point=0. -// Note: the length of the returned buffer has no meaning wrt the significance -// of its digits. That is, just because it contains '0's does not mean that -// any other digit would not satisfy the internal identity requirement. -// - PRECISION: produces 'requested_digits' where the first digit is not '0'. -// Even though the length of produced digits usually equals -// 'requested_digits', the function is allowed to return fewer digits, in -// which case the caller has to fill the missing digits with '0's. -// Halfway cases are again rounded up. -// 'BignumDtoa' expects the given buffer to be big enough to hold all digits -// and a terminating null-character. -void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, - Vector buffer, int* length, int* point); - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_ diff --git a/libazure/src/mfbt/double-conversion/bignum.cc b/libazure/src/mfbt/double-conversion/bignum.cc deleted file mode 100644 index 747491a..0000000 --- a/libazure/src/mfbt/double-conversion/bignum.cc +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "bignum.h" -#include "utils.h" - -namespace double_conversion { - -Bignum::Bignum() - : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) { - for (int i = 0; i < kBigitCapacity; ++i) { - bigits_[i] = 0; - } -} - - -template -static int BitSize(S value) { - return 8 * sizeof(value); -} - -// Guaranteed to lie in one Bigit. -void Bignum::AssignUInt16(uint16_t value) { - ASSERT(kBigitSize >= BitSize(value)); - Zero(); - if (value == 0) return; - - EnsureCapacity(1); - bigits_[0] = value; - used_digits_ = 1; -} - - -void Bignum::AssignUInt64(uint64_t value) { - const int kUInt64Size = 64; - - Zero(); - if (value == 0) return; - - int needed_bigits = kUInt64Size / kBigitSize + 1; - EnsureCapacity(needed_bigits); - for (int i = 0; i < needed_bigits; ++i) { - bigits_[i] = value & kBigitMask; - value = value >> kBigitSize; - } - used_digits_ = needed_bigits; - Clamp(); -} - - -void Bignum::AssignBignum(const Bignum& other) { - exponent_ = other.exponent_; - for (int i = 0; i < other.used_digits_; ++i) { - bigits_[i] = other.bigits_[i]; - } - // Clear the excess digits (if there were any). - for (int i = other.used_digits_; i < used_digits_; ++i) { - bigits_[i] = 0; - } - used_digits_ = other.used_digits_; -} - - -static uint64_t ReadUInt64(Vector buffer, - int from, - int digits_to_read) { - uint64_t result = 0; - for (int i = from; i < from + digits_to_read; ++i) { - int digit = buffer[i] - '0'; - ASSERT(0 <= digit && digit <= 9); - result = result * 10 + digit; - } - return result; -} - - -void Bignum::AssignDecimalString(Vector value) { - // 2^64 = 18446744073709551616 > 10^19 - const int kMaxUint64DecimalDigits = 19; - Zero(); - int length = value.length(); - int pos = 0; - // Let's just say that each digit needs 4 bits. - while (length >= kMaxUint64DecimalDigits) { - uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); - pos += kMaxUint64DecimalDigits; - length -= kMaxUint64DecimalDigits; - MultiplyByPowerOfTen(kMaxUint64DecimalDigits); - AddUInt64(digits); - } - uint64_t digits = ReadUInt64(value, pos, length); - MultiplyByPowerOfTen(length); - AddUInt64(digits); - Clamp(); -} - - -static int HexCharValue(char c) { - if ('0' <= c && c <= '9') return c - '0'; - if ('a' <= c && c <= 'f') return 10 + c - 'a'; - if ('A' <= c && c <= 'F') return 10 + c - 'A'; - UNREACHABLE(); - return 0; // To make compiler happy. -} - - -void Bignum::AssignHexString(Vector value) { - Zero(); - int length = value.length(); - - int needed_bigits = length * 4 / kBigitSize + 1; - EnsureCapacity(needed_bigits); - int string_index = length - 1; - for (int i = 0; i < needed_bigits - 1; ++i) { - // These bigits are guaranteed to be "full". - Chunk current_bigit = 0; - for (int j = 0; j < kBigitSize / 4; j++) { - current_bigit += HexCharValue(value[string_index--]) << (j * 4); - } - bigits_[i] = current_bigit; - } - used_digits_ = needed_bigits - 1; - - Chunk most_significant_bigit = 0; // Could be = 0; - for (int j = 0; j <= string_index; ++j) { - most_significant_bigit <<= 4; - most_significant_bigit += HexCharValue(value[j]); - } - if (most_significant_bigit != 0) { - bigits_[used_digits_] = most_significant_bigit; - used_digits_++; - } - Clamp(); -} - - -void Bignum::AddUInt64(uint64_t operand) { - if (operand == 0) return; - Bignum other; - other.AssignUInt64(operand); - AddBignum(other); -} - - -void Bignum::AddBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); - - // If this has a greater exponent than other append zero-bigits to this. - // After this call exponent_ <= other.exponent_. - Align(other); - - // There are two possibilities: - // aaaaaaaaaaa 0000 (where the 0s represent a's exponent) - // bbbbb 00000000 - // ---------------- - // ccccccccccc 0000 - // or - // aaaaaaaaaa 0000 - // bbbbbbbbb 0000000 - // ----------------- - // cccccccccccc 0000 - // In both cases we might need a carry bigit. - - EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_); - Chunk carry = 0; - int bigit_pos = other.exponent_ - exponent_; - ASSERT(bigit_pos >= 0); - for (int i = 0; i < other.used_digits_; ++i) { - Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry; - bigits_[bigit_pos] = sum & kBigitMask; - carry = sum >> kBigitSize; - bigit_pos++; - } - - while (carry != 0) { - Chunk sum = bigits_[bigit_pos] + carry; - bigits_[bigit_pos] = sum & kBigitMask; - carry = sum >> kBigitSize; - bigit_pos++; - } - used_digits_ = Max(bigit_pos, used_digits_); - ASSERT(IsClamped()); -} - - -void Bignum::SubtractBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); - // We require this to be bigger than other. - ASSERT(LessEqual(other, *this)); - - Align(other); - - int offset = other.exponent_ - exponent_; - Chunk borrow = 0; - int i; - for (i = 0; i < other.used_digits_; ++i) { - ASSERT((borrow == 0) || (borrow == 1)); - Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow; - bigits_[i + offset] = difference & kBigitMask; - borrow = difference >> (kChunkSize - 1); - } - while (borrow != 0) { - Chunk difference = bigits_[i + offset] - borrow; - bigits_[i + offset] = difference & kBigitMask; - borrow = difference >> (kChunkSize - 1); - ++i; - } - Clamp(); -} - - -void Bignum::ShiftLeft(int shift_amount) { - if (used_digits_ == 0) return; - exponent_ += shift_amount / kBigitSize; - int local_shift = shift_amount % kBigitSize; - EnsureCapacity(used_digits_ + 1); - BigitsShiftLeft(local_shift); -} - - -void Bignum::MultiplyByUInt32(uint32_t factor) { - if (factor == 1) return; - if (factor == 0) { - Zero(); - return; - } - if (used_digits_ == 0) return; - - // The product of a bigit with the factor is of size kBigitSize + 32. - // Assert that this number + 1 (for the carry) fits into double chunk. - ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); - DoubleChunk carry = 0; - for (int i = 0; i < used_digits_; ++i) { - DoubleChunk product = static_cast(factor) * bigits_[i] + carry; - bigits_[i] = static_cast(product & kBigitMask); - carry = (product >> kBigitSize); - } - while (carry != 0) { - EnsureCapacity(used_digits_ + 1); - bigits_[used_digits_] = carry & kBigitMask; - used_digits_++; - carry >>= kBigitSize; - } -} - - -void Bignum::MultiplyByUInt64(uint64_t factor) { - if (factor == 1) return; - if (factor == 0) { - Zero(); - return; - } - ASSERT(kBigitSize < 32); - uint64_t carry = 0; - uint64_t low = factor & 0xFFFFFFFF; - uint64_t high = factor >> 32; - for (int i = 0; i < used_digits_; ++i) { - uint64_t product_low = low * bigits_[i]; - uint64_t product_high = high * bigits_[i]; - uint64_t tmp = (carry & kBigitMask) + product_low; - bigits_[i] = tmp & kBigitMask; - carry = (carry >> kBigitSize) + (tmp >> kBigitSize) + - (product_high << (32 - kBigitSize)); - } - while (carry != 0) { - EnsureCapacity(used_digits_ + 1); - bigits_[used_digits_] = carry & kBigitMask; - used_digits_++; - carry >>= kBigitSize; - } -} - - -void Bignum::MultiplyByPowerOfTen(int exponent) { - const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d); - const uint16_t kFive1 = 5; - const uint16_t kFive2 = kFive1 * 5; - const uint16_t kFive3 = kFive2 * 5; - const uint16_t kFive4 = kFive3 * 5; - const uint16_t kFive5 = kFive4 * 5; - const uint16_t kFive6 = kFive5 * 5; - const uint32_t kFive7 = kFive6 * 5; - const uint32_t kFive8 = kFive7 * 5; - const uint32_t kFive9 = kFive8 * 5; - const uint32_t kFive10 = kFive9 * 5; - const uint32_t kFive11 = kFive10 * 5; - const uint32_t kFive12 = kFive11 * 5; - const uint32_t kFive13 = kFive12 * 5; - const uint32_t kFive1_to_12[] = - { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6, - kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 }; - - ASSERT(exponent >= 0); - if (exponent == 0) return; - if (used_digits_ == 0) return; - - // We shift by exponent at the end just before returning. - int remaining_exponent = exponent; - while (remaining_exponent >= 27) { - MultiplyByUInt64(kFive27); - remaining_exponent -= 27; - } - while (remaining_exponent >= 13) { - MultiplyByUInt32(kFive13); - remaining_exponent -= 13; - } - if (remaining_exponent > 0) { - MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]); - } - ShiftLeft(exponent); -} - - -void Bignum::Square() { - ASSERT(IsClamped()); - int product_length = 2 * used_digits_; - EnsureCapacity(product_length); - - // Comba multiplication: compute each column separately. - // Example: r = a2a1a0 * b2b1b0. - // r = 1 * a0b0 + - // 10 * (a1b0 + a0b1) + - // 100 * (a2b0 + a1b1 + a0b2) + - // 1000 * (a2b1 + a1b2) + - // 10000 * a2b2 - // - // In the worst case we have to accumulate nb-digits products of digit*digit. - // - // Assert that the additional number of bits in a DoubleChunk are enough to - // sum up used_digits of Bigit*Bigit. - if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) { - UNIMPLEMENTED(); - } - DoubleChunk accumulator = 0; - // First shift the digits so we don't overwrite them. - int copy_offset = used_digits_; - for (int i = 0; i < used_digits_; ++i) { - bigits_[copy_offset + i] = bigits_[i]; - } - // We have two loops to avoid some 'if's in the loop. - for (int i = 0; i < used_digits_; ++i) { - // Process temporary digit i with power i. - // The sum of the two indices must be equal to i. - int bigit_index1 = i; - int bigit_index2 = 0; - // Sum all of the sub-products. - while (bigit_index1 >= 0) { - Chunk chunk1 = bigits_[copy_offset + bigit_index1]; - Chunk chunk2 = bigits_[copy_offset + bigit_index2]; - accumulator += static_cast(chunk1) * chunk2; - bigit_index1--; - bigit_index2++; - } - bigits_[i] = static_cast(accumulator) & kBigitMask; - accumulator >>= kBigitSize; - } - for (int i = used_digits_; i < product_length; ++i) { - int bigit_index1 = used_digits_ - 1; - int bigit_index2 = i - bigit_index1; - // Invariant: sum of both indices is again equal to i. - // Inner loop runs 0 times on last iteration, emptying accumulator. - while (bigit_index2 < used_digits_) { - Chunk chunk1 = bigits_[copy_offset + bigit_index1]; - Chunk chunk2 = bigits_[copy_offset + bigit_index2]; - accumulator += static_cast(chunk1) * chunk2; - bigit_index1--; - bigit_index2++; - } - // The overwritten bigits_[i] will never be read in further loop iterations, - // because bigit_index1 and bigit_index2 are always greater - // than i - used_digits_. - bigits_[i] = static_cast(accumulator) & kBigitMask; - accumulator >>= kBigitSize; - } - // Since the result was guaranteed to lie inside the number the - // accumulator must be 0 now. - ASSERT(accumulator == 0); - - // Don't forget to update the used_digits and the exponent. - used_digits_ = product_length; - exponent_ *= 2; - Clamp(); -} - - -void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { - ASSERT(base != 0); - ASSERT(power_exponent >= 0); - if (power_exponent == 0) { - AssignUInt16(1); - return; - } - Zero(); - int shifts = 0; - // We expect base to be in range 2-32, and most often to be 10. - // It does not make much sense to implement different algorithms for counting - // the bits. - while ((base & 1) == 0) { - base >>= 1; - shifts++; - } - int bit_size = 0; - int tmp_base = base; - while (tmp_base != 0) { - tmp_base >>= 1; - bit_size++; - } - int final_size = bit_size * power_exponent; - // 1 extra bigit for the shifting, and one for rounded final_size. - EnsureCapacity(final_size / kBigitSize + 2); - - // Left to Right exponentiation. - int mask = 1; - while (power_exponent >= mask) mask <<= 1; - - // The mask is now pointing to the bit above the most significant 1-bit of - // power_exponent. - // Get rid of first 1-bit; - mask >>= 2; - uint64_t this_value = base; - - bool delayed_multipliciation = false; - const uint64_t max_32bits = 0xFFFFFFFF; - while (mask != 0 && this_value <= max_32bits) { - this_value = this_value * this_value; - // Verify that there is enough space in this_value to perform the - // multiplication. The first bit_size bits must be 0. - if ((power_exponent & mask) != 0) { - uint64_t base_bits_mask = - ~((static_cast(1) << (64 - bit_size)) - 1); - bool high_bits_zero = (this_value & base_bits_mask) == 0; - if (high_bits_zero) { - this_value *= base; - } else { - delayed_multipliciation = true; - } - } - mask >>= 1; - } - AssignUInt64(this_value); - if (delayed_multipliciation) { - MultiplyByUInt32(base); - } - - // Now do the same thing as a bignum. - while (mask != 0) { - Square(); - if ((power_exponent & mask) != 0) { - MultiplyByUInt32(base); - } - mask >>= 1; - } - - // And finally add the saved shifts. - ShiftLeft(shifts * power_exponent); -} - - -// Precondition: this/other < 16bit. -uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); - ASSERT(other.used_digits_ > 0); - - // Easy case: if we have less digits than the divisor than the result is 0. - // Note: this handles the case where this == 0, too. - if (BigitLength() < other.BigitLength()) { - return 0; - } - - Align(other); - - uint16_t result = 0; - - // Start by removing multiples of 'other' until both numbers have the same - // number of digits. - while (BigitLength() > other.BigitLength()) { - // This naive approach is extremely inefficient if the this divided other - // might be big. This function is implemented for doubleToString where - // the result should be small (less than 10). - ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16)); - // Remove the multiples of the first digit. - // Example this = 23 and other equals 9. -> Remove 2 multiples. - result += bigits_[used_digits_ - 1]; - SubtractTimes(other, bigits_[used_digits_ - 1]); - } - - ASSERT(BigitLength() == other.BigitLength()); - - // Both bignums are at the same length now. - // Since other has more than 0 digits we know that the access to - // bigits_[used_digits_ - 1] is safe. - Chunk this_bigit = bigits_[used_digits_ - 1]; - Chunk other_bigit = other.bigits_[other.used_digits_ - 1]; - - if (other.used_digits_ == 1) { - // Shortcut for easy (and common) case. - int quotient = this_bigit / other_bigit; - bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; - result += quotient; - Clamp(); - return result; - } - - int division_estimate = this_bigit / (other_bigit + 1); - result += division_estimate; - SubtractTimes(other, division_estimate); - - if (other_bigit * (division_estimate + 1) > this_bigit) { - // No need to even try to subtract. Even if other's remaining digits were 0 - // another subtraction would be too much. - return result; - } - - while (LessEqual(other, *this)) { - SubtractBignum(other); - result++; - } - return result; -} - - -template -static int SizeInHexChars(S number) { - ASSERT(number > 0); - int result = 0; - while (number != 0) { - number >>= 4; - result++; - } - return result; -} - - -static char HexCharOfValue(int value) { - ASSERT(0 <= value && value <= 16); - if (value < 10) return value + '0'; - return value - 10 + 'A'; -} - - -bool Bignum::ToHexString(char* buffer, int buffer_size) const { - ASSERT(IsClamped()); - // Each bigit must be printable as separate hex-character. - ASSERT(kBigitSize % 4 == 0); - const int kHexCharsPerBigit = kBigitSize / 4; - - if (used_digits_ == 0) { - if (buffer_size < 2) return false; - buffer[0] = '0'; - buffer[1] = '\0'; - return true; - } - // We add 1 for the terminating '\0' character. - int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + - SizeInHexChars(bigits_[used_digits_ - 1]) + 1; - if (needed_chars > buffer_size) return false; - int string_index = needed_chars - 1; - buffer[string_index--] = '\0'; - for (int i = 0; i < exponent_; ++i) { - for (int j = 0; j < kHexCharsPerBigit; ++j) { - buffer[string_index--] = '0'; - } - } - for (int i = 0; i < used_digits_ - 1; ++i) { - Chunk current_bigit = bigits_[i]; - for (int j = 0; j < kHexCharsPerBigit; ++j) { - buffer[string_index--] = HexCharOfValue(current_bigit & 0xF); - current_bigit >>= 4; - } - } - // And finally the last bigit. - Chunk most_significant_bigit = bigits_[used_digits_ - 1]; - while (most_significant_bigit != 0) { - buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF); - most_significant_bigit >>= 4; - } - return true; -} - - -Bignum::Chunk Bignum::BigitAt(int index) const { - if (index >= BigitLength()) return 0; - if (index < exponent_) return 0; - return bigits_[index - exponent_]; -} - - -int Bignum::Compare(const Bignum& a, const Bignum& b) { - ASSERT(a.IsClamped()); - ASSERT(b.IsClamped()); - int bigit_length_a = a.BigitLength(); - int bigit_length_b = b.BigitLength(); - if (bigit_length_a < bigit_length_b) return -1; - if (bigit_length_a > bigit_length_b) return +1; - for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) { - Chunk bigit_a = a.BigitAt(i); - Chunk bigit_b = b.BigitAt(i); - if (bigit_a < bigit_b) return -1; - if (bigit_a > bigit_b) return +1; - // Otherwise they are equal up to this digit. Try the next digit. - } - return 0; -} - - -int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { - ASSERT(a.IsClamped()); - ASSERT(b.IsClamped()); - ASSERT(c.IsClamped()); - if (a.BigitLength() < b.BigitLength()) { - return PlusCompare(b, a, c); - } - if (a.BigitLength() + 1 < c.BigitLength()) return -1; - if (a.BigitLength() > c.BigitLength()) return +1; - // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than - // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one - // of 'a'. - if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) { - return -1; - } - - Chunk borrow = 0; - // Starting at min_exponent all digits are == 0. So no need to compare them. - int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_); - for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { - Chunk chunk_a = a.BigitAt(i); - Chunk chunk_b = b.BigitAt(i); - Chunk chunk_c = c.BigitAt(i); - Chunk sum = chunk_a + chunk_b; - if (sum > chunk_c + borrow) { - return +1; - } else { - borrow = chunk_c + borrow - sum; - if (borrow > 1) return -1; - borrow <<= kBigitSize; - } - } - if (borrow == 0) return 0; - return -1; -} - - -void Bignum::Clamp() { - while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) { - used_digits_--; - } - if (used_digits_ == 0) { - // Zero. - exponent_ = 0; - } -} - - -bool Bignum::IsClamped() const { - return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0; -} - - -void Bignum::Zero() { - for (int i = 0; i < used_digits_; ++i) { - bigits_[i] = 0; - } - used_digits_ = 0; - exponent_ = 0; -} - - -void Bignum::Align(const Bignum& other) { - if (exponent_ > other.exponent_) { - // If "X" represents a "hidden" digit (by the exponent) then we are in the - // following case (a == this, b == other): - // a: aaaaaaXXXX or a: aaaaaXXX - // b: bbbbbbX b: bbbbbbbbXX - // We replace some of the hidden digits (X) of a with 0 digits. - // a: aaaaaa000X or a: aaaaa0XX - int zero_digits = exponent_ - other.exponent_; - EnsureCapacity(used_digits_ + zero_digits); - for (int i = used_digits_ - 1; i >= 0; --i) { - bigits_[i + zero_digits] = bigits_[i]; - } - for (int i = 0; i < zero_digits; ++i) { - bigits_[i] = 0; - } - used_digits_ += zero_digits; - exponent_ -= zero_digits; - ASSERT(used_digits_ >= 0); - ASSERT(exponent_ >= 0); - } -} - - -void Bignum::BigitsShiftLeft(int shift_amount) { - ASSERT(shift_amount < kBigitSize); - ASSERT(shift_amount >= 0); - Chunk carry = 0; - for (int i = 0; i < used_digits_; ++i) { - Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount); - bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask; - carry = new_carry; - } - if (carry != 0) { - bigits_[used_digits_] = carry; - used_digits_++; - } -} - - -void Bignum::SubtractTimes(const Bignum& other, int factor) { - ASSERT(exponent_ <= other.exponent_); - if (factor < 3) { - for (int i = 0; i < factor; ++i) { - SubtractBignum(other); - } - return; - } - Chunk borrow = 0; - int exponent_diff = other.exponent_ - exponent_; - for (int i = 0; i < other.used_digits_; ++i) { - DoubleChunk product = static_cast(factor) * other.bigits_[i]; - DoubleChunk remove = borrow + product; - Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask); - bigits_[i + exponent_diff] = difference & kBigitMask; - borrow = static_cast((difference >> (kChunkSize - 1)) + - (remove >> kBigitSize)); - } - for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) { - if (borrow == 0) return; - Chunk difference = bigits_[i] - borrow; - bigits_[i] = difference & kBigitMask; - borrow = difference >> (kChunkSize - 1); - ++i; - } - Clamp(); -} - - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/bignum.h b/libazure/src/mfbt/double-conversion/bignum.h deleted file mode 100644 index 5ec3544..0000000 --- a/libazure/src/mfbt/double-conversion/bignum.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_BIGNUM_H_ -#define DOUBLE_CONVERSION_BIGNUM_H_ - -#include "utils.h" - -namespace double_conversion { - -class Bignum { - public: - // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately. - // This bignum can encode much bigger numbers, since it contains an - // exponent. - static const int kMaxSignificantBits = 3584; - - Bignum(); - void AssignUInt16(uint16_t value); - void AssignUInt64(uint64_t value); - void AssignBignum(const Bignum& other); - - void AssignDecimalString(Vector value); - void AssignHexString(Vector value); - - void AssignPowerUInt16(uint16_t base, int exponent); - - void AddUInt16(uint16_t operand); - void AddUInt64(uint64_t operand); - void AddBignum(const Bignum& other); - // Precondition: this >= other. - void SubtractBignum(const Bignum& other); - - void Square(); - void ShiftLeft(int shift_amount); - void MultiplyByUInt32(uint32_t factor); - void MultiplyByUInt64(uint64_t factor); - void MultiplyByPowerOfTen(int exponent); - void Times10() { return MultiplyByUInt32(10); } - // Pseudocode: - // int result = this / other; - // this = this % other; - // In the worst case this function is in O(this/other). - uint16_t DivideModuloIntBignum(const Bignum& other); - - bool ToHexString(char* buffer, int buffer_size) const; - - // Returns - // -1 if a < b, - // 0 if a == b, and - // +1 if a > b. - static int Compare(const Bignum& a, const Bignum& b); - static bool Equal(const Bignum& a, const Bignum& b) { - return Compare(a, b) == 0; - } - static bool LessEqual(const Bignum& a, const Bignum& b) { - return Compare(a, b) <= 0; - } - static bool Less(const Bignum& a, const Bignum& b) { - return Compare(a, b) < 0; - } - // Returns Compare(a + b, c); - static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c); - // Returns a + b == c - static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) { - return PlusCompare(a, b, c) == 0; - } - // Returns a + b <= c - static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) { - return PlusCompare(a, b, c) <= 0; - } - // Returns a + b < c - static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) { - return PlusCompare(a, b, c) < 0; - } - private: - typedef uint32_t Chunk; - typedef uint64_t DoubleChunk; - - static const int kChunkSize = sizeof(Chunk) * 8; - static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8; - // With bigit size of 28 we loose some bits, but a double still fits easily - // into two chunks, and more importantly we can use the Comba multiplication. - static const int kBigitSize = 28; - static const Chunk kBigitMask = (1 << kBigitSize) - 1; - // Every instance allocates kBigitLength chunks on the stack. Bignums cannot - // grow. There are no checks if the stack-allocated space is sufficient. - static const int kBigitCapacity = kMaxSignificantBits / kBigitSize; - - void EnsureCapacity(int size) { - if (size > kBigitCapacity) { - UNREACHABLE(); - } - } - void Align(const Bignum& other); - void Clamp(); - bool IsClamped() const; - void Zero(); - // Requires this to have enough capacity (no tests done). - // Updates used_digits_ if necessary. - // shift_amount must be < kBigitSize. - void BigitsShiftLeft(int shift_amount); - // BigitLength includes the "hidden" digits encoded in the exponent. - int BigitLength() const { return used_digits_ + exponent_; } - Chunk BigitAt(int index) const; - void SubtractTimes(const Bignum& other, int factor); - - Chunk bigits_buffer_[kBigitCapacity]; - // A vector backed by bigits_buffer_. This way accesses to the array are - // checked for out-of-bounds errors. - Vector bigits_; - int used_digits_; - // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). - int exponent_; - - DISALLOW_COPY_AND_ASSIGN(Bignum); -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_BIGNUM_H_ diff --git a/libazure/src/mfbt/double-conversion/cached-powers.cc b/libazure/src/mfbt/double-conversion/cached-powers.cc deleted file mode 100644 index c676429..0000000 --- a/libazure/src/mfbt/double-conversion/cached-powers.cc +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include - -#include "utils.h" - -#include "cached-powers.h" - -namespace double_conversion { - -struct CachedPower { - uint64_t significand; - int16_t binary_exponent; - int16_t decimal_exponent; -}; - -static const CachedPower kCachedPowers[] = { - {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, - {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, - {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, - {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, - {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, - {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, - {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, - {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, - {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, - {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, - {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, - {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, - {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, - {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, - {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, - {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, - {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, - {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, - {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, - {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, - {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, - {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, - {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, - {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, - {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, - {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, - {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, - {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, - {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, - {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, - {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, - {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, - {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, - {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, - {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, - {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, - {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, - {UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, - {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, - {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, - {UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, - {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, - {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, - {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, - {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, - {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, - {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, - {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, - {UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, - {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, - {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, - {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, - {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, - {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, - {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, - {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, - {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, - {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, - {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, - {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, - {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, - {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, - {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, - {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, - {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, - {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, - {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, - {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, - {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, - {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, - {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, - {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, - {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, - {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, - {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, - {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, - {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, -}; - -static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers); -static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. -static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) -// Difference between the decimal exponents in the table above. -const int PowersOfTenCache::kDecimalExponentDistance = 8; -const int PowersOfTenCache::kMinDecimalExponent = -348; -const int PowersOfTenCache::kMaxDecimalExponent = 340; - -void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( - int min_exponent, - int max_exponent, - DiyFp* power, - int* decimal_exponent) { - int kQ = DiyFp::kSignificandSize; - double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10); - int foo = kCachedPowersOffset; - int index = - (foo + static_cast(k) - 1) / kDecimalExponentDistance + 1; - ASSERT(0 <= index && index < kCachedPowersLength); - CachedPower cached_power = kCachedPowers[index]; - ASSERT(min_exponent <= cached_power.binary_exponent); - ASSERT(cached_power.binary_exponent <= max_exponent); - *decimal_exponent = cached_power.decimal_exponent; - *power = DiyFp(cached_power.significand, cached_power.binary_exponent); -} - - -void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent, - DiyFp* power, - int* found_exponent) { - ASSERT(kMinDecimalExponent <= requested_exponent); - ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); - int index = - (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; - CachedPower cached_power = kCachedPowers[index]; - *power = DiyFp(cached_power.significand, cached_power.binary_exponent); - *found_exponent = cached_power.decimal_exponent; - ASSERT(*found_exponent <= requested_exponent); - ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/cached-powers.h b/libazure/src/mfbt/double-conversion/cached-powers.h deleted file mode 100644 index 61a5061..0000000 --- a/libazure/src/mfbt/double-conversion/cached-powers.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_CACHED_POWERS_H_ -#define DOUBLE_CONVERSION_CACHED_POWERS_H_ - -#include "diy-fp.h" - -namespace double_conversion { - -class PowersOfTenCache { - public: - - // Not all powers of ten are cached. The decimal exponent of two neighboring - // cached numbers will differ by kDecimalExponentDistance. - static const int kDecimalExponentDistance; - - static const int kMinDecimalExponent; - static const int kMaxDecimalExponent; - - // Returns a cached power-of-ten with a binary exponent in the range - // [min_exponent; max_exponent] (boundaries included). - static void GetCachedPowerForBinaryExponentRange(int min_exponent, - int max_exponent, - DiyFp* power, - int* decimal_exponent); - - // Returns a cached power of ten x ~= 10^k such that - // k <= decimal_exponent < k + kCachedPowersDecimalDistance. - // The given decimal_exponent must satisfy - // kMinDecimalExponent <= requested_exponent, and - // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance. - static void GetCachedPowerForDecimalExponent(int requested_exponent, - DiyFp* power, - int* found_exponent); -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_ diff --git a/libazure/src/mfbt/double-conversion/diy-fp.cc b/libazure/src/mfbt/double-conversion/diy-fp.cc deleted file mode 100644 index ddd1891..0000000 --- a/libazure/src/mfbt/double-conversion/diy-fp.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -#include "diy-fp.h" -#include "utils.h" - -namespace double_conversion { - -void DiyFp::Multiply(const DiyFp& other) { - // Simply "emulates" a 128 bit multiplication. - // However: the resulting number only contains 64 bits. The least - // significant 64 bits are only used for rounding the most significant 64 - // bits. - const uint64_t kM32 = 0xFFFFFFFFU; - uint64_t a = f_ >> 32; - uint64_t b = f_ & kM32; - uint64_t c = other.f_ >> 32; - uint64_t d = other.f_ & kM32; - uint64_t ac = a * c; - uint64_t bc = b * c; - uint64_t ad = a * d; - uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); - // By adding 1U << 31 to tmp we round the final result. - // Halfway cases will be round up. - tmp += 1U << 31; - uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); - e_ += other.e_ + 64; - f_ = result_f; -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/diy-fp.h b/libazure/src/mfbt/double-conversion/diy-fp.h deleted file mode 100644 index 9dcf8fb..0000000 --- a/libazure/src/mfbt/double-conversion/diy-fp.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_DIY_FP_H_ -#define DOUBLE_CONVERSION_DIY_FP_H_ - -#include "utils.h" - -namespace double_conversion { - -// This "Do It Yourself Floating Point" class implements a floating-point number -// with a uint64 significand and an int exponent. Normalized DiyFp numbers will -// have the most significant bit of the significand set. -// Multiplication and Subtraction do not normalize their results. -// DiyFp are not designed to contain special doubles (NaN and Infinity). -class DiyFp { - public: - static const int kSignificandSize = 64; - - DiyFp() : f_(0), e_(0) {} - DiyFp(uint64_t f, int e) : f_(f), e_(e) {} - - // this = this - other. - // The exponents of both numbers must be the same and the significand of this - // must be bigger than the significand of other. - // The result will not be normalized. - void Subtract(const DiyFp& other) { - ASSERT(e_ == other.e_); - ASSERT(f_ >= other.f_); - f_ -= other.f_; - } - - // Returns a - b. - // The exponents of both numbers must be the same and this must be bigger - // than other. The result will not be normalized. - static DiyFp Minus(const DiyFp& a, const DiyFp& b) { - DiyFp result = a; - result.Subtract(b); - return result; - } - - - // this = this * other. - void Multiply(const DiyFp& other); - - // returns a * b; - static DiyFp Times(const DiyFp& a, const DiyFp& b) { - DiyFp result = a; - result.Multiply(b); - return result; - } - - void Normalize() { - ASSERT(f_ != 0); - uint64_t f = f_; - int e = e_; - - // This method is mainly called for normalizing boundaries. In general - // boundaries need to be shifted by 10 bits. We thus optimize for this case. - const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); - while ((f & k10MSBits) == 0) { - f <<= 10; - e -= 10; - } - while ((f & kUint64MSB) == 0) { - f <<= 1; - e--; - } - f_ = f; - e_ = e; - } - - static DiyFp Normalize(const DiyFp& a) { - DiyFp result = a; - result.Normalize(); - return result; - } - - uint64_t f() const { return f_; } - int e() const { return e_; } - - void set_f(uint64_t new_value) { f_ = new_value; } - void set_e(int new_value) { e_ = new_value; } - - private: - static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); - - uint64_t f_; - int e_; -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_DIY_FP_H_ diff --git a/libazure/src/mfbt/double-conversion/double-conversion.cc b/libazure/src/mfbt/double-conversion/double-conversion.cc deleted file mode 100644 index a79fe92..0000000 --- a/libazure/src/mfbt/double-conversion/double-conversion.cc +++ /dev/null @@ -1,889 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include - -#include "double-conversion.h" - -#include "bignum-dtoa.h" -#include "fast-dtoa.h" -#include "fixed-dtoa.h" -#include "ieee.h" -#include "strtod.h" -#include "utils.h" - -namespace double_conversion { - -const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { - int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; - static DoubleToStringConverter converter(flags, - "Infinity", - "NaN", - 'e', - -6, 21, - 6, 0); - return converter; -} - - -bool DoubleToStringConverter::HandleSpecialValues( - double value, - StringBuilder* result_builder) const { - Double double_inspect(value); - if (double_inspect.IsInfinite()) { - if (infinity_symbol_ == NULL) return false; - if (value < 0) { - result_builder->AddCharacter('-'); - } - result_builder->AddString(infinity_symbol_); - return true; - } - if (double_inspect.IsNan()) { - if (nan_symbol_ == NULL) return false; - result_builder->AddString(nan_symbol_); - return true; - } - return false; -} - - -void DoubleToStringConverter::CreateExponentialRepresentation( - const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const { - ASSERT(length != 0); - result_builder->AddCharacter(decimal_digits[0]); - if (length != 1) { - result_builder->AddCharacter('.'); - result_builder->AddSubstring(&decimal_digits[1], length-1); - } - result_builder->AddCharacter(exponent_character_); - if (exponent < 0) { - result_builder->AddCharacter('-'); - exponent = -exponent; - } else { - if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { - result_builder->AddCharacter('+'); - } - } - if (exponent == 0) { - result_builder->AddCharacter('0'); - return; - } - ASSERT(exponent < 1e4); - const int kMaxExponentLength = 5; - char buffer[kMaxExponentLength + 1]; - buffer[kMaxExponentLength] = '\0'; - int first_char_pos = kMaxExponentLength; - while (exponent > 0) { - buffer[--first_char_pos] = '0' + (exponent % 10); - exponent /= 10; - } - result_builder->AddSubstring(&buffer[first_char_pos], - kMaxExponentLength - first_char_pos); -} - - -void DoubleToStringConverter::CreateDecimalRepresentation( - const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const { - // Create a representation that is padded with zeros if needed. - if (decimal_point <= 0) { - // "0.00000decimal_rep". - result_builder->AddCharacter('0'); - if (digits_after_point > 0) { - result_builder->AddCharacter('.'); - result_builder->AddPadding('0', -decimal_point); - ASSERT(length <= digits_after_point - (-decimal_point)); - result_builder->AddSubstring(decimal_digits, length); - int remaining_digits = digits_after_point - (-decimal_point) - length; - result_builder->AddPadding('0', remaining_digits); - } - } else if (decimal_point >= length) { - // "decimal_rep0000.00000" or "decimal_rep.0000" - result_builder->AddSubstring(decimal_digits, length); - result_builder->AddPadding('0', decimal_point - length); - if (digits_after_point > 0) { - result_builder->AddCharacter('.'); - result_builder->AddPadding('0', digits_after_point); - } - } else { - // "decima.l_rep000" - ASSERT(digits_after_point > 0); - result_builder->AddSubstring(decimal_digits, decimal_point); - result_builder->AddCharacter('.'); - ASSERT(length - decimal_point <= digits_after_point); - result_builder->AddSubstring(&decimal_digits[decimal_point], - length - decimal_point); - int remaining_digits = digits_after_point - (length - decimal_point); - result_builder->AddPadding('0', remaining_digits); - } - if (digits_after_point == 0) { - if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { - result_builder->AddCharacter('.'); - } - if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { - result_builder->AddCharacter('0'); - } - } -} - - -bool DoubleToStringConverter::ToShortestIeeeNumber( - double value, - StringBuilder* result_builder, - DoubleToStringConverter::DtoaMode mode) const { - ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE); - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - int decimal_point; - bool sign; - const int kDecimalRepCapacity = kBase10MaximalLength + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - - bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - int exponent = decimal_point - 1; - if ((decimal_in_shortest_low_ <= exponent) && - (exponent < decimal_in_shortest_high_)) { - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, - decimal_point, - Max(0, decimal_rep_length - decimal_point), - result_builder); - } else { - CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, - result_builder); - } - return true; -} - - -bool DoubleToStringConverter::ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const { - ASSERT(kMaxFixedDigitsBeforePoint == 60); - const double kFirstNonFixed = 1e60; - - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - if (requested_digits > kMaxFixedDigitsAfterPoint) return false; - if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; - - // Find a sufficiently precise decimal representation of n. - int decimal_point; - bool sign; - // Add space for the '\0' byte. - const int kDecimalRepCapacity = - kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - DoubleToAscii(value, FIXED, requested_digits, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, - requested_digits, result_builder); - return true; -} - - -bool DoubleToStringConverter::ToExponential( - double value, - int requested_digits, - StringBuilder* result_builder) const { - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - if (requested_digits < -1) return false; - if (requested_digits > kMaxExponentialDigits) return false; - - int decimal_point; - bool sign; - // Add space for digit before the decimal point and the '\0' character. - const int kDecimalRepCapacity = kMaxExponentialDigits + 2; - ASSERT(kDecimalRepCapacity > kBase10MaximalLength); - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - if (requested_digits == -1) { - DoubleToAscii(value, SHORTEST, 0, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - } else { - DoubleToAscii(value, PRECISION, requested_digits + 1, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - ASSERT(decimal_rep_length <= requested_digits + 1); - - for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { - decimal_rep[i] = '0'; - } - decimal_rep_length = requested_digits + 1; - } - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - int exponent = decimal_point - 1; - CreateExponentialRepresentation(decimal_rep, - decimal_rep_length, - exponent, - result_builder); - return true; -} - - -bool DoubleToStringConverter::ToPrecision(double value, - int precision, - StringBuilder* result_builder) const { - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { - return false; - } - - // Find a sufficiently precise decimal representation of n. - int decimal_point; - bool sign; - // Add one for the terminating null character. - const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - DoubleToAscii(value, PRECISION, precision, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - ASSERT(decimal_rep_length <= precision); - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - // The exponent if we print the number as x.xxeyyy. That is with the - // decimal point after the first digit. - int exponent = decimal_point - 1; - - int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; - if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || - (decimal_point - precision + extra_zero > - max_trailing_padding_zeroes_in_precision_mode_)) { - // Fill buffer to contain 'precision' digits. - // Usually the buffer is already at the correct length, but 'DoubleToAscii' - // is allowed to return less characters. - for (int i = decimal_rep_length; i < precision; ++i) { - decimal_rep[i] = '0'; - } - - CreateExponentialRepresentation(decimal_rep, - precision, - exponent, - result_builder); - } else { - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, - Max(0, precision - decimal_point), - result_builder); - } - return true; -} - - -static BignumDtoaMode DtoaToBignumDtoaMode( - DoubleToStringConverter::DtoaMode dtoa_mode) { - switch (dtoa_mode) { - case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; - case DoubleToStringConverter::SHORTEST_SINGLE: - return BIGNUM_DTOA_SHORTEST_SINGLE; - case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; - case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; - default: - UNREACHABLE(); - return BIGNUM_DTOA_SHORTEST; // To silence compiler. - } -} - - -void DoubleToStringConverter::DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point) { - Vector vector(buffer, buffer_length); - ASSERT(!Double(v).IsSpecial()); - ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0); - - if (Double(v).Sign() < 0) { - *sign = true; - v = -v; - } else { - *sign = false; - } - - if (mode == PRECISION && requested_digits == 0) { - vector[0] = '\0'; - *length = 0; - return; - } - - if (v == 0) { - vector[0] = '0'; - vector[1] = '\0'; - *length = 1; - *point = 1; - return; - } - - bool fast_worked; - switch (mode) { - case SHORTEST: - fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); - break; - case SHORTEST_SINGLE: - fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0, - vector, length, point); - break; - case FIXED: - fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); - break; - case PRECISION: - fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, - vector, length, point); - break; - default: - UNREACHABLE(); - fast_worked = false; - } - if (fast_worked) return; - - // If the fast dtoa didn't succeed use the slower bignum version. - BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); - BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); - vector[*length] = '\0'; -} - - -// Consumes the given substring from the iterator. -// Returns false, if the substring does not match. -static bool ConsumeSubString(const char** current, - const char* end, - const char* substring) { - ASSERT(**current == *substring); - for (substring++; *substring != '\0'; substring++) { - ++*current; - if (*current == end || **current != *substring) return false; - } - ++*current; - return true; -} - - -// Maximum number of significant digits in decimal representation. -// The longest possible double in decimal representation is -// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 -// (768 digits). If we parse a number whose first digits are equal to a -// mean of 2 adjacent doubles (that could have up to 769 digits) the result -// must be rounded to the bigger one unless the tail consists of zeros, so -// we don't need to preserve all the digits. -const int kMaxSignificantDigits = 772; - - -// Returns true if a nonspace found and false if the end has reached. -static inline bool AdvanceToNonspace(const char** current, const char* end) { - while (*current != end) { - if (**current != ' ') return true; - ++*current; - } - return false; -} - - -static bool isDigit(int x, int radix) { - return (x >= '0' && x <= '9' && x < '0' + radix) - || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) - || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); -} - - -static double SignedZero(bool sign) { - return sign ? -0.0 : 0.0; -} - - -// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. -template -static double RadixStringToIeee(const char* current, - const char* end, - bool sign, - bool allow_trailing_junk, - double junk_string_value, - bool read_as_double, - const char** trailing_pointer) { - ASSERT(current != end); - - const int kDoubleSize = Double::kSignificandSize; - const int kSingleSize = Single::kSignificandSize; - const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize; - - // Skip leading 0s. - while (*current == '0') { - ++current; - if (current == end) { - *trailing_pointer = end; - return SignedZero(sign); - } - } - - int64_t number = 0; - int exponent = 0; - const int radix = (1 << radix_log_2); - - do { - int digit; - if (*current >= '0' && *current <= '9' && *current < '0' + radix) { - digit = static_cast(*current) - '0'; - } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) { - digit = static_cast(*current) - 'a' + 10; - } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) { - digit = static_cast(*current) - 'A' + 10; - } else { - if (allow_trailing_junk || !AdvanceToNonspace(¤t, end)) { - break; - } else { - return junk_string_value; - } - } - - number = number * radix + digit; - int overflow = static_cast(number >> kSignificandSize); - if (overflow != 0) { - // Overflow occurred. Need to determine which direction to round the - // result. - int overflow_bits_count = 1; - while (overflow > 1) { - overflow_bits_count++; - overflow >>= 1; - } - - int dropped_bits_mask = ((1 << overflow_bits_count) - 1); - int dropped_bits = static_cast(number) & dropped_bits_mask; - number >>= overflow_bits_count; - exponent = overflow_bits_count; - - bool zero_tail = true; - while (true) { - ++current; - if (current == end || !isDigit(*current, radix)) break; - zero_tail = zero_tail && *current == '0'; - exponent += radix_log_2; - } - - if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { - return junk_string_value; - } - - int middle_value = (1 << (overflow_bits_count - 1)); - if (dropped_bits > middle_value) { - number++; // Rounding up. - } else if (dropped_bits == middle_value) { - // Rounding to even to consistency with decimals: half-way case rounds - // up if significant part is odd and down otherwise. - if ((number & 1) != 0 || !zero_tail) { - number++; // Rounding up. - } - } - - // Rounding up may cause overflow. - if ((number & ((int64_t)1 << kSignificandSize)) != 0) { - exponent++; - number >>= 1; - } - break; - } - ++current; - } while (current != end); - - ASSERT(number < ((int64_t)1 << kSignificandSize)); - ASSERT(static_cast(static_cast(number)) == number); - - *trailing_pointer = current; - - if (exponent == 0) { - if (sign) { - if (number == 0) return -0.0; - number = -number; - } - return static_cast(number); - } - - ASSERT(number != 0); - return Double(DiyFp(number, exponent)).value(); -} - - -double StringToDoubleConverter::StringToIeee( - const char* input, - int length, - int* processed_characters_count, - bool read_as_double) { - const char* current = input; - const char* end = input + length; - - *processed_characters_count = 0; - - const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0; - const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; - const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; - const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; - - // To make sure that iterator dereferencing is valid the following - // convention is used: - // 1. Each '++current' statement is followed by check for equality to 'end'. - // 2. If AdvanceToNonspace returned false then current == end. - // 3. If 'current' becomes equal to 'end' the function returns or goes to - // 'parsing_done'. - // 4. 'current' is not dereferenced after the 'parsing_done' label. - // 5. Code before 'parsing_done' may rely on 'current != end'. - if (current == end) return empty_string_value_; - - if (allow_leading_spaces || allow_trailing_spaces) { - if (!AdvanceToNonspace(¤t, end)) { - *processed_characters_count = current - input; - return empty_string_value_; - } - if (!allow_leading_spaces && (input != current)) { - // No leading spaces allowed, but AdvanceToNonspace moved forward. - return junk_string_value_; - } - } - - // The longest form of simplified number is: "-.1eXXX\0". - const int kBufferSize = kMaxSignificantDigits + 10; - char buffer[kBufferSize]; // NOLINT: size is known at compile time. - int buffer_pos = 0; - - // Exponent will be adjusted if insignificant digits of the integer part - // or insignificant leading zeros of the fractional part are dropped. - int exponent = 0; - int significant_digits = 0; - int insignificant_digits = 0; - bool nonzero_digit_dropped = false; - - bool sign = false; - - if (*current == '+' || *current == '-') { - sign = (*current == '-'); - ++current; - const char* next_non_space = current; - // Skip following spaces (if allowed). - if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_; - if (!allow_spaces_after_sign && (current != next_non_space)) { - return junk_string_value_; - } - current = next_non_space; - } - - if (infinity_symbol_ != NULL) { - if (*current == infinity_symbol_[0]) { - if (!ConsumeSubString(¤t, end, infinity_symbol_)) { - return junk_string_value_; - } - - if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { - return junk_string_value_; - } - if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { - return junk_string_value_; - } - - ASSERT(buffer_pos == 0); - *processed_characters_count = current - input; - return sign ? -Double::Infinity() : Double::Infinity(); - } - } - - if (nan_symbol_ != NULL) { - if (*current == nan_symbol_[0]) { - if (!ConsumeSubString(¤t, end, nan_symbol_)) { - return junk_string_value_; - } - - if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { - return junk_string_value_; - } - if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { - return junk_string_value_; - } - - ASSERT(buffer_pos == 0); - *processed_characters_count = current - input; - return sign ? -Double::NaN() : Double::NaN(); - } - } - - bool leading_zero = false; - if (*current == '0') { - ++current; - if (current == end) { - *processed_characters_count = current - input; - return SignedZero(sign); - } - - leading_zero = true; - - // It could be hexadecimal value. - if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { - ++current; - if (current == end || !isDigit(*current, 16)) { - return junk_string_value_; // "0x". - } - - const char* tail_pointer = NULL; - double result = RadixStringToIeee<4>(current, - end, - sign, - allow_trailing_junk, - junk_string_value_, - read_as_double, - &tail_pointer); - if (tail_pointer != NULL) { - if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end); - *processed_characters_count = tail_pointer - input; - } - return result; - } - - // Ignore leading zeros in the integer part. - while (*current == '0') { - ++current; - if (current == end) { - *processed_characters_count = current - input; - return SignedZero(sign); - } - } - } - - bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; - - // Copy significant digits of the integer part (if any) to the buffer. - while (*current >= '0' && *current <= '9') { - if (significant_digits < kMaxSignificantDigits) { - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = static_cast(*current); - significant_digits++; - // Will later check if it's an octal in the buffer. - } else { - insignificant_digits++; // Move the digit into the exponential part. - nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; - } - octal = octal && *current < '8'; - ++current; - if (current == end) goto parsing_done; - } - - if (significant_digits == 0) { - octal = false; - } - - if (*current == '.') { - if (octal && !allow_trailing_junk) return junk_string_value_; - if (octal) goto parsing_done; - - ++current; - if (current == end) { - if (significant_digits == 0 && !leading_zero) { - return junk_string_value_; - } else { - goto parsing_done; - } - } - - if (significant_digits == 0) { - // octal = false; - // Integer part consists of 0 or is absent. Significant digits start after - // leading zeros (if any). - while (*current == '0') { - ++current; - if (current == end) { - *processed_characters_count = current - input; - return SignedZero(sign); - } - exponent--; // Move this 0 into the exponent. - } - } - - // There is a fractional part. - // We don't emit a '.', but adjust the exponent instead. - while (*current >= '0' && *current <= '9') { - if (significant_digits < kMaxSignificantDigits) { - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = static_cast(*current); - significant_digits++; - exponent--; - } else { - // Ignore insignificant digits in the fractional part. - nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; - } - ++current; - if (current == end) goto parsing_done; - } - } - - if (!leading_zero && exponent == 0 && significant_digits == 0) { - // If leading_zeros is true then the string contains zeros. - // If exponent < 0 then string was [+-]\.0*... - // If significant_digits != 0 the string is not equal to 0. - // Otherwise there are no digits in the string. - return junk_string_value_; - } - - // Parse exponential part. - if (*current == 'e' || *current == 'E') { - if (octal && !allow_trailing_junk) return junk_string_value_; - if (octal) goto parsing_done; - ++current; - if (current == end) { - if (allow_trailing_junk) { - goto parsing_done; - } else { - return junk_string_value_; - } - } - char sign = '+'; - if (*current == '+' || *current == '-') { - sign = static_cast(*current); - ++current; - if (current == end) { - if (allow_trailing_junk) { - goto parsing_done; - } else { - return junk_string_value_; - } - } - } - - if (current == end || *current < '0' || *current > '9') { - if (allow_trailing_junk) { - goto parsing_done; - } else { - return junk_string_value_; - } - } - - const int max_exponent = INT_MAX / 2; - ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); - int num = 0; - do { - // Check overflow. - int digit = *current - '0'; - if (num >= max_exponent / 10 - && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { - num = max_exponent; - } else { - num = num * 10 + digit; - } - ++current; - } while (current != end && *current >= '0' && *current <= '9'); - - exponent += (sign == '-' ? -num : num); - } - - if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { - return junk_string_value_; - } - if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { - return junk_string_value_; - } - if (allow_trailing_spaces) { - AdvanceToNonspace(¤t, end); - } - - parsing_done: - exponent += insignificant_digits; - - if (octal) { - double result; - const char* tail_pointer = NULL; - result = RadixStringToIeee<3>(buffer, - buffer + buffer_pos, - sign, - allow_trailing_junk, - junk_string_value_, - read_as_double, - &tail_pointer); - ASSERT(tail_pointer != NULL); - *processed_characters_count = current - input; - return result; - } - - if (nonzero_digit_dropped) { - buffer[buffer_pos++] = '1'; - exponent--; - } - - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos] = '\0'; - - double converted; - if (read_as_double) { - converted = Strtod(Vector(buffer, buffer_pos), exponent); - } else { - converted = Strtof(Vector(buffer, buffer_pos), exponent); - } - *processed_characters_count = current - input; - return sign? -converted: converted; -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/double-conversion.h b/libazure/src/mfbt/double-conversion/double-conversion.h deleted file mode 100644 index c62b16b..0000000 --- a/libazure/src/mfbt/double-conversion/double-conversion.h +++ /dev/null @@ -1,537 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ -#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ - -#include "mozilla/Types.h" -#include "utils.h" - -namespace double_conversion { - -class DoubleToStringConverter { - public: - // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint - // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the - // function returns false. - static const int kMaxFixedDigitsBeforePoint = 60; - static const int kMaxFixedDigitsAfterPoint = 60; - - // When calling ToExponential with a requested_digits - // parameter > kMaxExponentialDigits then the function returns false. - static const int kMaxExponentialDigits = 120; - - // When calling ToPrecision with a requested_digits - // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits - // then the function returns false. - static const int kMinPrecisionDigits = 1; - static const int kMaxPrecisionDigits = 120; - - enum Flags { - NO_FLAGS = 0, - EMIT_POSITIVE_EXPONENT_SIGN = 1, - EMIT_TRAILING_DECIMAL_POINT = 2, - EMIT_TRAILING_ZERO_AFTER_POINT = 4, - UNIQUE_ZERO = 8 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent - // form, emits a '+' for positive exponents. Example: 1.2e+2. - // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is - // converted into decimal format then a trailing decimal point is appended. - // Example: 2345.0 is converted to "2345.". - // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point - // emits a trailing '0'-character. This flag requires the - // EXMIT_TRAILING_DECIMAL_POINT flag. - // Example: 2345.0 is converted to "2345.0". - // - UNIQUE_ZERO: "-0.0" is converted to "0.0". - // - // Infinity symbol and nan_symbol provide the string representation for these - // special values. If the string is NULL and the special value is encountered - // then the conversion functions return false. - // - // The exponent_character is used in exponential representations. It is - // usually 'e' or 'E'. - // - // When converting to the shortest representation the converter will - // represent input numbers in decimal format if they are in the interval - // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ - // (lower boundary included, greater boundary excluded). - // Example: with decimal_in_shortest_low = -6 and - // decimal_in_shortest_high = 21: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // When converting to precision mode the converter may add - // max_leading_padding_zeroes before returning the number in exponential - // format. - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - DoubleToStringConverter(int flags, - const char* infinity_symbol, - const char* nan_symbol, - char exponent_character, - int decimal_in_shortest_low, - int decimal_in_shortest_high, - int max_leading_padding_zeroes_in_precision_mode, - int max_trailing_padding_zeroes_in_precision_mode) - : flags_(flags), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol), - exponent_character_(exponent_character), - decimal_in_shortest_low_(decimal_in_shortest_low), - decimal_in_shortest_high_(decimal_in_shortest_high), - max_leading_padding_zeroes_in_precision_mode_( - max_leading_padding_zeroes_in_precision_mode), - max_trailing_padding_zeroes_in_precision_mode_( - max_trailing_padding_zeroes_in_precision_mode) { - // When 'trailing zero after the point' is set, then 'trailing point' - // must be set too. - ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || - !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); - } - - // Returns a converter following the EcmaScript specification. - static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); - - // Computes the shortest string of digits that correctly represent the input - // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high - // (see constructor) it then either returns a decimal representation, or an - // exponential representation. - // Example with decimal_in_shortest_low = -6, - // decimal_in_shortest_high = 21, - // EMIT_POSITIVE_EXPONENT_SIGN activated, and - // EMIT_TRAILING_DECIMAL_POINT deactived: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // Note: the conversion may round the output if the returned string - // is accurate enough to uniquely identify the input-number. - // For example the most precise representation of the double 9e59 equals - // "899999999999999918767229449717619953810131273674690656206848", but - // the converter will return the shorter (but still correct) "9e59". - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except when the input value is special and no infinity_symbol or - // nan_symbol has been given to the constructor. - bool ToShortest(double value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST); - } - - // Same as ToShortest, but for single-precision floats. - bool ToShortestSingle(float value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); - } - - - // Computes a decimal representation with a fixed number of digits after the - // decimal point. The last emitted digit is rounded. - // - // Examples: - // ToFixed(3.12, 1) -> "3.1" - // ToFixed(3.1415, 3) -> "3.142" - // ToFixed(1234.56789, 4) -> "1234.5679" - // ToFixed(1.23, 5) -> "1.23000" - // ToFixed(0.1, 4) -> "0.1000" - // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" - // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" - // ToFixed(0.1, 17) -> "0.10000000000000001" - // - // If requested_digits equals 0, then the tail of the result depends on - // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples, for requested_digits == 0, - // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be - // - false and false: then 123.45 -> 123 - // 0.678 -> 1 - // - true and false: then 123.45 -> 123. - // 0.678 -> 1. - // - true and true: then 123.45 -> 123.0 - // 0.678 -> 1.0 - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'value' > 10^kMaxFixedDigitsBeforePoint, or - // - 'requested_digits' > kMaxFixedDigitsAfterPoint. - // The last two conditions imply that the result will never contain more than - // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters - // (one additional character for the sign, and one for the decimal point). - MFBT_API bool ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes a representation in exponential format with requested_digits - // after the decimal point. The last emitted digit is rounded. - // If requested_digits equals -1, then the shortest exponential representation - // is computed. - // - // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and - // exponent_character set to 'e'. - // ToExponential(3.12, 1) -> "3.1e0" - // ToExponential(5.0, 3) -> "5.000e0" - // ToExponential(0.001, 2) -> "1.00e-3" - // ToExponential(3.1415, -1) -> "3.1415e0" - // ToExponential(3.1415, 4) -> "3.1415e0" - // ToExponential(3.1415, 3) -> "3.142e0" - // ToExponential(123456789000000, 3) -> "1.235e14" - // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" - // ToExponential(1000000000000000019884624838656.0, 32) -> - // "1.00000000000000001988462483865600e30" - // ToExponential(1234, 0) -> "1e3" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'requested_digits' > kMaxExponentialDigits. - // The last condition implies that the result will never contain more than - // kMaxExponentialDigits + 8 characters (the sign, the digit before the - // decimal point, the decimal point, the exponent character, the - // exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToExponential(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes 'precision' leading digits of the given 'value' and returns them - // either in exponential or decimal format, depending on - // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the - // constructor). - // The last computed digit is rounded. - // - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no - // EMIT_TRAILING_ZERO_AFTER_POINT: - // ToPrecision(123450.0, 6) -> "123450" - // ToPrecision(123450.0, 5) -> "123450" - // ToPrecision(123450.0, 4) -> "123500" - // ToPrecision(123450.0, 3) -> "123000" - // ToPrecision(123450.0, 2) -> "1.2e5" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - precision < kMinPericisionDigits - // - precision > kMaxPrecisionDigits - // The last condition implies that the result will never contain more than - // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the - // exponent character, the exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToPrecision(double value, - int precision, - StringBuilder* result_builder) const; - - enum DtoaMode { - // Produce the shortest correct representation. - // For example the output of 0.299999999999999988897 is (the less accurate - // but correct) 0.3. - SHORTEST, - // Same as SHORTEST, but for single-precision floats. - SHORTEST_SINGLE, - // Produce a fixed number of digits after the decimal point. - // For instance fixed(0.1, 4) becomes 0.1000 - // If the input number is big, the output will be big. - FIXED, - // Fixed number of digits (independent of the decimal point). - PRECISION - }; - - // The maximal number of digits that are needed to emit a double in base 10. - // A higher precision can be achieved by using more digits, but the shortest - // accurate representation of any double will never use more digits than - // kBase10MaximalLength. - // Note that DoubleToAscii null-terminates its input. So the given buffer - // should be at least kBase10MaximalLength + 1 characters long. - static const MFBT_DATA int kBase10MaximalLength = 17; - - // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or - // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' - // after it has been casted to a single-precision float. That is, in this - // mode static_cast(v) must not be NaN, +Infinity or -Infinity. - // - // The result should be interpreted as buffer * 10^(point-length). - // - // The output depends on the given mode: - // - SHORTEST: produce the least amount of digits for which the internal - // identity requirement is still satisfied. If the digits are printed - // (together with the correct exponent) then reading this number will give - // 'v' again. The buffer will choose the representation that is closest to - // 'v'. If there are two at the same distance, than the one farther away - // from 0 is chosen (halfway cases - ending with 5 - are rounded up). - // In this mode the 'requested_digits' parameter is ignored. - // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. - // - FIXED: produces digits necessary to print a given number with - // 'requested_digits' digits after the decimal point. The produced digits - // might be too short in which case the caller has to fill the remainder - // with '0's. - // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. - // Halfway cases are rounded towards +/-Infinity (away from 0). The call - // toFixed(0.15, 2) thus returns buffer="2", point=0. - // The returned buffer may contain digits that would be truncated from the - // shortest representation of the input. - // - PRECISION: produces 'requested_digits' where the first digit is not '0'. - // Even though the length of produced digits usually equals - // 'requested_digits', the function is allowed to return fewer digits, in - // which case the caller has to fill the missing digits with '0's. - // Halfway cases are again rounded away from 0. - // DoubleToAscii expects the given buffer to be big enough to hold all - // digits and a terminating null-character. In SHORTEST-mode it expects a - // buffer of at least kBase10MaximalLength + 1. In all other modes the - // requested_digits parameter and the padding-zeroes limit the size of the - // output. Don't forget the decimal point, the exponent character and the - // terminating null-character when computing the maximal output size. - // The given length is only used in debug mode to ensure the buffer is big - // enough. - static MFBT_API void DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point); - - private: - // Implementation for ToShortest and ToShortestSingle. - MFBT_API bool ToShortestIeeeNumber(double value, - StringBuilder* result_builder, - DtoaMode mode) const; - - // If the value is a special value (NaN or Infinity) constructs the - // corresponding string using the configured infinity/nan-symbol. - // If either of them is NULL or the value is not special then the - // function returns false. - MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; - // Constructs an exponential representation (i.e. 1.234e56). - // The given exponent assumes a decimal point after the first decimal digit. - MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const; - // Creates a decimal representation (i.e 1234.5678). - MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const; - - const int flags_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - const char exponent_character_; - const int decimal_in_shortest_low_; - const int decimal_in_shortest_high_; - const int max_leading_padding_zeroes_in_precision_mode_; - const int max_trailing_padding_zeroes_in_precision_mode_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); -}; - - -class StringToDoubleConverter { - public: - // Enumeration for allowing octals and ignoring junk when converting - // strings to numbers. - enum Flags { - NO_FLAGS = 0, - ALLOW_HEX = 1, - ALLOW_OCTALS = 2, - ALLOW_TRAILING_JUNK = 4, - ALLOW_LEADING_SPACES = 8, - ALLOW_TRAILING_SPACES = 16, - ALLOW_SPACES_AFTER_SIGN = 32 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. - // Ex: StringToDouble("0x1234") -> 4660.0 - // In StringToDouble("0x1234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, - // the string will not be parsed as "0" followed by junk. - // - // - ALLOW_OCTALS: recognizes the prefix "0" for octals: - // If a sequence of octal digits starts with '0', then the number is - // read as octal integer. Octal numbers may only be integers. - // Ex: StringToDouble("01234") -> 668.0 - // StringToDouble("012349") -> 12349.0 // Not a sequence of octal - // // digits. - // In StringToDouble("01234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // In StringToDouble("01234e56") the characters "e56" are trailing - // junk, too. - // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of - // a double literal. - // - ALLOW_LEADING_SPACES: skip over leading spaces. - // - ALLOW_TRAILING_SPACES: ignore trailing spaces. - // - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign. - // Ex: StringToDouble("- 123.2") -> -123.2. - // StringToDouble("+ 123.2") -> 123.2 - // - // empty_string_value is returned when an empty string is given as input. - // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string - // containing only spaces is converted to the 'empty_string_value', too. - // - // junk_string_value is returned when - // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not - // part of a double-literal) is found. - // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a - // double literal. - // - // infinity_symbol and nan_symbol are strings that are used to detect - // inputs that represent infinity and NaN. They can be null, in which case - // they are ignored. - // The conversion routine first reads any possible signs. Then it compares the - // following character of the input-string with the first character of - // the infinity, and nan-symbol. If either matches, the function assumes, that - // a match has been found, and expects the following input characters to match - // the remaining characters of the special-value symbol. - // This means that the following restrictions apply to special-value symbols: - // - they must not start with signs ('+', or '-'), - // - they must not have the same first character. - // - they must not start with digits. - // - // Examples: - // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = "infinity", - // nan_symbol = "nan": - // StringToDouble("0x1234") -> 4660.0. - // StringToDouble("0x1234K") -> 4660.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> NaN // junk_string_value. - // StringToDouble(" 1") -> NaN // junk_string_value. - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("-123.45") -> -123.45. - // StringToDouble("--123.45") -> NaN // junk_string_value. - // StringToDouble("123e45") -> 123e45. - // StringToDouble("123E45") -> 123e45. - // StringToDouble("123e+45") -> 123e45. - // StringToDouble("123E-45") -> 123e-45. - // StringToDouble("123e") -> 123.0 // trailing junk ignored. - // StringToDouble("123e-") -> 123.0 // trailing junk ignored. - // StringToDouble("+NaN") -> NaN // NaN string literal. - // StringToDouble("-infinity") -> -inf. // infinity literal. - // StringToDouble("Infinity") -> NaN // junk_string_value. - // - // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = NULL, - // nan_symbol = NULL: - // StringToDouble("0x1234") -> NaN // junk_string_value. - // StringToDouble("01234") -> 668.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> 0.0 // empty_string_value. - // StringToDouble(" 1") -> 1.0 - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("0123e45") -> NaN // junk_string_value. - // StringToDouble("01239E45") -> 1239e45. - // StringToDouble("-infinity") -> NaN // junk_string_value. - // StringToDouble("NaN") -> NaN // junk_string_value. - StringToDoubleConverter(int flags, - double empty_string_value, - double junk_string_value, - const char* infinity_symbol, - const char* nan_symbol) - : flags_(flags), - empty_string_value_(empty_string_value), - junk_string_value_(junk_string_value), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol) { - } - - // Performs the conversion. - // The output parameter 'processed_characters_count' is set to the number - // of characters that have been processed to read the number. - // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included - // in the 'processed_characters_count'. Trailing junk is never included. - double StringToDouble(const char* buffer, - int length, - int* processed_characters_count) { - return StringToIeee(buffer, length, processed_characters_count, true); - } - - // Same as StringToDouble but reads a float. - // Note that this is not equivalent to static_cast(StringToDouble(...)) - // due to potential double-rounding. - float StringToFloat(const char* buffer, - int length, - int* processed_characters_count) { - return static_cast(StringToIeee(buffer, length, - processed_characters_count, false)); - } - - private: - const int flags_; - const double empty_string_value_; - const double junk_string_value_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - - double StringToIeee(const char* buffer, - int length, - int* processed_characters_count, - bool read_as_double); - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ diff --git a/libazure/src/mfbt/double-conversion/fast-dtoa.cc b/libazure/src/mfbt/double-conversion/fast-dtoa.cc deleted file mode 100644 index 1a0f823..0000000 --- a/libazure/src/mfbt/double-conversion/fast-dtoa.cc +++ /dev/null @@ -1,664 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "fast-dtoa.h" - -#include "cached-powers.h" -#include "diy-fp.h" -#include "ieee.h" - -namespace double_conversion { - -// The minimal and maximal target exponent define the range of w's binary -// exponent, where 'w' is the result of multiplying the input by a cached power -// of ten. -// -// A different range might be chosen on a different platform, to optimize digit -// generation, but a smaller range requires more powers of ten to be cached. -static const int kMinimalTargetExponent = -60; -static const int kMaximalTargetExponent = -32; - - -// Adjusts the last digit of the generated number, and screens out generated -// solutions that may be inaccurate. A solution may be inaccurate if it is -// outside the safe interval, or if we cannot prove that it is closer to the -// input than a neighboring representation of the same length. -// -// Input: * buffer containing the digits of too_high / 10^kappa -// * the buffer's length -// * distance_too_high_w == (too_high - w).f() * unit -// * unsafe_interval == (too_high - too_low).f() * unit -// * rest = (too_high - buffer * 10^kappa).f() * unit -// * ten_kappa = 10^kappa * unit -// * unit = the common multiplier -// Output: returns true if the buffer is guaranteed to contain the closest -// representable number to the input. -// Modifies the generated digits in the buffer to approach (round towards) w. -static bool RoundWeed(Vector buffer, - int length, - uint64_t distance_too_high_w, - uint64_t unsafe_interval, - uint64_t rest, - uint64_t ten_kappa, - uint64_t unit) { - uint64_t small_distance = distance_too_high_w - unit; - uint64_t big_distance = distance_too_high_w + unit; - // Let w_low = too_high - big_distance, and - // w_high = too_high - small_distance. - // Note: w_low < w < w_high - // - // The real w (* unit) must lie somewhere inside the interval - // ]w_low; w_high[ (often written as "(w_low; w_high)") - - // Basically the buffer currently contains a number in the unsafe interval - // ]too_low; too_high[ with too_low < w < too_high - // - // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ^v 1 unit ^ ^ ^ ^ - // boundary_high --------------------- . . . . - // ^v 1 unit . . . . - // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . . - // . . ^ . . - // . big_distance . . . - // . . . . rest - // small_distance . . . . - // v . . . . - // w_high - - - - - - - - - - - - - - - - - - . . . . - // ^v 1 unit . . . . - // w ---------------------------------------- . . . . - // ^v 1 unit v . . . - // w_low - - - - - - - - - - - - - - - - - - - - - . . . - // . . v - // buffer --------------------------------------------------+-------+-------- - // . . - // safe_interval . - // v . - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . - // ^v 1 unit . - // boundary_low ------------------------- unsafe_interval - // ^v 1 unit v - // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // - // Note that the value of buffer could lie anywhere inside the range too_low - // to too_high. - // - // boundary_low, boundary_high and w are approximations of the real boundaries - // and v (the input number). They are guaranteed to be precise up to one unit. - // In fact the error is guaranteed to be strictly less than one unit. - // - // Anything that lies outside the unsafe interval is guaranteed not to round - // to v when read again. - // Anything that lies inside the safe interval is guaranteed to round to v - // when read again. - // If the number inside the buffer lies inside the unsafe interval but not - // inside the safe interval then we simply do not know and bail out (returning - // false). - // - // Similarly we have to take into account the imprecision of 'w' when finding - // the closest representation of 'w'. If we have two potential - // representations, and one is closer to both w_low and w_high, then we know - // it is closer to the actual value v. - // - // By generating the digits of too_high we got the largest (closest to - // too_high) buffer that is still in the unsafe interval. In the case where - // w_high < buffer < too_high we try to decrement the buffer. - // This way the buffer approaches (rounds towards) w. - // There are 3 conditions that stop the decrementation process: - // 1) the buffer is already below w_high - // 2) decrementing the buffer would make it leave the unsafe interval - // 3) decrementing the buffer would yield a number below w_high and farther - // away than the current number. In other words: - // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high - // Instead of using the buffer directly we use its distance to too_high. - // Conceptually rest ~= too_high - buffer - // We need to do the following tests in this order to avoid over- and - // underflows. - ASSERT(rest <= unsafe_interval); - while (rest < small_distance && // Negated condition 1 - unsafe_interval - rest >= ten_kappa && // Negated condition 2 - (rest + ten_kappa < small_distance || // buffer{-1} > w_high - small_distance - rest >= rest + ten_kappa - small_distance)) { - buffer[length - 1]--; - rest += ten_kappa; - } - - // We have approached w+ as much as possible. We now test if approaching w- - // would require changing the buffer. If yes, then we have two possible - // representations close to w, but we cannot decide which one is closer. - if (rest < big_distance && - unsafe_interval - rest >= ten_kappa && - (rest + ten_kappa < big_distance || - big_distance - rest > rest + ten_kappa - big_distance)) { - return false; - } - - // Weeding test. - // The safe interval is [too_low + 2 ulp; too_high - 2 ulp] - // Since too_low = too_high - unsafe_interval this is equivalent to - // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp] - // Conceptually we have: rest ~= too_high - buffer - return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit); -} - - -// Rounds the buffer upwards if the result is closer to v by possibly adding -// 1 to the buffer. If the precision of the calculation is not sufficient to -// round correctly, return false. -// The rounding might shift the whole buffer in which case the kappa is -// adjusted. For example "99", kappa = 3 might become "10", kappa = 4. -// -// If 2*rest > ten_kappa then the buffer needs to be round up. -// rest can have an error of +/- 1 unit. This function accounts for the -// imprecision and returns false, if the rounding direction cannot be -// unambiguously determined. -// -// Precondition: rest < ten_kappa. -static bool RoundWeedCounted(Vector buffer, - int length, - uint64_t rest, - uint64_t ten_kappa, - uint64_t unit, - int* kappa) { - ASSERT(rest < ten_kappa); - // The following tests are done in a specific order to avoid overflows. They - // will work correctly with any uint64 values of rest < ten_kappa and unit. - // - // If the unit is too big, then we don't know which way to round. For example - // a unit of 50 means that the real number lies within rest +/- 50. If - // 10^kappa == 40 then there is no way to tell which way to round. - if (unit >= ten_kappa) return false; - // Even if unit is just half the size of 10^kappa we are already completely - // lost. (And after the previous test we know that the expression will not - // over/underflow.) - if (ten_kappa - unit <= unit) return false; - // If 2 * (rest + unit) <= 10^kappa we can safely round down. - if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) { - return true; - } - // If 2 * (rest - unit) >= 10^kappa, then we can safely round up. - if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) { - // Increment the last digit recursively until we find a non '9' digit. - buffer[length - 1]++; - for (int i = length - 1; i > 0; --i) { - if (buffer[i] != '0' + 10) break; - buffer[i] = '0'; - buffer[i - 1]++; - } - // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the - // exception of the first digit all digits are now '0'. Simply switch the - // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and - // the power (the kappa) is increased. - if (buffer[0] == '0' + 10) { - buffer[0] = '1'; - (*kappa) += 1; - } - return true; - } - return false; -} - -// Returns the biggest power of ten that is less than or equal to the given -// number. We furthermore receive the maximum number of bits 'number' has. -// -// Returns power == 10^(exponent_plus_one-1) such that -// power <= number < power * 10. -// If number_bits == 0 then 0^(0-1) is returned. -// The number of bits must be <= 32. -// Precondition: number < (1 << (number_bits + 1)). - -// Inspired by the method for finding an integer log base 10 from here: -// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 -static unsigned int const kSmallPowersOfTen[] = - {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, - 1000000000}; - -static void BiggestPowerTen(uint32_t number, - int number_bits, - uint32_t* power, - int* exponent_plus_one) { - ASSERT(number < (1u << (number_bits + 1))); - // 1233/4096 is approximately 1/lg(10). - int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12); - // We increment to skip over the first entry in the kPowersOf10 table. - // Note: kPowersOf10[i] == 10^(i-1). - exponent_plus_one_guess++; - // We don't have any guarantees that 2^number_bits <= number. - // TODO(floitsch): can we change the 'while' into an 'if'? We definitely see - // number < (2^number_bits - 1), but I haven't encountered - // number < (2^number_bits - 2) yet. - while (number < kSmallPowersOfTen[exponent_plus_one_guess]) { - exponent_plus_one_guess--; - } - *power = kSmallPowersOfTen[exponent_plus_one_guess]; - *exponent_plus_one = exponent_plus_one_guess; -} - -// Generates the digits of input number w. -// w is a floating-point number (DiyFp), consisting of a significand and an -// exponent. Its exponent is bounded by kMinimalTargetExponent and -// kMaximalTargetExponent. -// Hence -60 <= w.e() <= -32. -// -// Returns false if it fails, in which case the generated digits in the buffer -// should not be used. -// Preconditions: -// * low, w and high are correct up to 1 ulp (unit in the last place). That -// is, their error must be less than a unit of their last digits. -// * low.e() == w.e() == high.e() -// * low < w < high, and taking into account their error: low~ <= high~ -// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent -// Postconditions: returns false if procedure fails. -// otherwise: -// * buffer is not null-terminated, but len contains the number of digits. -// * buffer contains the shortest possible decimal digit-sequence -// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the -// correct values of low and high (without their error). -// * if more than one decimal representation gives the minimal number of -// decimal digits then the one closest to W (where W is the correct value -// of w) is chosen. -// Remark: this procedure takes into account the imprecision of its input -// numbers. If the precision is not enough to guarantee all the postconditions -// then false is returned. This usually happens rarely (~0.5%). -// -// Say, for the sake of example, that -// w.e() == -48, and w.f() == 0x1234567890abcdef -// w's value can be computed by w.f() * 2^w.e() -// We can obtain w's integral digits by simply shifting w.f() by -w.e(). -// -> w's integral part is 0x1234 -// w's fractional part is therefore 0x567890abcdef. -// Printing w's integral part is easy (simply print 0x1234 in decimal). -// In order to print its fraction we repeatedly multiply the fraction by 10 and -// get each digit. Example the first digit after the point would be computed by -// (0x567890abcdef * 10) >> 48. -> 3 -// The whole thing becomes slightly more complicated because we want to stop -// once we have enough digits. That is, once the digits inside the buffer -// represent 'w' we can stop. Everything inside the interval low - high -// represents w. However we have to pay attention to low, high and w's -// imprecision. -static bool DigitGen(DiyFp low, - DiyFp w, - DiyFp high, - Vector buffer, - int* length, - int* kappa) { - ASSERT(low.e() == w.e() && w.e() == high.e()); - ASSERT(low.f() + 1 <= high.f() - 1); - ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); - // low, w and high are imprecise, but by less than one ulp (unit in the last - // place). - // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that - // the new numbers are outside of the interval we want the final - // representation to lie in. - // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield - // numbers that are certain to lie in the interval. We will use this fact - // later on. - // We will now start by generating the digits within the uncertain - // interval. Later we will weed out representations that lie outside the safe - // interval and thus _might_ lie outside the correct interval. - uint64_t unit = 1; - DiyFp too_low = DiyFp(low.f() - unit, low.e()); - DiyFp too_high = DiyFp(high.f() + unit, high.e()); - // too_low and too_high are guaranteed to lie outside the interval we want the - // generated number in. - DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low); - // We now cut the input number into two parts: the integral digits and the - // fractionals. We will not write any decimal separator though, but adapt - // kappa instead. - // Reminder: we are currently computing the digits (stored inside the buffer) - // such that: too_low < buffer * 10^kappa < too_high - // We use too_high for the digit_generation and stop as soon as possible. - // If we stop early we effectively round down. - DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); - // Division by one is a shift. - uint32_t integrals = static_cast(too_high.f() >> -one.e()); - // Modulo by one is an and. - uint64_t fractionals = too_high.f() & (one.f() - 1); - uint32_t divisor; - int divisor_exponent_plus_one; - BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), - &divisor, &divisor_exponent_plus_one); - *kappa = divisor_exponent_plus_one; - *length = 0; - // Loop invariant: buffer = too_high / 10^kappa (integer division) - // The invariant holds for the first iteration: kappa has been initialized - // with the divisor exponent + 1. And the divisor is the biggest power of ten - // that is smaller than integrals. - while (*kappa > 0) { - int digit = integrals / divisor; - buffer[*length] = '0' + digit; - (*length)++; - integrals %= divisor; - (*kappa)--; - // Note that kappa now equals the exponent of the divisor and that the - // invariant thus holds again. - uint64_t rest = - (static_cast(integrals) << -one.e()) + fractionals; - // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e()) - // Reminder: unsafe_interval.e() == one.e() - if (rest < unsafe_interval.f()) { - // Rounding down (by not emitting the remaining digits) yields a number - // that lies within the unsafe interval. - return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(), - unsafe_interval.f(), rest, - static_cast(divisor) << -one.e(), unit); - } - divisor /= 10; - } - - // The integrals have been generated. We are at the point of the decimal - // separator. In the following loop we simply multiply the remaining digits by - // 10 and divide by one. We just need to pay attention to multiply associated - // data (like the interval or 'unit'), too. - // Note that the multiplication by 10 does not overflow, because w.e >= -60 - // and thus one.e >= -60. - ASSERT(one.e() >= -60); - ASSERT(fractionals < one.f()); - ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); - while (true) { - fractionals *= 10; - unit *= 10; - unsafe_interval.set_f(unsafe_interval.f() * 10); - // Integer division by one. - int digit = static_cast(fractionals >> -one.e()); - buffer[*length] = '0' + digit; - (*length)++; - fractionals &= one.f() - 1; // Modulo by one. - (*kappa)--; - if (fractionals < unsafe_interval.f()) { - return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit, - unsafe_interval.f(), fractionals, one.f(), unit); - } - } -} - - - -// Generates (at most) requested_digits digits of input number w. -// w is a floating-point number (DiyFp), consisting of a significand and an -// exponent. Its exponent is bounded by kMinimalTargetExponent and -// kMaximalTargetExponent. -// Hence -60 <= w.e() <= -32. -// -// Returns false if it fails, in which case the generated digits in the buffer -// should not be used. -// Preconditions: -// * w is correct up to 1 ulp (unit in the last place). That -// is, its error must be strictly less than a unit of its last digit. -// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent -// -// Postconditions: returns false if procedure fails. -// otherwise: -// * buffer is not null-terminated, but length contains the number of -// digits. -// * the representation in buffer is the most precise representation of -// requested_digits digits. -// * buffer contains at most requested_digits digits of w. If there are less -// than requested_digits digits then some trailing '0's have been removed. -// * kappa is such that -// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2. -// -// Remark: This procedure takes into account the imprecision of its input -// numbers. If the precision is not enough to guarantee all the postconditions -// then false is returned. This usually happens rarely, but the failure-rate -// increases with higher requested_digits. -static bool DigitGenCounted(DiyFp w, - int requested_digits, - Vector buffer, - int* length, - int* kappa) { - ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); - ASSERT(kMinimalTargetExponent >= -60); - ASSERT(kMaximalTargetExponent <= -32); - // w is assumed to have an error less than 1 unit. Whenever w is scaled we - // also scale its error. - uint64_t w_error = 1; - // We cut the input number into two parts: the integral digits and the - // fractional digits. We don't emit any decimal separator, but adapt kappa - // instead. Example: instead of writing "1.2" we put "12" into the buffer and - // increase kappa by 1. - DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); - // Division by one is a shift. - uint32_t integrals = static_cast(w.f() >> -one.e()); - // Modulo by one is an and. - uint64_t fractionals = w.f() & (one.f() - 1); - uint32_t divisor; - int divisor_exponent_plus_one; - BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), - &divisor, &divisor_exponent_plus_one); - *kappa = divisor_exponent_plus_one; - *length = 0; - - // Loop invariant: buffer = w / 10^kappa (integer division) - // The invariant holds for the first iteration: kappa has been initialized - // with the divisor exponent + 1. And the divisor is the biggest power of ten - // that is smaller than 'integrals'. - while (*kappa > 0) { - int digit = integrals / divisor; - buffer[*length] = '0' + digit; - (*length)++; - requested_digits--; - integrals %= divisor; - (*kappa)--; - // Note that kappa now equals the exponent of the divisor and that the - // invariant thus holds again. - if (requested_digits == 0) break; - divisor /= 10; - } - - if (requested_digits == 0) { - uint64_t rest = - (static_cast(integrals) << -one.e()) + fractionals; - return RoundWeedCounted(buffer, *length, rest, - static_cast(divisor) << -one.e(), w_error, - kappa); - } - - // The integrals have been generated. We are at the point of the decimal - // separator. In the following loop we simply multiply the remaining digits by - // 10 and divide by one. We just need to pay attention to multiply associated - // data (the 'unit'), too. - // Note that the multiplication by 10 does not overflow, because w.e >= -60 - // and thus one.e >= -60. - ASSERT(one.e() >= -60); - ASSERT(fractionals < one.f()); - ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); - while (requested_digits > 0 && fractionals > w_error) { - fractionals *= 10; - w_error *= 10; - // Integer division by one. - int digit = static_cast(fractionals >> -one.e()); - buffer[*length] = '0' + digit; - (*length)++; - requested_digits--; - fractionals &= one.f() - 1; // Modulo by one. - (*kappa)--; - } - if (requested_digits != 0) return false; - return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error, - kappa); -} - - -// Provides a decimal representation of v. -// Returns true if it succeeds, otherwise the result cannot be trusted. -// There will be *length digits inside the buffer (not null-terminated). -// If the function returns true then -// v == (double) (buffer * 10^decimal_exponent). -// The digits in the buffer are the shortest representation possible: no -// 0.09999999999999999 instead of 0.1. The shorter representation will even be -// chosen even if the longer one would be closer to v. -// The last digit will be closest to the actual v. That is, even if several -// digits might correctly yield 'v' when read again, the closest will be -// computed. -static bool Grisu3(double v, - FastDtoaMode mode, - Vector buffer, - int* length, - int* decimal_exponent) { - DiyFp w = Double(v).AsNormalizedDiyFp(); - // boundary_minus and boundary_plus are the boundaries between v and its - // closest floating-point neighbors. Any number strictly between - // boundary_minus and boundary_plus will round to v when convert to a double. - // Grisu3 will never output representations that lie exactly on a boundary. - DiyFp boundary_minus, boundary_plus; - if (mode == FAST_DTOA_SHORTEST) { - Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus); - } else { - ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE); - float single_v = static_cast(v); - Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus); - } - ASSERT(boundary_plus.e() == w.e()); - DiyFp ten_mk; // Cached power of ten: 10^-k - int mk; // -k - int ten_mk_minimal_binary_exponent = - kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); - int ten_mk_maximal_binary_exponent = - kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); - PowersOfTenCache::GetCachedPowerForBinaryExponentRange( - ten_mk_minimal_binary_exponent, - ten_mk_maximal_binary_exponent, - &ten_mk, &mk); - ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + - DiyFp::kSignificandSize) && - (kMaximalTargetExponent >= w.e() + ten_mk.e() + - DiyFp::kSignificandSize)); - // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a - // 64 bit significand and ten_mk is thus only precise up to 64 bits. - - // The DiyFp::Times procedure rounds its result, and ten_mk is approximated - // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now - // off by a small amount. - // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w. - // In other words: let f = scaled_w.f() and e = scaled_w.e(), then - // (f-1) * 2^e < w*10^k < (f+1) * 2^e - DiyFp scaled_w = DiyFp::Times(w, ten_mk); - ASSERT(scaled_w.e() == - boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize); - // In theory it would be possible to avoid some recomputations by computing - // the difference between w and boundary_minus/plus (a power of 2) and to - // compute scaled_boundary_minus/plus by subtracting/adding from - // scaled_w. However the code becomes much less readable and the speed - // enhancements are not terriffic. - DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk); - DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk); - - // DigitGen will generate the digits of scaled_w. Therefore we have - // v == (double) (scaled_w * 10^-mk). - // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an - // integer than it will be updated. For instance if scaled_w == 1.23 then - // the buffer will be filled with "123" und the decimal_exponent will be - // decreased by 2. - int kappa; - bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, - buffer, length, &kappa); - *decimal_exponent = -mk + kappa; - return result; -} - - -// The "counted" version of grisu3 (see above) only generates requested_digits -// number of digits. This version does not generate the shortest representation, -// and with enough requested digits 0.1 will at some point print as 0.9999999... -// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and -// therefore the rounding strategy for halfway cases is irrelevant. -static bool Grisu3Counted(double v, - int requested_digits, - Vector buffer, - int* length, - int* decimal_exponent) { - DiyFp w = Double(v).AsNormalizedDiyFp(); - DiyFp ten_mk; // Cached power of ten: 10^-k - int mk; // -k - int ten_mk_minimal_binary_exponent = - kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); - int ten_mk_maximal_binary_exponent = - kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); - PowersOfTenCache::GetCachedPowerForBinaryExponentRange( - ten_mk_minimal_binary_exponent, - ten_mk_maximal_binary_exponent, - &ten_mk, &mk); - ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + - DiyFp::kSignificandSize) && - (kMaximalTargetExponent >= w.e() + ten_mk.e() + - DiyFp::kSignificandSize)); - // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a - // 64 bit significand and ten_mk is thus only precise up to 64 bits. - - // The DiyFp::Times procedure rounds its result, and ten_mk is approximated - // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now - // off by a small amount. - // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w. - // In other words: let f = scaled_w.f() and e = scaled_w.e(), then - // (f-1) * 2^e < w*10^k < (f+1) * 2^e - DiyFp scaled_w = DiyFp::Times(w, ten_mk); - - // We now have (double) (scaled_w * 10^-mk). - // DigitGen will generate the first requested_digits digits of scaled_w and - // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It - // will not always be exactly the same since DigitGenCounted only produces a - // limited number of digits.) - int kappa; - bool result = DigitGenCounted(scaled_w, requested_digits, - buffer, length, &kappa); - *decimal_exponent = -mk + kappa; - return result; -} - - -bool FastDtoa(double v, - FastDtoaMode mode, - int requested_digits, - Vector buffer, - int* length, - int* decimal_point) { - ASSERT(v > 0); - ASSERT(!Double(v).IsSpecial()); - - bool result = false; - int decimal_exponent = 0; - switch (mode) { - case FAST_DTOA_SHORTEST: - case FAST_DTOA_SHORTEST_SINGLE: - result = Grisu3(v, mode, buffer, length, &decimal_exponent); - break; - case FAST_DTOA_PRECISION: - result = Grisu3Counted(v, requested_digits, - buffer, length, &decimal_exponent); - break; - default: - UNREACHABLE(); - } - if (result) { - *decimal_point = *length + decimal_exponent; - buffer[*length] = '\0'; - } - return result; -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/fast-dtoa.h b/libazure/src/mfbt/double-conversion/fast-dtoa.h deleted file mode 100644 index 5f1e8ee..0000000 --- a/libazure/src/mfbt/double-conversion/fast-dtoa.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_FAST_DTOA_H_ -#define DOUBLE_CONVERSION_FAST_DTOA_H_ - -#include "utils.h" - -namespace double_conversion { - -enum FastDtoaMode { - // Computes the shortest representation of the given input. The returned - // result will be the most accurate number of this length. Longer - // representations might be more accurate. - FAST_DTOA_SHORTEST, - // Same as FAST_DTOA_SHORTEST but for single-precision floats. - FAST_DTOA_SHORTEST_SINGLE, - // Computes a representation where the precision (number of digits) is - // given as input. The precision is independent of the decimal point. - FAST_DTOA_PRECISION -}; - -// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not -// include the terminating '\0' character. -static const int kFastDtoaMaximalLength = 17; -// Same for single-precision numbers. -static const int kFastDtoaMaximalSingleLength = 9; - -// Provides a decimal representation of v. -// The result should be interpreted as buffer * 10^(point - length). -// -// Precondition: -// * v must be a strictly positive finite double. -// -// Returns true if it succeeds, otherwise the result can not be trusted. -// There will be *length digits inside the buffer followed by a null terminator. -// If the function returns true and mode equals -// - FAST_DTOA_SHORTEST, then -// the parameter requested_digits is ignored. -// The result satisfies -// v == (double) (buffer * 10^(point - length)). -// The digits in the buffer are the shortest representation possible. E.g. -// if 0.099999999999 and 0.1 represent the same double then "1" is returned -// with point = 0. -// The last digit will be closest to the actual v. That is, even if several -// digits might correctly yield 'v' when read again, the buffer will contain -// the one closest to v. -// - FAST_DTOA_PRECISION, then -// the buffer contains requested_digits digits. -// the difference v - (buffer * 10^(point-length)) is closest to zero for -// all possible representations of requested_digits digits. -// If there are two values that are equally close, then FastDtoa returns -// false. -// For both modes the buffer must be large enough to hold the result. -bool FastDtoa(double d, - FastDtoaMode mode, - int requested_digits, - Vector buffer, - int* length, - int* decimal_point); - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_FAST_DTOA_H_ diff --git a/libazure/src/mfbt/double-conversion/fixed-dtoa.cc b/libazure/src/mfbt/double-conversion/fixed-dtoa.cc deleted file mode 100644 index d56b144..0000000 --- a/libazure/src/mfbt/double-conversion/fixed-dtoa.cc +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include - -#include "fixed-dtoa.h" -#include "ieee.h" - -namespace double_conversion { - -// Represents a 128bit type. This class should be replaced by a native type on -// platforms that support 128bit integers. -class UInt128 { - public: - UInt128() : high_bits_(0), low_bits_(0) { } - UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { } - - void Multiply(uint32_t multiplicand) { - uint64_t accumulator; - - accumulator = (low_bits_ & kMask32) * multiplicand; - uint32_t part = static_cast(accumulator & kMask32); - accumulator >>= 32; - accumulator = accumulator + (low_bits_ >> 32) * multiplicand; - low_bits_ = (accumulator << 32) + part; - accumulator >>= 32; - accumulator = accumulator + (high_bits_ & kMask32) * multiplicand; - part = static_cast(accumulator & kMask32); - accumulator >>= 32; - accumulator = accumulator + (high_bits_ >> 32) * multiplicand; - high_bits_ = (accumulator << 32) + part; - ASSERT((accumulator >> 32) == 0); - } - - void Shift(int shift_amount) { - ASSERT(-64 <= shift_amount && shift_amount <= 64); - if (shift_amount == 0) { - return; - } else if (shift_amount == -64) { - high_bits_ = low_bits_; - low_bits_ = 0; - } else if (shift_amount == 64) { - low_bits_ = high_bits_; - high_bits_ = 0; - } else if (shift_amount <= 0) { - high_bits_ <<= -shift_amount; - high_bits_ += low_bits_ >> (64 + shift_amount); - low_bits_ <<= -shift_amount; - } else { - low_bits_ >>= shift_amount; - low_bits_ += high_bits_ << (64 - shift_amount); - high_bits_ >>= shift_amount; - } - } - - // Modifies *this to *this MOD (2^power). - // Returns *this DIV (2^power). - int DivModPowerOf2(int power) { - if (power >= 64) { - int result = static_cast(high_bits_ >> (power - 64)); - high_bits_ -= static_cast(result) << (power - 64); - return result; - } else { - uint64_t part_low = low_bits_ >> power; - uint64_t part_high = high_bits_ << (64 - power); - int result = static_cast(part_low + part_high); - high_bits_ = 0; - low_bits_ -= part_low << power; - return result; - } - } - - bool IsZero() const { - return high_bits_ == 0 && low_bits_ == 0; - } - - int BitAt(int position) { - if (position >= 64) { - return static_cast(high_bits_ >> (position - 64)) & 1; - } else { - return static_cast(low_bits_ >> position) & 1; - } - } - - private: - static const uint64_t kMask32 = 0xFFFFFFFF; - // Value == (high_bits_ << 64) + low_bits_ - uint64_t high_bits_; - uint64_t low_bits_; -}; - - -static const int kDoubleSignificandSize = 53; // Includes the hidden bit. - - -static void FillDigits32FixedLength(uint32_t number, int requested_length, - Vector buffer, int* length) { - for (int i = requested_length - 1; i >= 0; --i) { - buffer[(*length) + i] = '0' + number % 10; - number /= 10; - } - *length += requested_length; -} - - -static void FillDigits32(uint32_t number, Vector buffer, int* length) { - int number_length = 0; - // We fill the digits in reverse order and exchange them afterwards. - while (number != 0) { - int digit = number % 10; - number /= 10; - buffer[(*length) + number_length] = '0' + digit; - number_length++; - } - // Exchange the digits. - int i = *length; - int j = *length + number_length - 1; - while (i < j) { - char tmp = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = tmp; - i++; - j--; - } - *length += number_length; -} - - -static void FillDigits64FixedLength(uint64_t number, int requested_length, - Vector buffer, int* length) { - const uint32_t kTen7 = 10000000; - // For efficiency cut the number into 3 uint32_t parts, and print those. - uint32_t part2 = static_cast(number % kTen7); - number /= kTen7; - uint32_t part1 = static_cast(number % kTen7); - uint32_t part0 = static_cast(number / kTen7); - - FillDigits32FixedLength(part0, 3, buffer, length); - FillDigits32FixedLength(part1, 7, buffer, length); - FillDigits32FixedLength(part2, 7, buffer, length); -} - - -static void FillDigits64(uint64_t number, Vector buffer, int* length) { - const uint32_t kTen7 = 10000000; - // For efficiency cut the number into 3 uint32_t parts, and print those. - uint32_t part2 = static_cast(number % kTen7); - number /= kTen7; - uint32_t part1 = static_cast(number % kTen7); - uint32_t part0 = static_cast(number / kTen7); - - if (part0 != 0) { - FillDigits32(part0, buffer, length); - FillDigits32FixedLength(part1, 7, buffer, length); - FillDigits32FixedLength(part2, 7, buffer, length); - } else if (part1 != 0) { - FillDigits32(part1, buffer, length); - FillDigits32FixedLength(part2, 7, buffer, length); - } else { - FillDigits32(part2, buffer, length); - } -} - - -static void RoundUp(Vector buffer, int* length, int* decimal_point) { - // An empty buffer represents 0. - if (*length == 0) { - buffer[0] = '1'; - *decimal_point = 1; - *length = 1; - return; - } - // Round the last digit until we either have a digit that was not '9' or until - // we reached the first digit. - buffer[(*length) - 1]++; - for (int i = (*length) - 1; i > 0; --i) { - if (buffer[i] != '0' + 10) { - return; - } - buffer[i] = '0'; - buffer[i - 1]++; - } - // If the first digit is now '0' + 10, we would need to set it to '0' and add - // a '1' in front. However we reach the first digit only if all following - // digits had been '9' before rounding up. Now all trailing digits are '0' and - // we simply switch the first digit to '1' and update the decimal-point - // (indicating that the point is now one digit to the right). - if (buffer[0] == '0' + 10) { - buffer[0] = '1'; - (*decimal_point)++; - } -} - - -// The given fractionals number represents a fixed-point number with binary -// point at bit (-exponent). -// Preconditions: -// -128 <= exponent <= 0. -// 0 <= fractionals * 2^exponent < 1 -// The buffer holds the result. -// The function will round its result. During the rounding-process digits not -// generated by this function might be updated, and the decimal-point variable -// might be updated. If this function generates the digits 99 and the buffer -// already contained "199" (thus yielding a buffer of "19999") then a -// rounding-up will change the contents of the buffer to "20000". -static void FillFractionals(uint64_t fractionals, int exponent, - int fractional_count, Vector buffer, - int* length, int* decimal_point) { - ASSERT(-128 <= exponent && exponent <= 0); - // 'fractionals' is a fixed-point number, with binary point at bit - // (-exponent). Inside the function the non-converted remainder of fractionals - // is a fixed-point number, with binary point at bit 'point'. - if (-exponent <= 64) { - // One 64 bit number is sufficient. - ASSERT(fractionals >> 56 == 0); - int point = -exponent; - for (int i = 0; i < fractional_count; ++i) { - if (fractionals == 0) break; - // Instead of multiplying by 10 we multiply by 5 and adjust the point - // location. This way the fractionals variable will not overflow. - // Invariant at the beginning of the loop: fractionals < 2^point. - // Initially we have: point <= 64 and fractionals < 2^56 - // After each iteration the point is decremented by one. - // Note that 5^3 = 125 < 128 = 2^7. - // Therefore three iterations of this loop will not overflow fractionals - // (even without the subtraction at the end of the loop body). At this - // time point will satisfy point <= 61 and therefore fractionals < 2^point - // and any further multiplication of fractionals by 5 will not overflow. - fractionals *= 5; - point--; - int digit = static_cast(fractionals >> point); - buffer[*length] = '0' + digit; - (*length)++; - fractionals -= static_cast(digit) << point; - } - // If the first bit after the point is set we have to round up. - if (((fractionals >> (point - 1)) & 1) == 1) { - RoundUp(buffer, length, decimal_point); - } - } else { // We need 128 bits. - ASSERT(64 < -exponent && -exponent <= 128); - UInt128 fractionals128 = UInt128(fractionals, 0); - fractionals128.Shift(-exponent - 64); - int point = 128; - for (int i = 0; i < fractional_count; ++i) { - if (fractionals128.IsZero()) break; - // As before: instead of multiplying by 10 we multiply by 5 and adjust the - // point location. - // This multiplication will not overflow for the same reasons as before. - fractionals128.Multiply(5); - point--; - int digit = fractionals128.DivModPowerOf2(point); - buffer[*length] = '0' + digit; - (*length)++; - } - if (fractionals128.BitAt(point - 1) == 1) { - RoundUp(buffer, length, decimal_point); - } - } -} - - -// Removes leading and trailing zeros. -// If leading zeros are removed then the decimal point position is adjusted. -static void TrimZeros(Vector buffer, int* length, int* decimal_point) { - while (*length > 0 && buffer[(*length) - 1] == '0') { - (*length)--; - } - int first_non_zero = 0; - while (first_non_zero < *length && buffer[first_non_zero] == '0') { - first_non_zero++; - } - if (first_non_zero != 0) { - for (int i = first_non_zero; i < *length; ++i) { - buffer[i - first_non_zero] = buffer[i]; - } - *length -= first_non_zero; - *decimal_point -= first_non_zero; - } -} - - -bool FastFixedDtoa(double v, - int fractional_count, - Vector buffer, - int* length, - int* decimal_point) { - const uint32_t kMaxUInt32 = 0xFFFFFFFF; - uint64_t significand = Double(v).Significand(); - int exponent = Double(v).Exponent(); - // v = significand * 2^exponent (with significand a 53bit integer). - // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we - // don't know how to compute the representation. 2^73 ~= 9.5*10^21. - // If necessary this limit could probably be increased, but we don't need - // more. - if (exponent > 20) return false; - if (fractional_count > 20) return false; - *length = 0; - // At most kDoubleSignificandSize bits of the significand are non-zero. - // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero - // bits: 0..11*..0xxx..53*..xx - if (exponent + kDoubleSignificandSize > 64) { - // The exponent must be > 11. - // - // We know that v = significand * 2^exponent. - // And the exponent > 11. - // We simplify the task by dividing v by 10^17. - // The quotient delivers the first digits, and the remainder fits into a 64 - // bit number. - // Dividing by 10^17 is equivalent to dividing by 5^17*2^17. - const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17 - uint64_t divisor = kFive17; - int divisor_power = 17; - uint64_t dividend = significand; - uint32_t quotient; - uint64_t remainder; - // Let v = f * 2^e with f == significand and e == exponent. - // Then need q (quotient) and r (remainder) as follows: - // v = q * 10^17 + r - // f * 2^e = q * 10^17 + r - // f * 2^e = q * 5^17 * 2^17 + r - // If e > 17 then - // f * 2^(e-17) = q * 5^17 + r/2^17 - // else - // f = q * 5^17 * 2^(17-e) + r/2^e - if (exponent > divisor_power) { - // We only allow exponents of up to 20 and therefore (17 - e) <= 3 - dividend <<= exponent - divisor_power; - quotient = static_cast(dividend / divisor); - remainder = (dividend % divisor) << divisor_power; - } else { - divisor <<= divisor_power - exponent; - quotient = static_cast(dividend / divisor); - remainder = (dividend % divisor) << exponent; - } - FillDigits32(quotient, buffer, length); - FillDigits64FixedLength(remainder, divisor_power, buffer, length); - *decimal_point = *length; - } else if (exponent >= 0) { - // 0 <= exponent <= 11 - significand <<= exponent; - FillDigits64(significand, buffer, length); - *decimal_point = *length; - } else if (exponent > -kDoubleSignificandSize) { - // We have to cut the number. - uint64_t integrals = significand >> -exponent; - uint64_t fractionals = significand - (integrals << -exponent); - if (integrals > kMaxUInt32) { - FillDigits64(integrals, buffer, length); - } else { - FillDigits32(static_cast(integrals), buffer, length); - } - *decimal_point = *length; - FillFractionals(fractionals, exponent, fractional_count, - buffer, length, decimal_point); - } else if (exponent < -128) { - // This configuration (with at most 20 digits) means that all digits must be - // 0. - ASSERT(fractional_count <= 20); - buffer[0] = '\0'; - *length = 0; - *decimal_point = -fractional_count; - } else { - *decimal_point = 0; - FillFractionals(significand, exponent, fractional_count, - buffer, length, decimal_point); - } - TrimZeros(buffer, length, decimal_point); - buffer[*length] = '\0'; - if ((*length) == 0) { - // The string is empty and the decimal_point thus has no importance. Mimick - // Gay's dtoa and and set it to -fractional_count. - *decimal_point = -fractional_count; - } - return true; -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/fixed-dtoa.h b/libazure/src/mfbt/double-conversion/fixed-dtoa.h deleted file mode 100644 index 3bdd08e..0000000 --- a/libazure/src/mfbt/double-conversion/fixed-dtoa.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_ -#define DOUBLE_CONVERSION_FIXED_DTOA_H_ - -#include "utils.h" - -namespace double_conversion { - -// Produces digits necessary to print a given number with -// 'fractional_count' digits after the decimal point. -// The buffer must be big enough to hold the result plus one terminating null -// character. -// -// The produced digits might be too short in which case the caller has to fill -// the gaps with '0's. -// Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and -// decimal_point = -2. -// Halfway cases are rounded towards +/-Infinity (away from 0). The call -// FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0. -// The returned buffer may contain digits that would be truncated from the -// shortest representation of the input. -// -// This method only works for some parameters. If it can't handle the input it -// returns false. The output is null-terminated when the function succeeds. -bool FastFixedDtoa(double v, int fractional_count, - Vector buffer, int* length, int* decimal_point); - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_FIXED_DTOA_H_ diff --git a/libazure/src/mfbt/double-conversion/ieee.h b/libazure/src/mfbt/double-conversion/ieee.h deleted file mode 100644 index 839dc47..0000000 --- a/libazure/src/mfbt/double-conversion/ieee.h +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_DOUBLE_H_ -#define DOUBLE_CONVERSION_DOUBLE_H_ - -#include "diy-fp.h" - -namespace double_conversion { - -// We assume that doubles and uint64_t have the same endianness. -static uint64_t double_to_uint64(double d) { return BitCast(d); } -static double uint64_to_double(uint64_t d64) { return BitCast(d64); } -static uint32_t float_to_uint32(float f) { return BitCast(f); } -static float uint32_to_float(uint32_t d32) { return BitCast(d32); } - -// Helper functions for doubles. -class Double { - public: - static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000); - static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000); - static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); - static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000); - static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit. - static const int kSignificandSize = 53; - - Double() : d64_(0) {} - explicit Double(double d) : d64_(double_to_uint64(d)) {} - explicit Double(uint64_t d64) : d64_(d64) {} - explicit Double(DiyFp diy_fp) - : d64_(DiyFpToUint64(diy_fp)) {} - - // The value encoded by this Double must be greater or equal to +0.0. - // It must not be special (infinity, or NaN). - DiyFp AsDiyFp() const { - ASSERT(Sign() > 0); - ASSERT(!IsSpecial()); - return DiyFp(Significand(), Exponent()); - } - - // The value encoded by this Double must be strictly greater than 0. - DiyFp AsNormalizedDiyFp() const { - ASSERT(value() > 0.0); - uint64_t f = Significand(); - int e = Exponent(); - - // The current double could be a denormal. - while ((f & kHiddenBit) == 0) { - f <<= 1; - e--; - } - // Do the final shifts in one go. - f <<= DiyFp::kSignificandSize - kSignificandSize; - e -= DiyFp::kSignificandSize - kSignificandSize; - return DiyFp(f, e); - } - - // Returns the double's bit as uint64. - uint64_t AsUint64() const { - return d64_; - } - - // Returns the next greater double. Returns +infinity on input +infinity. - double NextDouble() const { - if (d64_ == kInfinity) return Double(kInfinity).value(); - if (Sign() < 0 && Significand() == 0) { - // -0.0 - return 0.0; - } - if (Sign() < 0) { - return Double(d64_ - 1).value(); - } else { - return Double(d64_ + 1).value(); - } - } - - double PreviousDouble() const { - if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity(); - if (Sign() < 0) { - return Double(d64_ + 1).value(); - } else { - if (Significand() == 0) return -0.0; - return Double(d64_ - 1).value(); - } - } - - int Exponent() const { - if (IsDenormal()) return kDenormalExponent; - - uint64_t d64 = AsUint64(); - int biased_e = - static_cast((d64 & kExponentMask) >> kPhysicalSignificandSize); - return biased_e - kExponentBias; - } - - uint64_t Significand() const { - uint64_t d64 = AsUint64(); - uint64_t significand = d64 & kSignificandMask; - if (!IsDenormal()) { - return significand + kHiddenBit; - } else { - return significand; - } - } - - // Returns true if the double is a denormal. - bool IsDenormal() const { - uint64_t d64 = AsUint64(); - return (d64 & kExponentMask) == 0; - } - - // We consider denormals not to be special. - // Hence only Infinity and NaN are special. - bool IsSpecial() const { - uint64_t d64 = AsUint64(); - return (d64 & kExponentMask) == kExponentMask; - } - - bool IsNan() const { - uint64_t d64 = AsUint64(); - return ((d64 & kExponentMask) == kExponentMask) && - ((d64 & kSignificandMask) != 0); - } - - bool IsInfinite() const { - uint64_t d64 = AsUint64(); - return ((d64 & kExponentMask) == kExponentMask) && - ((d64 & kSignificandMask) == 0); - } - - int Sign() const { - uint64_t d64 = AsUint64(); - return (d64 & kSignMask) == 0? 1: -1; - } - - // Precondition: the value encoded by this Double must be greater or equal - // than +0.0. - DiyFp UpperBoundary() const { - ASSERT(Sign() > 0); - return DiyFp(Significand() * 2 + 1, Exponent() - 1); - } - - // Computes the two boundaries of this. - // The bigger boundary (m_plus) is normalized. The lower boundary has the same - // exponent as m_plus. - // Precondition: the value encoded by this Double must be greater than 0. - void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { - ASSERT(value() > 0.0); - DiyFp v = this->AsDiyFp(); - DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); - DiyFp m_minus; - if (LowerBoundaryIsCloser()) { - m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); - } else { - m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); - } - m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); - m_minus.set_e(m_plus.e()); - *out_m_plus = m_plus; - *out_m_minus = m_minus; - } - - bool LowerBoundaryIsCloser() const { - // The boundary is closer if the significand is of the form f == 2^p-1 then - // the lower boundary is closer. - // Think of v = 1000e10 and v- = 9999e9. - // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but - // at a distance of 1e8. - // The only exception is for the smallest normal: the largest denormal is - // at the same distance as its successor. - // Note: denormals have the same exponent as the smallest normals. - bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0); - return physical_significand_is_zero && (Exponent() != kDenormalExponent); - } - - double value() const { return uint64_to_double(d64_); } - - // Returns the significand size for a given order of magnitude. - // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude. - // This function returns the number of significant binary digits v will have - // once it's encoded into a double. In almost all cases this is equal to - // kSignificandSize. The only exceptions are denormals. They start with - // leading zeroes and their effective significand-size is hence smaller. - static int SignificandSizeForOrderOfMagnitude(int order) { - if (order >= (kDenormalExponent + kSignificandSize)) { - return kSignificandSize; - } - if (order <= kDenormalExponent) return 0; - return order - kDenormalExponent; - } - - static double Infinity() { - return Double(kInfinity).value(); - } - - static double NaN() { - return Double(kNaN).value(); - } - - private: - static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; - static const int kDenormalExponent = -kExponentBias + 1; - static const int kMaxExponent = 0x7FF - kExponentBias; - static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000); - static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000); - - const uint64_t d64_; - - static uint64_t DiyFpToUint64(DiyFp diy_fp) { - uint64_t significand = diy_fp.f(); - int exponent = diy_fp.e(); - while (significand > kHiddenBit + kSignificandMask) { - significand >>= 1; - exponent++; - } - if (exponent >= kMaxExponent) { - return kInfinity; - } - if (exponent < kDenormalExponent) { - return 0; - } - while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) { - significand <<= 1; - exponent--; - } - uint64_t biased_exponent; - if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) { - biased_exponent = 0; - } else { - biased_exponent = static_cast(exponent + kExponentBias); - } - return (significand & kSignificandMask) | - (biased_exponent << kPhysicalSignificandSize); - } -}; - -class Single { - public: - static const uint32_t kSignMask = 0x80000000; - static const uint32_t kExponentMask = 0x7F800000; - static const uint32_t kSignificandMask = 0x007FFFFF; - static const uint32_t kHiddenBit = 0x00800000; - static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit. - static const int kSignificandSize = 24; - - Single() : d32_(0) {} - explicit Single(float f) : d32_(float_to_uint32(f)) {} - explicit Single(uint32_t d32) : d32_(d32) {} - - // The value encoded by this Single must be greater or equal to +0.0. - // It must not be special (infinity, or NaN). - DiyFp AsDiyFp() const { - ASSERT(Sign() > 0); - ASSERT(!IsSpecial()); - return DiyFp(Significand(), Exponent()); - } - - // Returns the single's bit as uint64. - uint32_t AsUint32() const { - return d32_; - } - - int Exponent() const { - if (IsDenormal()) return kDenormalExponent; - - uint32_t d32 = AsUint32(); - int biased_e = - static_cast((d32 & kExponentMask) >> kPhysicalSignificandSize); - return biased_e - kExponentBias; - } - - uint32_t Significand() const { - uint32_t d32 = AsUint32(); - uint32_t significand = d32 & kSignificandMask; - if (!IsDenormal()) { - return significand + kHiddenBit; - } else { - return significand; - } - } - - // Returns true if the single is a denormal. - bool IsDenormal() const { - uint32_t d32 = AsUint32(); - return (d32 & kExponentMask) == 0; - } - - // We consider denormals not to be special. - // Hence only Infinity and NaN are special. - bool IsSpecial() const { - uint32_t d32 = AsUint32(); - return (d32 & kExponentMask) == kExponentMask; - } - - bool IsNan() const { - uint32_t d32 = AsUint32(); - return ((d32 & kExponentMask) == kExponentMask) && - ((d32 & kSignificandMask) != 0); - } - - bool IsInfinite() const { - uint32_t d32 = AsUint32(); - return ((d32 & kExponentMask) == kExponentMask) && - ((d32 & kSignificandMask) == 0); - } - - int Sign() const { - uint32_t d32 = AsUint32(); - return (d32 & kSignMask) == 0? 1: -1; - } - - // Computes the two boundaries of this. - // The bigger boundary (m_plus) is normalized. The lower boundary has the same - // exponent as m_plus. - // Precondition: the value encoded by this Single must be greater than 0. - void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { - ASSERT(value() > 0.0); - DiyFp v = this->AsDiyFp(); - DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); - DiyFp m_minus; - if (LowerBoundaryIsCloser()) { - m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); - } else { - m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); - } - m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); - m_minus.set_e(m_plus.e()); - *out_m_plus = m_plus; - *out_m_minus = m_minus; - } - - // Precondition: the value encoded by this Single must be greater or equal - // than +0.0. - DiyFp UpperBoundary() const { - ASSERT(Sign() > 0); - return DiyFp(Significand() * 2 + 1, Exponent() - 1); - } - - bool LowerBoundaryIsCloser() const { - // The boundary is closer if the significand is of the form f == 2^p-1 then - // the lower boundary is closer. - // Think of v = 1000e10 and v- = 9999e9. - // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but - // at a distance of 1e8. - // The only exception is for the smallest normal: the largest denormal is - // at the same distance as its successor. - // Note: denormals have the same exponent as the smallest normals. - bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0); - return physical_significand_is_zero && (Exponent() != kDenormalExponent); - } - - float value() const { return uint32_to_float(d32_); } - - static float Infinity() { - return Single(kInfinity).value(); - } - - static float NaN() { - return Single(kNaN).value(); - } - - private: - static const int kExponentBias = 0x7F + kPhysicalSignificandSize; - static const int kDenormalExponent = -kExponentBias + 1; - static const int kMaxExponent = 0xFF - kExponentBias; - static const uint32_t kInfinity = 0x7F800000; - static const uint32_t kNaN = 0x7FC00000; - - const uint32_t d32_; -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_DOUBLE_H_ diff --git a/libazure/src/mfbt/double-conversion/strtod.cc b/libazure/src/mfbt/double-conversion/strtod.cc deleted file mode 100644 index 9758989..0000000 --- a/libazure/src/mfbt/double-conversion/strtod.cc +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include - -#include "strtod.h" -#include "bignum.h" -#include "cached-powers.h" -#include "ieee.h" - -namespace double_conversion { - -// 2^53 = 9007199254740992. -// Any integer with at most 15 decimal digits will hence fit into a double -// (which has a 53bit significand) without loss of precision. -static const int kMaxExactDoubleIntegerDecimalDigits = 15; -// 2^64 = 18446744073709551616 > 10^19 -static const int kMaxUint64DecimalDigits = 19; - -// Max double: 1.7976931348623157 x 10^308 -// Min non-zero double: 4.9406564584124654 x 10^-324 -// Any x >= 10^309 is interpreted as +infinity. -// Any x <= 10^-324 is interpreted as 0. -// Note that 2.5e-324 (despite being smaller than the min double) will be read -// as non-zero (equal to the min non-zero double). -static const int kMaxDecimalPower = 309; -static const int kMinDecimalPower = -324; - -// 2^64 = 18446744073709551616 -static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); - - -static const double exact_powers_of_ten[] = { - 1.0, // 10^0 - 10.0, - 100.0, - 1000.0, - 10000.0, - 100000.0, - 1000000.0, - 10000000.0, - 100000000.0, - 1000000000.0, - 10000000000.0, // 10^10 - 100000000000.0, - 1000000000000.0, - 10000000000000.0, - 100000000000000.0, - 1000000000000000.0, - 10000000000000000.0, - 100000000000000000.0, - 1000000000000000000.0, - 10000000000000000000.0, - 100000000000000000000.0, // 10^20 - 1000000000000000000000.0, - // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 - 10000000000000000000000.0 -}; -static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); - -// Maximum number of significant digits in the decimal representation. -// In fact the value is 772 (see conversions.cc), but to give us some margin -// we round up to 780. -static const int kMaxSignificantDecimalDigits = 780; - -static Vector TrimLeadingZeros(Vector buffer) { - for (int i = 0; i < buffer.length(); i++) { - if (buffer[i] != '0') { - return buffer.SubVector(i, buffer.length()); - } - } - return Vector(buffer.start(), 0); -} - - -static Vector TrimTrailingZeros(Vector buffer) { - for (int i = buffer.length() - 1; i >= 0; --i) { - if (buffer[i] != '0') { - return buffer.SubVector(0, i + 1); - } - } - return Vector(buffer.start(), 0); -} - - -static void CutToMaxSignificantDigits(Vector buffer, - int exponent, - char* significant_buffer, - int* significant_exponent) { - for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { - significant_buffer[i] = buffer[i]; - } - // The input buffer has been trimmed. Therefore the last digit must be - // different from '0'. - ASSERT(buffer[buffer.length() - 1] != '0'); - // Set the last digit to be non-zero. This is sufficient to guarantee - // correct rounding. - significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; - *significant_exponent = - exponent + (buffer.length() - kMaxSignificantDecimalDigits); -} - - -// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits. -// If possible the input-buffer is reused, but if the buffer needs to be -// modified (due to cutting), then the input needs to be copied into the -// buffer_copy_space. -static void TrimAndCut(Vector buffer, int exponent, - char* buffer_copy_space, int space_size, - Vector* trimmed, int* updated_exponent) { - Vector left_trimmed = TrimLeadingZeros(buffer); - Vector right_trimmed = TrimTrailingZeros(left_trimmed); - exponent += left_trimmed.length() - right_trimmed.length(); - if (right_trimmed.length() > kMaxSignificantDecimalDigits) { - ASSERT(space_size >= kMaxSignificantDecimalDigits); - CutToMaxSignificantDigits(right_trimmed, exponent, - buffer_copy_space, updated_exponent); - *trimmed = Vector(buffer_copy_space, - kMaxSignificantDecimalDigits); - } else { - *trimmed = right_trimmed; - *updated_exponent = exponent; - } -} - - -// Reads digits from the buffer and converts them to a uint64. -// Reads in as many digits as fit into a uint64. -// When the string starts with "1844674407370955161" no further digit is read. -// Since 2^64 = 18446744073709551616 it would still be possible read another -// digit if it was less or equal than 6, but this would complicate the code. -static uint64_t ReadUint64(Vector buffer, - int* number_of_read_digits) { - uint64_t result = 0; - int i = 0; - while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { - int digit = buffer[i++] - '0'; - ASSERT(0 <= digit && digit <= 9); - result = 10 * result + digit; - } - *number_of_read_digits = i; - return result; -} - - -// Reads a DiyFp from the buffer. -// The returned DiyFp is not necessarily normalized. -// If remaining_decimals is zero then the returned DiyFp is accurate. -// Otherwise it has been rounded and has error of at most 1/2 ulp. -static void ReadDiyFp(Vector buffer, - DiyFp* result, - int* remaining_decimals) { - int read_digits; - uint64_t significand = ReadUint64(buffer, &read_digits); - if (buffer.length() == read_digits) { - *result = DiyFp(significand, 0); - *remaining_decimals = 0; - } else { - // Round the significand. - if (buffer[read_digits] >= '5') { - significand++; - } - // Compute the binary exponent. - int exponent = 0; - *result = DiyFp(significand, exponent); - *remaining_decimals = buffer.length() - read_digits; - } -} - - -static bool DoubleStrtod(Vector trimmed, - int exponent, - double* result) { -#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) - // On x86 the floating-point stack can be 64 or 80 bits wide. If it is - // 80 bits wide (as is the case on Linux) then double-rounding occurs and the - // result is not accurate. - // We know that Windows32 uses 64 bits and is therefore accurate. - // Note that the ARM simulator is compiled for 32bits. It therefore exhibits - // the same problem. - return false; -#endif - if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { - int read_digits; - // The trimmed input fits into a double. - // If the 10^exponent (resp. 10^-exponent) fits into a double too then we - // can compute the result-double simply by multiplying (resp. dividing) the - // two numbers. - // This is possible because IEEE guarantees that floating-point operations - // return the best possible approximation. - if (exponent < 0 && -exponent < kExactPowersOfTenSize) { - // 10^-exponent fits into a double. - *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); - *result /= exact_powers_of_ten[-exponent]; - return true; - } - if (0 <= exponent && exponent < kExactPowersOfTenSize) { - // 10^exponent fits into a double. - *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); - *result *= exact_powers_of_ten[exponent]; - return true; - } - int remaining_digits = - kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); - if ((0 <= exponent) && - (exponent - remaining_digits < kExactPowersOfTenSize)) { - // The trimmed string was short and we can multiply it with - // 10^remaining_digits. As a result the remaining exponent now fits - // into a double too. - *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); - *result *= exact_powers_of_ten[remaining_digits]; - *result *= exact_powers_of_ten[exponent - remaining_digits]; - return true; - } - } - return false; -} - - -// Returns 10^exponent as an exact DiyFp. -// The given exponent must be in the range [1; kDecimalExponentDistance[. -static DiyFp AdjustmentPowerOfTen(int exponent) { - ASSERT(0 < exponent); - ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); - // Simply hardcode the remaining powers for the given decimal exponent - // distance. - ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); - switch (exponent) { - case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); - case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); - case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); - case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); - case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); - case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); - case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); - default: - UNREACHABLE(); - return DiyFp(0, 0); - } -} - - -// If the function returns true then the result is the correct double. -// Otherwise it is either the correct double or the double that is just below -// the correct double. -static bool DiyFpStrtod(Vector buffer, - int exponent, - double* result) { - DiyFp input; - int remaining_decimals; - ReadDiyFp(buffer, &input, &remaining_decimals); - // Since we may have dropped some digits the input is not accurate. - // If remaining_decimals is different than 0 than the error is at most - // .5 ulp (unit in the last place). - // We don't want to deal with fractions and therefore keep a common - // denominator. - const int kDenominatorLog = 3; - const int kDenominator = 1 << kDenominatorLog; - // Move the remaining decimals into the exponent. - exponent += remaining_decimals; - int error = (remaining_decimals == 0 ? 0 : kDenominator / 2); - - int old_e = input.e(); - input.Normalize(); - error <<= old_e - input.e(); - - ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); - if (exponent < PowersOfTenCache::kMinDecimalExponent) { - *result = 0.0; - return true; - } - DiyFp cached_power; - int cached_decimal_exponent; - PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, - &cached_power, - &cached_decimal_exponent); - - if (cached_decimal_exponent != exponent) { - int adjustment_exponent = exponent - cached_decimal_exponent; - DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); - input.Multiply(adjustment_power); - if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { - // The product of input with the adjustment power fits into a 64 bit - // integer. - ASSERT(DiyFp::kSignificandSize == 64); - } else { - // The adjustment power is exact. There is hence only an error of 0.5. - error += kDenominator / 2; - } - } - - input.Multiply(cached_power); - // The error introduced by a multiplication of a*b equals - // error_a + error_b + error_a*error_b/2^64 + 0.5 - // Substituting a with 'input' and b with 'cached_power' we have - // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), - // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64 - int error_b = kDenominator / 2; - int error_ab = (error == 0 ? 0 : 1); // We round up to 1. - int fixed_error = kDenominator / 2; - error += error_b + error_ab + fixed_error; - - old_e = input.e(); - input.Normalize(); - error <<= old_e - input.e(); - - // See if the double's significand changes if we add/subtract the error. - int order_of_magnitude = DiyFp::kSignificandSize + input.e(); - int effective_significand_size = - Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); - int precision_digits_count = - DiyFp::kSignificandSize - effective_significand_size; - if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { - // This can only happen for very small denormals. In this case the - // half-way multiplied by the denominator exceeds the range of an uint64. - // Simply shift everything to the right. - int shift_amount = (precision_digits_count + kDenominatorLog) - - DiyFp::kSignificandSize + 1; - input.set_f(input.f() >> shift_amount); - input.set_e(input.e() + shift_amount); - // We add 1 for the lost precision of error, and kDenominator for - // the lost precision of input.f(). - error = (error >> shift_amount) + 1 + kDenominator; - precision_digits_count -= shift_amount; - } - // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. - ASSERT(DiyFp::kSignificandSize == 64); - ASSERT(precision_digits_count < 64); - uint64_t one64 = 1; - uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; - uint64_t precision_bits = input.f() & precision_bits_mask; - uint64_t half_way = one64 << (precision_digits_count - 1); - precision_bits *= kDenominator; - half_way *= kDenominator; - DiyFp rounded_input(input.f() >> precision_digits_count, - input.e() + precision_digits_count); - if (precision_bits >= half_way + error) { - rounded_input.set_f(rounded_input.f() + 1); - } - // If the last_bits are too close to the half-way case than we are too - // inaccurate and round down. In this case we return false so that we can - // fall back to a more precise algorithm. - - *result = Double(rounded_input).value(); - if (half_way - error < precision_bits && precision_bits < half_way + error) { - // Too imprecise. The caller will have to fall back to a slower version. - // However the returned number is guaranteed to be either the correct - // double, or the next-lower double. - return false; - } else { - return true; - } -} - - -// Returns -// - -1 if buffer*10^exponent < diy_fp. -// - 0 if buffer*10^exponent == diy_fp. -// - +1 if buffer*10^exponent > diy_fp. -// Preconditions: -// buffer.length() + exponent <= kMaxDecimalPower + 1 -// buffer.length() + exponent > kMinDecimalPower -// buffer.length() <= kMaxDecimalSignificantDigits -static int CompareBufferWithDiyFp(Vector buffer, - int exponent, - DiyFp diy_fp) { - ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); - ASSERT(buffer.length() + exponent > kMinDecimalPower); - ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); - // Make sure that the Bignum will be able to hold all our numbers. - // Our Bignum implementation has a separate field for exponents. Shifts will - // consume at most one bigit (< 64 bits). - // ln(10) == 3.3219... - ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); - Bignum buffer_bignum; - Bignum diy_fp_bignum; - buffer_bignum.AssignDecimalString(buffer); - diy_fp_bignum.AssignUInt64(diy_fp.f()); - if (exponent >= 0) { - buffer_bignum.MultiplyByPowerOfTen(exponent); - } else { - diy_fp_bignum.MultiplyByPowerOfTen(-exponent); - } - if (diy_fp.e() > 0) { - diy_fp_bignum.ShiftLeft(diy_fp.e()); - } else { - buffer_bignum.ShiftLeft(-diy_fp.e()); - } - return Bignum::Compare(buffer_bignum, diy_fp_bignum); -} - - -// Returns true if the guess is the correct double. -// Returns false, when guess is either correct or the next-lower double. -static bool ComputeGuess(Vector trimmed, int exponent, - double* guess) { - if (trimmed.length() == 0) { - *guess = 0.0; - return true; - } - if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { - *guess = Double::Infinity(); - return true; - } - if (exponent + trimmed.length() <= kMinDecimalPower) { - *guess = 0.0; - return true; - } - - if (DoubleStrtod(trimmed, exponent, guess) || - DiyFpStrtod(trimmed, exponent, guess)) { - return true; - } - if (*guess == Double::Infinity()) { - return true; - } - return false; -} - -double Strtod(Vector buffer, int exponent) { - char copy_buffer[kMaxSignificantDecimalDigits]; - Vector trimmed; - int updated_exponent; - TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, - &trimmed, &updated_exponent); - exponent = updated_exponent; - - double guess; - bool is_correct = ComputeGuess(trimmed, exponent, &guess); - if (is_correct) return guess; - - DiyFp upper_boundary = Double(guess).UpperBoundary(); - int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); - if (comparison < 0) { - return guess; - } else if (comparison > 0) { - return Double(guess).NextDouble(); - } else if ((Double(guess).Significand() & 1) == 0) { - // Round towards even. - return guess; - } else { - return Double(guess).NextDouble(); - } -} - -float Strtof(Vector buffer, int exponent) { - char copy_buffer[kMaxSignificantDecimalDigits]; - Vector trimmed; - int updated_exponent; - TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, - &trimmed, &updated_exponent); - exponent = updated_exponent; - - double double_guess; - bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); - - float float_guess = static_cast(double_guess); - if (float_guess == double_guess) { - // This shortcut triggers for integer values. - return float_guess; - } - - // We must catch double-rounding. Say the double has been rounded up, and is - // now a boundary of a float, and rounds up again. This is why we have to - // look at previous too. - // Example (in decimal numbers): - // input: 12349 - // high-precision (4 digits): 1235 - // low-precision (3 digits): - // when read from input: 123 - // when rounded from high precision: 124. - // To do this we simply look at the neigbors of the correct result and see - // if they would round to the same float. If the guess is not correct we have - // to look at four values (since two different doubles could be the correct - // double). - - double double_next = Double(double_guess).NextDouble(); - double double_previous = Double(double_guess).PreviousDouble(); - - float f1 = static_cast(double_previous); - float f2 = float_guess; - float f3 = static_cast(double_next); - float f4; - if (is_correct) { - f4 = f3; - } else { - double double_next2 = Double(double_next).NextDouble(); - f4 = static_cast(double_next2); - } - ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); - - // If the guess doesn't lie near a single-precision boundary we can simply - // return its float-value. - if (f1 == f4) { - return float_guess; - } - - ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || - (f1 == f2 && f2 != f3 && f3 == f4) || - (f1 == f2 && f2 == f3 && f3 != f4)); - - // guess and next are the two possible canditates (in the same way that - // double_guess was the lower candidate for a double-precision guess). - float guess = f1; - float next = f4; - DiyFp upper_boundary; - if (guess == 0.0f) { - float min_float = 1e-45f; - upper_boundary = Double(static_cast(min_float) / 2).AsDiyFp(); - } else { - upper_boundary = Single(guess).UpperBoundary(); - } - int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); - if (comparison < 0) { - return guess; - } else if (comparison > 0) { - return next; - } else if ((Single(guess).Significand() & 1) == 0) { - // Round towards even. - return guess; - } else { - return next; - } -} - -} // namespace double_conversion diff --git a/libazure/src/mfbt/double-conversion/strtod.h b/libazure/src/mfbt/double-conversion/strtod.h deleted file mode 100644 index ed0293b..0000000 --- a/libazure/src/mfbt/double-conversion/strtod.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_STRTOD_H_ -#define DOUBLE_CONVERSION_STRTOD_H_ - -#include "utils.h" - -namespace double_conversion { - -// The buffer must only contain digits in the range [0-9]. It must not -// contain a dot or a sign. It must not start with '0', and must not be empty. -double Strtod(Vector buffer, int exponent); - -// The buffer must only contain digits in the range [0-9]. It must not -// contain a dot or a sign. It must not start with '0', and must not be empty. -float Strtof(Vector buffer, int exponent); - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_STRTOD_H_ diff --git a/libazure/src/mfbt/double-conversion/update.sh b/libazure/src/mfbt/double-conversion/update.sh deleted file mode 100755 index 43091e3..0000000 --- a/libazure/src/mfbt/double-conversion/update.sh +++ /dev/null @@ -1,20 +0,0 @@ -# Usage: ./update.sh -# -# Copies the needed files from a directory containing the original -# double-conversion source that we need. - -# This was last updated with git rev e5b34421b763f7bf7e4f9081403db417d5a55a36. - -set -e - -cp $1/LICENSE ./ -cp $1/README ./ - -# Includes -cp $1/src/*.h ./ - -# Source -cp $1/src/*.cc ./ - -patch -p3 < add-mfbt-api-markers.patch -patch -p3 < use-StandardInteger.patch diff --git a/libazure/src/mfbt/double-conversion/use-StandardInteger.patch b/libazure/src/mfbt/double-conversion/use-StandardInteger.patch deleted file mode 100644 index 6cd49b3..0000000 --- a/libazure/src/mfbt/double-conversion/use-StandardInteger.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git a/mfbt/double-conversion/utils.h b/mfbt/double-conversion/utils.h -index cd3e330..bdc7d4b 100644 ---- a/mfbt/double-conversion/utils.h -+++ b/mfbt/double-conversion/utils.h -@@ -68,23 +68,7 @@ - #endif - - --#if defined(_WIN32) && !defined(__MINGW32__) -- --typedef signed char int8_t; --typedef unsigned char uint8_t; --typedef short int16_t; // NOLINT --typedef unsigned short uint16_t; // NOLINT --typedef int int32_t; --typedef unsigned int uint32_t; --typedef __int64 int64_t; --typedef unsigned __int64 uint64_t; --// intptr_t and friends are defined in crtdefs.h through stdio.h. -- --#else -- --#include -- --#endif -+#include "mozilla/StandardInteger.h" - - // The following macro works on both 32 and 64-bit platforms. - // Usage: instead of writing 0x1234567890123456 diff --git a/libazure/src/mfbt/double-conversion/utils.h b/libazure/src/mfbt/double-conversion/utils.h deleted file mode 100644 index 0eec2d9..0000000 --- a/libazure/src/mfbt/double-conversion/utils.h +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_UTILS_H_ -#define DOUBLE_CONVERSION_UTILS_H_ - -#include -#include - -#include -#ifndef ASSERT -#define ASSERT(condition) (assert(condition)) -#endif -#ifndef UNIMPLEMENTED -#define UNIMPLEMENTED() (abort()) -#endif -#ifndef UNREACHABLE -#define UNREACHABLE() (abort()) -#endif - -// Double operations detection based on target architecture. -// Linux uses a 80bit wide floating point stack on x86. This induces double -// rounding, which in turn leads to wrong results. -// An easy way to test if the floating-point operations are correct is to -// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then -// the result is equal to 89255e-22. -// The best way to test this, is to create a division-function and to compare -// the output of the division with the expected result. (Inlining must be -// disabled.) -// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) -#if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || \ - defined(__hppa__) || defined(__ia64__) || \ - defined(__mips__) || defined(__powerpc__) || \ - defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ - defined(__SH4__) || defined(__alpha__) || \ - defined(_MIPS_ARCH_MIPS32R2) -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#if defined(_WIN32) -// Windows uses a 64bit wide floating point stack. -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#else -#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS -#endif // _WIN32 -#else -#error Target architecture was not detected as supported by Double-Conversion. -#endif - - -#include "mozilla/StandardInteger.h" - -// The following macro works on both 32 and 64-bit platforms. -// Usage: instead of writing 0x1234567890123456 -// write UINT64_2PART_C(0x12345678,90123456); -#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) - - -// The expression ARRAY_SIZE(a) is a compile-time constant of type -// size_t which represents the number of elements of the given -// array. You should only use ARRAY_SIZE on statically allocated -// arrays. -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) -#endif - -// A macro to disallow the evil copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) -#endif - -namespace double_conversion { - -static const int kCharSize = sizeof(char); - -// Returns the maximum of the two parameters. -template -static T Max(T a, T b) { - return a < b ? b : a; -} - - -// Returns the minimum of the two parameters. -template -static T Min(T a, T b) { - return a < b ? a : b; -} - - -inline int StrLength(const char* string) { - size_t length = strlen(string); - ASSERT(length == static_cast(static_cast(length))); - return static_cast(length); -} - -// This is a simplified version of V8's Vector class. -template -class Vector { - public: - Vector() : start_(NULL), length_(0) {} - Vector(T* data, int length) : start_(data), length_(length) { - ASSERT(length == 0 || (length > 0 && data != NULL)); - } - - // Returns a vector using the same backing storage as this one, - // spanning from and including 'from', to but not including 'to'. - Vector SubVector(int from, int to) { - ASSERT(to <= length_); - ASSERT(from < to); - ASSERT(0 <= from); - return Vector(start() + from, to - from); - } - - // Returns the length of the vector. - int length() const { return length_; } - - // Returns whether or not the vector is empty. - bool is_empty() const { return length_ == 0; } - - // Returns the pointer to the start of the data in the vector. - T* start() const { return start_; } - - // Access individual vector elements - checks bounds in debug mode. - T& operator[](int index) const { - ASSERT(0 <= index && index < length_); - return start_[index]; - } - - T& first() { return start_[0]; } - - T& last() { return start_[length_ - 1]; } - - private: - T* start_; - int length_; -}; - - -// Helper class for building result strings in a character buffer. The -// purpose of the class is to use safe operations that checks the -// buffer bounds on all operations in debug mode. -class StringBuilder { - public: - StringBuilder(char* buffer, int size) - : buffer_(buffer, size), position_(0) { } - - ~StringBuilder() { if (!is_finalized()) Finalize(); } - - int size() const { return buffer_.length(); } - - // Get the current position in the builder. - int position() const { - ASSERT(!is_finalized()); - return position_; - } - - // Reset the position. - void Reset() { position_ = 0; } - - // Add a single character to the builder. It is not allowed to add - // 0-characters; use the Finalize() method to terminate the string - // instead. - void AddCharacter(char c) { - ASSERT(c != '\0'); - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_++] = c; - } - - // Add an entire string to the builder. Uses strlen() internally to - // compute the length of the input string. - void AddString(const char* s) { - AddSubstring(s, StrLength(s)); - } - - // Add the first 'n' characters of the given string 's' to the - // builder. The input string must have enough characters. - void AddSubstring(const char* s, int n) { - ASSERT(!is_finalized() && position_ + n < buffer_.length()); - ASSERT(static_cast(n) <= strlen(s)); - memmove(&buffer_[position_], s, n * kCharSize); - position_ += n; - } - - - // Add character padding to the builder. If count is non-positive, - // nothing is added to the builder. - void AddPadding(char c, int count) { - for (int i = 0; i < count; i++) { - AddCharacter(c); - } - } - - // Finalize the string by 0-terminating it and returning the buffer. - char* Finalize() { - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_] = '\0'; - // Make sure nobody managed to add a 0-character to the - // buffer while building the string. - ASSERT(strlen(buffer_.start()) == static_cast(position_)); - position_ = -1; - ASSERT(is_finalized()); - return buffer_.start(); - } - - private: - Vector buffer_; - int position_; - - bool is_finalized() const { return position_ < 0; } - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); -}; - -// The type-based aliasing rule allows the compiler to assume that pointers of -// different types (for some definition of different) never alias each other. -// Thus the following code does not work: -// -// float f = foo(); -// int fbits = *(int*)(&f); -// -// The compiler 'knows' that the int pointer can't refer to f since the types -// don't match, so the compiler may cache f in a register, leaving random data -// in fbits. Using C++ style casts makes no difference, however a pointer to -// char data is assumed to alias any other pointer. This is the 'memcpy -// exception'. -// -// Bit_cast uses the memcpy exception to move the bits from a variable of one -// type of a variable of another type. Of course the end result is likely to -// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) -// will completely optimize BitCast away. -// -// There is an additional use for BitCast. -// Recent gccs will warn when they see casts that may result in breakage due to -// the type-based aliasing rule. If you have checked that there is no breakage -// you can use BitCast to cast one pointer type to another. This confuses gcc -// enough that it can no longer see that you have cast one pointer type to -// another thus avoiding the warning. -template -inline Dest BitCast(const Source& source) { - // Compile time assertion: sizeof(Dest) == sizeof(Source) - // A compile error here means your Dest and Source have different sizes. - typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; - - Dest dest; - memmove(&dest, &source, sizeof(dest)); - return dest; -} - -template -inline Dest BitCast(Source* source) { - return BitCast(reinterpret_cast(source)); -} - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_UTILS_H_ diff --git a/libazure/src/mfbt/exported_headers.mk b/libazure/src/mfbt/exported_headers.mk deleted file mode 100644 index a1f8137..0000000 --- a/libazure/src/mfbt/exported_headers.mk +++ /dev/null @@ -1,45 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# This file defines the headers exported by mfbt. It is included by mfbt -# itself and by the JS engine, which, when built standalone, must install -# mfbt's exported headers itself. - -EXPORTS_NAMESPACES += mozilla - -EXPORTS_mozilla += \ - Assertions.h \ - Attributes.h \ - BloomFilter.h \ - Char16.h \ - CheckedInt.h \ - Compiler.h \ - Constants.h \ - DebugOnly.h \ - Endian.h \ - EnumSet.h \ - FloatingPoint.h \ - GuardObjects.h \ - HashFunctions.h \ - Likely.h \ - LinkedList.h \ - MathAlgorithms.h \ - MemoryChecking.h \ - MSStdInt.h \ - NullPtr.h \ - PodOperations.h \ - Range.h \ - RangedPtr.h \ - RefPtr.h \ - Scoped.h \ - SHA1.h \ - SplayTree.h \ - StandardInteger.h \ - ThreadLocal.h \ - TypedEnum.h \ - Types.h \ - TypeTraits.h \ - Util.h \ - WeakPtr.h \ - $(NULL) diff --git a/libazure/src/mfbt/moz.build b/libazure/src/mfbt/moz.build deleted file mode 100644 index b264ebb..0000000 --- a/libazure/src/mfbt/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -TEST_DIRS += ['tests'] - -MODULE = 'mozglue' - diff --git a/libazure/src/mfbt/sources.mk b/libazure/src/mfbt/sources.mk deleted file mode 100644 index eec2a2a..0000000 --- a/libazure/src/mfbt/sources.mk +++ /dev/null @@ -1,28 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -ifndef MFBT_ROOT -$(error Before including this file, you must define MFBT_ROOT to point to \ -the MFBT source directory) -endif - -CPPSRCS += \ - HashFunctions.cpp \ - SHA1.cpp \ - $(NULL) - -# Imported double-conversion sources. -VPATH += $(MFBT_ROOT)/double-conversion \ - $(NULL) - -CPPSRCS += \ - bignum-dtoa.cc \ - bignum.cc \ - cached-powers.cc \ - diy-fp.cc \ - double-conversion.cc \ - fast-dtoa.cc \ - fixed-dtoa.cc \ - strtod.cc \ - $(NULL) diff --git a/libazure/src/mfbt/tests/Makefile.in b/libazure/src/mfbt/tests/Makefile.in deleted file mode 100644 index 8767dab..0000000 --- a/libazure/src/mfbt/tests/Makefile.in +++ /dev/null @@ -1,38 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -STL_FLAGS = - -CPP_UNIT_TESTS = \ - TestBloomFilter.cpp \ - TestCheckedInt.cpp \ - TestEndian.cpp \ - TestEnumSet.cpp \ - TestSHA1.cpp \ - TestTypeTraits.cpp \ - TestWeakPtr.cpp \ - $(NULL) - -# in order to prevent rules.mk from trying to link to libraries that are -# not available to MFBT, we have to reset these MOZ_GLUE*_LDFLAGS before including it -# and LIBS_ after including it. For WRAP_LDFLAGS, it shouldn't matter. -# See later comments in bug 732875. - -MOZ_GLUE_PROGRAM_LDFLAGS= -MOZ_GLUE_LDFLAGS = -WRAP_LDFLAGS= - -# Since we link directly with MFBT object files, define IMPL_MFBT -DEFINES += -DIMPL_MFBT - -include $(topsrcdir)/config/rules.mk - -LIBS= $(call EXPAND_LIBNAME_PATH,mfbt,$(DEPTH)/mfbt) diff --git a/libazure/src/mfbt/tests/TestBloomFilter.cpp b/libazure/src/mfbt/tests/TestBloomFilter.cpp deleted file mode 100644 index 7a8a0ec..0000000 --- a/libazure/src/mfbt/tests/TestBloomFilter.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Assertions.h" -#include "mozilla/BloomFilter.h" - -#include -#include - -using mozilla::BloomFilter; - -class FilterChecker -{ - public: - FilterChecker(uint32_t hash) : mHash(hash) { } - - uint32_t hash() const { return mHash; } - - private: - uint32_t mHash; -}; - -int -main() -{ - BloomFilter<12, FilterChecker> *filter = new BloomFilter<12, FilterChecker>(); - MOZ_ASSERT(filter); - - FilterChecker one(1); - FilterChecker two(0x20000); - FilterChecker many(0x10000); - FilterChecker multiple(0x20001); - - filter->add(&one); - MOZ_ASSERT(filter->mightContain(&one), - "Filter should contain 'one'"); - - MOZ_ASSERT(!filter->mightContain(&multiple), - "Filter claims to contain 'multiple' when it should not"); - - MOZ_ASSERT(filter->mightContain(&many), - "Filter should contain 'many' (false positive)"); - - filter->add(&two); - MOZ_ASSERT(filter->mightContain(&multiple), - "Filter should contain 'multiple' (false positive)"); - - // Test basic removals - filter->remove(&two); - MOZ_ASSERT(!filter->mightContain(&multiple), - "Filter claims to contain 'multiple' when it should not after two " - "was removed"); - - // Test multiple addition/removal - const size_t FILTER_SIZE = 255; - for (size_t i = 0; i < FILTER_SIZE - 1; ++i) - filter->add(&two); - - MOZ_ASSERT(filter->mightContain(&multiple), - "Filter should contain 'multiple' after 'two' added lots of times " - "(false positive)"); - - for (size_t i = 0; i < FILTER_SIZE - 1; ++i) - filter->remove(&two); - - MOZ_ASSERT(!filter->mightContain(&multiple), - "Filter claims to contain 'multiple' when it should not after two " - "was removed lots of times"); - - // Test overflowing the filter buckets - for (size_t i = 0; i < FILTER_SIZE + 1; ++i) - filter->add(&two); - - MOZ_ASSERT(filter->mightContain(&multiple), - "Filter should contain 'multiple' after 'two' added lots more " - "times (false positive)"); - - for (size_t i = 0; i < FILTER_SIZE + 1; ++i) - filter->remove(&two); - - MOZ_ASSERT(filter->mightContain(&multiple), - "Filter claims to not contain 'multiple' even though we should " - "have run out of space in the buckets (false positive)"); - MOZ_ASSERT(filter->mightContain(&two), - "Filter claims to not contain 'two' even though we should have " - "run out of space in the buckets (false positive)"); - - filter->remove(&one); - - MOZ_ASSERT(!filter->mightContain(&one), - "Filter should not contain 'one', because we didn't overflow its " - "bucket"); - - filter->clear(); - - MOZ_ASSERT(!filter->mightContain(&multiple), - "clear() failed to work"); - - return 0; -} diff --git a/libazure/src/mfbt/tests/TestCheckedInt.cpp b/libazure/src/mfbt/tests/TestCheckedInt.cpp deleted file mode 100644 index 6d79da6..0000000 --- a/libazure/src/mfbt/tests/TestCheckedInt.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/CheckedInt.h" - -#include -#include - -#ifndef MOZ_CHECKEDINT_USE_MFBT -# error "MOZ_CHECKEDINT_USE_MFBT should be defined by CheckedInt.h" -#endif - -using namespace mozilla; - -int gIntegerTypesTested = 0; -int gTestsPassed = 0; -int gTestsFailed = 0; - -void verifyImplFunction(bool x, bool expected, - const char* file, int line, - int size, bool isTSigned) -{ - if (x == expected) { - gTestsPassed++; - } else { - gTestsFailed++; - std::cerr << "Test failed at " << file << ":" << line; - std::cerr << " with T a "; - if (isTSigned) - std::cerr << "signed"; - else - std::cerr << "unsigned"; - std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl; - } -} - -#define VERIFY_IMPL(x, expected) \ - verifyImplFunction((x), \ - (expected), \ - __FILE__, \ - __LINE__, \ - sizeof(T), \ - detail::IsSigned::value) - -#define VERIFY(x) VERIFY_IMPL(x, true) -#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false) -#define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true) -#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false) -#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition)) - -template -struct testTwiceBiggerType -{ - static void run() - { - VERIFY(detail::IsSupported::Type>::value); - VERIFY(sizeof(typename detail::TwiceBiggerType::Type) - == 2 * sizeof(T)); - VERIFY(bool(detail::IsSigned::Type>::value) - == bool(detail::IsSigned::value)); - } -}; - -template -struct testTwiceBiggerType -{ - static void run() - { - VERIFY_IS_FALSE(detail::IsSupported< - typename detail::TwiceBiggerType::Type - >::value); - } -}; - - -template -void test() -{ - static bool alreadyRun = false; - // Integer types from different families may just be typedefs for types from other families. - // e.g. int32_t might be just a typedef for int. No point re-running the same tests then. - if (alreadyRun) - return; - alreadyRun = true; - - VERIFY(detail::IsSupported::value); - const bool isTSigned = detail::IsSigned::value; - VERIFY(bool(isTSigned) == !bool(T(-1) > T(0))); - - testTwiceBiggerType::run(); - - typedef typename detail::UnsignedType::Type unsignedT; - - VERIFY(sizeof(unsignedT) == sizeof(T)); - VERIFY(detail::IsSigned::value == false); - - const CheckedInt max(detail::MaxValue::value); - const CheckedInt min(detail::MinValue::value); - - // Check MinValue and MaxValue, since they are custom implementations and a mistake there - // could potentially NOT be caught by any other tests... while making everything wrong! - - unsignedT bit = 1; - unsignedT unsignedMinValue(min.value()); - unsignedT unsignedMaxValue(max.value()); - for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++) - { - VERIFY((unsignedMinValue & bit) == 0); - bit <<= 1; - } - VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0))); - VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue)); - - const CheckedInt zero(0); - const CheckedInt one(1); - const CheckedInt two(2); - const CheckedInt three(3); - const CheckedInt four(4); - - /* Addition / subtraction checks */ - - VERIFY_IS_VALID(zero + zero); - VERIFY(zero + zero == zero); - VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true - VERIFY_IS_VALID(zero + one); - VERIFY(zero + one == one); - VERIFY_IS_VALID(one + one); - VERIFY(one + one == two); - - const CheckedInt maxMinusOne = max - one; - const CheckedInt maxMinusTwo = max - two; - VERIFY_IS_VALID(maxMinusOne); - VERIFY_IS_VALID(maxMinusTwo); - VERIFY_IS_VALID(maxMinusOne + one); - VERIFY_IS_VALID(maxMinusTwo + one); - VERIFY_IS_VALID(maxMinusTwo + two); - VERIFY(maxMinusOne + one == max); - VERIFY(maxMinusTwo + one == maxMinusOne); - VERIFY(maxMinusTwo + two == max); - - VERIFY_IS_VALID(max + zero); - VERIFY_IS_VALID(max - zero); - VERIFY_IS_INVALID(max + one); - VERIFY_IS_INVALID(max + two); - VERIFY_IS_INVALID(max + maxMinusOne); - VERIFY_IS_INVALID(max + max); - - const CheckedInt minPlusOne = min + one; - const CheckedInt minPlusTwo = min + two; - VERIFY_IS_VALID(minPlusOne); - VERIFY_IS_VALID(minPlusTwo); - VERIFY_IS_VALID(minPlusOne - one); - VERIFY_IS_VALID(minPlusTwo - one); - VERIFY_IS_VALID(minPlusTwo - two); - VERIFY(minPlusOne - one == min); - VERIFY(minPlusTwo - one == minPlusOne); - VERIFY(minPlusTwo - two == min); - - const CheckedInt minMinusOne = min - one; - VERIFY_IS_VALID(min + zero); - VERIFY_IS_VALID(min - zero); - VERIFY_IS_INVALID(min - one); - VERIFY_IS_INVALID(min - two); - VERIFY_IS_INVALID(min - minMinusOne); - VERIFY_IS_VALID(min - min); - - const CheckedInt maxOverTwo = max / two; - VERIFY_IS_VALID(maxOverTwo + maxOverTwo); - VERIFY_IS_VALID(maxOverTwo + one); - VERIFY((maxOverTwo + one) - one == maxOverTwo); - VERIFY_IS_VALID(maxOverTwo - maxOverTwo); - VERIFY(maxOverTwo - maxOverTwo == zero); - - const CheckedInt minOverTwo = min / two; - VERIFY_IS_VALID(minOverTwo + minOverTwo); - VERIFY_IS_VALID(minOverTwo + one); - VERIFY((minOverTwo + one) - one == minOverTwo); - VERIFY_IS_VALID(minOverTwo - minOverTwo); - VERIFY(minOverTwo - minOverTwo == zero); - - VERIFY_IS_INVALID(min - one); - VERIFY_IS_INVALID(min - two); - - if (isTSigned) { - VERIFY_IS_INVALID(min + min); - VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo); - VERIFY_IS_INVALID(zero - min + min); - VERIFY_IS_INVALID(one - min + min); - } - - /* Unary operator- checks */ - - const CheckedInt negOne = -one; - const CheckedInt negTwo = -two; - - if (isTSigned) { - VERIFY_IS_VALID(-max); - VERIFY_IS_INVALID(-min); - VERIFY(-max - min == one); - VERIFY_IS_VALID(-max - one); - VERIFY_IS_VALID(negOne); - VERIFY_IS_VALID(-max + negOne); - VERIFY_IS_VALID(negOne + one); - VERIFY(negOne + one == zero); - VERIFY_IS_VALID(negTwo); - VERIFY_IS_VALID(negOne + negOne); - VERIFY(negOne + negOne == negTwo); - } else { - VERIFY_IS_INVALID(-max); - VERIFY_IS_VALID(-min); - VERIFY(min == zero); - VERIFY_IS_INVALID(negOne); - } - - /* multiplication checks */ - - VERIFY_IS_VALID(zero * zero); - VERIFY(zero * zero == zero); - VERIFY_IS_VALID(zero * one); - VERIFY(zero * one == zero); - VERIFY_IS_VALID(one * zero); - VERIFY(one * zero == zero); - VERIFY_IS_VALID(one * one); - VERIFY(one * one == one); - VERIFY_IS_VALID(one * three); - VERIFY(one * three == three); - VERIFY_IS_VALID(two * two); - VERIFY(two * two == four); - - VERIFY_IS_INVALID(max * max); - VERIFY_IS_INVALID(maxOverTwo * max); - VERIFY_IS_INVALID(maxOverTwo * maxOverTwo); - - const CheckedInt maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2))); - - VERIFY_IS_VALID(maxApproxSqrt); - VERIFY_IS_VALID(maxApproxSqrt * two); - VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt); - VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt); - - if (isTSigned) { - VERIFY_IS_INVALID(min * min); - VERIFY_IS_INVALID(minOverTwo * min); - VERIFY_IS_INVALID(minOverTwo * minOverTwo); - - const CheckedInt minApproxSqrt = -maxApproxSqrt; - - VERIFY_IS_VALID(minApproxSqrt); - VERIFY_IS_VALID(minApproxSqrt * two); - VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt); - VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt); - } - - // make sure to check all 4 paths in signed multiplication validity check. - // test positive * positive - VERIFY_IS_VALID(max * one); - VERIFY(max * one == max); - VERIFY_IS_INVALID(max * two); - VERIFY_IS_VALID(maxOverTwo * two); - VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two)); - - if (isTSigned) { - // test positive * negative - VERIFY_IS_VALID(max * negOne); - VERIFY_IS_VALID(-max); - VERIFY(max * negOne == -max); - VERIFY_IS_VALID(one * min); - VERIFY_IS_INVALID(max * negTwo); - VERIFY_IS_VALID(maxOverTwo * negTwo); - VERIFY_IS_VALID(two * minOverTwo); - VERIFY_IS_VALID((maxOverTwo + one) * negTwo); - VERIFY_IS_INVALID((maxOverTwo + two) * negTwo); - VERIFY_IS_INVALID(two * (minOverTwo - one)); - - // test negative * positive - VERIFY_IS_VALID(min * one); - VERIFY_IS_VALID(minPlusOne * one); - VERIFY_IS_INVALID(min * two); - VERIFY_IS_VALID(minOverTwo * two); - VERIFY(minOverTwo * two == min); - VERIFY_IS_INVALID((minOverTwo - one) * negTwo); - VERIFY_IS_INVALID(negTwo * max); - VERIFY_IS_VALID(minOverTwo * two); - VERIFY(minOverTwo * two == min); - VERIFY_IS_VALID(negTwo * maxOverTwo); - VERIFY_IS_INVALID((minOverTwo - one) * two); - VERIFY_IS_VALID(negTwo * (maxOverTwo + one)); - VERIFY_IS_INVALID(negTwo * (maxOverTwo + two)); - - // test negative * negative - VERIFY_IS_INVALID(min * negOne); - VERIFY_IS_VALID(minPlusOne * negOne); - VERIFY(minPlusOne * negOne == max); - VERIFY_IS_INVALID(min * negTwo); - VERIFY_IS_INVALID(minOverTwo * negTwo); - VERIFY_IS_INVALID(negOne * min); - VERIFY_IS_VALID(negOne * minPlusOne); - VERIFY(negOne * minPlusOne == max); - VERIFY_IS_INVALID(negTwo * min); - VERIFY_IS_INVALID(negTwo * minOverTwo); - } - - /* Division checks */ - - VERIFY_IS_VALID(one / one); - VERIFY(one / one == one); - VERIFY_IS_VALID(three / three); - VERIFY(three / three == one); - VERIFY_IS_VALID(four / two); - VERIFY(four / two == two); - VERIFY((four*three)/four == three); - - // Check that div by zero is invalid - VERIFY_IS_INVALID(zero / zero); - VERIFY_IS_INVALID(one / zero); - VERIFY_IS_INVALID(two / zero); - VERIFY_IS_INVALID(negOne / zero); - VERIFY_IS_INVALID(max / zero); - VERIFY_IS_INVALID(min / zero); - - if (isTSigned) { - // Check that min / -1 is invalid - VERIFY_IS_INVALID(min / negOne); - - // Check that the test for div by -1 isn't banning other numerators than min - VERIFY_IS_VALID(one / negOne); - VERIFY_IS_VALID(zero / negOne); - VERIFY_IS_VALID(negOne / negOne); - VERIFY_IS_VALID(max / negOne); - } - - /* Check that invalidity is correctly preserved by arithmetic ops */ - - const CheckedInt someInvalid = max + max; - VERIFY_IS_INVALID(someInvalid + zero); - VERIFY_IS_INVALID(someInvalid - zero); - VERIFY_IS_INVALID(zero + someInvalid); - VERIFY_IS_INVALID(zero - someInvalid); - VERIFY_IS_INVALID(-someInvalid); - VERIFY_IS_INVALID(someInvalid * zero); - VERIFY_IS_INVALID(someInvalid * one); - VERIFY_IS_INVALID(zero * someInvalid); - VERIFY_IS_INVALID(one * someInvalid); - VERIFY_IS_INVALID(someInvalid / zero); - VERIFY_IS_INVALID(someInvalid / one); - VERIFY_IS_INVALID(zero / someInvalid); - VERIFY_IS_INVALID(one / someInvalid); - VERIFY_IS_INVALID(someInvalid + someInvalid); - VERIFY_IS_INVALID(someInvalid - someInvalid); - VERIFY_IS_INVALID(someInvalid * someInvalid); - VERIFY_IS_INVALID(someInvalid / someInvalid); - - /* Check that mixing checked integers with plain integers in expressions is allowed */ - - VERIFY(one + T(2) == three); - VERIFY(2 + one == three); - { - CheckedInt x = one; - x += 2; - VERIFY(x == three); - } - VERIFY(two - 1 == one); - VERIFY(2 - one == one); - { - CheckedInt x = two; - x -= 1; - VERIFY(x == one); - } - VERIFY(one * 2 == two); - VERIFY(2 * one == two); - { - CheckedInt x = one; - x *= 2; - VERIFY(x == two); - } - VERIFY(four / 2 == two); - VERIFY(4 / two == two); - { - CheckedInt x = four; - x /= 2; - VERIFY(x == two); - } - - VERIFY(one == 1); - VERIFY(1 == one); - VERIFY_IS_FALSE(two == 1); - VERIFY_IS_FALSE(1 == two); - VERIFY_IS_FALSE(someInvalid == 1); - VERIFY_IS_FALSE(1 == someInvalid); - - /* Check that construction of CheckedInt from an integer value of a mismatched type is checked */ - - #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \ - { \ - bool isUSigned = detail::IsSigned::value; \ - VERIFY_IS_VALID(CheckedInt(U(0))); \ - VERIFY_IS_VALID(CheckedInt(U(1))); \ - VERIFY_IS_VALID(CheckedInt(U(100))); \ - if (isUSigned) \ - VERIFY_IS_VALID_IF(CheckedInt(U(-1)), isTSigned); \ - if (sizeof(U) > sizeof(T)) \ - VERIFY_IS_INVALID(CheckedInt(U(detail::MaxValue::value) + one.value())); \ - VERIFY_IS_VALID_IF(CheckedInt(detail::MaxValue::value), \ - (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \ - VERIFY_IS_VALID_IF(CheckedInt(detail::MinValue::value), \ - isUSigned == false ? 1 : \ - bool(isTSigned) == false ? 0 : \ - sizeof(T) >= sizeof(U)); \ - } - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t) - - typedef signed char signedChar; - typedef unsigned char unsignedChar; - typedef unsigned short unsignedShort; - typedef unsigned int unsignedInt; - typedef unsigned long unsignedLong; - - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long) - VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong) - - /* Test increment/decrement operators */ - - CheckedInt x, y; - x = one; - y = x++; - VERIFY(x == two); - VERIFY(y == one); - x = one; - y = ++x; - VERIFY(x == two); - VERIFY(y == two); - x = one; - y = x--; - VERIFY(x == zero); - VERIFY(y == one); - x = one; - y = --x; - VERIFY(x == zero); - VERIFY(y == zero); - x = max; - VERIFY_IS_VALID(x++); - x = max; - VERIFY_IS_INVALID(++x); - x = min; - VERIFY_IS_VALID(x--); - x = min; - VERIFY_IS_INVALID(--x); - - gIntegerTypesTested++; -} - -int main() -{ - test(); - test(); - test(); - test(); - test(); - test(); - test(); - test(); - - test(); - test(); - test(); - test(); - test(); - test(); - test(); - test(); - test(); - - const int MIN_TYPES_TESTED = 9; - if (gIntegerTypesTested < MIN_TYPES_TESTED) { - std::cerr << "Only " << gIntegerTypesTested << " have been tested. " - << "This should not be less than " << MIN_TYPES_TESTED << "." - << std::endl; - gTestsFailed++; - } - - std::cerr << gTestsFailed << " tests failed, " - << gTestsPassed << " tests passed out of " - << gTestsFailed + gTestsPassed - << " tests, covering " << gIntegerTypesTested - << " distinct integer types." << std::endl; - - return gTestsFailed > 0; -} diff --git a/libazure/src/mfbt/tests/TestEndian.cpp b/libazure/src/mfbt/tests/TestEndian.cpp deleted file mode 100644 index 1ec520d..0000000 --- a/libazure/src/mfbt/tests/TestEndian.cpp +++ /dev/null @@ -1,398 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Assertions.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/Endian.h" - -using mozilla::BigEndian; -using mozilla::DebugOnly; -using mozilla::LittleEndian; -using mozilla::NativeEndian; - -template -void -TestSingleSwap(T value, T swappedValue) -{ -#if MOZ_LITTLE_ENDIAN - MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == swappedValue); - MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == swappedValue); - MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == swappedValue); - MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == swappedValue); -#else - MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == swappedValue); - MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == swappedValue); -#endif -} - -template -void -TestSingleNoSwap(T value, T notSwappedValue) -{ -#if MOZ_LITTLE_ENDIAN - MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == notSwappedValue); - MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == notSwappedValue); -#else - MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == notSwappedValue); - MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == notSwappedValue); - MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == notSwappedValue); - MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == notSwappedValue); -#endif -} - -// Endian.h functions are declared as protected in an base class and -// then re-exported as public in public derived classes. The -// standardese around explicit instantiation of templates is not clear -// in such cases. Provide these wrappers to make things more explicit. -// For your own enlightenment, you may wish to peruse: -// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently -// http://j.mp/XosS6S . -#define WRAP_COPYTO(NAME) \ - template \ - void \ - NAME(void* dst, const T* src, unsigned int count) \ - { \ - NativeEndian::NAME(dst, src, count); \ - } - -WRAP_COPYTO(copyAndSwapToLittleEndian) -WRAP_COPYTO(copyAndSwapToBigEndian) -WRAP_COPYTO(copyAndSwapToNetworkOrder) - -#define WRAP_COPYFROM(NAME) \ - template \ - void \ - NAME(T* dst, const void* src, unsigned int count) \ - { \ - NativeEndian::NAME(dst, src, count); \ - } - -WRAP_COPYFROM(copyAndSwapFromLittleEndian) -WRAP_COPYFROM(copyAndSwapFromBigEndian) -WRAP_COPYFROM(copyAndSwapFromNetworkOrder) - -#define WRAP_IN_PLACE(NAME) \ - template \ - void \ - NAME(T* p, unsigned int count) \ - { \ - NativeEndian::NAME(p, count); \ - } -WRAP_IN_PLACE(swapToLittleEndianInPlace) -WRAP_IN_PLACE(swapFromLittleEndianInPlace) -WRAP_IN_PLACE(swapToBigEndianInPlace) -WRAP_IN_PLACE(swapFromBigEndianInPlace) -WRAP_IN_PLACE(swapToNetworkOrderInPlace) -WRAP_IN_PLACE(swapFromNetworkOrderInPlace) - -enum SwapExpectation { - Swap, - NoSwap -}; - -template -void -TestBulkSwapToSub(enum SwapExpectation expectSwap, - const T (&values)[count], - void (*swapperFunc)(void*, const T*, unsigned int), - T (*readerFunc)(const void*)) -{ - const size_t arraySize = 2 * count; - const size_t bufferSize = arraySize * sizeof(T); - static uint8_t buffer[bufferSize]; - const uint8_t fillValue = 0xa5; - static uint8_t checkBuffer[bufferSize]; - - MOZ_ASSERT(bufferSize > 2 * sizeof(T)); - - memset(checkBuffer, fillValue, bufferSize); - - for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) { - for (size_t nValues = 0; nValues < count; ++nValues) { - memset(buffer, fillValue, bufferSize); - swapperFunc(buffer + startPosition, values, nValues); - - MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0); - DebugOnly valuesEndPosition = startPosition + sizeof(T) * nValues; - MOZ_ASSERT(memcmp(buffer + valuesEndPosition, - checkBuffer + valuesEndPosition, - bufferSize - valuesEndPosition) == 0); - if (expectSwap == NoSwap) { - MOZ_ASSERT(memcmp(buffer + startPosition, values, - nValues * sizeof(T)) == 0); - } - for (size_t i = 0; i < nValues; ++i) { - MOZ_ASSERT(readerFunc(buffer + startPosition + sizeof(T) * i) == - values[i]); - } - } - } -} - -template -void -TestBulkSwapFromSub(enum SwapExpectation expectSwap, - const T (&values)[count], - void (*swapperFunc)(T*, const void*, unsigned int), - T (*readerFunc)(const void*)) -{ - const size_t arraySize = 2 * count; - const size_t bufferSize = arraySize * sizeof(T); - static T buffer[arraySize]; - const uint8_t fillValue = 0xa5; - static T checkBuffer[arraySize]; - - memset(checkBuffer, fillValue, bufferSize); - - for (size_t startPosition = 0; startPosition < count; ++startPosition) { - for (size_t nValues = 0; nValues < (count - startPosition); ++nValues) { - memset(buffer, fillValue, bufferSize); - swapperFunc(buffer + startPosition, values, nValues); - - MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); - DebugOnly valuesEndPosition = startPosition + nValues; - MOZ_ASSERT(memcmp(buffer + valuesEndPosition, - checkBuffer + valuesEndPosition, - (arraySize - valuesEndPosition) * sizeof(T)) == 0); - if (expectSwap == NoSwap) { - MOZ_ASSERT(memcmp(buffer + startPosition, values, - nValues * sizeof(T)) == 0); - } - for (size_t i = 0; i < nValues; ++i) - MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); - } - } -} - - -template -void -TestBulkInPlaceSub(enum SwapExpectation expectSwap, - const T (&values)[count], - void (*swapperFunc)(T* p, unsigned int), - T (*readerFunc)(const void*)) -{ - const size_t bufferCount = 4 * count; - const size_t bufferSize = bufferCount * sizeof(T); - static T buffer[bufferCount]; - const T fillValue = 0xa5; - static T checkBuffer[bufferCount]; - - MOZ_ASSERT(bufferSize > 2 * sizeof(T)); - - memset(checkBuffer, fillValue, bufferSize); - - for (size_t startPosition = 0; startPosition < count; ++startPosition) { - for (size_t nValues = 0; nValues < count; ++nValues) { - memset(buffer, fillValue, bufferSize); - memcpy(buffer + startPosition, values, nValues * sizeof(T)); - swapperFunc(buffer + startPosition, nValues); - - MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); - DebugOnly valuesEndPosition = startPosition + nValues; - MOZ_ASSERT(memcmp(buffer + valuesEndPosition, - checkBuffer + valuesEndPosition, - bufferSize - valuesEndPosition * sizeof(T)) == 0); - if (expectSwap == NoSwap) { - MOZ_ASSERT(memcmp(buffer + startPosition, values, - nValues * sizeof(T)) == 0); - } - for (size_t i = 0; i < nValues; ++i) - MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); - } - } -} - -template -struct Reader -{ -}; - -#define SPECIALIZE_READER(TYPE, READ_FUNC) \ - template<> \ - struct Reader \ - { \ - static TYPE readLE(const void* p) { return LittleEndian::READ_FUNC(p); } \ - static TYPE readBE(const void* p) { return BigEndian::READ_FUNC(p); } \ - }; - -SPECIALIZE_READER(uint16_t, readUint16) -SPECIALIZE_READER(uint32_t, readUint32) -SPECIALIZE_READER(uint64_t, readUint64) -SPECIALIZE_READER(int16_t, readInt16) -SPECIALIZE_READER(int32_t, readInt32) -SPECIALIZE_READER(int64_t, readInt64) - -template -void -TestBulkSwap(const T (&bytes)[count]) -{ -#if MOZ_LITTLE_ENDIAN - TestBulkSwapToSub(Swap, bytes, copyAndSwapToBigEndian, Reader::readBE); - TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromBigEndian, Reader::readBE); - TestBulkSwapToSub(Swap, bytes, copyAndSwapToNetworkOrder, Reader::readBE); - TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromNetworkOrder, Reader::readBE); -#else - TestBulkSwapToSub(Swap, bytes, copyAndSwapToLittleEndian, Reader::readLE); - TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromLittleEndian, Reader::readLE); -#endif -} - -template -void -TestBulkNoSwap(const T (&bytes)[count]) -{ -#if MOZ_LITTLE_ENDIAN - TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToLittleEndian, Reader::readLE); - TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromLittleEndian, Reader::readLE); -#else - TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToBigEndian, Reader::readBE); - TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromBigEndian, Reader::readBE); - TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToNetworkOrder, Reader::readBE); - TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromNetworkOrder, Reader::readBE); -#endif -} - -template -void -TestBulkInPlaceSwap(const T (&bytes)[count]) -{ -#if MOZ_LITTLE_ENDIAN - TestBulkInPlaceSub(Swap, bytes, swapToBigEndianInPlace, Reader::readBE); - TestBulkInPlaceSub(Swap, bytes, swapFromBigEndianInPlace, Reader::readBE); - TestBulkInPlaceSub(Swap, bytes, swapToNetworkOrderInPlace, Reader::readBE); - TestBulkInPlaceSub(Swap, bytes, swapFromNetworkOrderInPlace, Reader::readBE); -#else - TestBulkInPlaceSub(Swap, bytes, swapToLittleEndianInPlace, Reader::readLE); - TestBulkInPlaceSub(Swap, bytes, swapFromLittleEndianInPlace, Reader::readLE); -#endif -} - -template -void -TestBulkInPlaceNoSwap(const T (&bytes)[count]) -{ -#if MOZ_LITTLE_ENDIAN - TestBulkInPlaceSub(NoSwap, bytes, swapToLittleEndianInPlace, Reader::readLE); - TestBulkInPlaceSub(NoSwap, bytes, swapFromLittleEndianInPlace, Reader::readLE); -#else - TestBulkInPlaceSub(NoSwap, bytes, swapToBigEndianInPlace, Reader::readBE); - TestBulkInPlaceSub(NoSwap, bytes, swapFromBigEndianInPlace, Reader::readBE); - TestBulkInPlaceSub(NoSwap, bytes, swapToNetworkOrderInPlace, Reader::readBE); - TestBulkInPlaceSub(NoSwap, bytes, swapFromNetworkOrderInPlace, Reader::readBE); -#endif -} - -int -main() -{ - static const uint8_t unsigned_bytes[16] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, - 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }; - static const int8_t signed_bytes[16] = { -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08, - -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08 }; - static const uint16_t uint16_values[8] = { 0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708 }; - static const int16_t int16_values[8] = { int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8), - int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8) }; - static const uint32_t uint32_values[4] = { 0x1020304, 0x5060708, 0x1020304, 0x5060708 }; - static const int32_t int32_values[4] = { int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8), - int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8) }; - static const uint64_t uint64_values[2] = { 0x102030405060708, 0x102030405060708 }; - static const int64_t int64_values[2] = { int64_t(0xf1f2f3f4f5f6f7f8), - int64_t(0xf1f2f3f4f5f6f7f8) }; - uint8_t buffer[8]; - - MOZ_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201); - MOZ_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102); - - MOZ_ASSERT(LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U); - MOZ_ASSERT(BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U); - - MOZ_ASSERT(LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL); - MOZ_ASSERT(BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL); - - LittleEndian::writeUint16(&buffer[0], 0x201); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); - BigEndian::writeUint16(&buffer[0], 0x102); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); - - LittleEndian::writeUint32(&buffer[0], 0x4030201U); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); - BigEndian::writeUint32(&buffer[0], 0x1020304U); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); - - LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); - BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL); - MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); - - MOZ_ASSERT(LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1)); - MOZ_ASSERT(BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2)); - - MOZ_ASSERT(LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1)); - MOZ_ASSERT(BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4)); - - MOZ_ASSERT(LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL)); - MOZ_ASSERT(BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL)); - - LittleEndian::writeInt16(&buffer[0], 0xf2f1); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); - BigEndian::writeInt16(&buffer[0], 0xf1f2); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); - - LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); - BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); - - LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); - BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL); - MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); - - TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2)); - TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4)); - TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8)); - - TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2)); - TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4)); - TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8)); - - TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1)); - TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1)); - TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1)); - - TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1)); - TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1)); - TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1)); - - TestBulkSwap(uint16_values); - TestBulkSwap(int16_values); - TestBulkSwap(uint32_values); - TestBulkSwap(int32_values); - TestBulkSwap(uint64_values); - TestBulkSwap(int64_values); - - TestBulkNoSwap(uint16_values); - TestBulkNoSwap(int16_values); - TestBulkNoSwap(uint32_values); - TestBulkNoSwap(int32_values); - TestBulkNoSwap(uint64_values); - TestBulkNoSwap(int64_values); - - TestBulkInPlaceSwap(uint16_values); - TestBulkInPlaceSwap(int16_values); - TestBulkInPlaceSwap(uint32_values); - TestBulkInPlaceSwap(int32_values); - TestBulkInPlaceSwap(uint64_values); - TestBulkInPlaceSwap(int64_values); - - TestBulkInPlaceNoSwap(uint16_values); - TestBulkInPlaceNoSwap(int16_values); - TestBulkInPlaceNoSwap(uint32_values); - TestBulkInPlaceNoSwap(int32_values); - TestBulkInPlaceNoSwap(uint64_values); - TestBulkInPlaceNoSwap(int64_values); - - return 0; -} diff --git a/libazure/src/mfbt/tests/TestEnumSet.cpp b/libazure/src/mfbt/tests/TestEnumSet.cpp deleted file mode 100644 index dc43fe3..0000000 --- a/libazure/src/mfbt/tests/TestEnumSet.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/EnumSet.h" - -using namespace mozilla; - -enum SeaBird { - PENGUIN, - ALBATROSS, - FULMAR, - PRION, - SHEARWATER, - GADFLY_PETREL, - TRUE_PETREL, - DIVING_PETREL, - STORM_PETREL, - PELICAN, - GANNET, - BOOBY, - CORMORANT, - FRIGATEBIRD, - TROPICBIRD, - SKUA, - GULL, - TERN, - SKIMMER, - AUK -}; - -class EnumSetSuite { - public: - EnumSetSuite() - : mAlcidae(), - mDiomedeidae(ALBATROSS), - mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL), - mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER), - mPetrels(GADFLY_PETREL, TRUE_PETREL, DIVING_PETREL, STORM_PETREL) - { } - - void runTests() { - testSize(); - testContains(); - testAddTo(); - testAdd(); - testAddAll(); - testUnion(); - testRemoveFrom(); - testRemove(); - testRemoveAllFrom(); - testRemoveAll(); - testIntersect(); - testInsersection(); - testEquality(); - testDuplicates(); - } - - private: - void testSize() { - MOZ_ASSERT(mAlcidae.size() == 0); - MOZ_ASSERT(mDiomedeidae.size() == 1); - MOZ_ASSERT(mPetrelProcellariidae.size() == 2); - MOZ_ASSERT(mNonPetrelProcellariidae.size() == 3); - MOZ_ASSERT(mPetrels.size() == 4); - } - - void testContains() { - MOZ_ASSERT(!mPetrels.contains(PENGUIN)); - MOZ_ASSERT(!mPetrels.contains(ALBATROSS)); - MOZ_ASSERT(!mPetrels.contains(FULMAR)); - MOZ_ASSERT(!mPetrels.contains(PRION)); - MOZ_ASSERT(!mPetrels.contains(SHEARWATER)); - MOZ_ASSERT(mPetrels.contains(GADFLY_PETREL)); - MOZ_ASSERT(mPetrels.contains(TRUE_PETREL)); - MOZ_ASSERT(mPetrels.contains(DIVING_PETREL)); - MOZ_ASSERT(mPetrels.contains(STORM_PETREL)); - MOZ_ASSERT(!mPetrels.contains(PELICAN)); - MOZ_ASSERT(!mPetrels.contains(GANNET)); - MOZ_ASSERT(!mPetrels.contains(BOOBY)); - MOZ_ASSERT(!mPetrels.contains(CORMORANT)); - MOZ_ASSERT(!mPetrels.contains(FRIGATEBIRD)); - MOZ_ASSERT(!mPetrels.contains(TROPICBIRD)); - MOZ_ASSERT(!mPetrels.contains(SKUA)); - MOZ_ASSERT(!mPetrels.contains(GULL)); - MOZ_ASSERT(!mPetrels.contains(TERN)); - MOZ_ASSERT(!mPetrels.contains(SKIMMER)); - MOZ_ASSERT(!mPetrels.contains(AUK)); - } - - void testCopy() { - EnumSet likes = mPetrels; - likes -= TRUE_PETREL; - MOZ_ASSERT(mPetrels.size() == 4); - MOZ_ASSERT(mPetrels.contains(TRUE_PETREL)); - - MOZ_ASSERT(likes.size() == 3); - MOZ_ASSERT(likes.contains(GADFLY_PETREL)); - MOZ_ASSERT(likes.contains(DIVING_PETREL)); - MOZ_ASSERT(likes.contains(STORM_PETREL)); - } - - void testAddTo() { - EnumSet seen = mPetrels; - seen += CORMORANT; - seen += TRUE_PETREL; - MOZ_ASSERT(mPetrels.size() == 4); - MOZ_ASSERT(!mPetrels.contains(CORMORANT)); - MOZ_ASSERT(seen.size() == 5); - MOZ_ASSERT(seen.contains(GADFLY_PETREL)); - MOZ_ASSERT(seen.contains(TRUE_PETREL)); - MOZ_ASSERT(seen.contains(DIVING_PETREL)); - MOZ_ASSERT(seen.contains(STORM_PETREL)); - MOZ_ASSERT(seen.contains(CORMORANT)); - } - - void testAdd() { - EnumSet seen = mPetrels + CORMORANT + - STORM_PETREL; - MOZ_ASSERT(mPetrels.size() == 4); - MOZ_ASSERT(!mPetrels.contains(CORMORANT)); - MOZ_ASSERT(seen.size() == 5); - MOZ_ASSERT(seen.contains(GADFLY_PETREL)); - MOZ_ASSERT(seen.contains(TRUE_PETREL)); - MOZ_ASSERT(seen.contains(DIVING_PETREL)); - MOZ_ASSERT(seen.contains(STORM_PETREL)); - MOZ_ASSERT(seen.contains(CORMORANT)); - } - - void testAddAll() { - EnumSet procellariidae; - procellariidae += mPetrelProcellariidae; - procellariidae += mNonPetrelProcellariidae; - MOZ_ASSERT(procellariidae.size() == 5); - - // Both procellariidae and mPetrels include GADFLY_PERTEL and TRUE_PETREL - EnumSet procellariiformes; - procellariiformes += mDiomedeidae; - procellariiformes += procellariidae; - procellariiformes += mPetrels; - MOZ_ASSERT(procellariiformes.size() == 8); - } - - void testUnion() { - EnumSet procellariidae = mPetrelProcellariidae + - mNonPetrelProcellariidae; - MOZ_ASSERT(procellariidae.size() == 5); - - // Both procellariidae and mPetrels include GADFLY_PETREL and TRUE_PETREL - EnumSet procellariiformes = mDiomedeidae + procellariidae + - mPetrels; - MOZ_ASSERT(procellariiformes.size() == 8); - } - - void testRemoveFrom() { - EnumSet likes = mPetrels; - likes -= TRUE_PETREL; - likes -= DIVING_PETREL; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(GADFLY_PETREL)); - MOZ_ASSERT(likes.contains(STORM_PETREL)); - } - - void testRemove() { - EnumSet likes = mPetrels - TRUE_PETREL - - DIVING_PETREL; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(GADFLY_PETREL)); - MOZ_ASSERT(likes.contains(STORM_PETREL)); - } - - void testRemoveAllFrom() { - EnumSet likes = mPetrels; - likes -= mPetrelProcellariidae; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(DIVING_PETREL)); - MOZ_ASSERT(likes.contains(STORM_PETREL)); - } - - void testRemoveAll() { - EnumSet likes = mPetrels - mPetrelProcellariidae; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(DIVING_PETREL)); - MOZ_ASSERT(likes.contains(STORM_PETREL)); - } - - void testIntersect() { - EnumSet likes = mPetrels; - likes &= mPetrelProcellariidae; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(GADFLY_PETREL)); - MOZ_ASSERT(likes.contains(TRUE_PETREL)); - } - - void testInsersection() { - EnumSet likes = mPetrels & mPetrelProcellariidae; - MOZ_ASSERT(likes.size() == 2); - MOZ_ASSERT(likes.contains(GADFLY_PETREL)); - MOZ_ASSERT(likes.contains(TRUE_PETREL)); - } - - void testEquality() { - EnumSet likes = mPetrels & mPetrelProcellariidae; - MOZ_ASSERT(likes == EnumSet(GADFLY_PETREL, - TRUE_PETREL)); - } - - void testDuplicates() { - EnumSet likes = mPetrels; - likes += GADFLY_PETREL; - likes += TRUE_PETREL; - likes += DIVING_PETREL; - likes += STORM_PETREL; - MOZ_ASSERT(likes.size() == 4); - MOZ_ASSERT(likes == mPetrels); - } - - - EnumSet mAlcidae; - EnumSet mDiomedeidae; - EnumSet mPetrelProcellariidae; - EnumSet mNonPetrelProcellariidae; - EnumSet mPetrels; -}; - -int main() -{ - EnumSetSuite suite; - suite.runTests(); - return 0; -} diff --git a/libazure/src/mfbt/tests/TestSHA1.cpp b/libazure/src/mfbt/tests/TestSHA1.cpp deleted file mode 100644 index 0d30dbe..0000000 --- a/libazure/src/mfbt/tests/TestSHA1.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Assertions.h" -#include "mozilla/SHA1.h" - -using mozilla::SHA1Sum; - -static unsigned int testV[1024] = { - 0x048edc1a, 0x4345588c, 0x0ef03cbf, 0x1d6438f5, 0x094e0a1e, 0x68535f60, - 0x14e8c927, 0x60190043, 0x5d640ab7, 0x73dc7c62, 0x364223f9, 0x47320292, - 0x3924cae0, 0x5f6b26d3, 0x5efa04ef, 0x7aab361e, 0x2773b1aa, 0x1631b07d, - 0x385b5dd1, 0x26c809b0, 0x28ad3a9f, 0x0315292a, 0x1a544e67, 0x1e79dcb9, - 0x787683e8, 0x3a591c75, 0x1dd338c7, 0x01c539e5, 0x1c15b23e, 0x0697c25c, - 0x4df5fd45, 0x672aa324, 0x39f74e6e, 0x269cdd5f, 0x087b6fce, 0x293509db, - 0x0aef54a9, 0x210c4cc5, 0x29d6dc4a, 0x16320825, 0x3ab7b181, 0x56d6fd25, - 0x6837fda2, 0x3e7994c2, 0x37f77529, 0x48c85472, 0x424fd84d, 0x00aba7fa, - 0x6d8475de, 0x354634a7, 0x0c73bb49, 0x0a335de6, 0x0a9ea542, 0x5ffb31f1, - 0x00a6a3f2, 0x76b14a03, 0x1e436a37, 0x173b766a, 0x33cf3ca0, 0x34eb0f1a, - 0x4ca073ee, 0x27591fe6, 0x5eaf3356, 0x10c24493, 0x1bad88b6, 0x676f2309, - 0x7f5e2d91, 0x74bd4c83, 0x66549b43, 0x52ffdf24, 0x2dfa0a83, 0x7c3e1cbf, - 0x1edf87fc, 0x1f6fa930, 0x7c29bc74, 0x374bcd2f, 0x5b43de94, 0x0d09a3a6, - 0x7437ecb0, 0x635117f8, 0x2aa78f65, 0x2c788958, 0x098cb9f3, 0x13ed5b3f, - 0x41b7c7ba, 0x696b2d88, 0x42e20d63, 0x69585b1d, 0x4a9b027c, 0x0c761cba, - 0x563bdbc4, 0x3bde2f5b, 0x0bab9730, 0x7740104c, 0x11641702, 0x26f03c32, - 0x011a87c6, 0x2c5e4e6c, 0x46c34200, 0x6a167e84, 0x34205728, 0x0e8a6152, - 0x0014604b, 0x6793bacd, 0x442bca9c, 0x6f2018ce, 0x4313e07e, 0x77f2c69c, - 0x62621441, 0x47bf6358, 0x59c45e04, 0x16ba3426, 0x6ac0c19d, 0x20218c6b, - 0x510b4ddc, 0x585f6c9d, 0x1ed02b0c, 0x366bf0a9, 0x131c7f59, 0x0ebcd320, - 0x00ca858a, 0x5efbcb77, 0x2a7a1859, 0x64bb5afd, 0x76258886, 0x6505c895, - 0x602cfa32, 0x17040942, 0x783df744, 0x3838e0ae, 0x6a021e39, 0x4c8c9c5a, - 0x4a5e96b6, 0x10f4477d, 0x247fda4f, 0x4c390400, 0x0cbe048c, 0x7b547d26, - 0x1e2e6897, 0x4ba7e01b, 0x5cfea1bb, 0x39a2d199, 0x45aee64a, 0x12615500, - 0x0151615f, 0x1a9f5d33, 0x4542ed44, 0x101357eb, 0x35a16b1f, 0x3420b3e1, - 0x6442bac7, 0x1c0f2a8c, 0x68d642f1, 0x45744fc4, 0x048e60cb, 0x5f217f44, - 0x6cc7d151, 0x27f41984, 0x2d01eb09, 0x2bb15aea, 0x6dda49f8, 0x590dd6bc, - 0x280cc20b, 0x7e2592b5, 0x043642f0, 0x292b5d29, 0x2e0a9b69, 0x41162471, - 0x1e55db6b, 0x648b96fe, 0x05f8f9d1, 0x4a9d4cbb, 0x38517039, 0x2b0f8917, - 0x4d1e67bb, 0x713e0974, 0x64fdf214, 0x11223963, 0x2bd09d24, 0x19924092, - 0x4b4a70f0, 0x1ece6b03, 0x1780c9c1, 0x09b4c3ac, 0x58ac7e73, 0x5c9a4747, - 0x321f943b, 0x41167667, 0x3a19cf8c, 0x53f4144d, 0x03a498de, 0x6fb4b742, - 0x54d793cb, 0x7ee164e2, 0x501af74c, 0x43201e7f, 0x0ad581be, 0x497f046a, - 0x3b1d2a9f, 0x53b88eb0, 0x2c3a26c5, 0x5ae970ba, 0x7d7ee4ff, 0x471366c5, - 0x46119703, 0x3bfc2e58, 0x456d6c4f, 0x4b6bb181, 0x45d7c872, 0x0d023221, - 0x021176d1, 0x4195ad44, 0x4621ec90, 0x3ae68279, 0x57952f71, 0x1796080c, - 0x228077bb, 0x5e2b7fee, 0x3d71dd88, 0x4a651849, 0x7f1c8081, 0x04c333fc, - 0x1f99bff6, 0x11b7754c, 0x740be324, 0x069bf2e2, 0x0802f3e0, 0x371cf30e, - 0x1d44dda5, 0x6033b9e5, 0x5639a9b0, 0x6526bfff, 0x14d7d9b7, 0x4182b6a7, - 0x01a5fa76, 0x7aa5e581, 0x762465e6, 0x386b3a2e, 0x495a3ab0, 0x04421b2e, - 0x46e04591, 0x472af458, 0x6a007dd3, 0x2e8be484, 0x18660abe, 0x7969af82, - 0x5a242a83, 0x581b5f72, 0x5f0eff6d, 0x38aea98c, 0x2acb5853, 0x6d650b35, - 0x10b750d7, 0x18fdcd14, 0x09b4816c, 0x3ceef016, 0x6957153c, 0x27cf39fb, - 0x60e3495d, 0x381e1da6, 0x4b5be02d, 0x14b6f309, 0x6380c589, 0x1a31f436, - 0x4b5e50c1, 0x493ac048, 0x314baad1, 0x71e24ab7, 0x718af49c, 0x022f4658, - 0x1a419d5b, 0x1854610d, 0x2ec4e99a, 0x7096ce50, 0x5467ba00, 0x404aab4c, - 0x1a5ab015, 0x217580f7, 0x2d50071e, 0x71a9f437, 0x27f758b5, 0x11cd8b3f, - 0x63b089c9, 0x53c860c1, 0x2fa6b7d7, 0x61e54771, 0x5c0ba6b9, 0x3138f796, - 0x5c7359cd, 0x4c2c5654, 0x549d581c, 0x3129ebf7, 0x4958a248, 0x1a460541, - 0x68e64964, 0x597c0609, 0x57afcbab, 0x2f1c6479, 0x57a0ad5c, 0x5936938f, - 0x536a5cbe, 0x29aacf0b, 0x43eca70d, 0x6e7a3e4e, 0x563c1e3b, 0x32f23909, - 0x12faa42d, 0x28b0bbde, 0x797e2842, 0x1b827bdf, 0x0df96a6e, 0x542ef7f4, - 0x6226d368, 0x01cb4258, 0x77bcba08, 0x7e6dc041, 0x0571eda3, 0x0fdf5065, - 0x5c9b9f7a, 0x2b496dd6, 0x02d3b40b, 0x3a5752db, 0x4843a293, 0x6fdc9c3f, - 0x42963996, 0x39c9e4eb, 0x01db58ad, 0x7e79381c, 0x5bb207bb, 0x2df5de51, - 0x1549ec82, 0x64f01e70, 0x536eb0d0, 0x10fa6e03, 0x5b7f9a20, 0x2d8b625d, - 0x397410c7, 0x7778284e, 0x1ab75170, 0x254f304e, 0x395ba877, 0x0c2e2815, - 0x5c723dec, 0x63b91327, 0x7c5954b5, 0x67dd69a3, 0x21d220c7, 0x5a287fcd, - 0x0d0b9c59, 0x22444c9f, 0x6305cb43, 0x12f717cc, 0x77c11945, 0x0e79bda8, - 0x6e014391, 0x441d0179, 0x5e17dd2f, 0x53e57a5c, 0x692f4b9a, 0x76c1e94b, - 0x5a872d81, 0x044f7e7e, 0x0970844f, 0x25e34e73, 0x57865d3c, 0x640771d2, - 0x12d410ed, 0x1424e079, 0x3e1c7fd7, 0x0e89295a, 0x48dcf262, 0x55a29550, - 0x0fd4d360, 0x7494d449, 0x41e6f260, 0x2230d4e7, 0x5ad1cd49, 0x7f8dd428, - 0x7722b48a, 0x7a14848d, 0x2a83335a, 0x548c0d9b, 0x24f5d43b, 0x33a417cb, - 0x3061e078, 0x1a1bc935, 0x5aedb5df, 0x6755f3e4, 0x795e4cdb, 0x64dfcd1c, - 0x6d5164fc, 0x34a3df0e, 0x2cc92142, 0x2569127d, 0x130f3d86, 0x43617cc2, - 0x25eaf1fa, 0x044ae792, 0x4b47ee17, 0x6879ea87, 0x7eb455fa, 0x54481e19, - 0x13bba2f0, 0x6da3fe79, 0x19c306ff, 0x42591e38, 0x2b0e205d, 0x60bd48bc, - 0x550aa0ce, 0x2296a6ef, 0x551eb052, 0x76df1b8e, 0x242a2d22, 0x0ada0b06, - 0x58b661ec, 0x490bec94, 0x20bd7c59, 0x760de8c3, 0x7a048ee8, 0x44ba6dcd, - 0x3816abd9, 0x47e8527e, 0x2194a188, 0x6967a480, 0x7f7e2083, 0x0ec455f3, - 0x78198eab, 0x3d710773, 0x05969198, 0x76ffcffe, 0x54be4797, 0x11105781, - 0x3a851719, 0x516284b8, 0x4295de1c, 0x3905be43, 0x6d4e7d6a, 0x0877796d, - 0x0b9e986a, 0x5e2b853f, 0x7e6c79cd, 0x4a44a54c, 0x1e28b9a2, 0x5b1e408e, - 0x6a1c8eac, 0x62a87929, 0x4f075dac, 0x5c030e8c, 0x3df73ce9, 0x321c3c69, - 0x2325cc45, 0x4eaf0759, 0x486a31fb, 0x12d04b94, 0x714e15d5, 0x420d1910, - 0x092dc45b, 0x0119beac, 0x68b2bfdb, 0x74863a17, 0x3c7ab8e5, 0x035bc2df, - 0x4e7a7965, 0x017f58d6, 0x6414074e, 0x3a1e64ae, 0x2d6725d8, 0x0f22f82a, - 0x0a0affa0, 0x4159f31e, 0x4002cb9d, 0x234e393f, 0x6028169f, 0x3b804078, - 0x0c16e2e1, 0x0e198020, 0x24b13c40, 0x1ceb2143, 0x38dd4246, 0x6f483590, - 0x69b20a6e, 0x105580b1, 0x5d60f184, 0x065d18eb, 0x09a28739, 0x70345728, - 0x595a5934, 0x14a78a43, 0x449f05c7, 0x6556fcfc, 0x260bc0b2, 0x3afb600e, - 0x1f47bb91, 0x145c14b6, 0x541832fe, 0x54f10f23, 0x3013650e, 0x6c0d32ba, - 0x4f202c8d, 0x66bcc661, 0x6131dc7f, 0x04828b25, 0x1737565d, 0x520e967f, - 0x16cf0438, 0x6f2bc19e, 0x553c3dda, 0x356906b0, 0x333916d5, 0x2887c195, - 0x11e7440b, 0x6354f182, 0x06b2f977, 0x6d2c9a5c, 0x2d02bfb7, 0x74fafcf6, - 0x2b955161, 0x74035c38, 0x6e9bc991, 0x09a3a5b9, 0x460f416a, 0x11afabfc, - 0x66e32d10, 0x4a56ac6e, 0x6448afa8, 0x680b0044, 0x05d0e296, 0x49569eac, - 0x0adb563b, 0x4a9da168, 0x4f857004, 0x0f234600, 0x6db386ec, 0x280b94bf, - 0x7cd258a5, 0x6165fd88, 0x3bf2aac9, 0x2cb47c44, 0x2381c2a4, 0x4fe42552, - 0x21d4c81e, 0x24baa9af, 0x365231cb, 0x11b7fc81, 0x419748fb, 0x38ff637e, - 0x065f3365, 0x21f1aba8, 0x2df41ace, 0x5cec1d95, 0x22c078a8, 0x7bb894fc, - 0x2d66fc53, 0x7ed82ccc, 0x4485c9d7, 0x1af210fc, 0x5d2faa09, 0x3b33412e, - 0x79d12ea8, 0x7bb8103b, 0x5cea1a7b, 0x2779db45, 0x1250ed5b, 0x0c4d8964, - 0x6c18e9f5, 0x501ddc60, 0x3de43ae4, 0x6c0e8577, 0x0adfb426, 0x7ec718f5, - 0x1991f387, 0x101ccb9c, 0x632360b4, 0x7d52ce4d, 0x0b58c91c, 0x1fa59d53, - 0x0b0b48b0, 0x297315d0, 0x7f3132ff, 0x323b85d1, 0x2f852141, 0x23e84bdc, - 0x3732cb25, 0x1274eb57, 0x21a882c3, 0x095288a9, 0x2120e253, 0x617799ce, - 0x5e4926b3, 0x52575363, 0x696722e0, 0x509c9117, 0x3b60f14f, 0x423310fa, - 0x4e694e80, 0x000a647e, 0x453e283a, 0x3f1d21ef, 0x527c91f0, 0x7ac2e88a, - 0x1ba3b840, 0x1c3f253a, 0x04c40280, 0x437dc361, 0x7247859c, 0x61e5b34c, - 0x20746a53, 0x58cfc2df, 0x79edf48e, 0x5b48e723, 0x7b08baac, 0x1d1035ea, - 0x023fc918, 0x2de0427c, 0x71540904, 0x4030e8f5, 0x2b0961f6, 0x4ec98ef0, - 0x781076ee, 0x0dac959b, 0x16f66214, 0x273411e5, 0x02334297, 0x3b568cd1, - 0x7cf4e8c0, 0x0f4c2c91, 0x2d8dd28e, 0x4a7b3fb0, 0x237969ae, 0x363d6cb6, - 0x75fee60a, 0x5825f4df, 0x29f79f9d, 0x22de4f33, 0x2309590e, 0x1977c2bd, - 0x67f7bebe, 0x452b8330, 0x5dc70832, 0x5cddbea4, 0x59091e0b, 0x4d287830, - 0x2bbc2ce6, 0x420ee023, 0x02d6e086, 0x228a7a14, 0x48207207, 0x1d5ccc5a, - 0x37d32cdc, 0x50dc6508, 0x0b795304, 0x5b9fd543, 0x2a3f2925, 0x72e71606, - 0x0dc8ba42, 0x3279a910, 0x6bd2c2e2, 0x775065d8, 0x547c59a6, 0x4b5374cf, - 0x0c45cd18, 0x532096d6, 0x351c9bd1, 0x107fdce0, 0x3ae69075, 0x5dddd5de, - 0x3bb0ba8b, 0x0b1a0019, 0x6c226525, 0x109e9002, 0x312191be, 0x16fa3de8, - 0x4a5197aa, 0x0931b2d2, 0x79ee6e1b, 0x657a142b, 0x6ab74d38, 0x77440cff, - 0x11e37956, 0x5c335799, 0x269d3be3, 0x18923cfd, 0x4dd71b00, 0x77c58014, - 0x07145324, 0x1678546a, 0x5dfd4f6a, 0x207f4e13, 0x6b0a98c0, 0x015bc2cf, - 0x1636d8fe, 0x7bc5f038, 0x183a0661, 0x573ec5f3, 0x54cf2255, 0x2fcc905c, - 0x71bb70b9, 0x2b122a89, 0x59f86e5b, 0x5528273d, 0x464cf857, 0x27efdeec, - 0x1d0bcfcc, 0x64d7837f, 0x1e7a659a, 0x02aa611c, 0x53969ad5, 0x0e83f59f, - 0x50a6d11b, 0x79513c59, 0x0e5c3c98, 0x2ed7bbcf, 0x117de9d9, 0x375ec696, - 0x19c830aa, 0x66950511, 0x2b6dbbaa, 0x5ca18c9b, 0x0a487514, 0x6f44a887, - 0x6921bc6e, 0x3ef8130b, 0x26f6cde3, 0x686d7605, 0x6583553a, 0x29bcf7cc, - 0x55d42201, 0x1c93497c, 0x64c53231, 0x32088f6e, 0x381c5770, 0x617574d8, - 0x09757952, 0x1a616eb0, 0x1140e8aa, 0x0ff66ffb, 0x32039001, 0x5a455e7c, - 0x0027b906, 0x21cf154c, 0x67d3527f, 0x56fd7602, 0x150f8b25, 0x2ae8e4c8, - 0x0bf10aec, 0x3d26a40f, 0x5c4c8ffc, 0x3c291322, 0x737fd02c, 0x4b506209, - 0x484ddaa4, 0x00b44669, 0x5974bdd1, 0x7d39d617, 0x12995404, 0x48f00bbe, - 0x44f7c59a, 0x23cb9292, 0x6476f20b, 0x034fbd59, 0x2893161c, 0x1dbae8c0, - 0x50348c2e, 0x797f0957, 0x685ddeaf, 0x36fb8a2e, 0x0fceb6f4, 0x10347ab4, - 0x72720bfc, 0x292a4304, 0x0cbf8a27, 0x3cea6db7, 0x4b0c6b15, 0x57e8e716, - 0x4e9c54cc, 0x4fc7f7ca, 0x49a6d3e2, 0x10fc2df3, 0x73db387e, 0x72cb89c3, - 0x71dba437, 0x4b14048c, 0x6e1af265, 0x1084b213, 0x3842107d, 0x6ecdc171, - 0x647919b2, 0x41a80841, 0x7b387c76, 0x46bc094b, 0x331b312a, 0x2f140cc4, - 0x355d0a11, 0x19390200, 0x69b05263, 0x582963fa, 0x44897e31, 0x66a473f0, - 0x0374f08d, 0x35879e45, 0x5e1dd7ef, 0x34d6a311, 0x6e4e18eb, 0x7b44734b, - 0x0e421333, 0x3da026d8, 0x5becbf4b, 0x56db4a1f, 0x1f2089bc, 0x28c733f2, - 0x04b0975d, 0x6156f224, 0x12d1f40f, 0x7f4d30f4, 0x2c0b9861, 0x769a083b, - 0x739544fb, 0x1dbd1067, 0x0e8cd717, 0x4c246fb2, 0x115eff39, 0x19e22f2a, - 0x4563ba61, 0x5d33a617, 0x54af83cf, 0x030bde73, 0x54b4736d, 0x0f01dfec, - 0x08869c01, 0x4e9e4d7b, 0x4739855a, 0x62d964a3, 0x26948fde, 0x30adf212, - 0x1f57b400, 0x3766c914, 0x1e7f9d1c, 0x33258b59, 0x522ab2c2, 0x3dc99798, - 0x15f53fe2, 0x05636669, 0x354b59c3, 0x1c37ebd4, 0x0bb7ebf9, 0x0e4e87f9, - 0x680d3124, 0x2770d549, 0x0c5e112e, 0x74aaa7ed, 0x06c0b550, 0x342b5922, - 0x4532ab5b, 0x4257dbee, 0x087f32a9, 0x45ada3e3, 0x7a854272, 0x061625f2, - 0x47c85a91, 0x25ad375d, 0x2809bd9d, 0x168b9348, 0x4381b0a3, 0x6f2dc6ca, - 0x122e54f6, 0x6c3228a6, 0x653c1652, 0x60b60584, 0x1d304b77, 0x4cc74c58, - 0x087e3dd5, 0x79bd540e, 0x79ab7a70, 0x26fcd1c9, 0x342abaaf, 0x644716b0, - 0x01f076cb, 0x73628937, 0x20b01ff8, 0x5832b80b, 0x2f77fc92, 0x4468d962, - 0x2bac2679, 0x7f850778, 0x47d2997c, 0x02690cb7, 0x7de54951, 0x54d80b14, - 0x5e0c6854, 0x313cc749, 0x622b86ba, 0x38dbf6d3, 0x045d3e52, 0x574f87fd, - 0x09f1b078, 0x31784f71, 0x4f01dd2f, 0x1874c9f9, 0x5837c7af, 0x2372f768, - 0x531bd1e8, 0x61816c0b, 0x4592995f, 0x156463c0, 0x250c5afe, 0x40c83178, - 0x4396f6b7, 0x29bdbec0, 0x43ea8ca5, 0x5c474696, 0x2c869192, 0x2ff2f51a, - 0x7c963fe5, 0x294319c1, 0x019fbe26, 0x72fa8e68, 0x245ca463, 0x4ca88208, - 0x72ac845a, 0x25307181, 0x2cdf88f7, 0x0adbfebd, 0x2eea465b, 0x52e4eee0, - 0x084daacd, 0x717ce67e, 0x594087c2, 0x2b8ee5c7, 0x4558f811, 0x76b65ba4, - 0x5de05e09, 0x3db76e27, 0x3c75110d, 0x04ca67e7, 0x51cd6d09, 0x7b4e9c3e, - 0x7cdda4d2, 0x674fb021, 0x7d372d2d, 0x13f7978b, 0x5fb106b1, 0x034377d1, - 0x2e5336f3, 0x099bb17d, 0x04e6755e, 0x34f73c1e, 0x004e0a0d, 0x7f2c32e2, - 0x1fc8f910, 0x67d0859d, 0x76462b25, 0x59fa9a17, 0x028e53ef, 0x3d6d5fdd, - 0x79a4671e, 0x5cbec506, 0x2c23ee6d, 0x628a2c1e, 0x4dae87bd, 0x07a189ea, - 0x3a414a96, 0x5915f622, 0x6bea011e, 0x412674cf, 0x07ecc314, 0x6a7dbce8, - 0x7e176f10, 0x68e60d47, 0x079ea970, 0x79f3b55c, 0x65a46098, 0x56155533, - 0x7e5d0272, 0x795bfad5, 0x094da770, 0x05ba427c, 0x152e430e, 0x187d8470, - 0x08e607bc, 0x45ce5ef9, 0x654231ae, 0x38d8cb48, 0x605632f8, 0x25cf8ee9, - 0x11497170, 0x171a3b00, 0x0f103d49, 0x24826483, 0x2848e187, 0x7498919b, - 0x1bb788cb, 0x791ad5c7, 0x5129330e, 0x016c4436, 0x430f05bf, 0x1f06b5cd, - 0x62df1378, 0x0423b9b4, 0x0341acaf, 0x3189543c, 0x7b96b2ea, 0x6c4865c3, - 0x4cc7adc3, 0x78a2bff6, 0x642db7c7, 0x70d02300, 0x7cd43ac0, 0x4f5fe414, - 0x333b52c2, 0x500d3c74, 0x65782c01, 0x3f72a2c5, 0x278f59d8, 0x493bf7f8, - 0x16bf51a0, 0x6cc70ced, 0x6ed15979, 0x1a77abae, 0x08cadbb7, 0x2f2e0bc0, - 0x236f5e8d, 0x1a4b4495, 0x360bd008, 0x32227d40 -}; - -int -main() -{ - SHA1Sum sum; - SHA1Sum::Hash hash; - sum.update(reinterpret_cast(testV), sizeof(testV)); - sum.finish(hash); - - static const uint8_t expected[20] = - { 0xc8, 0xf2, 0x09, 0x59, 0x4e, 0x64, 0x40, 0xaa, 0x7b, 0xf7, 0xb8, 0xe0, - 0xfa, 0x44, 0xb2, 0x31, 0x95, 0xad, 0x94, 0x81 }; - - MOZ_STATIC_ASSERT(sizeof(expected) == sizeof(SHA1Sum::Hash), - "expected-data size should be the same as the actual hash " - "size"); - - for (size_t i = 0; i < SHA1Sum::HashSize; i++) - MOZ_ASSERT(hash[i] == expected[i]); - - return 0; -} diff --git a/libazure/src/mfbt/tests/TestTypeTraits.cpp b/libazure/src/mfbt/tests/TestTypeTraits.cpp deleted file mode 100644 index a7b2eaf..0000000 --- a/libazure/src/mfbt/tests/TestTypeTraits.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Assertions.h" -#include "mozilla/TypeTraits.h" - -using mozilla::IsBaseOf; -using mozilla::IsConvertible; - -namespace CPlusPlus11IsBaseOf { - -// Adapted from C++11 § 20.9.6. -struct B {}; -struct B1 : B {}; -struct B2 : B {}; -struct D : private B1, private B2 {}; - -static void -StandardIsBaseOfTests() -{ - MOZ_ASSERT((IsBaseOf::value) == true); - MOZ_ASSERT((IsBaseOf::value) == true); - MOZ_ASSERT((IsBaseOf::value) == true); - MOZ_ASSERT((IsBaseOf::value) == true); - MOZ_ASSERT((IsBaseOf::value) == false); - MOZ_ASSERT((IsBaseOf::value) == false); - MOZ_ASSERT((IsBaseOf::value) == false); - // We fail at the following test. To fix it, we need to specialize IsBaseOf - // for all built-in types. - // MOZ_ASSERT((IsBaseOf::value) == false); -} - -} /* namespace CPlusPlus11IsBaseOf */ - -class A { }; -class B : public A { }; -class C : private A { }; -class D { }; -class E : public A { }; -class F : public B, public E { }; - -static void -TestIsBaseOf() -{ - MOZ_ASSERT((IsBaseOf::value), - "A is a base of B"); - MOZ_ASSERT((!IsBaseOf::value), - "B is not a base of A"); - MOZ_ASSERT((IsBaseOf::value), - "A is a base of C"); - MOZ_ASSERT((!IsBaseOf::value), - "C is not a base of A"); - MOZ_ASSERT((IsBaseOf::value), - "A is a base of F"); - MOZ_ASSERT((!IsBaseOf::value), - "F is not a base of A"); - MOZ_ASSERT((!IsBaseOf::value), - "A is not a base of D"); - MOZ_ASSERT((!IsBaseOf::value), - "D is not a base of A"); - MOZ_ASSERT((IsBaseOf::value), - "B is the same as B (and therefore, a base of B)"); -} - -static void -TestIsConvertible() -{ - // Pointer type convertibility - MOZ_ASSERT((IsConvertible::value), - "A* should convert to A*"); - MOZ_ASSERT((IsConvertible::value), - "B* should convert to A*"); - MOZ_ASSERT((!IsConvertible::value), - "A* shouldn't convert to B*"); - MOZ_ASSERT((!IsConvertible::value), - "A* shouldn't convert to C*"); - MOZ_ASSERT((!IsConvertible::value), - "A* shouldn't convert to unrelated D*"); - MOZ_ASSERT((!IsConvertible::value), - "D* shouldn't convert to unrelated A*"); - - // Instance type convertibility - MOZ_ASSERT((IsConvertible::value), - "A is A"); - MOZ_ASSERT((IsConvertible::value), - "B converts to A"); - MOZ_ASSERT((!IsConvertible::value), - "D and A are unrelated"); - MOZ_ASSERT((!IsConvertible::value), - "A and D are unrelated"); - - // These cases seem to require C++11 support to properly implement them, so - // for now just disable them. - //MOZ_ASSERT((!IsConvertible::value), - // "C* shouldn't convert to A* (private inheritance)"); - //MOZ_ASSERT((!IsConvertible::value), - // "C doesn't convert to A (private inheritance)"); -} - -int -main() -{ - CPlusPlus11IsBaseOf::StandardIsBaseOfTests(); - TestIsBaseOf(); - TestIsConvertible(); -} diff --git a/libazure/src/mfbt/tests/TestWeakPtr.cpp b/libazure/src/mfbt/tests/TestWeakPtr.cpp deleted file mode 100644 index 510dd06..0000000 --- a/libazure/src/mfbt/tests/TestWeakPtr.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/WeakPtr.h" - -using mozilla::SupportsWeakPtr; -using mozilla::WeakPtr; - -// To have a class C support weak pointers, inherit from SupportsWeakPtr. -class C : public SupportsWeakPtr -{ - public: - int num; - void act() {} -}; - -static void -Example() -{ - - C* ptr = new C(); - - // Get weak pointers to ptr. The first time asWeakPtr is called - // a reference counted WeakReference object is created that - // can live beyond the lifetime of 'ptr'. The WeakReference - // object will be notified of 'ptr's destruction. - WeakPtr weak = ptr->asWeakPtr(); - WeakPtr other = ptr->asWeakPtr(); - - // Test a weak pointer for validity before using it. - if (weak) { - weak->num = 17; - weak->act(); - } - - // Destroying the underlying object clears weak pointers to it. - delete ptr; - - MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); - MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); -} - -struct A : public SupportsWeakPtr -{ - int data; -}; - - -int -main() -{ - - A* a = new A; - - // a2 is unused to test the case when we haven't initialized - // the internal WeakReference pointer. - A* a2 = new A; - - a->data = 5; - WeakPtr ptr = a->asWeakPtr(); - { - WeakPtr ptr2 = a->asWeakPtr(); - MOZ_ASSERT(ptr->data == 5); - WeakPtr ptr3 = a->asWeakPtr(); - MOZ_ASSERT(ptr->data == 5); - } - - delete a; - MOZ_ASSERT(!ptr); - - delete a2; - - Example(); - - return 0; -} diff --git a/libazure/unittest/Main.cpp b/libazure/unittest/Main.cpp new file mode 100644 index 0000000..484292b --- /dev/null +++ b/libazure/unittest/Main.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SanityChecks.h" +#include "TestPoint.h" +#include "TestRect.h" +#include "TestMatrix.h" +#include "TestScaling.h" +#include "TestBugs.h" +#ifdef WIN32 +#include +#ifdef USE_D2D1_1 +#include +#endif +#endif +#include "TestDrawTarget.h" +#include "TestPath.h" + +#include +#include + +struct TestObject { + TestBase *test; + std::string name; +}; + + +using namespace std; +using namespace mozilla; +using namespace mozilla::gfx; + +int +main() +{ +#ifdef WIN32 + RefPtr mDevice; + ::D3D10CreateDevice1(nullptr, + D3D10_DRIVER_TYPE_HARDWARE, + nullptr, + D3D10_CREATE_DEVICE_BGRA_SUPPORT | + D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, + D3D10_FEATURE_LEVEL_10_0, + D3D10_1_SDK_VERSION, + byRef(mDevice)); + + Factory::SetDirect3D10Device(mDevice); + +#ifdef USE_D2D1_1 + RefPtr d3d11device; + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3 + }; + + + HRESULT hr = ::D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + featureLevels, sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL), + D3D11_SDK_VERSION, byRef(d3d11device), nullptr, nullptr); + + Factory::SetDirect3D11Device(d3d11device); +#endif +#endif + + TestObject tests[] = + { + { new SanityChecks(), "Sanity Checks" }, + #ifdef WIN32 + { new TestDrawTargetD2D(), "DrawTarget (D2D)" }, + { new TestPathD2D(), "Path (D2D)" }, + { new TestDrawTargetCapture(), "DrawTarget (Capture)" }, + #ifdef USE_D2D1_1 + { new TestDrawTargetD2D1(), "DrawTarget (D2D 1.1)" }, + #endif + #endif + #ifdef USE_CAIRO + { new TestDrawTargetCairoImage(), "DrawTarget (Cairo Image)" }, + { new TestPathCairo(), "Path (Cairo)" }, + #endif + #ifdef USE_SKIA + { new TestDrawTargetSkiaSoftware(), "DrawTarget (Skia Software)" }, + { new TestPathSkia(), "Path (Skia)" }, + #endif + { new TestPoint(), "Point Tests" }, + { new TestRect(), "Rect Tests" }, + { new TestMatrix(), "Matrix Tests" }, + { new TestScaling(), "Scaling Tests" }, + { new TestBugs(), "Bug Tests" } + }; + + int totalFailures = 0; + int totalTests = 0; + stringstream message; + printf("------ STARTING RUNNING TESTS ------\n"); + for (int i = 0; i < sizeof(tests) / sizeof(TestObject); i++) { + message << "--- RUNNING TESTS: " << tests[i].name << " ---\n"; + printf("%s", message.str().c_str()); + message.str(""); + int failures = 0; + totalTests += tests[i].test->RunTests(&failures); + totalFailures += failures; + // Done with this test! + delete tests[i].test; + } + message << "------ FINISHED RUNNING TESTS ------\nTests run: " << totalTests << " - Passes: " << totalTests - totalFailures << " - Failures: " << totalFailures << "\n"; + printf("%s", message.str().c_str()); + return totalFailures; +} diff --git a/libazure/src/gfx/2d/unittest/SanityChecks.cpp b/libazure/unittest/SanityChecks.cpp similarity index 81% rename from libazure/src/gfx/2d/unittest/SanityChecks.cpp rename to libazure/unittest/SanityChecks.cpp index 428c198..5300307 100644 --- a/libazure/src/gfx/2d/unittest/SanityChecks.cpp +++ b/libazure/unittest/SanityChecks.cpp @@ -7,7 +7,9 @@ SanityChecks::SanityChecks() { - REGISTER_TEST(SanityChecks, AlwaysPasses); +#define TEST_CLASS SanityChecks + REGISTER_TEST(AlwaysPasses); +#undef TEST_CLASS } void diff --git a/libazure/src/gfx/2d/unittest/SanityChecks.h b/libazure/unittest/SanityChecks.h similarity index 100% rename from libazure/src/gfx/2d/unittest/SanityChecks.h rename to libazure/unittest/SanityChecks.h diff --git a/libazure/src/gfx/2d/unittest/TestBase.cpp b/libazure/unittest/TestBase.cpp similarity index 71% rename from libazure/src/gfx/2d/unittest/TestBase.cpp rename to libazure/unittest/TestBase.cpp index 3655e34..dd72194 100644 --- a/libazure/src/gfx/2d/unittest/TestBase.cpp +++ b/libazure/unittest/TestBase.cpp @@ -2,47 +2,71 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestBase.h" - -#include - -using namespace std; - -int -TestBase::RunTests(int *aFailures) -{ - int testsRun = 0; - *aFailures = 0; - - for(unsigned int i = 0; i < mTests.size(); i++) { - stringstream stream; - stream << "Test (" << mTests[i].name << "): "; - LogMessage(stream.str()); - stream.str(""); - - mTestFailed = false; - - // Don't try this at home! We know these are actually pointers to members - // of child clases, so we reinterpret cast those child class pointers to - // TestBase and then call the functions. Because the compiler believes - // these function calls are members of TestBase. - ((*reinterpret_cast((mTests[i].implPointer))).*(mTests[i].funcCall))(); - - if (!mTestFailed) { - LogMessage("PASSED\n"); - } else { - LogMessage("FAILED\n"); - (*aFailures)++; - } - testsRun++; - } - - return testsRun; -} - -void -TestBase::LogMessage(string aMessage) -{ - printf(aMessage.c_str()); -} + +#include "TestBase.h" + +#include + +using namespace std; + +#ifdef WIN32 +#include +#endif + +bool +RunTest(TestBase::Test &aTest) +{ +#ifdef WIN32 + __try { +#endif + // Don't try this at home! We know these are actually pointers to members + // of child clases, so we reinterpret cast those child class pointers to + // TestBase and then call the functions. Because the compiler believes + // these function calls are members of TestBase. + ((*reinterpret_cast((aTest.implPointer))).*(aTest.funcCall))(); +#ifdef WIN32 + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return false; + } +#endif + + return true; +} + +int +TestBase::RunTests(int *aFailures) +{ + int testsRun = 0; + *aFailures = 0; + + for(unsigned int i = 0; i < mTests.size(); i++) { + stringstream stream; + stream << "Test (" << mTests[i].name << "): "; + LogMessage(stream.str()); + stream.str(""); + + mTestFailed = false; + + if (!RunTest(mTests[i])) { + LogMessage("Unexpected exception occured. "); + mTestFailed = true; + } + + if (!mTestFailed) { + LogMessage("PASSED\n"); + } else { + LogMessage("FAILED\n"); + (*aFailures)++; + } + testsRun++; + } + + return testsRun; +} + +void +TestBase::LogMessage(string aMessage) +{ + printf("%s", aMessage.c_str()); +} diff --git a/libazure/unittest/TestBase.h b/libazure/unittest/TestBase.h new file mode 100644 index 0000000..a55200c --- /dev/null +++ b/libazure/unittest/TestBase.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include +#include +#include + +#include "Point.h" + +#ifdef _MSC_VER +// On MSVC otherwise our generic member pointer trick doesn't work. +#pragma pointers_to_members(full_generality, single_inheritance) +#endif + +#define VERIFY(arg) if (!(arg)) { \ + LogMessage("VERIFY FAILED: "#arg"\n"); \ + mTestFailed = true; \ + } + +#define VERIFYVALUE(arg1, arg2) if (!VerifyValue(arg1, arg2, #arg1, #arg2)) { mTestFailed = true; } +#define VERIFYVALUEFUZZY(arg1, arg2, arg3) if (!VerifyValueFuzzy(arg1, arg2, arg3, #arg1, #arg2)) { mTestFailed = true; } + +#define REGISTER_CLASS_TEST(className, testName) \ + mTests.push_back(Test(static_cast(&className::testName), #testName, this)) +#define REGISTER_TEST(testName) REGISTER_CLASS_TEST(TEST_CLASS, testName) + +class TestBase +{ +public: + TestBase() {} + virtual ~TestBase() {} + + typedef void (TestBase::*TestCall)(); + + int RunTests(int *aFailures); + + struct Test { + Test(TestCall aCall, std::string aName, void *aImplPointer) + : funcCall(aCall) + , name(aName) + , implPointer(aImplPointer) + { + } + TestCall funcCall; + std::string name; + void *implPointer; + }; +protected: + static void LogMessage(std::string aMessage); + + std::vector mTests; + + template + bool VerifyValue(T aVal1, T aVal2, std::string aVal1String, std::string aVal2String) + { + std::stringstream msg; + + if (aVal1 != aVal2) { + msg << "VERIFY FAILED: " << aVal1String << " (" << aVal1 << ") != " << aVal2String << " (" << aVal2 << ")"; + LogMessage(msg.str()); + return false; + } + return true; + } + + bool VerifyValue(mozilla::gfx::Point aVal1, mozilla::gfx::Point aVal2, std::string aVal1String, std::string aVal2String) + { + std::stringstream msg; + + if (aVal1 != aVal2) { + msg << "VERIFY FAILED: " << aVal1String << " (" << aVal1.x << "x" << aVal2.y << ") != " << aVal2String << " (" << aVal2.x << "x" << aVal2.y << ")"; + LogMessage(msg.str()); + return false; + } + return true; + } + + template + bool VerifyValueFuzzy(T aVal1, T aVal2, T aFuzz, std::string aVal1String, std::string aVal2String) + { + std::stringstream msg; + + if ((aVal1 < (aVal2 - aFuzz)) || (aVal1 > (aVal2 + aFuzz))) { + msg << "VERIFY FAILED: " << aVal1String << " (" << aVal1 << ") != " << aVal2String << " (" << aVal2 << ") - Fuzz: " << aFuzz; + LogMessage(msg.str()); + return false; + } + return true; + } + + bool mTestFailed; + +private: + // This doesn't really work with our generic member pointer trick. + TestBase(const TestBase &aOther); +}; diff --git a/libazure/unittest/TestBugs.cpp b/libazure/unittest/TestBugs.cpp new file mode 100644 index 0000000..9d24755 --- /dev/null +++ b/libazure/unittest/TestBugs.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestBugs.h" +#include "2D.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +TestBugs::TestBugs() +{ +#define TEST_CLASS TestBugs +#ifdef USE_CAIRO + REGISTER_TEST(CairoClip918671); + REGISTER_TEST(PushPopClip950550); +#endif +#undef TEST_CLASS +} + +void +TestBugs::CairoClip918671() +{ + RefPtr dt = Factory::CreateDrawTarget(BackendType::CAIRO, + IntSize(100, 100), + SurfaceFormat::B8G8R8A8); + RefPtr ref = Factory::CreateDrawTarget(BackendType::CAIRO, + IntSize(100, 100), + SurfaceFormat::B8G8R8A8); + // Create a path that extends around the center rect but doesn't intersect it. + RefPtr pb1 = dt->CreatePathBuilder(); + pb1->MoveTo(Point(10, 10)); + pb1->LineTo(Point(90, 10)); + pb1->LineTo(Point(90, 20)); + pb1->LineTo(Point(10, 20)); + pb1->Close(); + pb1->MoveTo(Point(90, 90)); + pb1->LineTo(Point(91, 90)); + pb1->LineTo(Point(91, 91)); + pb1->LineTo(Point(91, 90)); + pb1->Close(); + + RefPtr path1 = pb1->Finish(); + dt->PushClip(path1); + + // This center rect must NOT be rectilinear! + RefPtr pb2 = dt->CreatePathBuilder(); + pb2->MoveTo(Point(50, 50)); + pb2->LineTo(Point(55, 51)); + pb2->LineTo(Point(54, 55)); + pb2->LineTo(Point(50, 56)); + pb2->Close(); + + RefPtr path2 = pb2->Finish(); + dt->PushClip(path2); + + dt->FillRect(Rect(0, 0, 100, 100), ColorPattern(Color(1,0,0))); + + RefPtr surf1 = dt->Snapshot(); + RefPtr surf2 = ref->Snapshot(); + + RefPtr dataSurf1 = surf1->GetDataSurface(); + RefPtr dataSurf2 = surf2->GetDataSurface(); + + for (int y = 0; y < dt->GetSize().height; y++) { + VERIFY(memcmp(dataSurf1->GetData() + y * dataSurf1->Stride(), + dataSurf2->GetData() + y * dataSurf2->Stride(), + dataSurf1->GetSize().width * 4) == 0); + } + +} + +void +TestBugs::PushPopClip950550() +{ + RefPtr dt = Factory::CreateDrawTarget(BackendType::CAIRO, + IntSize(500, 500), + SurfaceFormat::B8G8R8A8); + dt->PushClipRect(Rect(0, 0, 100, 100)); + Matrix m(1, 0, 0, 1, 45, -100); + dt->SetTransform(m); + dt->PopClip(); + + // We fail the test if we assert in this call because our draw target's + // transforms are out of sync. + dt->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.5f, 0, 0, 1.0f))); +} + diff --git a/libazure/unittest/TestBugs.h b/libazure/unittest/TestBugs.h new file mode 100644 index 0000000..0c715df --- /dev/null +++ b/libazure/unittest/TestBugs.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestBase.h" + +class TestBugs : public TestBase +{ +public: + TestBugs(); + + void CairoClip918671(); + void PushPopClip950550(); +}; + diff --git a/libazure/unittest/TestDrawTarget.cpp b/libazure/unittest/TestDrawTarget.cpp new file mode 100644 index 0000000..879049e --- /dev/null +++ b/libazure/unittest/TestDrawTarget.cpp @@ -0,0 +1,1378 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTarget.h" +#include "PathHelpers.h" +#include "Filters.h" +#include + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace std; + +TestDrawTargetBase::TestDrawTargetBase() +{ +#define TEST_CLASS TestDrawTargetBase + REGISTER_TEST(Initialized); + REGISTER_TEST(FillCompletely); + REGISTER_TEST(FillRect); + REGISTER_TEST(StrokeRect); + REGISTER_TEST(StrokeLine); + REGISTER_TEST(Translate); + REGISTER_TEST(FillMultiRect); + REGISTER_TEST(FillMultiRectTransform1); + REGISTER_TEST(FillMultiRectTransform2); + REGISTER_TEST(FillMultiRectTransform3); + REGISTER_TEST(ClipRect); + REGISTER_TEST(ClipRectClear); + REGISTER_TEST(Clip); + REGISTER_TEST(FillTriangle); + REGISTER_TEST(StrokeTriangle); + REGISTER_TEST(DrawSurface); + REGISTER_TEST(FillWithSurface); + REGISTER_TEST(FillWithPartialLargeSurface); + REGISTER_TEST(FillWithScaledLargeSurface); + REGISTER_TEST(FillGradient); + REGISTER_TEST(FillRadialGradient); + REGISTER_TEST(FillWithSnapshot); + REGISTER_TEST(Mask); + REGISTER_TEST(CopySurface); + REGISTER_TEST(Shadow); + REGISTER_TEST(StreamToSink); + REGISTER_TEST(RoundtripThroughA8MakesColorsBlack); + REGISTER_TEST(ColorMatrix); + REGISTER_TEST(Blend); + REGISTER_TEST(Morphology); + REGISTER_TEST(Flood); + REGISTER_TEST(Tile); + REGISTER_TEST(TableTransfer); + REGISTER_TEST(DiscreteTransfer); + REGISTER_TEST(LinearTransfer); + REGISTER_TEST(GammaTransfer); + REGISTER_TEST(ConvolveMatrixNone); + REGISTER_TEST(ConvolveMatrixWrap); + REGISTER_TEST(ConvolveMatrixOffset); + REGISTER_TEST(OffsetFilter); + REGISTER_TEST(DisplacementMap); + REGISTER_TEST(Turbulence); + REGISTER_TEST(ArithmeticCombine); + REGISTER_TEST(Composite); + REGISTER_TEST(GaussianBlur); +#undef TEST_CLASS +} + +void +TestDrawTargetBase::Initialized() +{ + VERIFY(mDT); +} + +void +TestDrawTargetBase::FillCompletely() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillRect() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + mDT->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.502f, 0, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyPixel(IntPoint(49, 49), Color(0, 0.502f, 0, 1.0f)); + VerifyPixel(IntPoint(50, 50), Color(0.502f, 0, 0, 1.0f)); + VerifyPixel(IntPoint(99, 99), Color(0.502f, 0, 0, 1.0f)); + VerifyPixel(IntPoint(100, 100), Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::StrokeRect() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->StrokeRect(Rect(DT_WIDTH / 4, DT_WIDTH / 4, DT_WIDTH / 2, DT_HEIGHT / 2), + ColorPattern(Color(0, 0.502f, 0, 1.0f)), + StrokeOptions(max(DT_WIDTH / 2, DT_HEIGHT / 2))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::StrokeLine() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->StrokeLine(Point(DT_WIDTH / 2, 0), Point(DT_WIDTH / 2, DT_HEIGHT), + ColorPattern(Color(0, 0.502f, 0, 1.0f)), + StrokeOptions(DT_WIDTH)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Translate() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + Matrix mat; + mat.PreTranslate(100, 100); + mDT->SetTransform(mat); + mDT->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.502f, 0, 0, 1.0f))); + mDT->SetTransform(Matrix()); + + RefreshSnapshot(); + + VerifyPixel(IntPoint(149, 149), Color(0, 0.502f, 0, 1.0f)); + VerifyPixel(IntPoint(150, 150), Color(0.502f, 0, 0, 1.0f)); + VerifyPixel(IntPoint(199, 199), Color(0.502f, 0, 0, 1.0f)); + VerifyPixel(IntPoint(200, 200), Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillMultiRect() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + + builder->MoveTo(Point(0, 0)); + builder->LineTo(Point(DT_WIDTH, 0)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 1)); + builder->LineTo(Point(0, DT_HEIGHT / 2 + 1)); + builder->Close(); + builder->MoveTo(Point(0, DT_HEIGHT / 2 - 1)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 - 1)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT)); + builder->LineTo(Point(0, DT_HEIGHT)); + builder->Close(); + + RefPtr path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillMultiRectTransform1() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + + builder->MoveTo(Point(0, 10)); + builder->LineTo(Point(DT_WIDTH, 10)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 11)); + builder->LineTo(Point(0, DT_HEIGHT / 2 + 11)); + builder->Close(); + builder->MoveTo(Point(0, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT + 10)); + builder->LineTo(Point(0, DT_HEIGHT + 10)); + builder->Close(); + + RefPtr path = builder->Finish(); + + Matrix mat; + mat.PreTranslate(0, -10); + mDT->SetTransform(mat); + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + mDT->SetTransform(Matrix()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillMultiRectTransform2() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + Matrix mat; + mat.PreTranslate(0, -10); + mDT->SetTransform(mat); + + RefPtr builder = mDT->CreatePathBuilder(); + + builder->MoveTo(Point(0, 10)); + builder->LineTo(Point(DT_WIDTH, 10)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 11)); + builder->LineTo(Point(0, DT_HEIGHT / 2 + 11)); + builder->Close(); + builder->MoveTo(Point(0, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT + 10)); + builder->LineTo(Point(0, DT_HEIGHT + 10)); + builder->Close(); + + RefPtr path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + mDT->SetTransform(Matrix()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillMultiRectTransform3() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + + builder->MoveTo(Point(0, 10)); + builder->LineTo(Point(DT_WIDTH, 10)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 11)); + builder->LineTo(Point(0, DT_HEIGHT / 2 + 11)); + builder->Close(); + + Matrix mat; + mat.PreTranslate(0, -10); + mDT->SetTransform(mat); + + builder->MoveTo(Point(0, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT / 2 + 9)); + builder->LineTo(Point(DT_WIDTH, DT_HEIGHT + 10)); + builder->LineTo(Point(0, DT_HEIGHT + 10)); + builder->Close(); + + RefPtr path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + mDT->SetTransform(Matrix()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::ClipRect() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + mDT->PushClipRect(Rect(0, 0, 0, 0)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + mDT->PopClip(); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void TestDrawTargetBase::ClipRectClear() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(1.0f, 0, 0, 0.502f))); + mDT->PushClipRect(Rect(0, 100, DT_WIDTH, DT_HEIGHT - 100)); + + Matrix temp; + temp.PreTranslate(0, -100); + mDT->SetTransform(temp); + mDT->ClearRect(Rect(0, 0, DT_WIDTH, 100)); + mDT->SetTransform(Matrix()); + mDT->PopClip(); + + RefreshSnapshot(); + + VerifyAllPixels(Color(1.0f, 0, 0, 0.502f)); +} + +void +TestDrawTargetBase::Clip() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(0, 0)); + builder->LineTo(Point(0, 0)); + builder->Close(); + RefPtr path = builder->Finish(); + + mDT->PushClip(path); + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + mDT->PopClip(); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} +void +TestDrawTargetBase::FillTriangle() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(-10000, -10000)); + builder->LineTo(Point(10000, -10000)); + builder->LineTo(Point(0, 10000)); + builder->Close(); + RefPtr path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::StrokeTriangle() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(0, 0)); + builder->LineTo(Point(250, 500)); + builder->LineTo(Point(500, 0)); + builder->Close(); + RefPtr path = builder->Finish(); + + mDT->Stroke(path, ColorPattern(Color(0, 0.502f, 0, 1.0f)), StrokeOptions(500.0f)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::DrawSurface() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + uint32_t pixel = 0xff008000; + + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)&pixel, IntSize(1, 1), 4, SurfaceFormat::B8G8R8A8); + + mDT->DrawSurface(src, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Rect(0, 0, 1, 1)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillWithPartialLargeSurface() +{ + // This test will test if a DrawTarget correctly displays an extremely + // large image when only part of it is shown. + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + uint32_t *data = new uint32_t[18000 * DT_HEIGHT]; + + for (int i = 0; i < 18000 * DT_HEIGHT; i++) { + data[i] = 0xff008000; + } + + { + RefPtr src = + Factory::CreateWrappingDataSourceSurface((uint8_t*)data, 18000 * 4, IntSize(18000, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), SurfacePattern(src, ExtendMode::REPEAT)); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillWithScaledLargeSurface() +{ + // This test will test if a DrawTarget correctly displays an extremely + // large image when it is scaled down to be completely visible. + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + uint32_t *data = new uint32_t[18000 * DT_HEIGHT]; + + for (int i = 0; i < 18000 * DT_HEIGHT; i++) { + data[i] = 0xff008000; + } + + { + RefPtr src = + Factory::CreateWrappingDataSourceSurface((uint8_t*)data, 18000 * 4, IntSize(18000, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + Matrix mat; + mat.PreScale(Float(DT_WIDTH) / 18000, Float(DT_HEIGHT)); + mDT->FillRect(Rect(0, 0, 18000, DT_HEIGHT), SurfacePattern(src, ExtendMode::REPEAT)); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillWithSurface() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + uint32_t pixel = 0xff008000; + + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)&pixel, IntSize(1, 1), 4, SurfaceFormat::B8G8R8A8); + + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), SurfacePattern(src, ExtendMode::REPEAT)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillGradient() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + GradientStop rawStops[2]; + rawStops[0].color = Color(0, 0.502f, 0, 1.0f); + rawStops[0].offset = 0; + rawStops[1].color = Color(0, 0.502f, 0, 1.0f); + rawStops[1].offset = 1.0f; + + RefPtr stops = mDT->CreateGradientStops(rawStops, 2); + + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), LinearGradientPattern(Point(0, 0), Point(0, DT_HEIGHT), stops)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillRadialGradient() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + GradientStop rawStops[2]; + rawStops[0].color = Color(0, 0.502f, 0, 1.0f); + rawStops[0].offset = 0; + rawStops[1].color = Color(0, 0.502f, 0, 1.0f); + rawStops[1].offset = 1.0f; + + RefPtr stops = mDT->CreateGradientStops(rawStops, 2); + + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), RadialGradientPattern(Point(0, 0), Point(0, 0), 0, 1000, stops)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::FillWithSnapshot() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr tempDT = mDT->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::B8G8R8X8); + tempDT->FillRect(Rect(0, 0, 20, 20), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + RefPtr src = tempDT->Snapshot(); + + mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), SurfacePattern(src, ExtendMode::REPEAT)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Mask() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr tempDT = mDT->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::A8); + tempDT->FillRect(Rect(0, 0, 20, 20), ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); + RefPtr src = tempDT->Snapshot(); + + mDT->Mask(ColorPattern(Color(0, 0.502f, 0, 1.0f)), SurfacePattern(src, ExtendMode::REPEAT)); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::CopySurface() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr tempDT = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + tempDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + RefPtr src = tempDT->Snapshot(); + + mDT->CopySurface(src, IntRect(0, 0, DT_WIDTH, DT_HEIGHT), IntPoint()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Shadow() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr tempDT = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + tempDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + RefPtr src = tempDT->Snapshot(); + + mDT->DrawSurfaceWithShadow(src, Point(-DT_WIDTH, -DT_HEIGHT), Color(0, 0.502f, 0, 1.0f), Point(DT_WIDTH, DT_HEIGHT), 0, CompositionOp::OP_OVER); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::StreamToSink() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(-10000, -10000)); + builder->LineTo(Point(10000, -10000)); + builder->LineTo(Point(0, 10000)); + builder->Close(); + RefPtr path = builder->Finish(); + + builder = mDT->CreatePathBuilder(); + path->StreamToSink(builder); + path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); + + builder = mDT->CreatePathBuilder(); + builder->MoveTo(Point(-2000, -1000)); + builder->LineTo(Point(2000, -1000)); + builder->BezierTo(Point(-2000, 10000), Point(2000, 10000), Point(2000, -1000)); + builder->Close(); + path = builder->Finish(); + + builder = mDT->CreatePathBuilder(); + path->StreamToSink(builder); + path = builder->Finish(); + + mDT->Fill(path, ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void TestDrawTargetBase::RoundtripThroughA8MakesColorsBlack() +{ + // XXX This test fails with D2D. Remove it? + return; + + Rect r(0, 0, DT_WIDTH, DT_HEIGHT); + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr rgbaDT = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + rgbaDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0.1f, 0.2f, 0.3f, 0.4f))); + RefPtr rgbaSrc = rgbaDT->Snapshot(); + RefPtr alphaDT = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::A8); + alphaDT->DrawSurface(rgbaSrc, r, r); + RefPtr alphaSrc = alphaDT->Snapshot(); + mDT->DrawSurface(alphaSrc, r, r); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0, 0, 0.4f)); +} + +void +TestDrawTargetBase::ColorMatrix() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::COLOR_MATRIX); + + Matrix5x4 mat(-255, 1.0, 0.0, -8.0, + 0.0, 1.0, -6.0, -2.0, + 0.33, 0.0, 0.0, 5.0, + 25.0, 0.0, 0.0, 0.0, + 0.0, 0.1, 0.5, 0.1); + + filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, mat); + filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE, (uint32_t)ALPHA_MODE_STRAIGHT); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + dt->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0.099f, 0.2f, 0.3f, 1.0f))); + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + RefPtr premultiply = mDT->CreateFilter(FilterType::PREMULTIPLY); + premultiply->SetInput(0, filter); + mDT->DrawFilter(premultiply, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0.1, 0.4, 0, 0.4), 2); +} + +void +TestDrawTargetBase::Blend() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::BLEND); + + filter->SetAttribute(ATT_BLEND_BLENDMODE, (uint32_t)BLEND_MODE_MULTIPLY); + + uint32_t *data = new uint32_t[DT_WIDTH * DT_HEIGHT * 4]; + for (int i = 0; i < DT_WIDTH * DT_HEIGHT; i += 16) { + data[i ] = 0xff008000; + data[i+1] = 0xff800080; + data[i+2] = 0xff0040a0; + data[i+3] = 0xff204080; + + data[i+4] = 0x80000000; + data[i+5] = 0xa0000000; + data[i+6] = 0x20000000; + data[i+7] = 0x40000000; + + data[i+8 ] = 0xff008000; + data[i+8+2] = 0xff800080; + data[i+8+5] = 0xff0040a0; + data[i+8+6] = 0xff204080; + + data[i+8+1] = 0x80000000; + data[i+8+3] = 0xa0000000; + data[i+8+4] = 0x20000000; + data[i+8+7] = 0x40000000; + } + + { + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + RefPtr src2 = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + + filter->SetInput(0, src); + filter->SetInput(1, src2); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyPixel(IntPoint(0, 0), Color(0, 0.25f, 0, 1.0f), 1); + VerifyPixel(IntPoint(1, 0), Color(0.25f, 0, 0.25, 1.0f), 1); + VerifyPixel(IntPoint(2, 0), Color(0, 0.0625f, 0.393f, 1.0f), 1); + VerifyPixel(IntPoint(3, 0), Color(0.0157f, 0.0625f, 0.25f, 1.0f), 1); + + // alphablending: Float alpha = 1 - (1 - destAlpha) * (1 - sourceAlpha); + VerifyPixel(IntPoint(4, 0), Color(0, 0, 0, 0.75f), 1); + VerifyPixel(IntPoint(5, 0), Color(0, 0, 0, 0.860f), 1); + VerifyPixel(IntPoint(6, 0), Color(0, 0, 0, 0.233f), 1); + VerifyPixel(IntPoint(7, 0), Color(0, 0, 0, 0.437f), 1); + + // XXX need testcases with two different inputs + VerifyPixel(IntPoint(8+0, 0), Color(0, 0.25f, 0, 1.0f), 1); + VerifyPixel(IntPoint(8+2, 0), Color(0.25f, 0, 0.25, 1.0f), 1); + VerifyPixel(IntPoint(8+5, 0), Color(0, 0.0625f, 0.393f, 1.0f), 1); + VerifyPixel(IntPoint(8+6, 0), Color(0.0157f, 0.0625f, 0.25f, 1.0f), 1); + + VerifyPixel(IntPoint(8+1, 0), Color(0, 0, 0, 0.75f), 1); + VerifyPixel(IntPoint(8+3, 0), Color(0, 0, 0, 0.860f), 1); + VerifyPixel(IntPoint(8+4, 0), Color(0, 0, 0, 0.233f), 1); + VerifyPixel(IntPoint(8+7, 0), Color(0, 0, 0, 0.437f), 1); +} + +void +TestDrawTargetBase::Morphology() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::MORPHOLOGY); + + filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(10, 10)); + filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)MORPHOLOGY_OPERATOR_DILATE); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(500, 500), SurfaceFormat::B8G8R8A8); + dt->FillRect(Rect(10, 10, 480, 480), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Flood() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::FLOOD); + + filter->SetAttribute(ATT_FLOOD_COLOR, Color(0, 0.502f, 0, 1.0f)); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Tile() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::TILE); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(500, 500), SurfaceFormat::B8G8R8A8); + dt->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + dt->FillRect(Rect(100, 100, 300, 300), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + filter->SetAttribute(ATT_TILE_SOURCE_RECT, IntRect(100, 100, 300, 300)); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::TableTransfer() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::TABLE_TRANSFER); + + filter->SetAttribute(ATT_TABLE_TRANSFER_DISABLE_R, false); + filter->SetAttribute(ATT_TABLE_TRANSFER_DISABLE_G, false); + filter->SetAttribute(ATT_TABLE_TRANSFER_DISABLE_B, false); + filter->SetAttribute(ATT_TABLE_TRANSFER_DISABLE_A, true); + + Float coeffs[] = { 0, 0, 1.0f }; + + filter->SetAttribute(ATT_TABLE_TRANSFER_TABLE_R, coeffs, 3); + filter->SetAttribute(ATT_TABLE_TRANSFER_TABLE_G, coeffs, 3); + filter->SetAttribute(ATT_TABLE_TRANSFER_TABLE_B, coeffs, 3); + + uint32_t *data = new uint32_t[DT_WIDTH * DT_HEIGHT * 4]; + uint32_t pixelVal = Color(0.498f, 0.75f, 0.498f, 1.0f).ToABGR(); + for (int i = 0; i < DT_WIDTH * DT_HEIGHT; i++) { + data[i] = pixelVal; + } + + { + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + + filter->SetInput(0, src); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.498f, 0, 1.0f)); +} + +void +TestDrawTargetBase::DiscreteTransfer() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::DISCRETE_TRANSFER); + + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_R, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_G, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_B, false); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_DISABLE_A, true); + + Float coeffs[] = { 0, 0.502f, 0, 1.0f }; + + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_R, coeffs, 3); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_G, coeffs, 3); + filter->SetAttribute(ATT_DISCRETE_TRANSFER_TABLE_B, coeffs, 3); + + uint32_t *data = new uint32_t[DT_WIDTH * DT_HEIGHT * 4]; + uint32_t pixelVal = Color(0.7f, 0.4f, 0.2f, 1.0f).ToABGR(); + for (int i = 0; i < DT_WIDTH * DT_HEIGHT; i++) { + data[i] = pixelVal; + } + + { + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + + filter->SetInput(0, src); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::LinearTransfer() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::LINEAR_TRANSFER); + + filter->SetAttribute(ATT_LINEAR_TRANSFER_DISABLE_R, false); + filter->SetAttribute(ATT_LINEAR_TRANSFER_DISABLE_G, false); + filter->SetAttribute(ATT_LINEAR_TRANSFER_DISABLE_B, false); + filter->SetAttribute(ATT_LINEAR_TRANSFER_DISABLE_A, true); + + filter->SetAttribute(ATT_LINEAR_TRANSFER_INTERCEPT_R, 0.502f); + filter->SetAttribute(ATT_LINEAR_TRANSFER_SLOPE_R, -5.0f); + filter->SetAttribute(ATT_LINEAR_TRANSFER_INTERCEPT_G, 0.f); + filter->SetAttribute(ATT_LINEAR_TRANSFER_SLOPE_G, 1.0f); + filter->SetAttribute(ATT_LINEAR_TRANSFER_INTERCEPT_B, 0.502f); + filter->SetAttribute(ATT_LINEAR_TRANSFER_SLOPE_B, -5.0f); + + uint32_t *data = new uint32_t[DT_WIDTH * DT_HEIGHT * 4]; + for (int i = 0; i < DT_WIDTH * DT_HEIGHT; i++) { + data[i] = 0xff808080; + } + + { + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + + filter->SetInput(0, src); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::GammaTransfer() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::GAMMA_TRANSFER); + + filter->SetAttribute(ATT_GAMMA_TRANSFER_DISABLE_R, false); + filter->SetAttribute(ATT_GAMMA_TRANSFER_DISABLE_G, false); + filter->SetAttribute(ATT_GAMMA_TRANSFER_DISABLE_B, false); + filter->SetAttribute(ATT_GAMMA_TRANSFER_DISABLE_A, true); + + filter->SetAttribute(ATT_GAMMA_TRANSFER_AMPLITUDE_R, 0.f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_EXPONENT_R, 1.f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_OFFSET_R, 0.f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_AMPLITUDE_G, 1.0f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_EXPONENT_G, 2.0f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_OFFSET_G, 0.25f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_AMPLITUDE_B, 2.0f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_EXPONENT_B, 2.0f); + filter->SetAttribute(ATT_GAMMA_TRANSFER_OFFSET_B, -0.502f); + + uint32_t *data = new uint32_t[DT_WIDTH * DT_HEIGHT * 4]; + for (int i = 0; i < DT_WIDTH * DT_HEIGHT; i++) { + data[i] = 0xff808080; + } + + { + RefPtr src = + mDT->CreateSourceSurfaceFromData((uint8_t*)data, IntSize(DT_WIDTH, DT_HEIGHT), DT_WIDTH * 4, SurfaceFormat::B8G8R8A8); + + filter->SetInput(0, src); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + } + + delete [] data; + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::ConvolveMatrixNone() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::CONVOLVE_MATRIX); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH + 3, DT_HEIGHT + 3), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(0, 0, DT_WIDTH + 3, DT_HEIGHT + 3), ColorPattern(Color(0, 0, 0, 1.0f))); + for (int x = 0; x < DT_WIDTH + 3; x += 3) { + dt->FillRect(Rect(x, 0, 1, DT_HEIGHT + 3), ColorPattern(Color(0, 1.0f, 0, 1.0f))); + } + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)EDGE_MODE_NONE); + + Float kernel[] = { 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f }; + + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX, kernel, 9); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, IntSize(3, 3)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA, true); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR, 3.0f / 0.502f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS, 0.f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, Size(1.0f, 1.0f)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET, IntPoint(0, 0)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT, IntRect(IntPoint(), src->GetSize())); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::ConvolveMatrixWrap() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::CONVOLVE_MATRIX); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH + 3, DT_HEIGHT + 3), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(0, 0, DT_WIDTH + 3, DT_HEIGHT + 3), ColorPattern(Color(0, 0.5f, 0, 1.0f))); + + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)EDGE_MODE_DUPLICATE); + + Float kernel[] = { 1.0f, 1.0f, + 1.0f, 1.0f }; + + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX, kernel, 4); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, IntSize(2, 2)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA, true); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR, 4.0f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS, 0.f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, Size(1.0f, 1.0f)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET, IntPoint(1, 0)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT, IntRect(IntPoint(), src->GetSize())); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::ConvolveMatrixOffset() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(100, 100), SurfaceFormat::B8G8R8A8); + dt->FillRect(Rect(50, 50, 1, 1), ColorPattern(Color(0, 1, 0, 1))); + RefPtr src = dt->Snapshot(); + + RefPtr filter = mDT->CreateFilter(FilterType::CONVOLVE_MATRIX); + filter->SetInput(0, src); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_EDGE_MODE, (uint32_t)EDGE_MODE_DUPLICATE); + + Float kernel[] = { 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f }; + + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX, kernel, 9); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, IntSize(3, 3)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA, false); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_DIVISOR, 1.0f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_BIAS, 0.0f); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH, Size(1.0f, 1.0f)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET, IntPoint(1, 1)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_SOURCE_RECT, IntRect(0, 0, 100, 100)); + + mDT->DrawFilter(filter, Rect(20, 20, 80, 80), Point(20, 20)); + + RefreshSnapshot(); + + VerifyPixel(IntPoint(50, 50), Color(0, 1, 0, 1)); + VerifyPixel(IntPoint(49, 50), Color(0, 0, 0, 0)); + VerifyPixel(IntPoint(51, 50), Color(0, 0, 0, 0)); + VerifyPixel(IntPoint(50, 49), Color(0, 0, 0, 0)); + VerifyPixel(IntPoint(50, 51), Color(0, 0, 0, 0)); + + + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + Float kernel2[1] = { 1.0f }; + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_MATRIX, kernel2, 1); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE, IntSize(1, 1)); + filter->SetAttribute(ATT_CONVOLVE_MATRIX_TARGET, IntPoint(0, 0)); + + mDT->DrawFilter(filter, Rect(20, 20, 80, 80), Point(20, 20)); + + RefreshSnapshot(); + + VerifyPixel(IntPoint(50, 50), Color(0, 1, 0, 1)); + VerifyPixel(IntPoint(49, 50), Color(0, 0, 0, 0)); + VerifyPixel(IntPoint(51, 50), Color(0, 0, 0, 0)); + VerifyPixel(IntPoint(50, 49), Color(0, 0, 0, 0)); +} + +void +TestDrawTargetBase::OffsetFilter() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::TRANSFORM); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH + 100, DT_HEIGHT + 100), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(100, 100, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f))); + + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + filter->SetAttribute(ATT_TRANSFORM_MATRIX, Matrix().PreTranslate(-100, -100)); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::DisplacementMap() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::DISPLACEMENT_MAP); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + RefPtr dtDisplacement = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(100, 100, DT_WIDTH - 200, DT_HEIGHT - 200), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0.502f, 0.502f, 0.502f, 1.0f))); + dtDisplacement->FillRect(Rect(0, 0, 100, 100), ColorPattern(Color(1.0f, 1.0f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(100, 0, DT_WIDTH - 200, 100), ColorPattern(Color(0.502f, 1.0f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(DT_WIDTH - 101, 0, 101, 100), ColorPattern(Color(0, 1.0f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(0, 100, 100, DT_HEIGHT - 200), ColorPattern(Color(1.0f, 0.502f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(DT_WIDTH - 101, 100, 101, DT_HEIGHT - 200), ColorPattern(Color(0, 0.502f, 0, 1.0f))); + dtDisplacement->FillRect(Rect(0, DT_HEIGHT - 101, 100, 101), ColorPattern(Color(1.0f, 0, 0, 1.0f))); + dtDisplacement->FillRect(Rect(100, DT_HEIGHT - 101, DT_WIDTH - 200, 101), ColorPattern(Color(0.502f, 0, 0, 1.0f))); + dtDisplacement->FillRect(Rect(DT_WIDTH - 101, DT_HEIGHT - 101, 101, 101), ColorPattern(Color(0, 0, 0, 1.0f))); + + RefPtr src = dt->Snapshot(); + RefPtr srcDisplacement = dtDisplacement->Snapshot(); + filter->SetInput(0, src); + filter->SetInput(1, srcDisplacement); + + filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE, 220.0f); + filter->SetAttribute(ATT_DISPLACEMENT_MAP_X_CHANNEL, (uint32_t)COLOR_CHANNEL_R); + filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL, (uint32_t)COLOR_CHANNEL_G); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Turbulence() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::TURBULENCE); + + filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY, Size(10.0f, 10.0f)); + filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES, uint32_t(1)); + filter->SetAttribute(ATT_TURBULENCE_STITCHABLE, false); + filter->SetAttribute(ATT_TURBULENCE_TYPE, uint32_t(TURBULENCE_TYPE_FRACTAL_NOISE)); + filter->SetAttribute(ATT_TURBULENCE_RECT, IntRect(0, 0, DT_WIDTH, DT_HEIGHT)); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData(); + + Float avgR = 0; + Float avgG = 0; + Float avgB = 0; + Float avgA = 0; + for (int y = 0; y < DT_HEIGHT; y++) { + Float avgRRow = 0; + Float avgGRow = 0; + Float avgBRow = 0; + Float avgARow = 0; + for (int x = 0; x < DT_WIDTH; x++) { + Color currentColor = Color::FromABGR(colVal[(y * mDataSnapshot->Stride()) / 4 + x]); + avgRRow += currentColor.r; + avgGRow += currentColor.g; + avgBRow += currentColor.b; + avgARow += currentColor.a; + } + avgRRow /= Float(DT_WIDTH); + avgGRow /= Float(DT_WIDTH); + avgBRow /= Float(DT_WIDTH); + avgARow /= Float(DT_WIDTH); + avgR += avgRRow; + avgG += avgGRow; + avgB += avgBRow; + avgA += avgARow; + } + + avgR /= Float(DT_HEIGHT); + avgG /= Float(DT_HEIGHT); + avgB /= Float(DT_HEIGHT); + avgA /= Float(DT_HEIGHT); + + if (avgR < 0.2f || avgR > 0.3f) { + mTestFailed = true; + LogMessage("Average red value outside of expected range."); + return; + } + if (avgG < 0.2f || avgG > 0.3f) { + mTestFailed = true; + LogMessage("Average green value outside of expected range."); + return; + } + if (avgB < 0.2f || avgB > 0.3f) { + mTestFailed = true; + LogMessage("Average blue value outside of expected range."); + return; + } + if (avgA < 0.45f || avgA > 0.55f) { + mTestFailed = true; + LogMessage("Average alpha value outside of expected range."); + return; + } +} + +void +TestDrawTargetBase::ArithmeticCombine() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::ARITHMETIC_COMBINE); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + RefPtr dt2 = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f))); + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + dt2->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0.25f, 0.5f, 0.25f, 1.0f))); + src = dt2->Snapshot(); + filter->SetInput(1, src); + + Float coeffs[4] = { 1.0f, 1.0f, -1.0f, 0.25f }; + + + filter->SetAttribute(ATT_ARITHMETIC_COMBINE_COEFFICIENTS, coeffs, 4); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::Composite() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::COMPOSITE); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + RefPtr dt2 = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + RefPtr dt3 = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f))); + dt2->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 1.0f, 0, 0.5f))); + dt3->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0, 0, 0.332f))); + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + src = dt2->Snapshot(); + filter->SetInput(1, src); + src = dt3->Snapshot(); + filter->SetInput(2, src); + + filter->SetAttribute(ATT_COMPOSITE_OPERATOR, uint32_t(COMPOSITE_OPERATOR_OVER)); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + VerifyAllPixels(Color(0, 0.502f, 0, 1.0f)); +} + +void +TestDrawTargetBase::GaussianBlur() +{ + mDT->ClearRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT)); + + RefPtr filter = mDT->CreateFilter(FilterType::GAUSSIAN_BLUR); + + RefPtr dt = mDT->CreateSimilarDrawTarget(IntSize(DT_WIDTH, DT_HEIGHT), SurfaceFormat::B8G8R8A8); + + dt->FillRect(Rect(100, 100, DT_WIDTH - 200, DT_HEIGHT - 200), ColorPattern(Color(0, 0.5f, 0, 1.0f))); + + RefPtr src = dt->Snapshot(); + filter->SetInput(0, src); + + filter->SetAttribute(ATT_GAUSSIAN_BLUR_STD_DEVIATION, 44.0f); + + mDT->DrawFilter(filter, Rect(0, 0, DT_WIDTH, DT_HEIGHT), Point()); + + RefreshSnapshot(); + + // XXX - Find a more solid test for this. + VerifyPixel(IntPoint(250, 250), Color(0, 0.5f, 0, 1.0f), 3); + VerifyPixel(IntPoint(0, 0), Color(0, 0, 0, 0)); +} + +void +TestDrawTargetBase::RefreshSnapshot() +{ + RefPtr snapshot = mDT->Snapshot(); + mDataSnapshot = snapshot->GetDataSurface(); +} + +void +TestDrawTargetBase::VerifyAllPixels(const Color &aColor, + uint8_t aTolerance) +{ + uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData(); + + uint32_t expected = BGRAPixelFromColor(aColor); + + for (int y = 0; y < DT_HEIGHT; y++) { + for (int x = 0; x < DT_WIDTH; x++) { + if (colVal[y * (mDataSnapshot->Stride() / 4) + x] != expected) { + stringstream message; + int32_t rawActual = colVal[y * (mDataSnapshot->Stride() / 4) + x]; + int32_t actb = rawActual & 0xFF; + int32_t actg = (rawActual & 0xFF00) >> 8; + int32_t actr = (rawActual & 0xFF0000) >> 16; + int32_t acta = (rawActual & 0xFF000000) >> 24; + int32_t expb = expected & 0xFF; + int32_t expg = (expected & 0xFF00) >> 8; + int32_t expr = (expected & 0xFF0000) >> 16; + int32_t expa = (expected & 0xFF000000) >> 24; + + if (abs(actb - expb) > aTolerance || + abs(actg - expg) > aTolerance || + abs(actr - expr) > aTolerance || + abs(acta - expa) > aTolerance) { + message << "Verify Pixel (" << x << "x" << y << ") Failed." + " Expected (" << expr << "," << expg << "," << expb << "," << expa << ") " + " Got (" << actr << "," << actg << "," << actb << "," << acta << ")\n"; + + LogMessage(message.str()); + LogMessage("VerifyAllPixels Failed\n"); + mTestFailed = true; + return; + } + } + } + } +} + +void +TestDrawTargetBase::VerifyPixel(const IntPoint &aPoint, const mozilla::gfx::Color &aColor, + uint8_t aTolerance) +{ + uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData(); + + uint32_t expected = BGRAPixelFromColor(aColor); + uint32_t rawActual = colVal[aPoint.y * (mDataSnapshot->Stride() / 4) + aPoint.x]; + + if (rawActual != expected) { + stringstream message; + int32_t actb = rawActual & 0xFF; + int32_t actg = (rawActual & 0xFF00) >> 8; + int32_t actr = (rawActual & 0xFF0000) >> 16; + int32_t acta = (rawActual & 0xFF000000) >> 24; + int32_t expb = expected & 0xFF; + int32_t expg = (expected & 0xFF00) >> 8; + int32_t expr = (expected & 0xFF0000) >> 16; + int32_t expa = (expected & 0xFF000000) >> 24; + + if (abs(actb - expb) > aTolerance || + abs(actg - expg) > aTolerance || + abs(actr - expr) > aTolerance || + abs(acta - expa) > aTolerance) { + message << "Verify Pixel (" << aPoint.x << "x" << aPoint.y << ") Failed." + " Expected (" << expr << "," << expg << "," << expb << "," << expa << ") " + " Got (" << actr << "," << actg << "," << actb << "," << acta << ")\n"; + + LogMessage(message.str()); + mTestFailed = true; + return; + } + } +} + +uint32_t +TestDrawTargetBase::BGRAPixelFromColor(const Color &aColor) +{ + union { + uint32_t color; + uint8_t components[4]; + }; + components[2] = uint8_t(aColor.r * aColor.a * 255.0f + 0.5f); + components[1] = uint8_t(aColor.g * aColor.a * 255.0f + 0.5f); + components[0] = uint8_t(aColor.b * aColor.a * 255.0f + 0.5f); + components[3] = uint8_t(aColor.a * 255.0f + 0.5f); + return color; +} diff --git a/libazure/unittest/TestDrawTarget.h b/libazure/unittest/TestDrawTarget.h new file mode 100644 index 0000000..f9ed8c0 --- /dev/null +++ b/libazure/unittest/TestDrawTarget.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "2D.h" +#include "TestBase.h" +#include "TestHelpers.h" + +/* This general DrawTarget test class can be reimplemented by a child class + * with optional additional drawtarget-specific tests. And is intended to run + * on a 500x500 32 BPP drawtarget. + */ +class TestDrawTargetBase : public TestBase +{ +public: + void Initialized(); + void FillCompletely(); + void FillRect(); + void StrokeRect(); + void StrokeLine(); + void Translate(); + void FillMultiRect(); + void FillMultiRectTransform1(); + void FillMultiRectTransform2(); + void FillMultiRectTransform3(); + void ClipRect(); + void ClipRectClear(); + void Clip(); + void FillTriangle(); + void StrokeTriangle(); + void DrawSurface(); + void FillWithSurface(); + void FillWithPartialLargeSurface(); + void FillWithScaledLargeSurface(); + void FillGradient(); + void FillRadialGradient(); + void FillWithSnapshot(); + void Mask(); + void CopySurface(); + void Shadow(); + void StreamToSink(); + void RoundtripThroughA8MakesColorsBlack(); + void ColorMatrix(); + void Blend(); + void Morphology(); + void Flood(); + void Tile(); + void TableTransfer(); + void DiscreteTransfer(); + void LinearTransfer(); + void GammaTransfer(); + void ConvolveMatrixNone(); + void ConvolveMatrixWrap(); + void ConvolveMatrixOffset(); + void OffsetFilter(); + void DisplacementMap(); + void Turbulence(); + void ArithmeticCombine(); + void Composite(); + void GaussianBlur(); + +protected: + TestDrawTargetBase(); + + void RefreshSnapshot(); + + void VerifyAllPixels(const mozilla::gfx::Color &aColor, + uint8_t aTolerance = 0); + void VerifyPixel(const mozilla::gfx::IntPoint &aPoint, + const mozilla::gfx::Color &aColor, + uint8_t aTolerance = 0); + + uint32_t BGRAPixelFromColor(const mozilla::gfx::Color &aColor); + + mozilla::RefPtr mDT; + mozilla::RefPtr mDataSnapshot; +}; + +#ifdef WIN32 +IMPLEMENT_DT_TESTS(D2D, DIRECT2D, TestDrawTarget); +#ifdef USE_D2D1_1 +IMPLEMENT_DT_TESTS(D2D1, DIRECT2D1_1, TestDrawTarget); +#endif +#endif +#ifdef USE_SKIA +IMPLEMENT_DT_TESTS(SkiaSoftware, SKIA, TestDrawTarget); +#endif +#ifdef USE_CAIRO +IMPLEMENT_DT_TESTS(CairoImage, CAIRO, TestDrawTarget); +#endif + +class TestDrawTargetCapture : public TestDrawTargetBase +{ +public: + TestDrawTargetCapture() + { + mozilla::RefPtr dt = + mozilla::gfx::Factory::CreateDrawTarget(mozilla::gfx::BackendType::DIRECT2D, + mozilla::gfx::IntSize(1, 1), + mozilla::gfx::SurfaceFormat::B8G8R8A8); + + mDT = dt->CreateCaptureDT(mozilla::gfx::IntSize(DT_WIDTH, DT_HEIGHT)); + } +}; diff --git a/libazure/unittest/TestDrawTargetD2D1.cpp b/libazure/unittest/TestDrawTargetD2D1.cpp new file mode 100644 index 0000000..a002e0a --- /dev/null +++ b/libazure/unittest/TestDrawTargetD2D1.cpp @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetD2D1.h" +#include + +using namespace mozilla::gfx; +TestDrawTargetD2D1::TestDrawTargetD2D1() +{ + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3 + }; + + + HRESULT hr = ::D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, + D3D11_CREATE_DEVICE_BGRA_SUPPORT, + featureLevels, sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL), + D3D11_SDK_VERSION, byRef(mDevice), nullptr, nullptr); + + Factory::SetDirect3D11Device(mDevice); + + mDT = Factory::CreateDrawTarget(BACKEND_DIRECT2D1_1, IntSize(DT_WIDTH, DT_HEIGHT), FORMAT_B8G8R8A8); +} diff --git a/libazure/unittest/TestDrawTargetD2D1.h b/libazure/unittest/TestDrawTargetD2D1.h new file mode 100644 index 0000000..cffef38 --- /dev/null +++ b/libazure/unittest/TestDrawTargetD2D1.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestDrawTargetBase.h" + +class TestDrawTargetD2D1 : public TestDrawTargetBase +{ +public: + TestDrawTargetD2D1(); + +private: + mozilla::RefPtr mDevice; +}; diff --git a/libazure/unittest/TestDrawTargetD2DRecording.cpp b/libazure/unittest/TestDrawTargetD2DRecording.cpp new file mode 100644 index 0000000..327e112 --- /dev/null +++ b/libazure/unittest/TestDrawTargetD2DRecording.cpp @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestDrawTargetD2DRecording.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +TestDrawTargetD2DRecording::TestDrawTargetD2DRecording() +{ + RefPtr recorder = Factory::CreateEventRecorderForFile("unittestrecording.aer"); + + RefPtr d2dDT = Factory::CreateDrawTarget(BACKEND_DIRECT2D, IntSize(DT_WIDTH, DT_HEIGHT), FORMAT_B8G8R8A8); + + mDT = Factory::CreateRecordingDrawTarget(recorder, d2dDT); +} diff --git a/libazure/unittest/TestDrawTargetD2DRecording.h b/libazure/unittest/TestDrawTargetD2DRecording.h new file mode 100644 index 0000000..4c58f3d --- /dev/null +++ b/libazure/unittest/TestDrawTargetD2DRecording.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestDrawTargetBase.h" + +#include + +class TestDrawTargetD2DRecording : public TestDrawTargetBase +{ +public: + TestDrawTargetD2DRecording(); + +private: + mozilla::RefPtr mDevice; +}; diff --git a/libazure/unittest/TestHelpers.h b/libazure/unittest/TestHelpers.h new file mode 100644 index 0000000..c3f722c --- /dev/null +++ b/libazure/unittest/TestHelpers.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define DT_WIDTH 500 +#define DT_HEIGHT 500 + +#define IMPLEMENT_DT_TESTS(backendName, backendValue, className) \ + class className##backendName : public className##Base \ + { \ + public: \ + className##backendName() \ + { mDT = mozilla::gfx::Factory::CreateDrawTarget(mozilla::gfx::BackendType::backendValue, \ + mozilla::gfx::IntSize(DT_WIDTH, DT_HEIGHT), \ + mozilla::gfx::SurfaceFormat::B8G8R8A8); } \ + } diff --git a/libazure/unittest/TestMatrix.cpp b/libazure/unittest/TestMatrix.cpp new file mode 100644 index 0000000..2f088c1 --- /dev/null +++ b/libazure/unittest/TestMatrix.cpp @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestMatrix.h" + +#include "Matrix.h" + +using namespace mozilla::gfx; + +TestMatrix::TestMatrix() +{ +#define TEST_CLASS TestMatrix + REGISTER_TEST(Multiplication5x4); +#undef TEST_CLASS +} + +static Matrix5x4 +MakeColorsBlack() +{ + Matrix5x4 result; + result._11 = result._22 = result._33 = 0; + return result; +} + +static Matrix5x4 +TurnRedAllTheWayUp() +{ + Matrix5x4 result; + result._11 = 0; + result._51 = 1; + return result; +} + +static Matrix5x4 +RotateRedGreenBlue() +{ + Matrix5x4 result; + result._11 = result._22 = result._33 = 0; + result._12 = result._23 = result._31 = 1; + return result; +} + +void +TestMatrix::Multiplication5x4() +{ + Matrix5x4 a1 = MakeColorsBlack() * TurnRedAllTheWayUp(); + VERIFY(a1 != MakeColorsBlack()); + VERIFY(a1 != TurnRedAllTheWayUp()); + VERIFY(a1._11 == 0); + VERIFY(a1._51 == 1); + VERIFY(a1._44 == 1); + + Matrix5x4 a2 = TurnRedAllTheWayUp() * MakeColorsBlack(); + VERIFY(a2 == MakeColorsBlack()); + + Matrix5x4 b1 = TurnRedAllTheWayUp() * RotateRedGreenBlue(); + VERIFY(b1 != TurnRedAllTheWayUp()); + VERIFY(b1 != RotateRedGreenBlue()); + VERIFY(b1._11 + b1._21 + b1._31 + b1._41 == 1); + VERIFY(b1._12 + b1._22 + b1._32 + b1._42 == 0); + VERIFY(b1._13 + b1._23 + b1._33 + b1._43 == 1); + VERIFY(b1._14 + b1._24 + b1._34 + b1._44 == 1); + VERIFY(b1._51 == 0); + VERIFY(b1._52 == 1); + VERIFY(b1._53 == 0); + + Matrix5x4 b2 = RotateRedGreenBlue() * TurnRedAllTheWayUp(); + VERIFY(b2 != RotateRedGreenBlue()); + VERIFY(b2 != TurnRedAllTheWayUp()); + VERIFY(b2._11 + b2._21 + b2._31 + b2._41 == 0); + VERIFY(b2._12 + b2._22 + b2._32 + b2._42 == 1); + VERIFY(b2._13 + b2._23 + b2._33 + b2._43 == 1); + VERIFY(b2._14 + b2._24 + b2._34 + b2._44 == 1); + VERIFY(b2._51 == 1); + VERIFY(b2._52 == 0); + VERIFY(b2._53 == 0); + + Matrix5x4 b3 = RotateRedGreenBlue(); + b3 *= TurnRedAllTheWayUp(); + VERIFY(b2 == b3); +} diff --git a/libazure/unittest/TestMatrix.h b/libazure/unittest/TestMatrix.h new file mode 100644 index 0000000..6828cc0 --- /dev/null +++ b/libazure/unittest/TestMatrix.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestBase.h" + +class TestMatrix : public TestBase +{ +public: + TestMatrix(); + + void Multiplication5x4(); +}; diff --git a/libazure/unittest/TestPath.cpp b/libazure/unittest/TestPath.cpp new file mode 100644 index 0000000..68b6dd4 --- /dev/null +++ b/libazure/unittest/TestPath.cpp @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TestPath.h" +#include "PathHelpers.h" + +using namespace mozilla::gfx; + +TestPathBase::TestPathBase() +{ +#define TEST_CLASS TestPathBase + REGISTER_TEST(Line); + REGISTER_TEST(PolyLine); + REGISTER_TEST(SegmentEndVector); + REGISTER_TEST(ZeroLengthPath); + REGISTER_TEST(SimpleBezier); + REGISTER_TEST(LinearBezier); + REGISTER_TEST(LineAndBezier); + REGISTER_TEST(SingleInflection); + REGISTER_TEST(Cusp); + REGISTER_TEST(DoubleInflection); + REGISTER_TEST(EndsInEmptySegments); + REGISTER_TEST(MultipleEmptySegments); + REGISTER_TEST(MultipleMoves); + REGISTER_TEST(ClosedPathEnding); + REGISTER_TEST(Bug984796); +#undef TEST_CLASS +} + +void +TestPathBase::Line() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(100, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(100); + VerifyComputePointAtLength(0, Point(0, 0), Point(1, 0)); + VerifyComputePointAtLength(50, Point(50, 0), Point(1, 0)); + VerifyComputePointAtLength(100, Point(100, 0), Point(1, 0)); +} + +void +TestPathBase::PolyLine() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(100, 0)); + mBuilder->LineTo(Point(100, 100)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(200); + VerifyComputePointAtLength(0, Point(0, 0), Point(1, 0)); + VerifyComputePointAtLength(50, Point(50, 0), Point(1, 0)); + VerifyComputePointAtLength(100, Point(100, 0), Point(0, 1)); + VerifyComputePointAtLength(150, Point(100, 50), Point(0, 1)); + VerifyComputePointAtLength(200, Point(100, 100), Point(0, 1)); +} + +void +TestPathBase::SegmentEndVector() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(0, 0)); + mPath = mBuilder->Finish(); + + VerifyComputePointAtLength(10, Point(10, 0), Point(-1, 0)); +} + +void +TestPathBase::SimpleBezier() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(200, 100)); + ArcToBezier(mBuilder, Point(100, 100), Size(100.f, 100.f), 0.f, Float(M_PI) / 2.0f, false); + mPath = mBuilder->Finish(); + + VerifyComputeLength(Float(M_PI) / 2.0f * 100); + VerifyComputePointAtLength(0, Point(200, 100), Point(0, 1)); + VerifyComputePointAtLength(mPath->ComputeLength(), Point(100, 200), Point(-1, 0)); +} + +void +TestPathBase::LinearBezier() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->BezierTo(Point(50, 0), Point(100, 0), Point(150, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(150); + VerifyComputePointAtLength(50, Point(50, 0), Point(1, 0)); +} + +void TestPathBase::LineAndBezier() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(100, 100)); + mBuilder->LineTo(Point(200, 100)); + ArcToBezier(mBuilder, Point(100, 100), Size(100.f, 100.f), 0.f, Float(M_PI) / 2.0f, false); + mPath = mBuilder->Finish(); + + VerifyComputeLength(Float(M_PI) / 2.0f * 100 + 100); +} + +void +TestPathBase::SingleInflection() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(20, 500)); + mBuilder->BezierTo(Point(20, -100), Point(520, 500), Point(520, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(864.45f); +} + +void +TestPathBase::Cusp() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(20, 500)); + mBuilder->BezierTo(Point(520, 0), Point(20, 0), Point(520, 500)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(914.18f); +} + +void +TestPathBase::DoubleInflection() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(20, 500)); + mBuilder->BezierTo(Point(440, 150), Point(70, 150), Point(520, 500)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(729.48f); +} + +void +TestPathBase::ZeroLengthPath() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(0); + VerifyComputePointAtLength(0, Point(0, 0), Point(0, 0)); +} + +void +TestPathBase::EndsInEmptySegments() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(10); + VerifyComputePointAtLength(10, Point(10, 0), Point(1, 0)); +} + +void +TestPathBase::MultipleEmptySegments() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 10)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(20); + VerifyComputePointAtLength(10, Point(10, 0), Point(0, 1)); +} + +void +TestPathBase::MultipleMoves() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->MoveTo(Point(0, 10)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(0); + VerifyComputePointAtLength(0, Point(0, 10), Point(0, 1)); +} + +void +TestPathBase::ClosedPathEnding() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(0, 0)); + mBuilder->LineTo(Point(10, 0)); + mBuilder->LineTo(Point(10, 10)); + mBuilder->LineTo(Point(0, 10)); + mBuilder->Close(); + mPath = mBuilder->Finish(); + + VerifyComputeLength(40); + VerifyComputePointAtLength(40, Point(0, 0), Point(0, -1)); +} + +void +TestPathBase::Bug984796() +{ + mBuilder = mDT->CreatePathBuilder(); + mBuilder->MoveTo(Point(124, 46)); + mBuilder->BezierTo(Point(100, 73), Point(40, 0), Point(0, 0)); + mPath = mBuilder->Finish(); + + VerifyComputeLength(138.8f); +} + +void +TestPathBase::VerifyComputeLength(Float aExpectedLength) +{ + VERIFYVALUEFUZZY(mPath->ComputeLength(), aExpectedLength, 0.1f); +} + +void +TestPathBase::VerifyComputePointAtLength(Float aLength, const Point& aExpectedPoint, const Point& aExpectedTangent) +{ + Point tangent; + Point point = mPath->ComputePointAtLength(aLength, &tangent); + VERIFYVALUEFUZZY(point.x, aExpectedPoint.x, 0.05f); + VERIFYVALUEFUZZY(point.y, aExpectedPoint.y, 0.05f); + VERIFYVALUEFUZZY(tangent.x, aExpectedTangent.x, 0.05f); + VERIFYVALUEFUZZY(tangent.y, aExpectedTangent.y, 0.05f); +} diff --git a/libazure/unittest/TestPath.h b/libazure/unittest/TestPath.h new file mode 100644 index 0000000..1e246e6 --- /dev/null +++ b/libazure/unittest/TestPath.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "TestBase.h" +#include "TestHelpers.h" +#include "2D.h" + +class TestPathBase : public TestBase +{ +public: + TestPathBase(); + + void Line(); + void PolyLine(); + void SegmentEndVector(); + void ZeroLengthPath(); + void LinearBezier(); + void SimpleBezier(); + void LineAndBezier(); + void SingleInflection(); + void Cusp(); + void DoubleInflection(); + void EndsInEmptySegments(); + void MultipleEmptySegments(); + void MultipleMoves(); + void ClosedPathEnding(); + void Bug984796(); + +protected: + mozilla::RefPtr mDT; + mozilla::RefPtr mBuilder; + mozilla::RefPtr mPath; + +private: + void VerifyComputeLength(mozilla::gfx::Float aLength); + void VerifyComputePointAtLength(mozilla::gfx::Float aLength, + const mozilla::gfx::Point &aPoint, + const mozilla::gfx::Point &aTangent); +}; + +#ifdef WIN32 +IMPLEMENT_DT_TESTS(D2D, DIRECT2D, TestPath); +#endif +#ifdef USE_SKIA +IMPLEMENT_DT_TESTS(Skia, SKIA, TestPath); +#endif +#ifdef USE_CAIRO +IMPLEMENT_DT_TESTS(Cairo, CAIRO, TestPath); +#endif diff --git a/libazure/src/gfx/2d/unittest/TestPoint.cpp b/libazure/unittest/TestPoint.cpp similarity index 74% rename from libazure/src/gfx/2d/unittest/TestPoint.cpp rename to libazure/unittest/TestPoint.cpp index 21d9dfe..7b11a99 100644 --- a/libazure/src/gfx/2d/unittest/TestPoint.cpp +++ b/libazure/unittest/TestPoint.cpp @@ -2,45 +2,47 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TestPoint.h" - -#include "Point.h" - -using namespace mozilla::gfx; - -TestPoint::TestPoint() -{ - REGISTER_TEST(TestPoint, Addition); - REGISTER_TEST(TestPoint, Subtraction); -} - -void -TestPoint::Addition() -{ - Point a, b; - a.x = 2; - a.y = 2; - b.x = 5; - b.y = -5; - - a += b; - - VERIFY(a.x == 7); - VERIFY(a.y == -3); -} - -void -TestPoint::Subtraction() -{ - Point a, b; - a.x = 2; - a.y = 2; - b.x = 5; - b.y = -5; - - a -= b; - - VERIFY(a.x == -3); - VERIFY(a.y == 7); -} + +#include "TestPoint.h" + +#include "Point.h" + +using namespace mozilla::gfx; + +TestPoint::TestPoint() +{ +#define TEST_CLASS TestPoint + REGISTER_TEST(Addition); + REGISTER_TEST(Subtraction); +#undef TEST_CLASS +} + +void +TestPoint::Addition() +{ + Point a, b; + a.x = 2; + a.y = 2; + b.x = 5; + b.y = -5; + + a += b; + + VERIFY(a.x == 7.f); + VERIFY(a.y == -3.f); +} + +void +TestPoint::Subtraction() +{ + Point a, b; + a.x = 2; + a.y = 2; + b.x = 5; + b.y = -5; + + a -= b; + + VERIFY(a.x == -3.f); + VERIFY(a.y == 7.f); +} diff --git a/libazure/src/gfx/2d/unittest/TestPoint.h b/libazure/unittest/TestPoint.h similarity index 100% rename from libazure/src/gfx/2d/unittest/TestPoint.h rename to libazure/unittest/TestPoint.h diff --git a/libazure/unittest/TestRect.cpp b/libazure/unittest/TestRect.cpp new file mode 100644 index 0000000..2c0f742 --- /dev/null +++ b/libazure/unittest/TestRect.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +#include "TestRect.h" + +#include "Rect.h" + +using namespace mozilla::gfx; + +TestRect::TestRect() +{ +#define TEST_CLASS TestRect + REGISTER_TEST(ClampRect); +#undef TEST_CLASS +} + +void +TestRect::ClampRect() +{ + Rect a(2, 5, 10, 20); + Rect b; + Rect dest; + + b.SetRect(0, 0, 8, 12); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(2, 5, 8, 12))); + + b.SetRect(19, 0, 8, 12); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(4, 5, 8, 12))); + + b.SetRect(-2, 40, 8, 12); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(2, 13, 8, 12))); + + b.SetRect(22, 80, 8, 12); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(4, 13, 8, 12))); + + b.SetRect(22, 80, 20, 40); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(2, 5, 10, 20))); + + b.SetRect(5, 10, 3, 6); + dest = a.ForceInside(b); + VERIFY(dest.IsEqualEdges(Rect(5, 10, 3, 6))); +} + diff --git a/libazure/unittest/TestRect.h b/libazure/unittest/TestRect.h new file mode 100644 index 0000000..61fb59e --- /dev/null +++ b/libazure/unittest/TestRect.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +#ifndef moz2d_unittest_TestRect_h +#define moz2d_unittest_TestRect_h + +#include "TestBase.h" + +class TestRect : public TestBase +{ +public: + TestRect(); + + void ClampRect(); +}; + +#endif diff --git a/libazure/src/gfx/2d/unittest/TestScaling.cpp b/libazure/unittest/TestScaling.cpp similarity index 92% rename from libazure/src/gfx/2d/unittest/TestScaling.cpp rename to libazure/unittest/TestScaling.cpp index 451fdf8..a3a01c2 100644 --- a/libazure/src/gfx/2d/unittest/TestScaling.cpp +++ b/libazure/unittest/TestScaling.cpp @@ -11,13 +11,15 @@ using namespace mozilla::gfx; TestScaling::TestScaling() { - REGISTER_TEST(TestScaling, BasicHalfScale); - REGISTER_TEST(TestScaling, DoubleHalfScale); - REGISTER_TEST(TestScaling, UnevenHalfScale); - REGISTER_TEST(TestScaling, OddStrideHalfScale); - REGISTER_TEST(TestScaling, VerticalHalfScale); - REGISTER_TEST(TestScaling, HorizontalHalfScale); - REGISTER_TEST(TestScaling, MixedHalfScale); +#define TEST_CLASS TestScaling + REGISTER_TEST(BasicHalfScale); + REGISTER_TEST(DoubleHalfScale); + REGISTER_TEST(UnevenHalfScale); + REGISTER_TEST(OddStrideHalfScale); + REGISTER_TEST(VerticalHalfScale); + REGISTER_TEST(HorizontalHalfScale); + REGISTER_TEST(MixedHalfScale); +#undef TEST_CLASS } void diff --git a/libazure/src/gfx/2d/unittest/TestScaling.h b/libazure/unittest/TestScaling.h similarity index 100% rename from libazure/src/gfx/2d/unittest/TestScaling.h rename to libazure/unittest/TestScaling.h diff --git a/libazure/unittest/unittest.vcxproj b/libazure/unittest/unittest.vcxproj new file mode 100644 index 0000000..ad807e2 --- /dev/null +++ b/libazure/unittest/unittest.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug (With Skia) + Win32 + + + Debug + Win32 + + + Release (With Skia) + Win32 + + + Release + Win32 + + + + {CCF4BC8B-0CED-47CA-B621-ABF1832527D9} + unittest + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + $(ProjectDir)..\;$(IncludePath) + + + $(SolutionDir)\..\cairo\src\Debug;$(SolutionDir)\..\skia\out\Debug;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + $(ProjectDir)..\;$(IncludePath) + + + $(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + $(SolutionDir)\..\cairo\src\Release;$(SolutionDir)\..\skia\out\Release;$(DXSDK_DIR)\Lib\x86;$(VCInstallDir)lib;$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(FrameworkSDKDir)\lib + + + + Level3 + Disabled + ../ + WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions); + + + true + ../$(Configuration)/gfx2d.lib;d3d11.lib;opengl32.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + ../ + WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions);USE_CAIRO;USE_SKIA + + + true + ../$(Configuration)/gfx2d.lib;d3d11.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + Level3 + MaxSpeed + true + true + ../ + USE_NVPR;WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions); + + + true + true + true + ../$(Configuration)/gfx2d.lib;d3d11.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + ../ + WIN32;USE_D2D1_1;_MBCS;%(PreprocessorDefinitions);USE_CAIRO;USE_SKIA + + + true + true + true + ../$(Configuration)/gfx2d.lib;d3d11.lib;dxguid.lib;d3d10_1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);skia_core.lib;skia_effects.lib;skia_utils.lib;skia_ports.lib;skia_opts.lib;skia_images.lib;skia_skgpu.lib;skia_opts_ssse3.lib;skia_sfnt.lib;usp10.lib;opengl32.lib;cairo-static.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/makefile.cargo b/makefile.cargo index 3d481d8..817cc11 100644 --- a/makefile.cargo +++ b/makefile.cargo @@ -1,52 +1,47 @@ ifeq (androideabi,$(findstring androideabi,$(TARGET))) - CXX := $(TARGET)-g++ AR := $(TARGET)-ar - else - CXX ?= g++ AR ?= ar - -endif - -ifeq (darwin,$(findstring darwin,$(TARGET))) - OSTYPE=darwin endif -ifeq (linux,$(findstring linux,$(TARGET))) - OSTYPE=linux -endif -ifeq (androideabi,$(findstring androideabi,$(TARGET))) - OSTYPE=android -endif - -MOZALLOC_CPP_SRC = \ - libazure/src/memory/mozalloc/mozalloc_abort.cpp \ - libazure/src/memory/mozalloc/mozalloc.cpp \ - libazure/src/memory/mozalloc/mozalloc_oom.cpp \ - $(NULL) AZURE_CPP_SRC = \ - $(addprefix libazure/src/gfx/2d/,\ - Blur.cpp \ - DrawEventRecorder.cpp \ - DrawTargetRecording.cpp \ - Factory.cpp \ - ImageScaling.cpp \ - Matrix.cpp \ - PathRecording.cpp \ - RecordedEvent.cpp \ - Rect.cpp \ - Scale.cpp \ - ScaledFontBase.cpp \ - SourceSurfaceRawData.cpp \ - convolver.cpp \ - image_operations.cpp) + src/azure-c.cpp \ + libazure/Blur.cpp \ + libazure/convolver.cpp \ + libazure/DataSourceSurface.cpp \ + libazure/DataSurfaceHelpers.cpp \ + libazure/DrawEventRecorder.cpp \ + libazure/DrawTargetCapture.cpp \ + libazure/DrawTarget.cpp \ + libazure/DrawTargetDual.cpp \ + libazure/DrawTargetRecording.cpp \ + libazure/DrawTargetSkia.cpp \ + libazure/DrawTargetTiled.cpp \ + libazure/Factory.cpp \ + libazure/FilterNodeSoftware.cpp \ + libazure/FilterProcessing.cpp \ + libazure/FilterProcessingScalar.cpp \ + libazure/ImageScaling.cpp \ + libazure/Matrix.cpp \ + libazure/Path.cpp \ + libazure/PathHelpers.cpp \ + libazure/PathRecording.cpp \ + libazure/PathSkia.cpp \ + libazure/RecordedEvent.cpp \ + libazure/ScaledFontBase.cpp \ + libazure/ScaledFontSkia.cpp \ + libazure/SourceSurfaceRawData.cpp \ + libazure/SourceSurfaceSkia.cpp -ifneq (arm,$(findstring arm,$(TARGET))) - AZURE_CPP_SRC += $(addprefix libazure/src/gfx/2d/, ImageScalingSSE2.cpp) -endif -AZURE_CPP_SRC += src/azure-c.cpp +CXXFLAGS += \ + -std=c++11 \ + -fPIC \ + -Ilibazure \ + -DMOZ_GFX \ + -DMOZ_WARN_UNUSED_RESULT="" \ + $(NULL) ifeq ($(CFG_ENABLE_DEBUG_SKIA),1) CXXFLAGS += \ @@ -64,33 +59,12 @@ CXXFLAGS += \ $(NULL) endif -#SSE2 instruction support required. -CXXFLAGS += \ - -fPIC \ - -Ilibazure/include \ - -Ilibazure/include/mozilla/gfx \ - -Ilibazure/include/mozilla/ipc/chromium/src \ - -Ilibazure/include/mozilla/xpcom/base \ - -Ilibazure/include/mozilla/xpcom/build \ - -Ilibazure/include/mozilla/xpcom/glue \ - -Ilibazure/include/mozilla/xpcom/string/public \ - -DMOZ_GFX \ - -DNS_ATTR_MALLOC="" -DNS_WARN_UNUSED_RESULT="" \ - $(NULL) - -#SSE2 instruction support required. -ifneq (arm,$(findstring arm,$(TARGET))) - CXXFLAGS += -msse2 -endif - -AZURE_CPP_SRC += \ - $(addprefix libazure/src/gfx/2d/,\ - DrawTargetSkia.cpp \ - PathSkia.cpp \ - SourceSurfaceSkia.cpp) - SKIA_OUTDIR = $(shell find $(OUT_DIR)/.. -name 'skia-sys-*' -type d) +FREETYPE_OUTDIR = $(shell find $(OUT_DIR)/.. -name 'freetype-sys-*' -type d) + CXXFLAGS += \ + -I $(FREETYPE_OUTDIR)/include \ + -iquote $(SKIA_OUTDIR)/include \ -iquote $(SKIA_OUTDIR)/include/core \ -iquote $(SKIA_OUTDIR)/include/config \ -iquote $(SKIA_OUTDIR)/include/effects \ @@ -99,61 +73,54 @@ CXXFLAGS += \ -iquote $(SKIA_OUTDIR)/include/gpu \ -iquote $(SKIA_OUTDIR)/include/gpu/gl \ -DUSE_SKIA \ - -DUSE_SKIA_GPU \ - $(NULL) + -DUSE_SKIA_GPU USE_CLANG = $(shell $(CXX) --version|grep -c 'clang') -ifeq ($(USE_CLANG),1) - CXXFLAGS += -Wno-c++11-extensions +ifneq (arm,$(findstring arm,$(TARGET))) +AZURE_CPP_SRC += \ + libazure/BlurSSE2.cpp \ + libazure/FilterProcessingSSE2.cpp \ + libazure/ImageScalingSSE2.cpp \ + libazure/convolverSSE2.cpp + +CXXFLAGS += \ + -msse2 \ + -DUSE_SSE2 endif -ifeq ($(OSTYPE),darwin) +ifeq (darwin,$(findstring darwin,$(TARGET))) CXXFLAGS += \ -DXP_MACOSX \ -DXP_UNIX \ - -DMALLOC_H="" \ - -Ilibazure/include/mozilla/gfx/gl \ - $(NULL) + -Dtypeof=__typeof__ AZURE_CPP_SRC += \ - libazure/src/gfx/2d/ScaledFontMac.cpp \ - libazure/src/gfx/2d/DrawTargetCG.cpp \ - libazure/src/gfx/2d/PathCG.cpp \ - libazure/src/gfx/2d/SourceSurfaceCG.cpp \ - $(NULL) - -AZURE_OBJCPP_SRC = libazure/src/gfx/2d/QuartzSupport.mm + libazure/DrawTargetCG.cpp \ + libazure/MacIOSurface.cpp \ + libazure/PathCG.cpp \ + libazure/ScaledFontMac.cpp \ + libazure/SourceSurfaceCG.cpp endif -ifeq ($(OSTYPE),linux) +ifeq (linux,$(findstring linux,$(TARGET))) CXXFLAGS += \ + -DMOZ_ENABLE_FREETYPE \ -DXP_UNIX \ - $(NULL) -AZURE_OBJCPP_SRC = - -CXXFLAGS += -DMOZ_ENABLE_FREETYPE -AZURE_CPP_SRC += \ - $(addprefix libazure/src/gfx/2d/,\ - ScaledFontFreetype.cpp) + -DSK_BUILD_FOR_UNIX endif -ifeq ($(OSTYPE),android) - CXXFLAGS += \ - -DXP_UNIX \ - -DSK_BUILD_FOR_ANDROID \ - $(NULL) - AZURE_OBJCPP_SRC = - - CXXFLAGS += -DMOZ_ENABLE_FREETYPE - AZURE_CPP_SRC += \ - $(addprefix libazure/src/gfx/2d/,\ - ScaledFontFreetype.cpp) +ifeq (androideabi,$(findstring androideabi,$(TARGET))) +CXXFLAGS += \ + -DXP_UNIX \ + -DSK_BUILD_FOR_ANDROID + +CXXFLAGS += \ + -DMOZ_ENABLE_FREETYPE endif -ALL_CPP_SRC = $(MOZALLOC_CPP_SRC) $(AZURE_CPP_SRC) -ALL_OBJCPP_SRC = $(AZURE_OBJCPP_SRC) -ALL_OBJS = $(ALL_CPP_SRC:%.cpp=$(OUT_DIR)/%.o) $(ALL_OBJCPP_SRC:%.mm=$(OUT_DIR)/%.o) +ALL_CPP_SRC = $(AZURE_CPP_SRC) +ALL_OBJS = $(ALL_CPP_SRC:%.cpp=$(OUT_DIR)/%.o) .PHONY: all all: $(OUT_DIR)/libazure.a @@ -161,8 +128,5 @@ all: $(OUT_DIR)/libazure.a $(OUT_DIR)/%.o: %.cpp mkdir -p `dirname $@` && $(CXX) $< -o $@ -c $(CXXFLAGS) -$(OUT_DIR)/%.o: %.mm - mkdir -p `dirname $@` && $(CXX) -ObjC++ $< -o $@ -c $(CXXFLAGS) - $(OUT_DIR)/libazure.a: $(ALL_OBJS) $(AR) rcs $@ $(ALL_OBJS) diff --git a/src/azure-c.cpp b/src/azure-c.cpp index 0774e63..d4bd8a1 100644 --- a/src/azure-c.cpp +++ b/src/azure-c.cpp @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "azure-c.h" -#include "mozilla/gfx/2D.h" +#include "2D.h" +#include "ScaledFontSkia.h" #include #include @@ -20,7 +21,10 @@ static AzIntSize IntSizeToC(gfx::IntSize src) { #define CHECK_SIZE(name) assert(sizeof(Az##name) == sizeof(gfx::name)) -#define CHECK_ENUM(name) assert((int)AZ_##name == (int)gfx::name) +#define CHECK_ENUM(azureEnumName, rustAzurePrefix, name) assert((int)rustAzurePrefix##_##name == (int)gfx::azureEnumName::name) + +#define STATIC_ASSERT_EQUALS(a, b)\ + typedef char assert_failed_ ## name [ (a - b) ? 1 : -1 ] extern "C" void AzSanityCheck() { @@ -41,103 +45,122 @@ void AzSanityCheck() { CHECK_SIZE(GlyphBuffer); CHECK_SIZE(NativeFont); - CHECK_ENUM(SURFACE_DATA); - CHECK_ENUM(SURFACE_D2D1_BITMAP); - CHECK_ENUM(SURFACE_D2D1_DRAWTARGET); - CHECK_ENUM(SURFACE_CAIRO); - CHECK_ENUM(SURFACE_CAIRO_IMAGE); - CHECK_ENUM(SURFACE_COREGRAPHICS_IMAGE); - CHECK_ENUM(SURFACE_COREGRAPHICS_CGCONTEXT); - CHECK_ENUM(SURFACE_SKIA); - CHECK_ENUM(SURFACE_DUAL_DT); - - CHECK_ENUM(FORMAT_B8G8R8A8); - CHECK_ENUM(FORMAT_B8G8R8X8); - CHECK_ENUM(FORMAT_R5G6B5); - CHECK_ENUM(FORMAT_A8); - - CHECK_ENUM(BACKEND_NONE); - CHECK_ENUM(BACKEND_DIRECT2D); - CHECK_ENUM(BACKEND_COREGRAPHICS); - CHECK_ENUM(BACKEND_CAIRO); - CHECK_ENUM(BACKEND_SKIA); - - CHECK_ENUM(FONT_DWRITE); - CHECK_ENUM(FONT_GDI); - CHECK_ENUM(FONT_MAC); - CHECK_ENUM(FONT_SKIA); - CHECK_ENUM(FONT_CAIRO); - CHECK_ENUM(FONT_COREGRAPHICS); - - CHECK_ENUM(NATIVE_SURFACE_D3D10_TEXTURE); - CHECK_ENUM(NATIVE_SURFACE_CAIRO_SURFACE); - CHECK_ENUM(NATIVE_SURFACE_CGCONTEXT); - - CHECK_ENUM(NATIVE_FONT_DWRITE_FONT_FACE); - CHECK_ENUM(NATIVE_FONT_GDI_FONT_FACE); - CHECK_ENUM(NATIVE_FONT_MAC_FONT_FACE); - CHECK_ENUM(NATIVE_FONT_SKIA_FONT_FACE); - CHECK_ENUM(NATIVE_FONT_CAIRO_FONT_FACE); - - CHECK_ENUM(OP_OVER); - CHECK_ENUM(OP_ADD); - CHECK_ENUM(OP_ATOP); - CHECK_ENUM(OP_OUT); - CHECK_ENUM(OP_IN); - CHECK_ENUM(OP_SOURCE); - CHECK_ENUM(OP_DEST_IN); - CHECK_ENUM(OP_DEST_OUT); - CHECK_ENUM(OP_DEST_OVER); - CHECK_ENUM(OP_DEST_ATOP); - CHECK_ENUM(OP_XOR); - CHECK_ENUM(OP_MULTIPLY); - CHECK_ENUM(OP_SCREEN); - CHECK_ENUM(OP_OVERLAY); - /* ... */ - CHECK_ENUM(OP_LUMINOSITY); - CHECK_ENUM(OP_COUNT); - - CHECK_ENUM(EXTEND_CLAMP); - CHECK_ENUM(EXTEND_REPEAT); - CHECK_ENUM(EXTEND_REFLECT); - - CHECK_ENUM(FILL_WINDING); - CHECK_ENUM(FILL_EVEN_ODD); - - CHECK_ENUM(AA_NONE); - CHECK_ENUM(AA_GRAY); - CHECK_ENUM(AA_SUBPIXEL); - - CHECK_ENUM(SNAP_NONE); - CHECK_ENUM(SNAP_ALIGNED); - - CHECK_ENUM(FILTER_LINEAR); - CHECK_ENUM(FILTER_POINT); - - CHECK_ENUM(PATTERN_COLOR); - CHECK_ENUM(PATTERN_SURFACE); - CHECK_ENUM(PATTERN_LINEAR_GRADIENT); - CHECK_ENUM(PATTERN_RADIAL_GRADIENT); - - CHECK_ENUM(JOIN_BEVEL); - CHECK_ENUM(JOIN_ROUND); - CHECK_ENUM(JOIN_MITER); - CHECK_ENUM(JOIN_MITER_OR_BEVEL); - - CHECK_ENUM(CAP_BUTT); - CHECK_ENUM(CAP_ROUND); - CHECK_ENUM(CAP_SQUARE); - - CHECK_ENUM(SAMPLING_UNBOUNDED); - CHECK_ENUM(SAMPLING_BOUNDED); - - assert((int)AZ_eSideTop == (int)css::eSideTop); - assert((int)AZ_eSideRight == (int)css::eSideRight); - assert((int)AZ_eSideBottom == (int)css::eSideBottom); - assert((int)AZ_eSideLeft == (int)css::eSideLeft); + CHECK_ENUM(SurfaceType, AZ_SURFACE, DATA); + CHECK_ENUM(SurfaceType, AZ_SURFACE, D2D1_BITMAP); + CHECK_ENUM(SurfaceType, AZ_SURFACE, D2D1_DRAWTARGET); + CHECK_ENUM(SurfaceType, AZ_SURFACE, CAIRO); + CHECK_ENUM(SurfaceType, AZ_SURFACE, CAIRO_IMAGE); + CHECK_ENUM(SurfaceType, AZ_SURFACE, COREGRAPHICS_IMAGE); + CHECK_ENUM(SurfaceType, AZ_SURFACE, COREGRAPHICS_CGCONTEXT); + CHECK_ENUM(SurfaceType, AZ_SURFACE, SKIA); + CHECK_ENUM(SurfaceType, AZ_SURFACE, DUAL_DT); + CHECK_ENUM(SurfaceType, AZ_SURFACE, D2D1_1_IMAGE); + CHECK_ENUM(SurfaceType, AZ_SURFACE, RECORDING); + CHECK_ENUM(SurfaceType, AZ_SURFACE, NVPR_TEXTURE); + CHECK_ENUM(SurfaceType, AZ_SURFACE, TILED); + + CHECK_ENUM(SurfaceFormat, AZ_FORMAT, B8G8R8A8); + CHECK_ENUM(SurfaceFormat, AZ_FORMAT, B8G8R8X8); + CHECK_ENUM(SurfaceFormat, AZ_FORMAT, R5G6B5); + CHECK_ENUM(SurfaceFormat, AZ_FORMAT, A8); + + CHECK_ENUM(BackendType, AZ_BACKEND, NONE); + CHECK_ENUM(BackendType, AZ_BACKEND, DIRECT2D); + CHECK_ENUM(BackendType, AZ_BACKEND, COREGRAPHICS); + CHECK_ENUM(BackendType, AZ_BACKEND, CAIRO); + CHECK_ENUM(BackendType, AZ_BACKEND, SKIA); + CHECK_ENUM(BackendType, AZ_BACKEND, RECORDING); + CHECK_ENUM(BackendType, AZ_BACKEND, DIRECT2D1_1); + CHECK_ENUM(BackendType, AZ_BACKEND, NVPR); + + CHECK_ENUM(FontType, AZ_FONT, DWRITE); + CHECK_ENUM(FontType, AZ_FONT, GDI); + CHECK_ENUM(FontType, AZ_FONT, MAC); + CHECK_ENUM(FontType, AZ_FONT, SKIA); + CHECK_ENUM(FontType, AZ_FONT, CAIRO); + CHECK_ENUM(FontType, AZ_FONT, COREGRAPHICS); + CHECK_ENUM(FontType, AZ_FONT, NVPR); + + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, D3D10_TEXTURE); + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, CAIRO_SURFACE); + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, CAIRO_CONTEXT); + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, CGCONTEXT); + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, CGCONTEXT_ACCELERATED); + CHECK_ENUM(NativeSurfaceType, AZ_NATIVE_SURFACE, OPENGL_TEXTURE); + + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, DWRITE_FONT_FACE); + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, GDI_FONT_FACE); + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, MAC_FONT_FACE); + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, SKIA_FONT_FACE); + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, CAIRO_FONT_FACE); + CHECK_ENUM(NativeFontType, AZ_NATIVE_FONT, NVPR_FONT_FACE); + + CHECK_ENUM(CompositionOp, AZ, OP_OVER); + CHECK_ENUM(CompositionOp, AZ, OP_ADD); + CHECK_ENUM(CompositionOp, AZ, OP_ATOP); + CHECK_ENUM(CompositionOp, AZ, OP_OUT); + CHECK_ENUM(CompositionOp, AZ, OP_IN); + CHECK_ENUM(CompositionOp, AZ, OP_SOURCE); + CHECK_ENUM(CompositionOp, AZ, OP_DEST_IN); + CHECK_ENUM(CompositionOp, AZ, OP_DEST_OUT); + CHECK_ENUM(CompositionOp, AZ, OP_DEST_OVER); + CHECK_ENUM(CompositionOp, AZ, OP_DEST_ATOP); + CHECK_ENUM(CompositionOp, AZ, OP_XOR); + CHECK_ENUM(CompositionOp, AZ, OP_MULTIPLY); + CHECK_ENUM(CompositionOp, AZ, OP_SCREEN); + CHECK_ENUM(CompositionOp, AZ, OP_OVERLAY); + CHECK_ENUM(CompositionOp, AZ, OP_DARKEN); + CHECK_ENUM(CompositionOp, AZ, OP_LIGHTEN); + CHECK_ENUM(CompositionOp, AZ, OP_COLOR_DODGE); + CHECK_ENUM(CompositionOp, AZ, OP_COLOR_BURN); + CHECK_ENUM(CompositionOp, AZ, OP_HARD_LIGHT); + CHECK_ENUM(CompositionOp, AZ, OP_SOFT_LIGHT); + CHECK_ENUM(CompositionOp, AZ, OP_DIFFERENCE); + CHECK_ENUM(CompositionOp, AZ, OP_EXCLUSION); + CHECK_ENUM(CompositionOp, AZ, OP_HUE); + CHECK_ENUM(CompositionOp, AZ, OP_SATURATION); + CHECK_ENUM(CompositionOp, AZ, OP_COLOR); + CHECK_ENUM(CompositionOp, AZ, OP_LUMINOSITY); + CHECK_ENUM(CompositionOp, AZ, OP_COUNT); + + CHECK_ENUM(ExtendMode, AZ_EXTEND, CLAMP); + CHECK_ENUM(ExtendMode, AZ_EXTEND, REPEAT); + CHECK_ENUM(ExtendMode, AZ_EXTEND, REFLECT); + + CHECK_ENUM(FillRule, AZ, FILL_WINDING); + CHECK_ENUM(FillRule, AZ, FILL_EVEN_ODD); + + CHECK_ENUM(AntialiasMode, AZ_AA, NONE); + CHECK_ENUM(AntialiasMode, AZ_AA, GRAY); + CHECK_ENUM(AntialiasMode, AZ_AA, SUBPIXEL); + + CHECK_ENUM(Filter, AZ_FILTER, GOOD); + CHECK_ENUM(Filter, AZ_FILTER, LINEAR); + CHECK_ENUM(Filter, AZ_FILTER, POINT); + + CHECK_ENUM(PatternType, AZ_PATTERN, COLOR); + CHECK_ENUM(PatternType, AZ_PATTERN, SURFACE); + CHECK_ENUM(PatternType, AZ_PATTERN, LINEAR_GRADIENT); + CHECK_ENUM(PatternType, AZ_PATTERN, RADIAL_GRADIENT); + + CHECK_ENUM(JoinStyle, AZ_JOIN, BEVEL); + CHECK_ENUM(JoinStyle, AZ_JOIN, ROUND); + CHECK_ENUM(JoinStyle, AZ_JOIN, MITER); + CHECK_ENUM(JoinStyle, AZ_JOIN, MITER_OR_BEVEL); + + CHECK_ENUM(CapStyle, AZ_CAP, BUTT); + CHECK_ENUM(CapStyle, AZ_CAP, ROUND); + CHECK_ENUM(CapStyle, AZ_CAP, SQUARE); + + CHECK_ENUM(SamplingBounds, AZ_SAMPLING, UNBOUNDED); + CHECK_ENUM(SamplingBounds, AZ_SAMPLING, BOUNDED); + + assert((int)AZ_eSideTop == (int)mozilla::eSideTop); + assert((int)AZ_eSideRight == (int)mozilla::eSideRight); + assert((int)AZ_eSideBottom == (int)mozilla::eSideBottom); + assert((int)AZ_eSideLeft == (int)mozilla::eSideLeft); } - extern "C" AzColorPatternRef AzCreateColorPattern(AzColor *aColor) { gfx::Color *gfxColor = reinterpret_cast(aColor); @@ -161,13 +184,13 @@ AzCreateSkiaSharedGLContext(AzGLNativeContextRef aNativeContext, AzIntSize *aSiz extern "C" void AzRetainSkiaSharedGLContext(AzSkiaSharedGLContextRef aGLContext) { SkNativeSharedGLContext *sharedGLContext = static_cast(aGLContext); - sharedGLContext->AddRef(); + sharedGLContext->ref(); } extern "C" void AzReleaseSkiaSharedGLContext(AzSkiaSharedGLContextRef aGLContext) { SkNativeSharedGLContext *sharedGLContext = static_cast(aGLContext); - sharedGLContext->Release(); + sharedGLContext->unref(); } extern "C" unsigned int @@ -235,10 +258,10 @@ AzCreateSkiaDrawTargetForFBO(AzSkiaSharedGLContextRef aGLContext, AzIntSize *aSi GrContext *grContext = sharedGLContext->getGrContext(); gfx::IntSize *size = reinterpret_cast(aSize); gfx::SurfaceFormat surfaceFormat = static_cast(aFormat); - RefPtr target = gfx::Factory::CreateSkiaDrawTargetForFBO(sharedGLContext->getFBOID(), - grContext, - *size, - surfaceFormat); + RefPtr target = gfx::Factory::CreateDrawTargetSkiaWithGrContextAndFBO(grContext, + sharedGLContext->getFBOID(), + *size, + surfaceFormat); if (target != NULL) { target->AddRef(); } @@ -495,7 +518,24 @@ AzSourceSurfaceGetSize(AzSourceSurfaceRef aSurface) { extern "C" AzSurfaceFormat AzSourceSurfaceGetFormat(AzSourceSurfaceRef aSurface) { gfx::SourceSurface *gfxSourceSurface = static_cast(aSurface); - return static_cast(gfxSourceSurface->GetFormat()); + switch (gfxSourceSurface->GetFormat()) { + case gfx::SurfaceFormat::B8G8R8A8: + return AZ_FORMAT_B8G8R8A8; + case gfx::SurfaceFormat::B8G8R8X8: + return AZ_FORMAT_B8G8R8X8; + case gfx::SurfaceFormat::R8G8B8A8: + return AZ_FORMAT_R8G8B8A8; + case gfx::SurfaceFormat::R8G8B8X8: + return AZ_FORMAT_R8G8B8X8; + case gfx::SurfaceFormat::R5G6B5: + return AZ_FORMAT_R5G6B5; + case gfx::SurfaceFormat::A8: + return AZ_FORMAT_A8; + case gfx::SurfaceFormat::YUV: + return AZ_FORMAT_YUV; + case gfx::SurfaceFormat::UNKNOWN: + return AZ_FORMAT_UNKNOWN; + } } extern "C" AzDataSourceSurfaceRef @@ -524,6 +564,13 @@ AzCreateScaledFontForNativeFont(AzNativeFont *aNativeFont, AzFloat aSize) { return font; } +extern "C" AzScaledFontRef +AzCreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, uint32_t aFaceIndex, AzFloat aGlyphSize, AzFontType) { + RefPtr font = new gfx::ScaledFontSkia(aData, aSize, aFaceIndex, aGlyphSize); + font->AddRef(); + return font; +} + extern "C" void AzReleaseScaledFont(AzScaledFontRef aFont) { gfx::ScaledFont *gfxFont = static_cast(aFont); @@ -544,21 +591,6 @@ AzCreateFontOptionsForName(char *aName, AzFontStyle aStyle) { gfx::FontOptions *options = new gfx::FontOptions; options->mName = std::string(aName); options->mStyle = static_cast(aStyle); - options->mData = NULL; - options->mDataSize = 0; - return options; - #else - abort(); - #endif -} - -extern "C" AzFontOptions* -AzCreateFontOptionsForData(uint8_t *aFontData, uint32_t aFontDataSize) { - #ifdef MOZ_ENABLE_FREETYPE - gfx::FontOptions *options = new gfx::FontOptions; - options->mStyle = gfx::FONT_STYLE_NORMAL; - options->mData = aFontData; - options->mDataSize = aFontDataSize; return options; #else abort(); diff --git a/src/azure-c.h b/src/azure-c.h index c76cc23..f546eda 100644 --- a/src/azure-c.h +++ b/src/azure-c.h @@ -55,15 +55,52 @@ enum AzSurfaceType AZ_SURFACE_COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */ AZ_SURFACE_COREGRAPHICS_CGCONTEXT, /* Surface wrapping a CG context */ AZ_SURFACE_SKIA, /* Surface wrapping a Skia bitmap */ - AZ_SURFACE_DUAL_DT /* Snapshot of a dual drawtarget */ + AZ_SURFACE_DUAL_DT, /* Snapshot of a dual drawtarget */ + AZ_SURFACE_D2D1_1_IMAGE, /* A D2D 1.1 ID2D1Image SourceSurface */ + AZ_SURFACE_RECORDING, /* Surface used for recording */ + AZ_SURFACE_NVPR_TEXTURE, /* Surface wrapping an OpenGL texture, used by NV_path_rendering */ + AZ_SURFACE_TILED /* Surface from a tiled DrawTarget */ }; enum AzSurfaceFormat { AZ_FORMAT_B8G8R8A8, AZ_FORMAT_B8G8R8X8, + AZ_FORMAT_R8G8B8A8, + AZ_FORMAT_R8G8B8X8, AZ_FORMAT_R5G6B5, - AZ_FORMAT_A8 + AZ_FORMAT_A8, + AZ_FORMAT_YUV, + AZ_FORMAT_UNKNOWN +}; + +enum AzFilterType { + AZ_FILTER_TYPE_BLEND, + AZ_FILTER_TYPE_TRANSFORM, + AZ_FILTER_TYPE_MORPHOLOGY, + AZ_FILTER_TYPE_COLOR_MATRIX, + AZ_FILTER_TYPE_FLOOD, + AZ_FILTER_TYPE_TILE, + AZ_FILTER_TYPE_TABLE_TRANSFER, + AZ_FILTER_TYPE_DISCRETE_TRANSFER, + AZ_FILTER_TYPE_LINEAR_TRANSFER, + AZ_FILTER_TYPE_GAMMA_TRANSFER, + AZ_FILTER_TYPE_CONVOLVE_MATRIX, + AZ_FILTER_TYPE_DISPLACEMENT_MAP, + AZ_FILTER_TYPE_TURBULENCE, + AZ_FILTER_TYPE_ARITHMETIC_COMBINE, + AZ_FILTER_TYPE_COMPOSITE, + AZ_FILTER_TYPE_DIRECTIONAL_BLUR, + AZ_FILTER_TYPE_GAUSSIAN_BLUR, + AZ_FILTER_TYPE_POINT_DIFFUSE, + AZ_FILTER_TYPE_POINT_SPECULAR, + AZ_FILTER_TYPE_SPOT_DIFFUSE, + AZ_FILTER_TYPE_SPOT_SPECULAR, + AZ_FILTER_TYPE_DISTANT_DIFFUSE, + AZ_FILTER_TYPE_DISTANT_SPECULAR, + AZ_FILTER_TYPE_CROP, + AZ_FILTER_TYPE_PREMULTIPLY, + AZ_FILTER_TYPE_UNPREMULTIPLY }; enum AzBackendType @@ -73,7 +110,10 @@ enum AzBackendType AZ_BACKEND_COREGRAPHICS, AZ_BACKEND_COREGRAPHICS_ACCELERATED, AZ_BACKEND_CAIRO, - AZ_BACKEND_SKIA + AZ_BACKEND_SKIA, + AZ_BACKEND_RECORDING, + AZ_BACKEND_DIRECT2D1_1, + AZ_BACKEND_NVPR }; enum AzFontType @@ -83,14 +123,18 @@ enum AzFontType AZ_FONT_MAC, AZ_FONT_SKIA, AZ_FONT_CAIRO, - AZ_FONT_COREGRAPHICS + AZ_FONT_COREGRAPHICS, + AZ_FONT_NVPR }; enum AzNativeSurfaceType { AZ_NATIVE_SURFACE_D3D10_TEXTURE, AZ_NATIVE_SURFACE_CAIRO_SURFACE, - AZ_NATIVE_SURFACE_CGCONTEXT + AZ_NATIVE_SURFACE_CAIRO_CONTEXT, + AZ_NATIVE_SURFACE_CGCONTEXT, + AZ_NATIVE_SURFACE_CGCONTEXT_ACCELERATED, + AZ_NATIVE_SURFACE_OPENGL_TEXTURE }; enum AzNativeFontType @@ -99,7 +143,8 @@ enum AzNativeFontType AZ_NATIVE_FONT_GDI_FONT_FACE, AZ_NATIVE_FONT_MAC_FONT_FACE, AZ_NATIVE_FONT_SKIA_FONT_FACE, - AZ_NATIVE_FONT_CAIRO_FONT_FACE + AZ_NATIVE_FONT_CAIRO_FONT_FACE, + AZ_NATIVE_FONT_NVPR_FONT_FACE }; enum AzFontStyle @@ -154,15 +199,12 @@ enum AzFillRule { enum AzAntialiasMode { AZ_AA_NONE, AZ_AA_GRAY, - AZ_AA_SUBPIXEL -}; - -enum AzSnapping { - AZ_SNAP_NONE, - AZ_SNAP_ALIGNED + AZ_AA_SUBPIXEL, + AZ_AA_DEFAULT }; enum AzFilter { + AZ_FILTER_GOOD, AZ_FILTER_LINEAR, AZ_FILTER_POINT }; @@ -257,7 +299,6 @@ typedef struct _AzDrawOptions { /* enum AzCompositionOp mCompositionOp : 8; enum AzAntialiasMode mAntialiasMode : 2; - enum AzSnapping mSnapping : 1; */ } AzDrawOptions; diff --git a/src/azure.rs b/src/azure.rs index d88e3a6..c0497c7 100644 --- a/src/azure.rs +++ b/src/azure.rs @@ -23,12 +23,20 @@ pub static AZ_SURFACE_COREGRAPHICS_IMAGE: u32 = 5_u32; pub static AZ_SURFACE_COREGRAPHICS_CGCONTEXT: u32 = 6_u32; pub static AZ_SURFACE_SKIA: u32 = 7_u32; pub static AZ_SURFACE_DUAL_DT: u32 = 8_u32; +pub static AZ_SURFACE_D2D1_1_IMAGE: u32 = 9_u32; +pub static AZ_SURFACE_RECORDING: u32 = 10_u32; +pub static AZ_SURFACE_NVPR_TEXTURE: u32 = 11_u32; +pub static AZ_SURFACE_TILED: u32 = 12_u32; pub type enum_AzSurfaceFormat = c_uint; pub static AZ_FORMAT_B8G8R8A8: u32 = 0_u32; pub static AZ_FORMAT_B8G8R8X8: u32 = 1_u32; -pub static AZ_FORMAT_R5G6B5: u32 = 2_u32; -pub static AZ_FORMAT_A8: u32 = 3_u32; +pub static AZ_FORMAT_R8G8B8A8: u32 = 2_u32; +pub static AZ_FORMAT_R8G8B8X8: u32 = 3_u32; +pub static AZ_FORMAT_R5G6B5: u32 = 4_u32; +pub static AZ_FORMAT_A8: u32 = 5_u32; +pub static AZ_FORMAT_YUV: u32 = 6_u32; +pub static AZ_FORMAT_UNKNOWN: u32 = 7_u32; pub type AzSurfaceFormat = enum_AzSurfaceFormat; @@ -40,9 +48,41 @@ pub static AZ_BACKEND_COREGRAPHICS_ACCELERATED: u32 = 3_u32; pub static AZ_BACKEND_CAIRO: u32 = 4_u32; pub static AZ_BACKEND_SKIA: u32 = 5_u32; pub static AZ_BACKEND_RECORDING: u32 = 6_u32; +pub static AZ_BACKEND_DIRECT2D1_1: u32 = 7_u32; +pub static AZ_BACKEND_NVP: u32 = 8_u32; pub type AzBackendType = enum_AzBackendType; +pub type enum_AzFilterType = c_uint; +pub static AZ_FILTER_TYPE_BLEND: u32 = 0_u32; +pub static AZ_FILTER_TYPE_TRANSFORM: u32 = 1_u32; +pub static AZ_FILTER_TYPE_MORPHOLOGY: u32 = 2_u32; +pub static AZ_FILTER_TYPE_COLOR_MATRIX: u32 = 3_u32; +pub static AZ_FILTER_TYPE_FLOOD: u32 = 4_u32; +pub static AZ_FILTER_TYPE_TILE: u32 = 5_u32; +pub static AZ_FILTER_TYPE_TABLE_TRANSFER: u32 = 6_u32; +pub static AZ_FILTER_TYPE_DISCRETE_TRANSFER: u32 = 7_u32; +pub static AZ_FILTER_TYPE_LINEAR_TRANSFER: u32 = 8_u32; +pub static AZ_FILTER_TYPE_GAMMA_TRANSFER: u32 = 9_u32; +pub static AZ_FILTER_TYPE_CONVOLVE_MATRIX: u32 = 10_u32; +pub static AZ_FILTER_TYPE_DISPLACEMENT_MAP: u32 = 11_u32; +pub static AZ_FILTER_TYPE_TURBULENCE: u32 = 12_u32; +pub static AZ_FILTER_TYPE_ARITHMETIC_COMBINE: u32 = 13_u32; +pub static AZ_FILTER_TYPE_COMPOSITE: u32 = 14_u32; +pub static AZ_FILTER_TYPE_DIRECTIONAL_BLUR: u32 = 15_u32; +pub static AZ_FILTER_TYPE_GAUSSIAN_BLUR: u32 = 16_u32; +pub static AZ_FILTER_TYPE_POINT_DIFFUSE: u32 = 17_u32; +pub static AZ_FILTER_TYPE_POINT_SPECULAR: u32 = 18_u32; +pub static AZ_FILTER_TYPE_SPOT_DIFFUSE: u32 = 19_u32; +pub static AZ_FILTER_TYPE_SPOT_SPECULAR: u32 = 20_u32; +pub static AZ_FILTER_TYPE_DISTANT_DIFFUSE: u32 = 21_u32; +pub static AZ_FILTER_TYPE_DISTANT_SPECULAR: u32 = 22_u32; +pub static AZ_FILTER_TYPE_CROP: u32 = 23_u32; +pub static AZ_FILTER_TYPE_PREMULTIPLY: u32 = 24_u32; +pub static AZ_FILTER_TYPE_UNPREMULTIPL: u32 = 25_u32; + +pub type AzFilterType = enum_AzFilterType; + pub type enum_AzFontType = c_uint; pub static AZ_FONT_DWRITE: u32 = 0_u32; pub static AZ_FONT_GDI: u32 = 1_u32; @@ -50,11 +90,15 @@ pub static AZ_FONT_MAC: u32 = 2_u32; pub static AZ_FONT_SKIA: u32 = 3_u32; pub static AZ_FONT_CAIRO: u32 = 4_u32; pub static AZ_FONT_COREGRAPHICS: u32 = 5_u32; +pub static AZ_FONT_NVPR: u32 = 6_u32; pub type enum_AzNativeSurfaceType = c_uint; pub static AZ_NATIVE_SURFACE_D3D10_TEXTURE: u32 = 0_u32; pub static AZ_NATIVE_SURFACE_CAIRO_SURFACE: u32 = 1_u32; -pub static AZ_NATIVE_SURFACE_CGCONTEXT: u32 = 2_u32; +pub static AZ_NATIVE_SURFACE_CAIRO_CONTEXT: u32 = 2_u32; +pub static AZ_NATIVE_SURFACE_CGCONTEXT: u32 = 3_u32; +pub static AZ_NATIVE_SURFACE_CGCONTEXT_ACCELERATED: u32 = 4_u32; +pub static AZ_NATIVE_SURFACE_OPENGL_TEXTUR: u32 = 5_u32; pub type enum_AzNativeFontType = c_uint; pub static AZ_NATIVE_FONT_DWRITE_FONT_FACE: u32 = 0_u32; @@ -62,6 +106,7 @@ pub static AZ_NATIVE_FONT_GDI_FONT_FACE: u32 = 1_u32; pub static AZ_NATIVE_FONT_MAC_FONT_FACE: u32 = 2_u32; pub static AZ_NATIVE_FONT_SKIA_FONT_FACE: u32 = 3_u32; pub static AZ_NATIVE_FONT_CAIRO_FONT_FACE: u32 = 4_u32; +pub static AZ_NATIVE_FONT_NVPR_FONT_FAC: u32 = 5_u32; pub type enum_AzFontStyle = c_uint; pub static AZ_FONT_STYLE_NORMAL: u32 = 0_u32; @@ -112,14 +157,12 @@ pub type enum_AzAntialiasMode = c_uint; pub static AZ_AA_NONE: u32 = 0_u32; pub static AZ_AA_GRAY: u32 = 1_u32; pub static AZ_AA_SUBPIXEL: u32 = 2_u32; - -pub type enum_AzSnapping = c_uint; -pub static AZ_SNAP_NONE: u32 = 0_u32; -pub static AZ_SNAP_ALIGNED: u32 = 1_u32; +pub static AZ_AA_DEFAULT: u32 = 3_u32; pub type enum_AzFilter = c_uint; -pub static AZ_FILTER_LINEAR: u32 = 0_u32; -pub static AZ_FILTER_POINT: u32 = 1_u32; +pub static AZ_FILTER_GOOD: u32 = 0_u32; +pub static AZ_FILTER_LINEAR: u32 = 1_u32; +pub static AZ_FILTER_POINT: u32 = 2_u32; pub type AzFilter = enum_AzFilter; @@ -445,12 +488,12 @@ pub fn AzDataSourceSurfaceGetStride(aSurface: AzDataSourceSurfaceRef) -> i32; pub fn AzCreateScaledFontForNativeFont(aNativeFont: *mut AzNativeFont, aSize: AzFloat) -> AzScaledFontRef; +pub fn AzCreateScaledFontForTrueTypeData(aFontData: *const u8, aFontDataSize: u32, aFaceIndex: u32, aGlyphSize: f32, aType: enum_AzFontType) -> AzScaledFontRef; + pub fn AzReleaseScaledFont(aFont: AzScaledFontRef); pub fn AzDrawTargetSetTransform(aDrawTarget: AzDrawTargetRef, aTransform: *mut AzMatrix); -pub fn AzCreateFontOptionsForData(aFontData: *const u8, aFontDataSize: u32) -> *mut AzFontOptions; - pub fn AzCreateFontOptionsForName(aName: *const c_char, aStyle: enum_AzFontStyle) -> *mut AzFontOptions; pub fn AzDestroyFontOptions(aOptions: *mut AzFontOptions); diff --git a/src/azure_hl.rs b/src/azure_hl.rs index 051335d..cbd4305 100644 --- a/src/azure_hl.rs +++ b/src/azure_hl.rs @@ -49,9 +49,6 @@ use std::mem; use std::ptr; use std::slice; -#[cfg(target_os="linux")] -use libc::c_void; - pub trait AsAzureRect { fn as_azure_rect(&self) -> AzRect; } @@ -162,6 +159,7 @@ pub enum CompositionOp { SaturationOp, ColorOp, LuminosityOp, + CountOp, } #[allow(non_snake_case)] @@ -236,20 +234,18 @@ impl DrawOptions { let style = ((style & 7) as u16) << 8; self.fields = self.fields | style; } - - pub fn set_snapping(&mut self, style: u8) { - self.fields = self.fields & 0b1111_0111_1111_1111_u16; - let style = ((style & 1) as u16) << 11; - self.fields = self.fields | style; - } } pub enum SurfaceFormat { B8G8R8A8, B8G8R8X8, + R8G8B8A8, + R8G8B8X8, R5G6B5, - A8 + A8, + YUV, + UNKNOWN } impl SurfaceFormat { @@ -261,14 +257,19 @@ impl SurfaceFormat { match azure_surface_format { 0 => SurfaceFormat::B8G8R8A8, 1 => SurfaceFormat::B8G8R8X8, - 2 => SurfaceFormat::R5G6B5, - 3 => SurfaceFormat::A8, + 2 => SurfaceFormat::R8G8B8A8, + 3 => SurfaceFormat::R8G8B8X8, + 4 => SurfaceFormat::R5G6B5, + 5 => SurfaceFormat::A8, + 6 => SurfaceFormat::YUV, + 7 => SurfaceFormat::UNKNOWN, _ => panic!("SurfaceFormat::new(): unknown Azure surface format") } } } pub enum Filter { + Good, Linear, Point } @@ -308,7 +309,9 @@ pub enum BackendType { CoreGraphicsAcceleratedBackend, CairoBackend, SkiaBackend, - RecordingBackend + RecordingBackend, + Direct2D11Backend, + NVPathRenderingBackend, } impl BackendType { @@ -321,6 +324,8 @@ impl BackendType { BackendType::CairoBackend => 4, BackendType::SkiaBackend => 5, BackendType::RecordingBackend => 6, + BackendType::Direct2D11Backend => 7, + BackendType::NVPathRenderingBackend => 8, } } } diff --git a/src/lib.rs b/src/lib.rs index 4edd90b..367fe6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,8 +46,7 @@ pub use azure::{AzFontOptions, AzFloat, enum_AzSurfaceType, AZ_SURFACE_DATA, AZ_OP_COUNT, enum_AzExtendMode, AZ_EXTEND_CLAMP, AZ_EXTEND_REPEAT, AZ_EXTEND_REFLECT, enum_AzFillRule, AZ_FILL_WINDING, AZ_FILL_EVEN_ODD, enum_AzAntialiasMode, AZ_AA_NONE, AZ_AA_GRAY, AZ_AA_SUBPIXEL, - enum_AzSnapping, AZ_SNAP_NONE, AZ_SNAP_ALIGNED, enum_AzFilter, - AZ_FILTER_LINEAR, AZ_FILTER_POINT, AzFilter, enum_AzPatternType, + enum_AzFilter, AZ_FILTER_LINEAR, AZ_FILTER_POINT, AzFilter, enum_AzPatternType, AZ_PATTERN_COLOR, AZ_PATTERN_SURFACE, AZ_PATTERN_LINEAR_GRADIENT, AZ_PATTERN_RADIAL_GRADIENT, enum_AzJoinStyle, AZ_JOIN_BEVEL, AZ_JOIN_ROUND, AZ_JOIN_MITER, AZ_JOIN_MITER_OR_BEVEL, enum_AzCapStyle, AZ_CAP_BUTT, AZ_CAP_ROUND, @@ -75,7 +74,7 @@ pub use azure::{AzFontOptions, AzFloat, enum_AzSurfaceType, AZ_SURFACE_DATA, AzDrawTargetDrawSurface, AzDrawTargetGetSnapshot, AzDrawTargetCreateSourceSurfaceFromData, AzReleaseSourceSurface, AzSourceSurfaceGetSize, AzSourceSurfaceGetFormat, AzSourceSurfaceGetDataSurface, AzDataSourceSurfaceGetData, AzDataSourceSurfaceGetStride, AzCreateScaledFontForNativeFont, AzReleaseScaledFont, AzDrawTargetSetTransform, - AzCreateFontOptionsForData, AzCreateFontOptionsForName, AzDestroyFontOptions, AzSkiaGetCurrentGLContext, AzCreatePathBuilder, + AzCreateFontOptionsForName, AzDestroyFontOptions, AzSkiaGetCurrentGLContext, AzCreatePathBuilder, AzReleasePathBuilder, AzPathBuilderMoveTo, AzPathBuilderLineTo, AzPathBuilderFinish, AzReleasePath}; pub mod azure_hl; diff --git a/src/scaled_font.rs b/src/scaled_font.rs index 3b5e856..97ce3af 100644 --- a/src/scaled_font.rs +++ b/src/scaled_font.rs @@ -67,32 +67,39 @@ impl ScaledFont { pub fn new(backend: BackendType, font_info: FontInfo, size: AzFloat) -> ScaledFont { use azure::AZ_NATIVE_FONT_SKIA_FONT_FACE; - use azure::{AzCreateFontOptionsForData, AzCreateFontOptionsForName, AzDestroyFontOptions}; + use azure::{AzCreateFontOptionsForName, AzDestroyFontOptions, AzCreateScaledFontForTrueTypeData}; let mut azure_native_font = struct__AzNativeFont { mType: 0, mFont: ptr::null_mut() }; - + match backend { SkiaBackend => { unsafe { - let options = match font_info { + match font_info { FontInfo::NativeFont(native_font) => { // NOTE: azure style flags and freetype style flags are the same in the lowest 2 bits let style = ((*native_font).style_flags & 3) as u32; - AzCreateFontOptionsForName(&*(*native_font).family_name, style) + let options = AzCreateFontOptionsForName(&*(*native_font).family_name, style); + azure_native_font.mType = AZ_NATIVE_FONT_SKIA_FONT_FACE; + azure_native_font.mFont = mem::transmute(options); + let azure_native_font_ptr = &mut azure_native_font; + let azure_scaled_font = + AzCreateScaledFontForNativeFont(azure_native_font_ptr, size); + AzDestroyFontOptions(options); + ScaledFont { azure_scaled_font: azure_scaled_font } }, FontInfo::FontData(bytes) => { - AzCreateFontOptionsForData(bytes.as_ptr(), bytes.len() as u32) + let azure_scaled_font = + AzCreateScaledFontForTrueTypeData(bytes.as_ptr(), + bytes.len() as u32, + 0, + size, + AZ_NATIVE_FONT_SKIA_FONT_FACE); + ScaledFont { azure_scaled_font: azure_scaled_font } }, - }; - azure_native_font.mType = AZ_NATIVE_FONT_SKIA_FONT_FACE; - azure_native_font.mFont = mem::transmute(options); - let azure_native_font_ptr = &mut azure_native_font; - let azure_scaled_font = AzCreateScaledFontForNativeFont(azure_native_font_ptr, size); - AzDestroyFontOptions(options); - ScaledFont { azure_scaled_font: azure_scaled_font } + } } } _ => { panic!("don't know how to make a scaled font for this backend"); }