Mozart: Specify texture origin explicitly.

Previously we assumed the origin was always top-left but OpenGL
likes to create textures with the origin in the bottom-left.
Since we don't always get what we want in this life, let the client
specify what origin it used.  Maybe later we can grumble about it
and replace (or augment) this with a more general means of specifying
texture coordinates or texture matrices for rendering.

Flipping the node's coordinate system upside-down in Spinning Cube
has undesirable consequences on the input dispatch (since the events
get flipped too, as expected) so it was time to remove the old hack
and resolve the origin problem.

BUG=
R=abarth@google.com

Review URL: https://codereview.chromium.org/1776643004 .
diff --git a/examples/ui/spinning_cube/spinning_cube_view.cc b/examples/ui/spinning_cube/spinning_cube_view.cc
index 294d328..7b090b6 100644
--- a/examples/ui/spinning_cube/spinning_cube_view.cc
+++ b/examples/ui/spinning_cube/spinning_cube_view.cc
@@ -163,10 +163,6 @@
   auto root_node = mojo::gfx::composition::Node::New();
   root_node->content_transform = mojo::Transform::New();
   mojo::SetIdentityTransform(root_node->content_transform.get());
-  // TODO(jeffbrown): Figure out why spinning cube is drawing upside down.
-  // Other GL based programs don't seem to have this problem.
-  root_node->content_transform->matrix[5] = -1;  // flip image vertically
-  root_node->content_transform->matrix[7] = size_.height;
   root_node->op = mojo::gfx::composition::NodeOp::New();
   root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New());
   root_node->op->get_image()->content_rect = bounds.Clone();
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/gfx/composition/resources.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/gfx/composition/resources.mojom.dart
index 945acea..1ea62bf 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/gfx/composition/resources.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/gfx/composition/resources.mojom.dart
@@ -85,12 +85,65 @@
 }
 
 
+class MailboxTextureResourceOrigin extends bindings.MojoEnum {
+  static const MailboxTextureResourceOrigin topLeft = const MailboxTextureResourceOrigin._(0);
+  static const MailboxTextureResourceOrigin bottomLeft = const MailboxTextureResourceOrigin._(1);
+
+  const MailboxTextureResourceOrigin._(int v) : super(v);
+
+  static const Map<String, MailboxTextureResourceOrigin> valuesMap = const {
+    "topLeft": topLeft,
+    "bottomLeft": bottomLeft,
+  };
+  static const List<MailboxTextureResourceOrigin> values = const [
+    topLeft,
+    bottomLeft,
+  ];
+
+  static MailboxTextureResourceOrigin valueOf(String name) => valuesMap[name];
+
+  factory MailboxTextureResourceOrigin(int v) {
+    switch (v) {
+      case 0:
+        return MailboxTextureResourceOrigin.topLeft;
+      case 1:
+        return MailboxTextureResourceOrigin.bottomLeft;
+      default:
+        return null;
+    }
+  }
+
+  static MailboxTextureResourceOrigin decode(bindings.Decoder decoder0, int offset) {
+    int v = decoder0.decodeUint32(offset);
+    MailboxTextureResourceOrigin result = new MailboxTextureResourceOrigin(v);
+    if (result == null) {
+      throw new bindings.MojoCodecError(
+          'Bad value $v for enum MailboxTextureResourceOrigin.');
+    }
+    return result;
+  }
+
+  String toString() {
+    switch(this) {
+      case topLeft:
+        return 'MailboxTextureResourceOrigin.topLeft';
+      case bottomLeft:
+        return 'MailboxTextureResourceOrigin.bottomLeft';
+      default:
+        return null;
+    }
+  }
+
+  int toJson() => mojoEnumValue;
+}
+
 class MailboxTextureResource extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(40, 0)
   ];
   List<int> mailboxName = null;
   int syncPoint = 0;
+  MailboxTextureResourceOrigin origin = new MailboxTextureResourceOrigin(0);
   geometry_mojom.Size size = null;
   Object callback = null;
 
@@ -139,6 +192,14 @@
     }
     if (mainDataHeader.version >= 0) {
       
+        result.origin = MailboxTextureResourceOrigin.decode(decoder0, 20);
+        if (result.origin == null) {
+          throw new bindings.MojoCodecError(
+            'Trying to decode null union for non-nullable MailboxTextureResourceOrigin.');
+        }
+    }
+    if (mainDataHeader.version >= 0) {
+      
       var decoder1 = decoder0.decodePointer(24, false);
       result.size = geometry_mojom.Size.decode(decoder1);
     }
@@ -166,6 +227,13 @@
       rethrow;
     }
     try {
+      encoder0.encodeEnum(origin, 20);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "origin of struct MailboxTextureResource: $e";
+      rethrow;
+    }
+    try {
       encoder0.encodeStruct(size, 24, false);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
@@ -185,6 +253,7 @@
     return "MailboxTextureResource("
            "mailboxName: $mailboxName" ", "
            "syncPoint: $syncPoint" ", "
+           "origin: $origin" ", "
            "size: $size" ", "
            "callback: $callback" ")";
   }
diff --git a/mojo/services/gfx/composition/cpp/formatting.cc b/mojo/services/gfx/composition/cpp/formatting.cc
index 4666619..73911be 100644
--- a/mojo/services/gfx/composition/cpp/formatting.cc
+++ b/mojo/services/gfx/composition/cpp/formatting.cc
@@ -80,7 +80,20 @@
     std::ostream& os,
     const mojo::gfx::composition::MailboxTextureResource& value) {
   return os << "{sync_point=" << value.sync_point << ", size=" << value.size
-            << "}";
+            << ", origin=" << &value.origin << "}";
+}
+
+std::ostream& operator<<(
+    std::ostream& os,
+    const mojo::gfx::composition::MailboxTextureResource::Origin* value) {
+  switch (*value) {
+    case mojo::gfx::composition::MailboxTextureResource::Origin::TOP_LEFT:
+      return os << "TOP_LEFT";
+    case mojo::gfx::composition::MailboxTextureResource::Origin::BOTTOM_LEFT:
+      return os << "BOTTOM_LEFT";
+    default:
+      return os << "???";
+  }
 }
 
 std::ostream& operator<<(std::ostream& os,
diff --git a/mojo/services/gfx/composition/cpp/formatting.h b/mojo/services/gfx/composition/cpp/formatting.h
index baf8eec..38f43be 100644
--- a/mojo/services/gfx/composition/cpp/formatting.h
+++ b/mojo/services/gfx/composition/cpp/formatting.h
@@ -28,6 +28,9 @@
 std::ostream& operator<<(
     std::ostream& os,
     const mojo::gfx::composition::MailboxTextureResource& value);
+std::ostream& operator<<(
+    std::ostream& os,
+    const mojo::gfx::composition::MailboxTextureResource::Origin* value);
 
 std::ostream& operator<<(std::ostream& os,
                          const mojo::gfx::composition::Node& value);
diff --git a/mojo/services/gfx/composition/interfaces/resources.mojom b/mojo/services/gfx/composition/interfaces/resources.mojom
index f2f9a52..71c73eb 100644
--- a/mojo/services/gfx/composition/interfaces/resources.mojom
+++ b/mojo/services/gfx/composition/interfaces/resources.mojom
@@ -37,6 +37,12 @@
 //
 // TODO(jeffbrown): Replace this with Image and ImagePipe.
 struct MailboxTextureResource {
+  // The origin of the texture.
+  enum Origin {
+    TOP_LEFT,
+    BOTTOM_LEFT,
+  };
+
   // The name of the mailbox, as produced by glGenMailboxCHROMIUM().
   array<uint8, 64> mailbox_name;
 
@@ -47,6 +53,9 @@
   // The size of the texture in pixels.
   mojo.Size size;
 
+  // The origin of the texture.
+  Origin origin = Origin.TOP_LEFT;
+
   // The callback interface to be notified when it is safe to release or
   // recycle the underlying texture storage once the resource has been
   // removed from the scene.
diff --git a/mojo/skia/ganesh_image_factory.cc b/mojo/skia/ganesh_image_factory.cc
index 5300d99..23d38ab 100644
--- a/mojo/skia/ganesh_image_factory.cc
+++ b/mojo/skia/ganesh_image_factory.cc
@@ -29,6 +29,7 @@
     uint32_t texture_id,
     uint32_t width,
     uint32_t height,
+    GrSurfaceOrigin origin,
     const base::Closure& release_callback) {
   DCHECK(texture_id);
   DCHECK(width);
@@ -44,7 +45,7 @@
   desc.fWidth = width;
   desc.fHeight = height;
   desc.fConfig = kSkia8888_GrPixelConfig;
-  desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+  desc.fOrigin = origin;
   desc.fTextureHandle = reinterpret_cast<GrBackendObject>(&info);
   return ::skia::AdoptRef(SkImage::NewFromTexture(
       scope.gr_context(), desc, kPremul_SkAlphaType, &ReleaseThunk,
@@ -55,9 +56,11 @@
     const GLbyte mailbox_name[GL_MAILBOX_SIZE_CHROMIUM],
     GLuint sync_point,
     uint32_t width,
-    uint32_t height)
+    uint32_t height,
+    GrSurfaceOrigin origin)
     : SkImageGenerator(SkImageInfo::MakeN32Premul(width, height)),
-      sync_point_(sync_point) {
+      sync_point_(sync_point),
+      origin_(origin) {
   DCHECK(mailbox_name);
   memcpy(mailbox_name_, mailbox_name, GL_MAILBOX_SIZE_CHROMIUM);
 }
@@ -85,7 +88,7 @@
   desc.fWidth = getInfo().width();
   desc.fHeight = getInfo().height();
   desc.fConfig = kSkia8888_GrPixelConfig;
-  desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+  desc.fOrigin = origin_;
   desc.fTextureHandle = reinterpret_cast<GrBackendObject>(&info);
   return context->textureProvider()->wrapBackendTexture(desc,
                                                         kAdopt_GrWrapOwnership);
diff --git a/mojo/skia/ganesh_image_factory.h b/mojo/skia/ganesh_image_factory.h
index ae4bfc0..ddd3630 100644
--- a/mojo/skia/ganesh_image_factory.h
+++ b/mojo/skia/ganesh_image_factory.h
@@ -12,6 +12,7 @@
 #include "mojo/skia/ganesh_context.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkImageGenerator.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
 
 class SkImage;
 
@@ -26,6 +27,7 @@
     uint32_t texture_id,
     uint32_t width,
     uint32_t height,
+    GrSurfaceOrigin origin,
     const base::Closure& release_callback);
 
 // Generates backing content for SkImages from a texture mailbox.
@@ -39,7 +41,8 @@
       const GLbyte mailbox_name[GL_MAILBOX_SIZE_CHROMIUM],
       GLuint sync_point,
       uint32_t width,
-      uint32_t height);
+      uint32_t height,
+      GrSurfaceOrigin origin);
   ~MailboxTextureImageGenerator() override;
 
   GrTexture* onGenerateTexture(GrContext* context,
@@ -48,6 +51,7 @@
  private:
   GLbyte mailbox_name_[GL_MAILBOX_SIZE_CHROMIUM];
   GLuint sync_point_;
+  GrSurfaceOrigin origin_;
 };
 
 }  // namespace skia
diff --git a/mojo/ui/ganesh_renderer.cc b/mojo/ui/ganesh_renderer.cc
index a1f47b3..0587305 100644
--- a/mojo/ui/ganesh_renderer.cc
+++ b/mojo/ui/ganesh_renderer.cc
@@ -38,7 +38,9 @@
     texture = texture_surface.TakeTexture();
   }
 
-  return gl_renderer_.BindTextureResource(std::move(texture));
+  return gl_renderer_.BindTextureResource(
+      std::move(texture),
+      mojo::gfx::composition::MailboxTextureResource::Origin::TOP_LEFT);
 }
 
 static void RunCanvasCallback(
diff --git a/mojo/ui/gl_renderer.cc b/mojo/ui/gl_renderer.cc
index 3adf507..3e60c82 100644
--- a/mojo/ui/gl_renderer.cc
+++ b/mojo/ui/gl_renderer.cc
@@ -45,7 +45,8 @@
 }
 
 mojo::gfx::composition::ResourcePtr GLRenderer::BindTextureResource(
-    std::unique_ptr<GLTexture> texture) {
+    std::unique_ptr<GLTexture> texture,
+    mojo::gfx::composition::MailboxTextureResource::Origin origin) {
   if (!gl_context_)
     return nullptr;
 
@@ -67,6 +68,7 @@
          sizeof(mailbox));
   resource->get_mailbox_texture()->sync_point = sync_point;
   resource->get_mailbox_texture()->size = texture->size().Clone();
+  resource->get_mailbox_texture()->origin = origin;
   resource->get_mailbox_texture()->callback =
       (new GLTextureReleaser(
            weak_factory_.GetWeakPtr(),
diff --git a/mojo/ui/gl_renderer.h b/mojo/ui/gl_renderer.h
index a21c799..71cf0d9 100644
--- a/mojo/ui/gl_renderer.h
+++ b/mojo/ui/gl_renderer.h
@@ -47,7 +47,9 @@
   // The caller should add the resource to its scene.
   // Returns a nullptr if the GLContext was destroyed.
   mojo::gfx::composition::ResourcePtr BindTextureResource(
-      std::unique_ptr<GLTexture> texture);
+      std::unique_ptr<GLTexture> texture,
+      mojo::gfx::composition::MailboxTextureResource::Origin origin =
+          mojo::gfx::composition::MailboxTextureResource::Origin::BOTTOM_LEFT);
 
   // Allocates a GL texture, binds it to a framebuffer, invokes the
   // provided function, then returns the resulting resource.
diff --git a/services/gfx/compositor/graph/scene_def.cc b/services/gfx/compositor/graph/scene_def.cc
index 649c43e..1a8e4ef 100644
--- a/services/gfx/compositor/graph/scene_def.cc
+++ b/services/gfx/compositor/graph/scene_def.cc
@@ -193,9 +193,11 @@
     const GLbyte* const mailbox_name = reinterpret_cast<GLbyte*>(
         mailbox_texture_resource_decl->mailbox_name.data());
     const GLuint sync_point = mailbox_texture_resource_decl->sync_point;
+    const mojo::gfx::composition::MailboxTextureResource::Origin origin =
+        mailbox_texture_resource_decl->origin;
 
     std::shared_ptr<RenderImage> image = RenderImage::CreateFromMailboxTexture(
-        mailbox_name, sync_point, width, height,
+        mailbox_name, sync_point, width, height, origin,
         base::MessageLoop::current()->task_runner(),
         base::Bind(
             &ReleaseMailboxTexture,
diff --git a/services/gfx/compositor/render/render_image.cc b/services/gfx/compositor/render/render_image.cc
index a62a289..1d34675 100644
--- a/services/gfx/compositor/render/render_image.cc
+++ b/services/gfx/compositor/render/render_image.cc
@@ -33,8 +33,13 @@
             const GLbyte mailbox_name[GL_MAILBOX_SIZE_CHROMIUM],
             GLuint sync_point,
             uint32_t width,
-            uint32_t height)
-      : MailboxTextureImageGenerator(mailbox_name, sync_point, width, height),
+            uint32_t height,
+            GrSurfaceOrigin origin)
+      : MailboxTextureImageGenerator(mailbox_name,
+                                     sync_point,
+                                     width,
+                                     height,
+                                     origin),
         releaser_(releaser) {
     DCHECK(releaser_);
   }
@@ -59,12 +64,17 @@
     GLuint sync_point,
     uint32_t width,
     uint32_t height,
+    mojo::gfx::composition::MailboxTextureResource::Origin origin,
     const scoped_refptr<base::TaskRunner>& task_runner,
     const base::Closure& release_task) {
   std::shared_ptr<Releaser> releaser =
       std::make_shared<Releaser>(task_runner, release_task);
   skia::RefPtr<SkImage> image = skia::AdoptRef(SkImage::NewFromGenerator(
-      new Generator(releaser, mailbox_name, sync_point, width, height)));
+      new Generator(releaser, mailbox_name, sync_point, width, height,
+                    origin == mojo::gfx::composition::MailboxTextureResource::
+                                  Origin::BOTTOM_LEFT
+                        ? kBottomLeft_GrSurfaceOrigin
+                        : kTopLeft_GrSurfaceOrigin)));
   if (!image)
     return nullptr;
 
diff --git a/services/gfx/compositor/render/render_image.h b/services/gfx/compositor/render/render_image.h
index f90e579..f1d65b3 100644
--- a/services/gfx/compositor/render/render_image.h
+++ b/services/gfx/compositor/render/render_image.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/task_runner.h"
+#include "mojo/services/gfx/composition/interfaces/resources.mojom.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkImage.h"
 
@@ -45,6 +46,7 @@
       GLuint sync_point,
       uint32_t width,
       uint32_t height,
+      mojo::gfx::composition::MailboxTextureResource::Origin origin,
       const scoped_refptr<base::TaskRunner>& task_runner,
       const base::Closure& release_task);