1154f4ee1d8c32363201b82eeab248616e942a8b
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / TextureMapperGL.cpp
1 /*
2  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3  Copyright (C) 2012 Igalia S.L.
4  Copyright (C) 2012 Adobe Systems Incorporated
5
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  Library General Public License for more details.
15
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB.  If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "TextureMapperGL.h"
24
25 #include "Extensions3D.h"
26 #include "FilterOperations.h"
27 #include "GraphicsContext.h"
28 #include "Image.h"
29 #include "LengthFunctions.h"
30 #include "NotImplemented.h"
31 #include "TextureMapperShaderProgram.h"
32 #include "Timer.h"
33 #include <wtf/HashMap.h>
34 #include <wtf/PassRefPtr.h>
35 #include <wtf/RefCounted.h>
36 #include <wtf/TemporaryChange.h>
37
38 #if USE(CAIRO)
39 #include "CairoUtilities.h"
40 #include "RefPtrCairo.h"
41 #include <cairo.h>
42 #include <wtf/text/CString.h>
43 #endif
44
45 #if !USE(TEXMAP_OPENGL_ES_2)
46 // FIXME: Move to Extensions3D.h.
47 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
48 #define GL_UNPACK_ROW_LENGTH 0x0CF2
49 #define GL_UNPACK_SKIP_PIXELS 0x0CF4
50 #define GL_UNPACK_SKIP_ROWS 0x0CF3
51 #endif
52
53 #if USE(TEXTURE_MAPPER)
54
55 namespace WebCore {
56 struct TextureMapperGLData {
57     WTF_MAKE_FAST_ALLOCATED;
58 public:
59     struct SharedGLData : public RefCounted<SharedGLData> {
60
61         typedef HashMap<PlatformGraphicsContext3D, SharedGLData*> GLContextDataMap;
62         static GLContextDataMap& glContextDataMap()
63         {
64             static GLContextDataMap map;
65             return map;
66         }
67
68         static PassRefPtr<SharedGLData> currentSharedGLData(GraphicsContext3D* context)
69         {
70             GLContextDataMap::iterator it = glContextDataMap().find(context->platformGraphicsContext3D());
71             if (it != glContextDataMap().end())
72                 return it->value;
73
74             return adoptRef(new SharedGLData(context));
75         }
76
77         PassRefPtr<TextureMapperShaderProgram> getShaderProgram(TextureMapperShaderProgram::Options options)
78         {
79             HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> >::AddResult result = m_programs.add(options, nullptr);
80             if (result.isNewEntry)
81                 result.iterator->value = TextureMapperShaderProgram::create(m_context, options);
82
83             return result.iterator->value;
84         }
85
86         HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> > m_programs;
87         RefPtr<GraphicsContext3D> m_context;
88
89         explicit SharedGLData(GraphicsContext3D* context)
90             : m_context(context)
91         {
92             glContextDataMap().add(context->platformGraphicsContext3D(), this);
93         }
94
95         ~SharedGLData()
96         {
97             for (auto it = glContextDataMap().begin(), end = glContextDataMap().end(); it != end; ++it) {
98                 if (it->value == this) {
99                     glContextDataMap().remove(it);
100                     return;
101                 }
102             }
103
104             ASSERT_NOT_REACHED();
105         }
106     };
107
108     SharedGLData& sharedGLData() const
109     {
110         return *sharedData;
111     }
112
113     void initializeStencil();
114
115     explicit TextureMapperGLData(GraphicsContext3D* context)
116         : context(context)
117         , PaintFlags(0)
118         , previousProgram(0)
119         , targetFrameBuffer(0)
120         , didModifyStencil(false)
121         , previousScissorState(0)
122         , previousDepthState(0)
123         , sharedData(TextureMapperGLData::SharedGLData::currentSharedGLData(this->context))
124         , filterInfo(0)
125     { }
126
127     ~TextureMapperGLData();
128     Platform3DObject getStaticVBO(GC3Denum target, GC3Dsizeiptr, const void* data);
129
130     GraphicsContext3D* context;
131     TransformationMatrix projectionMatrix;
132     TextureMapper::PaintFlags PaintFlags;
133     GC3Dint previousProgram;
134     GC3Dint targetFrameBuffer;
135     bool didModifyStencil;
136     GC3Dint previousScissorState;
137     GC3Dint previousDepthState;
138     GC3Dint viewport[4];
139     GC3Dint previousScissor[4];
140     RefPtr<SharedGLData> sharedData;
141     RefPtr<BitmapTexture> currentSurface;
142     HashMap<const void*, Platform3DObject> vbos;
143     const BitmapTextureGL::FilterInfo* filterInfo;
144 };
145
146 Platform3DObject TextureMapperGLData::getStaticVBO(GC3Denum target, GC3Dsizeiptr size, const void* data)
147 {
148     HashMap<const void*, Platform3DObject>::AddResult result = vbos.add(data, 0);
149     if (result.isNewEntry) {
150         Platform3DObject vbo = context->createBuffer();
151         context->bindBuffer(target, vbo);
152         context->bufferData(target, size, data, GraphicsContext3D::STATIC_DRAW);
153         result.iterator->value = vbo;
154     }
155
156     return result.iterator->value;
157 }
158
159 TextureMapperGLData::~TextureMapperGLData()
160 {
161     for (auto& entry : vbos)
162         context->deleteBuffer(entry.value);
163 }
164
165 void TextureMapperGL::ClipStack::reset(const IntRect& rect, TextureMapperGL::ClipStack::YAxisMode mode)
166 {
167     clipStack.clear();
168     size = rect.size();
169     yAxisMode = mode;
170     clipState = TextureMapperGL::ClipState(rect);
171     clipStateDirty = true;
172 }
173
174 void TextureMapperGL::ClipStack::intersect(const IntRect& rect)
175 {
176     clipState.scissorBox.intersect(rect);
177     clipStateDirty = true;
178 }
179
180 void TextureMapperGL::ClipStack::setStencilIndex(int stencilIndex)
181 {
182     clipState.stencilIndex = stencilIndex;
183     clipStateDirty = true;
184 }
185
186 void TextureMapperGL::ClipStack::push()
187 {
188     clipStack.append(clipState);
189     clipStateDirty = true;
190 }
191
192 void TextureMapperGL::ClipStack::pop()
193 {
194     if (clipStack.isEmpty())
195         return;
196     clipState = clipStack.last();
197     clipStack.removeLast();
198     clipStateDirty = true;
199 }
200
201 void TextureMapperGL::ClipStack::apply(GraphicsContext3D* context)
202 {
203     if (clipState.scissorBox.isEmpty())
204         return;
205
206     context->scissor(clipState.scissorBox.x(),
207         (yAxisMode == InvertedYAxis) ? size.height() - clipState.scissorBox.maxY() : clipState.scissorBox.y(),
208         clipState.scissorBox.width(), clipState.scissorBox.height());
209     context->stencilOp(GraphicsContext3D::KEEP, GraphicsContext3D::KEEP, GraphicsContext3D::KEEP);
210     context->stencilFunc(GraphicsContext3D::EQUAL, clipState.stencilIndex - 1, clipState.stencilIndex - 1);
211     if (clipState.stencilIndex == 1)
212         context->disable(GraphicsContext3D::STENCIL_TEST);
213     else
214         context->enable(GraphicsContext3D::STENCIL_TEST);
215 }
216
217 void TextureMapperGL::ClipStack::applyIfNeeded(GraphicsContext3D* context)
218 {
219     if (!clipStateDirty)
220         return;
221
222     clipStateDirty = false;
223     apply(context);
224 }
225
226 void TextureMapperGLData::initializeStencil()
227 {
228     if (currentSurface) {
229         static_cast<BitmapTextureGL*>(currentSurface.get())->initializeStencil();
230         return;
231     }
232
233     if (didModifyStencil)
234         return;
235
236     context->clearStencil(0);
237     context->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
238     didModifyStencil = true;
239 }
240
241 BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture)
242 {
243     if (!texture || !texture->isBackedByOpenGL())
244         return 0;
245
246     return static_cast<BitmapTextureGL*>(texture);
247 }
248
249 TextureMapperGL::TextureMapperGL()
250     : TextureMapper(OpenGLMode)
251     , m_enableEdgeDistanceAntialiasing(false)
252 {
253     m_context3D = GraphicsContext3D::createForCurrentGLContext();
254     m_data = new TextureMapperGLData(m_context3D.get());
255 }
256
257 TextureMapperGL::ClipStack& TextureMapperGL::clipStack()
258 {
259     return data().currentSurface ? toBitmapTextureGL(data().currentSurface.get())->m_clipStack : m_clipStack;
260 }
261
262 void TextureMapperGL::beginPainting(PaintFlags flags)
263 {
264     m_context3D->getIntegerv(GraphicsContext3D::CURRENT_PROGRAM, &data().previousProgram);
265     data().previousScissorState = m_context3D->isEnabled(GraphicsContext3D::SCISSOR_TEST);
266     data().previousDepthState = m_context3D->isEnabled(GraphicsContext3D::DEPTH_TEST);
267     m_context3D->disable(GraphicsContext3D::DEPTH_TEST);
268     m_context3D->enable(GraphicsContext3D::SCISSOR_TEST);
269     data().didModifyStencil = false;
270     m_context3D->depthMask(0);
271     m_context3D->getIntegerv(GraphicsContext3D::VIEWPORT, data().viewport);
272     m_context3D->getIntegerv(GraphicsContext3D::SCISSOR_BOX, data().previousScissor);
273     m_clipStack.reset(IntRect(0, 0, data().viewport[2], data().viewport[3]), ClipStack::InvertedYAxis);
274     m_context3D->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &data().targetFrameBuffer);
275     data().PaintFlags = flags;
276     bindSurface(0);
277 }
278
279 void TextureMapperGL::endPainting()
280 {
281     if (data().didModifyStencil) {
282         m_context3D->clearStencil(1);
283         m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
284     }
285
286     m_context3D->useProgram(data().previousProgram);
287
288     m_context3D->scissor(data().previousScissor[0], data().previousScissor[1], data().previousScissor[2], data().previousScissor[3]);
289     if (data().previousScissorState)
290         m_context3D->enable(GraphicsContext3D::SCISSOR_TEST);
291     else
292         m_context3D->disable(GraphicsContext3D::SCISSOR_TEST);
293
294     if (data().previousDepthState)
295         m_context3D->enable(GraphicsContext3D::DEPTH_TEST);
296     else
297         m_context3D->disable(GraphicsContext3D::DEPTH_TEST);
298 }
299
300 void TextureMapperGL::drawBorder(const Color& color, float width, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix)
301 {
302     if (clipStack().isCurrentScissorBoxEmpty())
303         return;
304
305     RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor);
306     m_context3D->useProgram(program->programID());
307
308     float r, g, b, a;
309     Color(premultipliedARGBFromColor(color)).getRGBA(r, g, b, a);
310     m_context3D->uniform4f(program->colorLocation(), r, g, b, a);
311     m_context3D->lineWidth(width);
312
313     draw(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::LINE_LOOP, color.hasAlpha() ? ShouldBlend : 0);
314 }
315
316 // FIXME: drawNumber() should save a number texture-atlas and re-use whenever possible.
317 void TextureMapperGL::drawNumber(int number, const Color& color, const FloatPoint& targetPoint, const TransformationMatrix& modelViewMatrix)
318 {
319     int pointSize = 8;
320
321 #if USE(CAIRO)
322     CString counterString = String::number(number).ascii();
323     // cairo_text_extents() requires a cairo_t, so dimensions need to be guesstimated.
324     int width = counterString.length() * pointSize * 1.2;
325     int height = pointSize * 1.5;
326
327     cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
328     cairo_t* cr = cairo_create(surface);
329
330     float r, g, b, a;
331     color.getRGBA(r, g, b, a);
332     cairo_set_source_rgba(cr, b, g, r, a); // Since we won't swap R+B when uploading a texture, paint with the swapped R+B color.
333     cairo_rectangle(cr, 0, 0, width, height);
334     cairo_fill(cr);
335
336     cairo_select_font_face(cr, "Monospace", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
337     cairo_set_font_size(cr, pointSize);
338     cairo_set_source_rgb(cr, 1, 1, 1);
339     cairo_move_to(cr, 2, pointSize);
340     cairo_show_text(cr, counterString.data());
341
342     IntSize size(width, height);
343     IntRect sourceRect(IntPoint::zero(), size);
344     IntRect targetRect(roundedIntPoint(targetPoint), size);
345
346     RefPtr<BitmapTexture> texture = acquireTextureFromPool(size);
347     const unsigned char* bits = cairo_image_surface_get_data(surface);
348     int stride = cairo_image_surface_get_stride(surface);
349     static_cast<BitmapTextureGL*>(texture.get())->updateContentsNoSwizzle(bits, sourceRect, IntPoint::zero(), stride);
350     drawTexture(*texture, targetRect, modelViewMatrix, 1.0f, AllEdges);
351
352     cairo_surface_destroy(surface);
353     cairo_destroy(cr);
354
355 #else
356     UNUSED_PARAM(number);
357     UNUSED_PARAM(pointSize);
358     UNUSED_PARAM(targetPoint);
359     UNUSED_PARAM(modelViewMatrix);
360     notImplemented();
361 #endif
362 }
363
364 static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation::OperationType type, unsigned pass)
365 {
366     switch (type) {
367     case FilterOperation::GRAYSCALE:
368         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::GrayscaleFilter;
369     case FilterOperation::SEPIA:
370         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SepiaFilter;
371     case FilterOperation::SATURATE:
372         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SaturateFilter;
373     case FilterOperation::HUE_ROTATE:
374         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::HueRotateFilter;
375     case FilterOperation::INVERT:
376         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::InvertFilter;
377     case FilterOperation::BRIGHTNESS:
378         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::BrightnessFilter;
379     case FilterOperation::CONTRAST:
380         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::ContrastFilter;
381     case FilterOperation::OPACITY:
382         return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::OpacityFilter;
383     case FilterOperation::BLUR:
384         return TextureMapperShaderProgram::BlurFilter;
385     case FilterOperation::DROP_SHADOW:
386         return TextureMapperShaderProgram::AlphaBlur
387             | (pass ? TextureMapperShaderProgram::ContentTexture | TextureMapperShaderProgram::SolidColor: 0);
388     default:
389         ASSERT_NOT_REACHED();
390         return 0;
391     }
392 }
393
394 static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
395 {
396     switch (type) {
397     case FilterOperation::GRAYSCALE:
398     case FilterOperation::SEPIA:
399     case FilterOperation::SATURATE:
400     case FilterOperation::HUE_ROTATE:
401     case FilterOperation::INVERT:
402     case FilterOperation::BRIGHTNESS:
403     case FilterOperation::CONTRAST:
404     case FilterOperation::OPACITY:
405         return 1;
406     case FilterOperation::BLUR:
407     case FilterOperation::DROP_SHADOW:
408         // We use two-passes (vertical+horizontal) for blur and drop-shadow.
409         return 2;
410     default:
411         return 0;
412     }
413 }
414
415 // Create a normal distribution of 21 values between -2 and 2.
416 static const unsigned GaussianKernelHalfWidth = 11;
417 static const float GaussianKernelStep = 0.2;
418
419 static inline float gauss(float x)
420 {
421     return exp(-(x * x) / 2.);
422 }
423
424 static float* gaussianKernel()
425 {
426     static bool prepared = false;
427     static float kernel[GaussianKernelHalfWidth] = {0, };
428
429     if (prepared)
430         return kernel;
431
432     kernel[0] = gauss(0);
433     float sum = kernel[0];
434     for (unsigned i = 1; i < GaussianKernelHalfWidth; ++i) {
435         kernel[i] = gauss(i * GaussianKernelStep);
436         sum += 2 * kernel[i];
437     }
438
439     // Normalize the kernel.
440     float scale = 1 / sum;
441     for (unsigned i = 0; i < GaussianKernelHalfWidth; ++i)
442         kernel[i] *= scale;
443
444     prepared = true;
445     return kernel;
446 }
447
448 static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture)
449 {
450     RefPtr<GraphicsContext3D> context = program->context();
451     context->useProgram(program->programID());
452
453     switch (operation.type()) {
454     case FilterOperation::GRAYSCALE:
455     case FilterOperation::SEPIA:
456     case FilterOperation::SATURATE:
457     case FilterOperation::HUE_ROTATE:
458         context->uniform1f(program->filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount());
459         break;
460     case FilterOperation::INVERT:
461     case FilterOperation::BRIGHTNESS:
462     case FilterOperation::CONTRAST:
463     case FilterOperation::OPACITY:
464         context->uniform1f(program->filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount());
465         break;
466     case FilterOperation::BLUR: {
467         const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation);
468         FloatSize radius;
469
470         // Blur is done in two passes, first horizontally and then vertically. The same shader is used for both.
471         if (pass)
472             radius.setHeight(floatValueForLength(blur.stdDeviation(), size.height()) / size.height());
473         else
474             radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width());
475
476         context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height());
477         context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
478         break;
479     }
480     case FilterOperation::DROP_SHADOW: {
481         const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation);
482         context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
483         switch (pass) {
484         case 0:
485             // First pass: horizontal alpha blur.
486             context->uniform2f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0);
487             context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height()));
488             break;
489         case 1:
490             // Second pass: we need the shadow color and the content texture for compositing.
491             float r, g, b, a;
492             Color(premultipliedARGBFromColor(shadow.color())).getRGBA(r, g, b, a);
493             context->uniform4f(program->colorLocation(), r, g, b, a);
494             context->uniform2f(program->blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height()));
495             context->uniform2f(program->shadowOffsetLocation(), 0, 0);
496             context->activeTexture(GraphicsContext3D::TEXTURE1);
497             context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture);
498             context->uniform1i(program->contentTextureLocation(), 1);
499             break;
500         }
501         break;
502     }
503     default:
504         break;
505     }
506 }
507
508 void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned exposedEdges)
509 {
510     if (!texture.isValid())
511         return;
512
513     if (clipStack().isCurrentScissorBoxEmpty())
514         return;
515
516     const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture);
517     TemporaryChange<const BitmapTextureGL::FilterInfo*> filterInfo(data().filterInfo, textureGL.filterInfo());
518
519     drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : ShouldBlend, textureGL.size(), targetRect, matrix, opacity, exposedEdges);
520 }
521
522 void TextureMapperGL::drawTexture(Platform3DObject texture, Flags flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, unsigned exposedEdges)
523 {
524     bool useRect = flags & ShouldUseARBTextureRect;
525     bool useAntialiasing = m_enableEdgeDistanceAntialiasing
526         && exposedEdges == AllEdges
527         && !modelViewMatrix.mapQuad(targetRect).isRectilinear();
528
529     TextureMapperShaderProgram::Options options = TextureMapperShaderProgram::Texture;
530     if (useRect)
531         options |= TextureMapperShaderProgram::Rect;
532     if (opacity < 1)
533         options |= TextureMapperShaderProgram::Opacity;
534     if (useAntialiasing) {
535         options |= TextureMapperShaderProgram::Antialiasing;
536         flags |= ShouldAntialias;
537     }
538
539     RefPtr<FilterOperation> filter = data().filterInfo ? data().filterInfo->filter: 0;
540     GC3Duint filterContentTextureID = 0;
541
542     if (filter) {
543         if (data().filterInfo->contentTexture)
544             filterContentTextureID = toBitmapTextureGL(data().filterInfo->contentTexture.get())->id();
545         options |= optionsForFilterType(filter->type(), data().filterInfo->pass);
546         if (filter->affectsOpacity())
547             flags |= ShouldBlend;
548     }
549
550     if (useAntialiasing || opacity < 1)
551         flags |= ShouldBlend;
552
553     RefPtr<TextureMapperShaderProgram> program;
554     program = data().sharedGLData().getShaderProgram(options);
555
556     if (filter)
557         prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
558
559     drawTexturedQuadWithProgram(program.get(), texture, flags, textureSize, targetRect, modelViewMatrix, opacity);
560 }
561
562 void TextureMapperGL::drawSolidColor(const FloatRect& rect, const TransformationMatrix& matrix, const Color& color)
563 {
564     Flags flags = 0;
565     TextureMapperShaderProgram::Options options = TextureMapperShaderProgram::SolidColor;
566     if (!matrix.mapQuad(rect).isRectilinear()) {
567         options |= TextureMapperShaderProgram::Antialiasing;
568         flags |= ShouldBlend | ShouldAntialias;
569     }
570
571     RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options);
572     m_context3D->useProgram(program->programID());
573
574     float r, g, b, a;
575     Color(premultipliedARGBFromColor(color)).getRGBA(r, g, b, a);
576     m_context3D->uniform4f(program->colorLocation(), r, g, b, a);
577     if (a < 1)
578         flags |= ShouldBlend;
579
580     draw(rect, matrix, program.get(), GraphicsContext3D::TRIANGLE_FAN, flags);
581 }
582
583 void TextureMapperGL::drawEdgeTriangles(TextureMapperShaderProgram* program)
584 {
585     const GC3Dfloat left = 0;
586     const GC3Dfloat top = 0;
587     const GC3Dfloat right = 1;
588     const GC3Dfloat bottom = 1;
589     const GC3Dfloat center = 0.5;
590
591 // Each 4d triangle consists of a center point and two edge points, where the zw coordinates
592 // of each vertex equals the nearest point to the vertex on the edge.
593 #define SIDE_TRIANGLE_DATA(x1, y1, x2, y2) \
594     x1, y1, x1, y1, \
595     x2, y2, x2, y2, \
596     center, center, (x1 + x2) / 2, (y1 + y2) / 2
597
598     static const GC3Dfloat unitRectSideTriangles[] = {
599         SIDE_TRIANGLE_DATA(left, top, right, top),
600         SIDE_TRIANGLE_DATA(left, top, left, bottom),
601         SIDE_TRIANGLE_DATA(right, top, right, bottom),
602         SIDE_TRIANGLE_DATA(left, bottom, right, bottom)
603     };
604 #undef SIDE_TRIANGLE_DATA
605
606     Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 48, unitRectSideTriangles);
607     m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo);
608     m_context3D->vertexAttribPointer(program->vertexLocation(), 4, GraphicsContext3D::FLOAT, false, 0, 0);
609     m_context3D->drawArrays(GraphicsContext3D::TRIANGLES, 0, 12);
610     m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
611 }
612
613 void TextureMapperGL::drawUnitRect(TextureMapperShaderProgram* program, GC3Denum drawingMode)
614 {
615     static const GC3Dfloat unitRect[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
616     Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 8, unitRect);
617     m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo);
618     m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0);
619     m_context3D->drawArrays(drawingMode, 0, 4);
620     m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
621 }
622
623 void TextureMapperGL::draw(const FloatRect& rect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GC3Denum drawingMode, Flags flags)
624 {
625     TransformationMatrix matrix =
626         TransformationMatrix(modelViewMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), rect));
627
628     m_context3D->enableVertexAttribArray(shaderProgram->vertexLocation());
629     shaderProgram->setMatrix(shaderProgram->modelViewMatrixLocation(), matrix);
630     shaderProgram->setMatrix(shaderProgram->projectionMatrixLocation(), data().projectionMatrix);
631
632     if (isInMaskMode()) {
633         m_context3D->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA);
634         m_context3D->enable(GraphicsContext3D::BLEND);
635     } else {
636         if (flags & ShouldBlend) {
637             m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
638             m_context3D->enable(GraphicsContext3D::BLEND);
639         } else
640             m_context3D->disable(GraphicsContext3D::BLEND);
641     }
642
643     if (flags & ShouldAntialias)
644         drawEdgeTriangles(shaderProgram);
645     else
646         drawUnitRect(shaderProgram, drawingMode);
647
648     m_context3D->disableVertexAttribArray(shaderProgram->vertexLocation());
649     m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA);
650     m_context3D->enable(GraphicsContext3D::BLEND);
651 }
652
653 void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* program, uint32_t texture, Flags flags, const IntSize& size, const FloatRect& rect, const TransformationMatrix& modelViewMatrix, float opacity)
654 {
655     m_context3D->useProgram(program->programID());
656     m_context3D->activeTexture(GraphicsContext3D::TEXTURE0);
657     GC3Denum target = flags & ShouldUseARBTextureRect ? GC3Denum(Extensions3D::TEXTURE_RECTANGLE_ARB) : GC3Denum(GraphicsContext3D::TEXTURE_2D);
658     m_context3D->bindTexture(target, texture);
659     m_context3D->uniform1i(program->samplerLocation(), 0);
660     if (wrapMode() == RepeatWrap) {
661         m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::REPEAT);
662         m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::REPEAT);
663     }
664
665     TransformationMatrix patternTransform = this->patternTransform();
666     if (flags & ShouldFlipTexture)
667         patternTransform.flipY();
668     if (flags & ShouldUseARBTextureRect)
669         patternTransform.scaleNonUniform(size.width(), size.height());
670     if (flags & ShouldFlipTexture)
671         patternTransform.translate(0, -1);
672
673     program->setMatrix(program->textureSpaceMatrixLocation(), patternTransform);
674     m_context3D->uniform1f(program->opacityLocation(), opacity);
675
676     if (opacity < 1)
677         flags |= ShouldBlend;
678
679     draw(rect, modelViewMatrix, program, GraphicsContext3D::TRIANGLE_FAN, flags);
680     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
681     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
682 }
683
684 BitmapTextureGL::BitmapTextureGL(TextureMapperGL* textureMapper)
685     : m_id(0)
686     , m_fbo(0)
687     , m_rbo(0)
688     , m_depthBufferObject(0)
689     , m_shouldClear(true)
690     , m_context3D(textureMapper->graphicsContext3D())
691 {
692 }
693
694 bool BitmapTextureGL::canReuseWith(const IntSize& contentsSize, Flags)
695 {
696     return contentsSize == m_textureSize;
697 }
698
699 #if OS(DARWIN)
700 #define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
701 #else
702 #define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GraphicsContext3D::UNSIGNED_BYTE
703 #endif
704
705 static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0)
706 {
707     stride = stride ? stride : rect.width();
708     for (int y = rect.y(); y < rect.maxY(); ++y) {
709         uint32_t* p = data + y * stride;
710         for (int x = rect.x(); x < rect.maxX(); ++x)
711             p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
712     }
713 }
714
715 // If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES
716 // internal and external formats need to be BGRA
717 static bool driverSupportsExternalTextureBGRA(GraphicsContext3D* context)
718 {
719     if (context->isGLES2Compliant()) {
720         static bool supportsExternalTextureBGRA = context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888");
721         return supportsExternalTextureBGRA;
722     }
723
724     return true;
725 }
726
727 static bool driverSupportsSubImage(GraphicsContext3D* context)
728 {
729     if (context->isGLES2Compliant()) {
730         static bool supportsSubImage = context->getExtensions()->supports("GL_EXT_unpack_subimage");
731         return supportsSubImage;
732     }
733
734     return true;
735 }
736
737 void BitmapTextureGL::didReset()
738 {
739     if (!m_id)
740         m_id = m_context3D->createTexture();
741
742     m_shouldClear = true;
743     if (m_textureSize == contentSize())
744         return;
745
746
747     m_textureSize = contentSize();
748     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
749     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
750     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
751     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
752     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
753
754     Platform3DObject internalFormat = GraphicsContext3D::RGBA;
755     Platform3DObject externalFormat = GraphicsContext3D::BGRA;
756     if (m_context3D->isGLES2Compliant()) {
757         if (driverSupportsExternalTextureBGRA(m_context3D.get()))
758             internalFormat = GraphicsContext3D::BGRA;
759         else
760             externalFormat = GraphicsContext3D::RGBA;
761     }
762
763     m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, internalFormat, m_textureSize.width(), m_textureSize.height(), 0, externalFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, 0);
764 }
765
766 void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat)
767 {
768     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
769     if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images.
770         // Use the OpenGL sub-image extension, now that we know it's available.
771         m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel);
772         m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, sourceOffset.y());
773         m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, sourceOffset.x());
774     }
775
776     m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, srcData);
777
778     if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images.
779         m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, 0);
780         m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, 0);
781         m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
782     }
783 }
784
785 void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag)
786 {
787     Platform3DObject glFormat = GraphicsContext3D::RGBA;
788     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
789
790     const unsigned bytesPerPixel = 4;
791     char* data = reinterpret_cast<char*>(const_cast<void*>(srcData));
792     Vector<char> temporaryData;
793     IntPoint adjustedSourceOffset = sourceOffset;
794
795     // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload.
796     bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get())
797         && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero());
798
799     // prepare temporaryData if necessary
800     if ((!driverSupportsExternalTextureBGRA(m_context3D.get()) && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) {
801         temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel);
802         data = temporaryData.data();
803         const char* bits = static_cast<const char*>(srcData);
804         const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel;
805         char* dst = data;
806         const int targetBytesPerLine = targetRect.width() * bytesPerPixel;
807         for (int y = 0; y < targetRect.height(); ++y) {
808             memcpy(dst, src, targetBytesPerLine);
809             src += bytesPerLine;
810             dst += targetBytesPerLine;
811         }
812
813         bytesPerLine = targetBytesPerLine;
814         adjustedSourceOffset = IntPoint(0, 0);
815     }
816
817     if (driverSupportsExternalTextureBGRA(m_context3D.get()))
818         glFormat = GraphicsContext3D::BGRA;
819     else
820         swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel);
821
822     updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, glFormat);
823 }
824
825 void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag)
826 {
827     if (!image)
828         return;
829     NativeImagePtr frameImage = image->nativeImageForCurrentFrame();
830     if (!frameImage)
831         return;
832
833     int bytesPerLine;
834     const char* imageData;
835
836 #if USE(CAIRO)
837     cairo_surface_t* surface = frameImage.get();
838     imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface));
839     bytesPerLine = cairo_image_surface_get_stride(surface);
840 #endif
841
842     updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag);
843 }
844
845 void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture* contentTexture, const FilterOperation& filter, int pass)
846 {
847     // For standard filters, we always draw the whole texture without transformations.
848     TextureMapperShaderProgram::Options options = optionsForFilterType(filter.type(), pass);
849     RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options);
850     ASSERT(program);
851
852     prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), contentTexture ? static_cast<const BitmapTextureGL*>(contentTexture)->id() : 0);
853     FloatRect targetRect(IntPoint::zero(), sampler.contentSize());
854     drawTexturedQuadWithProgram(program.get(), static_cast<const BitmapTextureGL&>(sampler).id(), 0, IntSize(1, 1), targetRect, TransformationMatrix(), 1);
855 }
856
857 PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const FilterOperations& filters)
858 {
859     if (filters.isEmpty())
860         return this;
861
862     TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper);
863     RefPtr<BitmapTexture> previousSurface = texmapGL->data().currentSurface;
864     RefPtr<BitmapTexture> resultSurface = this;
865     RefPtr<BitmapTexture> intermediateSurface;
866     RefPtr<BitmapTexture> spareSurface;
867
868     m_filterInfo = FilterInfo();
869
870     for (size_t i = 0; i < filters.size(); ++i) {
871         RefPtr<FilterOperation> filter = filters.operations()[i];
872         ASSERT(filter);
873
874         int numPasses = getPassesRequiredForFilter(filter->type());
875         for (int j = 0; j < numPasses; ++j) {
876             bool last = (i == filters.size() - 1) && (j == numPasses - 1);
877             if (!last) {
878                 if (!intermediateSurface)
879                     intermediateSurface = texmapGL->acquireTextureFromPool(contentSize());
880                 texmapGL->bindSurface(intermediateSurface.get());
881             }
882
883             if (last) {
884                 toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface);
885                 break;
886             }
887
888             texmapGL->drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j);
889             if (!j && filter->type() == FilterOperation::DROP_SHADOW) {
890                 spareSurface = resultSurface;
891                 resultSurface.clear();
892             }
893             std::swap(resultSurface, intermediateSurface);
894         }
895     }
896
897     texmapGL->bindSurface(previousSurface.get());
898     return resultSurface;
899 }
900
901 static inline TransformationMatrix createProjectionMatrix(const IntSize& size, bool mirrored)
902 {
903     const float nearValue = 9999999;
904     const float farValue = -99999;
905
906     return TransformationMatrix(2.0 / float(size.width()), 0, 0, 0,
907                                 0, (mirrored ? 2.0 : -2.0) / float(size.height()), 0, 0,
908                                 0, 0, -2.f / (farValue - nearValue), 0,
909                                 -1, mirrored ? -1 : 1, -(farValue + nearValue) / (farValue - nearValue), 1);
910 }
911
912 void BitmapTextureGL::initializeStencil()
913 {
914     if (m_rbo)
915         return;
916
917     m_rbo = m_context3D->createRenderbuffer();
918     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo);
919 #ifdef TEXMAP_OPENGL_ES_2
920     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height());
921 #else
922     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_STENCIL, m_textureSize.width(), m_textureSize.height());
923 #endif
924     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
925     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo);
926     m_context3D->clearStencil(0);
927     m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
928 }
929
930 void BitmapTextureGL::initializeDepthBuffer()
931 {
932     if (m_depthBufferObject)
933         return;
934
935     m_depthBufferObject = m_context3D->createRenderbuffer();
936     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
937     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height());
938     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
939     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
940 }
941
942 void BitmapTextureGL::clearIfNeeded()
943 {
944     if (!m_shouldClear)
945         return;
946
947     m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), TextureMapperGL::ClipStack::DefaultYAxis);
948     m_clipStack.applyIfNeeded(m_context3D.get());
949     m_context3D->clearColor(0, 0, 0, 0);
950     m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
951     m_shouldClear = false;
952 }
953
954 void BitmapTextureGL::createFboIfNeeded()
955 {
956     if (m_fbo)
957         return;
958
959     m_fbo = m_context3D->createFramebuffer();
960     m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
961     m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0);
962     m_shouldClear = true;
963 }
964
965 void BitmapTextureGL::bind(TextureMapperGL* textureMapper)
966 {
967     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
968     createFboIfNeeded();
969     m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
970     m_context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height());
971     clearIfNeeded();
972     textureMapper->data().projectionMatrix = createProjectionMatrix(m_textureSize, true /* mirrored */);
973     m_clipStack.apply(m_context3D.get());
974 }
975
976 BitmapTextureGL::~BitmapTextureGL()
977 {
978     if (m_id)
979         m_context3D->deleteTexture(m_id);
980
981     if (m_fbo)
982         m_context3D->deleteFramebuffer(m_fbo);
983
984     if (m_rbo)
985         m_context3D->deleteRenderbuffer(m_rbo);
986
987     if (m_depthBufferObject)
988         m_context3D->deleteRenderbuffer(m_depthBufferObject);
989 }
990
991 bool BitmapTextureGL::isValid() const
992 {
993     return m_id;
994 }
995
996 IntSize BitmapTextureGL::size() const
997 {
998     return m_textureSize;
999 }
1000
1001 TextureMapperGL::~TextureMapperGL()
1002 {
1003     delete m_data;
1004 }
1005
1006 void TextureMapperGL::bindDefaultSurface()
1007 {
1008     m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, data().targetFrameBuffer);
1009     IntSize viewportSize(data().viewport[2], data().viewport[3]);
1010     data().projectionMatrix = createProjectionMatrix(viewportSize, data().PaintFlags & PaintingMirrored);
1011     m_context3D->viewport(data().viewport[0], data().viewport[1], viewportSize.width(), viewportSize.height());
1012     m_clipStack.apply(m_context3D.get());
1013     data().currentSurface.clear();
1014 }
1015
1016 void TextureMapperGL::bindSurface(BitmapTexture *surface)
1017 {
1018     if (!surface) {
1019         bindDefaultSurface();
1020         return;
1021     }
1022
1023     static_cast<BitmapTextureGL*>(surface)->bind(this);
1024     data().currentSurface = surface;
1025 }
1026
1027 bool TextureMapperGL::beginScissorClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect)
1028 {
1029     // 3D transforms are currently not supported in scissor clipping
1030     // resulting in cropped surfaces when z>0.
1031     if (!modelViewMatrix.isAffine())
1032         return false;
1033
1034     FloatQuad quad = modelViewMatrix.projectQuad(targetRect);
1035     IntRect rect = quad.enclosingBoundingBox();
1036
1037     // Only use scissors on rectilinear clips.
1038     if (!quad.isRectilinear() || rect.isEmpty())
1039         return false;
1040
1041     clipStack().intersect(rect);
1042     clipStack().applyIfNeeded(m_context3D.get());
1043     return true;
1044 }
1045
1046 void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect)
1047 {
1048     clipStack().push();
1049     if (beginScissorClip(modelViewMatrix, targetRect))
1050         return;
1051
1052     data().initializeStencil();
1053
1054     RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor);
1055
1056     m_context3D->useProgram(program->programID());
1057     m_context3D->enableVertexAttribArray(program->vertexLocation());
1058     const GC3Dfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1};
1059     m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(unitRect));
1060
1061     TransformationMatrix matrix = TransformationMatrix(modelViewMatrix)
1062         .multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect));
1063
1064     static const TransformationMatrix fullProjectionMatrix = TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), FloatRect(-1, -1, 2, 2));
1065
1066     int stencilIndex = clipStack().getStencilIndex();
1067
1068     m_context3D->enable(GraphicsContext3D::STENCIL_TEST);
1069
1070     // Make sure we don't do any actual drawing.
1071     m_context3D->stencilFunc(GraphicsContext3D::NEVER, stencilIndex, stencilIndex);
1072
1073     // Operate only on the stencilIndex and above.
1074     m_context3D->stencilMask(0xff & ~(stencilIndex - 1));
1075
1076     // First clear the entire buffer at the current index.
1077     program->setMatrix(program->projectionMatrixLocation(), fullProjectionMatrix);
1078     program->setMatrix(program->modelViewMatrixLocation(), TransformationMatrix());
1079     m_context3D->stencilOp(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO, GraphicsContext3D::ZERO);
1080     m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4);
1081
1082     // Now apply the current index to the new quad.
1083     m_context3D->stencilOp(GraphicsContext3D::REPLACE, GraphicsContext3D::REPLACE, GraphicsContext3D::REPLACE);
1084     program->setMatrix(program->projectionMatrixLocation(), data().projectionMatrix);
1085     program->setMatrix(program->modelViewMatrixLocation(), matrix);
1086     m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4);
1087
1088     // Clear the state.
1089     m_context3D->disableVertexAttribArray(program->vertexLocation());
1090     m_context3D->stencilMask(0);
1091
1092     // Increase stencilIndex and apply stencil testing.
1093     clipStack().setStencilIndex(stencilIndex * 2);
1094     clipStack().applyIfNeeded(m_context3D.get());
1095 }
1096
1097 void TextureMapperGL::endClip()
1098 {
1099     clipStack().pop();
1100     clipStack().applyIfNeeded(m_context3D.get());
1101 }
1102
1103 IntRect TextureMapperGL::clipBounds()
1104 {
1105     return clipStack().current().scissorBox;
1106 }
1107
1108 PassRefPtr<BitmapTexture> TextureMapperGL::createTexture()
1109 {
1110     BitmapTextureGL* texture = new BitmapTextureGL(this);
1111     return adoptRef(texture);
1112 }
1113
1114 #if USE(TEXTURE_MAPPER_GL)
1115 std::unique_ptr<TextureMapper> TextureMapper::platformCreateAccelerated()
1116 {
1117     return std::make_unique<TextureMapperGL>();
1118 }
1119 #endif
1120
1121 };
1122 #endif