Bug 1514803 - Replace XPCOM image encoder instance creation in gfxUtils::EncodeSourceSurface r=jrmuizel
authorBarret Rennie <barret@brennie.ca>
Wed, 09 Jan 2019 16:29:33 +0000
changeset 510174 cf9a58cbb9040639fb3f83e2f7b70e6f4b4518e8
parent 510173 ebeed768822e5d860e9f051c12f1800197e3697c
child 510175 47ced8013922dad7c08afd513cf07b00c22672a1
child 510203 5029552447c130b47c28cb86ed80fb68ce6de186
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1514803
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1514803 - Replace XPCOM image encoder instance creation in gfxUtils::EncodeSourceSurface r=jrmuizel gfxUtils::EncodeSourceSurface no longer uses a stringly-typed API to create a `imgIEncoder` for the relevant MIME type. Instead, we now use an enum class and switch on it to create the encoder. Depends on D14816 Differential Revision: https://phabricator.services.mozilla.com/D14817
gfx/layers/ProfilerScreenshots.cpp
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
widget/windows/WinUtils.cpp
--- a/gfx/layers/ProfilerScreenshots.cpp
+++ b/gfx/layers/ProfilerScreenshots.cpp
@@ -93,19 +93,18 @@ void ProfilerScreenshots::SubmitScreensh
           RefPtr<DataSourceSurface> surf =
               Factory::CreateWrappingDataSourceSurface(
                   scopedMap.GetData(), scopedMap.GetStride(), scaledSize,
                   SurfaceFormat::B8G8R8A8);
 
           // Encode surf to a JPEG data URL.
           nsCString dataURL;
           nsresult rv = gfxUtils::EncodeSourceSurface(
-              surf, NS_LITERAL_CSTRING("image/jpeg"),
-              NS_LITERAL_STRING("quality=85"), gfxUtils::eDataURIEncode,
-              nullptr, &dataURL);
+              surf, ImageType::JPEG, NS_LITERAL_STRING("quality=85"),
+              gfxUtils::eDataURIEncode, nullptr, &dataURL);
           if (NS_SUCCEEDED(rv)) {
             // Add a marker with the data URL.
             profiler_add_marker_for_thread(
                 sourceThread, "CompositorScreenshot",
                 MakeUnique<ScreenshotPayload>(timeStamp, std::move(dataURL),
                                               originalSize, windowIdentifier));
           }
         }
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -18,28 +18,33 @@
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/Swizzle.h"
 #include "mozilla/gfx/gfxVars.h"
+#include "mozilla/image/nsBMPEncoder.h"
+#include "mozilla/image/nsICOEncoder.h"
+#include "mozilla/image/nsJPEGEncoder.h"
+#include "mozilla/image/nsPNGEncoder.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Vector.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "nsAppRunner.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIClipboardHelper.h"
 #include "nsIFile.h"
 #include "nsIGfxInfo.h"
 #include "nsIPresShell.h"
+#include "nsMimeTypes.h"
 #include "nsPresContext.h"
 #include "nsRegion.h"
 #include "nsServiceManagerUtils.h"
 #include "GeckoProfiler.h"
 #include "ImageContainer.h"
 #include "ImageRegion.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
@@ -891,17 +896,17 @@ const uint32_t gfxUtils::sNumFrameColors
     MOZ_ASSERT(i == sNumFrameColors);
     initialized = true;
   }
 
   return colors[aFrameNumber % sNumFrameColors];
 }
 
 /* static */ nsresult gfxUtils::EncodeSourceSurface(
-    SourceSurface* aSurface, const nsACString& aMimeType,
+    SourceSurface* aSurface, const ImageType aImageType,
     const nsAString& aOutputOptions, BinaryOrData aBinaryOrData, FILE* aFile,
     nsACString* aStrOut) {
   MOZ_ASSERT(aBinaryOrData == gfxUtils::eDataURIEncode || aFile || aStrOut,
              "Copying binary encoding to clipboard not currently supported");
 
   const IntSize size = aSurface->GetSize();
   if (size.IsEmpty()) {
     return NS_ERROR_INVALID_ARG;
@@ -920,35 +925,41 @@ const uint32_t gfxUtils::sNumFrameColors
     return NS_ERROR_FAILURE;
   }
 
   DataSourceSurface::MappedSurface map;
   if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     return NS_ERROR_FAILURE;
   }
 
-  nsAutoCString encoderCID(
-      NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
-  nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
-  if (!encoder) {
-#ifdef DEBUG
-    int32_t w = std::min(size.width, 8);
-    int32_t h = std::min(size.height, 8);
-    printf("Could not create encoder. Top-left %dx%d pixels contain:\n", w, h);
-    for (int32_t y = 0; y < h; ++y) {
-      for (int32_t x = 0; x < w; ++x) {
-        printf("%x ",
-               reinterpret_cast<uint32_t*>(map.mData)[y * map.mStride + x]);
-      }
-    }
-#endif
-    dataSurface->Unmap();
-    return NS_ERROR_FAILURE;
+  RefPtr<imgIEncoder> encoder = nullptr;
+
+  switch (aImageType) {
+    case ImageType::BMP:
+      encoder = MakeRefPtr<nsBMPEncoder>();
+      break;
+
+    case ImageType::ICO:
+      encoder = MakeRefPtr<nsICOEncoder>();
+      break;
+
+    case ImageType::JPEG:
+      encoder = MakeRefPtr<nsJPEGEncoder>();
+      break;
+
+    case ImageType::PNG:
+      encoder = MakeRefPtr<nsPNGEncoder>();
+      break;
+
+    default:
+      break;
   }
 
+  MOZ_RELEASE_ASSERT(encoder != nullptr);
+
   nsresult rv = encoder->InitFromData(
       map.mData, BufferSizeFromStrideAndHeight(map.mStride, size.height),
       size.width, size.height, map.mStride, imgIEncoder::INPUT_FORMAT_HOSTARGB,
       aOutputOptions);
   dataSurface->Unmap();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInputStream> imgStream(encoder);
@@ -1001,52 +1012,71 @@ const uint32_t gfxUtils::sNumFrameColors
   }
 
   // base 64, result will be null-terminated
   nsCString encodedImg;
   rv = Base64Encode(Substring(imgData.begin(), imgSize), encodedImg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString stringBuf;
-  nsACString& string = aStrOut ? *aStrOut : stringBuf;
-  string.AppendLiteral("data:");
-  string.Append(aMimeType);
-  string.AppendLiteral(";base64,");
-  string.Append(encodedImg);
+  nsACString& dataURI = aStrOut ? *aStrOut : stringBuf;
+  dataURI.AppendLiteral("data:");
+
+  switch (aImageType) {
+    case ImageType::BMP:
+      dataURI.AppendLiteral(IMAGE_BMP);
+      break;
+
+    case ImageType::ICO:
+      dataURI.AppendLiteral(IMAGE_ICO_MS);
+      break;
+    case ImageType::JPEG:
+      dataURI.AppendLiteral(IMAGE_JPEG);
+      break;
+
+    case ImageType::PNG:
+      dataURI.AppendLiteral(IMAGE_PNG);
+      break;
+
+    default:
+      break;
+  }
+
+  dataURI.AppendLiteral(";base64,");
+  dataURI.Append(encodedImg);
 
   if (aFile) {
 #ifdef ANDROID
     if (aFile == stdout || aFile == stderr) {
       // ADB logcat cuts off long strings so we will break it down
-      const char* cStr = string.BeginReading();
+      const char* cStr = dataURI.BeginReading();
       size_t len = strlen(cStr);
       while (true) {
         printf_stderr("IMG: %.140s\n", cStr);
         if (len <= 140) break;
         len -= 140;
         cStr += 140;
       }
     }
 #endif
-    fprintf(aFile, "%s", string.BeginReading());
+    fprintf(aFile, "%s", dataURI.BeginReading());
   } else if (!aStrOut) {
     nsCOMPtr<nsIClipboardHelper> clipboard(
         do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
     if (clipboard) {
-      clipboard->CopyString(NS_ConvertASCIItoUTF16(string));
+      clipboard->CopyString(NS_ConvertASCIItoUTF16(dataURI));
     }
   }
   return NS_OK;
 }
 
 static nsCString EncodeSourceSurfaceAsPNGURI(SourceSurface* aSurface) {
   nsCString string;
-  gfxUtils::EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
-                                EmptyString(), gfxUtils::eDataURIEncode,
-                                nullptr, &string);
+  gfxUtils::EncodeSourceSurface(aSurface, ImageType::PNG, EmptyString(),
+                                gfxUtils::eDataURIEncode, nullptr, &string);
   return string;
 }
 
 // https://jdashg.github.io/misc/colors/from-coeffs.html
 const float kBT601NarrowYCbCrToRGB_RowMajor[16] = {
     1.16438f,  0.00000f, 1.59603f, -0.87420f, 1.16438f, -0.39176f,
     -0.81297f, 0.53167f, 1.16438f, 2.01723f,  0.00000f, -1.08563f,
     0.00000f,  0.00000f, 0.00000f, 1.00000f};
@@ -1149,18 +1179,18 @@ const float kBT709NarrowYCbCrToRGB_RowMa
       }
     }
     if (!file) {
       NS_WARNING("Failed to open file to create PNG!");
       return;
     }
   }
 
-  EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), EmptyString(),
-                      eBinaryEncode, file);
+  EncodeSourceSurface(aSurface, ImageType::PNG, EmptyString(), eBinaryEncode,
+                      file);
   fclose(file);
 }
 
 /* static */ void gfxUtils::WriteAsPNG(DrawTarget* aDT,
                                        const nsAString& aFile) {
   WriteAsPNG(aDT, NS_ConvertUTF16toUTF8(aFile).get());
 }
 
@@ -1187,18 +1217,18 @@ const float kBT709NarrowYCbCrToRGB_RowMa
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(context);  // already checked the draw target above
   aShell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context);
   WriteAsPNG(dt.get(), aFile);
 }
 
 /* static */ void gfxUtils::DumpAsDataURI(SourceSurface* aSurface,
                                           FILE* aFile) {
-  EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), EmptyString(),
-                      eDataURIEncode, aFile);
+  EncodeSourceSurface(aSurface, ImageType::PNG, EmptyString(), eDataURIEncode,
+                      aFile);
 }
 
 /* static */ nsCString gfxUtils::GetAsDataURI(SourceSurface* aSurface) {
   return EncodeSourceSurfaceAsPNGURI(aSurface);
 }
 
 /* static */ void gfxUtils::DumpAsDataURI(DrawTarget* aDT, FILE* aFile) {
   RefPtr<SourceSurface> surface = aDT->Snapshot();
@@ -1240,18 +1270,18 @@ const float kBT709NarrowYCbCrToRGB_RowMa
     return EncodeSourceSurfaceAsPNGURI(surface);
   } else {
     NS_WARNING("Failed to get surface!");
     return nsCString("");
   }
 }
 
 /* static */ void gfxUtils::CopyAsDataURI(SourceSurface* aSurface) {
-  EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"), EmptyString(),
-                      eDataURIEncode, nullptr);
+  EncodeSourceSurface(aSurface, ImageType::PNG, EmptyString(), eDataURIEncode,
+                      nullptr);
 }
 
 /* static */ void gfxUtils::CopyAsDataURI(DrawTarget* aDT) {
   RefPtr<SourceSurface> surface = aDT->Snapshot();
   if (surface) {
     CopyAsDataURI(surface);
   } else {
     NS_WARNING("Failed to get surface!");
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -36,16 +36,23 @@ class WebRenderCommand;
 namespace image {
 class ImageRegion;
 }  // namespace image
 namespace wr {
 class DisplayListBuilder;
 }  // namespace wr
 }  // namespace mozilla
 
+enum class ImageType {
+  BMP,
+  ICO,
+  JPEG,
+  PNG,
+};
+
 class gfxUtils {
  public:
   typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::IntPoint IntPoint;
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::SourceSurface SourceSurface;
   typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
@@ -220,19 +227,18 @@ class gfxUtils {
 
   enum BinaryOrData { eBinaryEncode, eDataURIEncode };
 
   /**
    * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder.
    * If both aFile and aString are null, the encoded data is copied to the
    * clipboard.
    *
-   * @param aMimeType The MIME-type of the image type that the surface is to
-   *   be encoded to. Used to create an appropriate imgIEncoder instance to
-   *   do the encoding.
+   * @param aImageType The image type that the surface is to be encoded to.
+   *   Used to create an appropriate imgIEncoder instance to do the encoding.
    *
    * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
    *   the value of the |outputOptions| parameter. Callers are responsible
    *   for making sure that this is a sane value for the passed MIME-type
    *   (i.e. for the type of encoder that will be created).
    *
    * @aBinaryOrData Flag used to determine if the surface is simply encoded
    *   to the requested binary image format, or if the binary image is
@@ -241,17 +247,17 @@ class gfxUtils {
    * @aFile If specified, the encoded data is written out to aFile.
    *
    * @aString If specified, the encoded data is written out to aString.
    *
    * TODO: Copying to the clipboard as a binary file is not currently
    * supported.
    */
   static nsresult EncodeSourceSurface(SourceSurface* aSurface,
-                                      const nsACString& aMimeType,
+                                      const ImageType aImageType,
                                       const nsAString& aOutputOptions,
                                       BinaryOrData aBinaryOrData, FILE* aFile,
                                       nsACString* aString = nullptr);
 
   /**
    * Write as a PNG file to the path aFile.
    */
   static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile);
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -1295,18 +1295,17 @@ NS_IMETHODIMP AsyncEncodeAndWriteIcon::R
         }
       }
     }
     if (!file) {
       return rv;
     }
   }
   nsresult rv = gfxUtils::EncodeSourceSurface(
-      surface, NS_LITERAL_CSTRING("image/vnd.microsoft.icon"), EmptyString(),
-      gfxUtils::eBinaryEncode, file);
+      surface, ImageType::ICO, EmptyString(), gfxUtils::eBinaryEncode, file);
   fclose(file);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mURLShortcut) {
     SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS,
                       0);
   }
   return rv;