/* * Copyright (C) 2009 Apple 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: * 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. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 GraphicsContext3D_h #define GraphicsContext3D_h #include "platform/PlatformExport.h" #include "platform/geometry/IntRect.h" #include "platform/graphics/Extensions3D.h" #include "platform/graphics/GraphicsTypes3D.h" #include "platform/graphics/Image.h" #include "platform/weborigin/KURL.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkBitmap.h" #include "wtf/HashMap.h" #include "wtf/HashSet.h" #include "wtf/ListHashSet.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" #include "wtf/RefCounted.h" #include "wtf/text/WTFString.h" // FIXME: Find a better way to avoid the name confliction for NO_ERROR. #if OS(WIN) #undef NO_ERROR #endif class GrContext; namespace blink { class WebGraphicsContext3D; class WebGraphicsContext3DProvider; } namespace WebCore { class DrawingBuffer; class Extensions3D; class GraphicsContext3DContextLostCallbackAdapter; class GraphicsContext3DErrorMessageCallbackAdapter; class Image; class ImageBuffer; class IntRect; class IntSize; struct ActiveInfo { String name; GC3Denum type; GC3Dint size; }; class PLATFORM_EXPORT GraphicsContext3D : public RefCounted { public: // Context creation attributes. struct Attributes { Attributes() : alpha(true) , depth(true) , stencil(false) , antialias(true) , premultipliedAlpha(true) , preserveDrawingBuffer(false) , noExtensions(false) , shareResources(true) , preferDiscreteGPU(false) , failIfMajorPerformanceCaveat(false) { } bool alpha; bool depth; bool stencil; bool antialias; bool premultipliedAlpha; bool preserveDrawingBuffer; bool noExtensions; bool shareResources; bool preferDiscreteGPU; bool failIfMajorPerformanceCaveat; KURL topDocumentURL; }; class ContextLostCallback { public: virtual void onContextLost() = 0; virtual ~ContextLostCallback() {} }; class ErrorMessageCallback { public: virtual void onErrorMessage(const String& message, GC3Dint id) = 0; virtual ~ErrorMessageCallback() { } }; void setContextLostCallback(PassOwnPtr); void setErrorMessageCallback(PassOwnPtr); static PassRefPtr create(Attributes); // Callers must make the context current before using it AND check that the context was created successfully // via ContextLost before using the context in any way. Once made current on a thread, the context cannot // be used on any other thread. static PassRefPtr createGraphicsContextFromWebContext(PassOwnPtr, bool preserveDrawingBuffer = false); static PassRefPtr createGraphicsContextFromProvider(PassOwnPtr, bool preserveDrawingBuffer = false); ~GraphicsContext3D(); GrContext* grContext(); blink::WebGraphicsContext3D* webContext() const { return m_impl; } bool makeContextCurrent(); uint32_t lastFlushID(); // Helper to texImage2D with pixel==0 case: pixels are initialized to 0. // Return true if no GL error is synthesized. // By default, alignment is 4, the OpenGL default setting. bool texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint alignment = 4); //---------------------------------------------------------------------- // Helpers for texture uploading and pixel readback. // // Computes the components per pixel and bytes per component // for the given format and type combination. Returns false if // either was an invalid enum. static bool computeFormatAndTypeParameters(GC3Denum format, GC3Denum type, unsigned int* componentsPerPixel, unsigned int* bytesPerComponent); // Computes the image size in bytes. If paddingInBytes is not null, padding // is also calculated in return. Returns NO_ERROR if succeed, otherwise // return the suggested GL error indicating the cause of the failure: // INVALID_VALUE if width/height is negative or overflow happens. // INVALID_ENUM if format/type is illegal. static GC3Denum computeImageSizeInBytes(GC3Denum format, GC3Denum type, GC3Dsizei width, GC3Dsizei height, GC3Dint alignment, unsigned int* imageSizeInBytes, unsigned int* paddingInBytes); // Attempt to enumerate all possible native image formats to // reduce the amount of temporary allocations during texture // uploading. This enum must be public because it is accessed // by non-member functions. enum DataFormat { DataFormatRGBA8 = 0, DataFormatRGBA16F, DataFormatRGBA32F, DataFormatRGB8, DataFormatRGB16F, DataFormatRGB32F, DataFormatBGR8, DataFormatBGRA8, DataFormatARGB8, DataFormatABGR8, DataFormatRGBA5551, DataFormatRGBA4444, DataFormatRGB565, DataFormatR8, DataFormatR16F, DataFormatR32F, DataFormatRA8, DataFormatRA16F, DataFormatRA32F, DataFormatAR8, DataFormatA8, DataFormatA16F, DataFormatA32F, DataFormatNumFormats }; // Check if the format is one of the formats from the ImageData or DOM elements. // The formats from ImageData is always RGBA8. // The formats from DOM elements vary with Graphics ports. It can only be RGBA8 or BGRA8. static ALWAYS_INLINE bool srcFormatComeFromDOMElementOrImageData(DataFormat SrcFormat) { return SrcFormat == DataFormatBGRA8 || SrcFormat == DataFormatRGBA8; } //---------------------------------------------------------------------- // Entry points for WebGL. // void activeTexture(GC3Denum texture); void attachShader(Platform3DObject program, Platform3DObject shader); void bindAttribLocation(Platform3DObject, GC3Duint index, const String& name); void bindBuffer(GC3Denum target, Platform3DObject); void bindFramebuffer(GC3Denum target, Platform3DObject); void bindRenderbuffer(GC3Denum target, Platform3DObject); void bindTexture(GC3Denum target, Platform3DObject); void blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha); void blendEquation(GC3Denum mode); void blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha); void blendFunc(GC3Denum sfactor, GC3Denum dfactor); void blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha); void bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage); void bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage); void bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data); GC3Denum checkFramebufferStatus(GC3Denum target); void clear(GC3Dbitfield mask); void clearColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha); void clearDepth(GC3Dclampf depth); void clearStencil(GC3Dint s); void colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha); void compileShader(Platform3DObject); void compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Dsizei imageSize, const void* data); void compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Dsizei imageSize, const void* data); void copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border); void copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); void cullFace(GC3Denum mode); void depthFunc(GC3Denum func); void depthMask(GC3Dboolean flag); void depthRange(GC3Dclampf zNear, GC3Dclampf zFar); void detachShader(Platform3DObject, Platform3DObject); void disable(GC3Denum cap); void disableVertexAttribArray(GC3Duint index); void drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count); void drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset); void enable(GC3Denum cap); void enableVertexAttribArray(GC3Duint index); void finish(); void flush(); void framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject); void framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject, GC3Dint level); void frontFace(GC3Denum mode); void generateMipmap(GC3Denum target); bool getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo&); bool getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo&); void getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders); GC3Dint getAttribLocation(Platform3DObject, const String& name); void getBooleanv(GC3Denum pname, GC3Dboolean* value); void getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); Attributes getContextAttributes(); GC3Denum getError(); void getFloatv(GC3Denum pname, GC3Dfloat* value); void getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum pname, GC3Dint* value); void getIntegerv(GC3Denum pname, GC3Dint* value); void getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value); String getProgramInfoLog(Platform3DObject); void getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); void getShaderiv(Platform3DObject, GC3Denum pname, GC3Dint* value); String getShaderInfoLog(Platform3DObject); void getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision); String getShaderSource(Platform3DObject); String getString(GC3Denum name); void getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value); void getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value); void getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value); void getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value); GC3Dint getUniformLocation(Platform3DObject, const String& name); void getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value); void getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value); GC3Dsizeiptr getVertexAttribOffset(GC3Duint index, GC3Denum pname); void hint(GC3Denum target, GC3Denum mode); GC3Dboolean isBuffer(Platform3DObject); GC3Dboolean isEnabled(GC3Denum cap); GC3Dboolean isFramebuffer(Platform3DObject); GC3Dboolean isProgram(Platform3DObject); GC3Dboolean isRenderbuffer(Platform3DObject); GC3Dboolean isShader(Platform3DObject); GC3Dboolean isTexture(Platform3DObject); void lineWidth(GC3Dfloat); void linkProgram(Platform3DObject); void pixelStorei(GC3Denum pname, GC3Dint param); void polygonOffset(GC3Dfloat factor, GC3Dfloat units); void readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data); void releaseShaderCompiler(); void renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height); void sampleCoverage(GC3Dclampf value, GC3Dboolean invert); void scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); void shaderSource(Platform3DObject, const String& string); void stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask); void stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask); void stencilMask(GC3Duint mask); void stencilMaskSeparate(GC3Denum face, GC3Duint mask); void stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass); void stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass); void texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels); void texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param); void texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param); void texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels); void uniform1f(GC3Dint location, GC3Dfloat x); void uniform1fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); void uniform1i(GC3Dint location, GC3Dint x); void uniform1iv(GC3Dint location, GC3Dsizei, GC3Dint* v); void uniform2f(GC3Dint location, GC3Dfloat x, GC3Dfloat y); void uniform2fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); void uniform2i(GC3Dint location, GC3Dint x, GC3Dint y); void uniform2iv(GC3Dint location, GC3Dsizei, GC3Dint* v); void uniform3f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z); void uniform3fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); void uniform3i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z); void uniform3iv(GC3Dint location, GC3Dsizei, GC3Dint* v); void uniform4f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w); void uniform4fv(GC3Dint location, GC3Dsizei, GC3Dfloat* v); void uniform4i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w); void uniform4iv(GC3Dint location, GC3Dsizei, GC3Dint* v); void uniformMatrix2fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); void uniformMatrix3fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); void uniformMatrix4fv(GC3Dint location, GC3Dsizei, GC3Dboolean transpose, GC3Dfloat* value); void useProgram(Platform3DObject); void validateProgram(Platform3DObject); void vertexAttrib1f(GC3Duint index, GC3Dfloat x); void vertexAttrib1fv(GC3Duint index, GC3Dfloat* values); void vertexAttrib2f(GC3Duint index, GC3Dfloat x, GC3Dfloat y); void vertexAttrib2fv(GC3Duint index, GC3Dfloat* values); void vertexAttrib3f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z); void vertexAttrib3fv(GC3Duint index, GC3Dfloat* values); void vertexAttrib4f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w); void vertexAttrib4fv(GC3Duint index, GC3Dfloat* values); void vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset); void viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height); void markContextChanged(); void markLayerComposited(); bool layerComposited() const; void paintRenderingResultsToCanvas(ImageBuffer*, DrawingBuffer*); PassRefPtr paintRenderingResultsToImageData(DrawingBuffer*, int&, int&); // Support for buffer creation and deletion Platform3DObject createBuffer(); Platform3DObject createFramebuffer(); Platform3DObject createProgram(); Platform3DObject createRenderbuffer(); Platform3DObject createShader(GC3Denum); Platform3DObject createTexture(); void deleteBuffer(Platform3DObject); void deleteFramebuffer(Platform3DObject); void deleteProgram(Platform3DObject); void deleteRenderbuffer(Platform3DObject); void deleteShader(Platform3DObject); void deleteTexture(Platform3DObject); // Synthesizes an OpenGL error which will be returned from a // later call to getError. This is used to emulate OpenGL ES // 2.0 behavior on the desktop and to enforce additional error // checking mandated by WebGL. // // Per the behavior of glGetError, this stores at most one // instance of any given error, and returns them from calls to // getError in the order they were added. void synthesizeGLError(GC3Denum error); // Support for extensions. Returns a non-null object, though not // all methods it contains may necessarily be supported on the // current hardware. Must call Extensions3D::supports() to // determine this. Extensions3D* extensions(); static unsigned getClearBitsByFormat(GC3Denum); enum ChannelBits { ChannelRed = 1, ChannelGreen = 2, ChannelBlue = 4, ChannelAlpha = 8, ChannelDepth = 16, ChannelStencil = 32, ChannelRGB = ChannelRed | ChannelGreen | ChannelBlue, ChannelRGBA = ChannelRGB | ChannelAlpha, }; static unsigned getChannelBitsByFormat(GC3Denum); // Possible alpha operations that may need to occur during // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must // be removed. enum AlphaOp { AlphaDoNothing = 0, AlphaDoPremultiply = 1, AlphaDoUnmultiply = 2 }; enum ImageHtmlDomSource { HtmlDomImage = 0, HtmlDomCanvas = 1, HtmlDomVideo = 2, HtmlDomNone = 3 }; class PLATFORM_EXPORT ImageExtractor { public: ImageExtractor(Image*, ImageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile); ~ImageExtractor(); bool extractSucceeded() { return m_extractSucceeded; } const void* imagePixelData() { return m_imagePixelData; } unsigned imageWidth() { return m_imageWidth; } unsigned imageHeight() { return m_imageHeight; } DataFormat imageSourceFormat() { return m_imageSourceFormat; } AlphaOp imageAlphaOp() { return m_alphaOp; } unsigned imageSourceUnpackAlignment() { return m_imageSourceUnpackAlignment; } ImageHtmlDomSource imageHtmlDomSource() { return m_imageHtmlDomSource; } private: // Extract the image and keeps track of its status, such as width, height, Source Alignment, format and AlphaOp etc. // This needs to lock the resources or relevant data if needed and return true upon success bool extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile); RefPtr m_nativeImage; RefPtr m_skiaImage; Image* m_image; ImageHtmlDomSource m_imageHtmlDomSource; bool m_extractSucceeded; const void* m_imagePixelData; unsigned m_imageWidth; unsigned m_imageHeight; DataFormat m_imageSourceFormat; AlphaOp m_alphaOp; unsigned m_imageSourceUnpackAlignment; }; // The Following functions are implemented in GraphicsContext3DImagePacking.cpp // Packs the contents of the given Image which is passed in |pixels| into the passed Vector // according to the given format and type, and obeying the flipY and AlphaOp flags. // Returns true upon success. static bool packImageData(Image*, const void* pixels, GC3Denum format, GC3Denum type, bool flipY, AlphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector& data); // Extracts the contents of the given ImageData into the passed Vector, // packing the pixel data according to the given format and type, // and obeying the flipY and premultiplyAlpha flags. Returns true // upon success. static bool extractImageData(const uint8_t*, const IntSize&, GC3Denum format, GC3Denum type, bool flipY, bool premultiplyAlpha, Vector& data); // Helper function which extracts the user-supplied texture // data, applying the flipY and premultiplyAlpha parameters. // If the data is not tightly packed according to the passed // unpackAlignment, the output data will be tightly packed. // Returns true if successful, false if any error occurred. static bool extractTextureData(unsigned width, unsigned height, GC3Denum format, GC3Denum type, unsigned unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, Vector& data); // End GraphicsContext3DImagePacking.cpp functions // This is the order of bytes to use when doing a readback. enum ReadbackOrder { ReadbackRGBA, ReadbackSkia }; // Helper function which does a readback from the currently-bound // framebuffer into a buffer of a certain size with 4-byte pixels. void readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder, AlphaOp); private: friend class Extensions3D; GraphicsContext3D(PassOwnPtr, bool preserveDrawingBuffer); GraphicsContext3D(PassOwnPtr, bool preserveDrawingBuffer); // Helper for packImageData/extractImageData/extractTextureData which implement packing of pixel // data into the specified OpenGL destination format and type. // A sourceUnpackAlignment of zero indicates that the source // data is tightly packed. Non-zero values may take a slow path. // Destination data will have no gaps between rows. // Implemented in GraphicsContext3DImagePacking.cpp static bool packPixels(const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, unsigned destinationFormat, unsigned destinationType, AlphaOp, void* destinationData, bool flipY); void paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer*); // Helper function to flip a bitmap vertically. void flipVertically(uint8_t* data, int width, int height); // Extensions3D support. bool supportsExtension(const String& name); bool ensureExtensionEnabled(const String& name); bool isExtensionEnabled(const String& name); void initializeExtensions(); bool preserveDrawingBuffer() const { return m_preserveDrawingBuffer; } OwnPtr m_provider; blink::WebGraphicsContext3D* m_impl; OwnPtr m_contextLostCallbackAdapter; OwnPtr m_errorMessageCallbackAdapter; OwnPtr m_ownedWebContext; OwnPtr m_extensions; bool m_initializedAvailableExtensions; HashSet m_enabledExtensions; HashSet m_requestableExtensions; bool m_layerComposited; bool m_preserveDrawingBuffer; int m_packAlignment; enum ResourceSafety { ResourceSafetyUnknown, ResourceSafe, ResourceUnsafe }; ResourceSafety m_resourceSafety; // If the width and height of the Canvas's backing store don't // match those that we were given in the most recent call to // reshape(), then we need an intermediate bitmap to read back the // frame buffer into. This seems to happen when CSS styles are // used to resize the Canvas. SkBitmap m_resizingBitmap; GrContext* m_grContext; // Used to flip a bitmap vertically. Vector m_scanline; }; } // namespace WebCore #endif // GraphicsContext3D_h