[Image-Orientation] Implement WebGL image-orientation

M-87 merge.

When creating textures for WebGL, always orient images
with EXIF orientation data.

This change also corrects the transposed size reported by
ImageBitmap. And it removes superfluous arguments from
CopyImageData.

(cherry picked from commit f373458c504c2d115c42f31b29ff5c19674acbbc)

Bug: 1100470, 1125337
Change-Id: I79aa798327a3582939aa574723926b3325c80e7c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2459400
Reviewed-by: Kenneth Russell <[email protected]>
Commit-Queue: Stephen Chenney <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#815359}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2464430
Reviewed-by: Stephen Chenney <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#274}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 08a9129..7a5f455e 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -173,11 +173,12 @@
 
 // This function results in a readback due to using SkImage::readPixels().
 // Returns transparent black pixels if the input SkImageInfo.bounds() does
-// not intersect with the input image boundaries.
+// not intersect with the input image boundaries. When apply_orientation
+// is true this method will orient the data according to the source's EXIF
+// information.
 Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input,
                               const SkImageInfo& info,
-                              const unsigned x = 0,
-                              const unsigned y = 0) {
+                              bool apply_orientation = true) {
   if (info.isEmpty())
     return {};
   PaintImage paint_image = input->PaintImageForCurrentFrame();
@@ -189,16 +190,29 @@
   Vector<uint8_t> dst_buffer(byte_length);
 
   bool read_pixels_successful =
-      paint_image.readPixels(info, dst_buffer.data(), info.minRowBytes(), x, y);
+      paint_image.readPixels(info, dst_buffer.data(), info.minRowBytes(), 0, 0);
   DCHECK(read_pixels_successful);
   if (!read_pixels_successful)
     return {};
+
+  // Orient the data, and re-read the pixels.
+  if (apply_orientation && !input->HasDefaultOrientation()) {
+    paint_image = Image::ResizeAndOrientImage(
+        paint_image, input->CurrentFrameOrientation(), FloatSize(1, 1), 1,
+        kInterpolationNone);
+    read_pixels_successful = paint_image.readPixels(info, dst_buffer.data(),
+                                                    info.minRowBytes(), 0, 0);
+    DCHECK(read_pixels_successful);
+    if (!read_pixels_successful)
+      return {};
+  }
+
   return dst_buffer;
 }
 
 Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input) {
   SkImageInfo info = GetSkImageInfo(input);
-  return CopyImageData(std::move(input), info);
+  return CopyImageData(std::move(input), info, false);
 }
 
 static inline bool ShouldAvoidPremul(
@@ -1058,12 +1072,13 @@
   auto color_type = info.colorType();
   if (color_type == kN32_SkColorType && u8_color_type == kRGBAColorType)
     color_type = kRGBA_8888_SkColorType;
+  // Note that width() and height() here apply EXIF orientation
   info =
       SkImageInfo::Make(width(), height(), color_type,
                         (alpha_op == kPremultiplyAlpha) ? kPremul_SkAlphaType
                                                         : kUnpremul_SkAlphaType,
                         info.refColorSpace());
-  return CopyImageData(image_, info);
+  return CopyImageData(image_, info, true);
 }
 
 Vector<uint8_t> ImageBitmap::CopyBitmapData() {
@@ -1095,7 +1110,7 @@
     return IntSize();
   DCHECK_GT(image_->width(), 0);
   DCHECK_GT(image_->height(), 0);
-  return IntSize(image_->width(), image_->height());
+  return image_->SizeRespectingOrientation();
 }
 
 ScriptPromise ImageBitmap::CreateImageBitmap(ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 98aadee5..59f4135 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -5466,10 +5466,12 @@
     return;
 
   scoped_refptr<Image> image_for_render = image->CachedImage()->GetImage();
-  if (IsA<SVGImage>(image_for_render.get())) {
-    if (canvas()) {
+  bool have_svg_image = IsA<SVGImage>(image_for_render.get());
+  if (have_svg_image || !image_for_render->HasDefaultOrientation()) {
+    if (have_svg_image && canvas()) {
       UseCounter::Count(canvas()->GetDocument(), WebFeature::kSVGInWebGL);
     }
+    // DrawImageIntoBuffer always respects orientation
     image_for_render =
         DrawImageIntoBuffer(std::move(image_for_render), image->width(),
                             image->height(), func_name);
@@ -6005,6 +6007,7 @@
                        level, internalformat, width, height, depth, 0, format,
                        type, xoffset, yoffset, zoffset))
     return;
+
   scoped_refptr<StaticBitmapImage> image = bitmap->BitmapImage();
   DCHECK(image);
 
@@ -6031,9 +6034,16 @@
     return;
   }
 
+  // Apply orientation if necessary
+  PaintImage paint_image = bitmap->BitmapImage()->PaintImageForCurrentFrame();
+  if (!image->HasDefaultOrientation()) {
+    paint_image = Image::ResizeAndOrientImage(
+        paint_image, image->CurrentFrameOrientation(), FloatSize(1, 1), 1,
+        kInterpolationNone);
+  }
+
   // TODO(kbr): refactor this away to use TexImageImpl on image.
-  sk_sp<SkImage> sk_image =
-      bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSwSkImage();
+  sk_sp<SkImage> sk_image = paint_image.GetSwSkImage();
   if (!sk_image) {
     SynthesizeGLError(GL_OUT_OF_MEMORY, func_name,
                       "ImageBitmap unexpectedly empty");