Make SkImageGeneratorCG apply encoded origin

SkImageGeneratorCG:
- Detect the origin and apply it to the output
- Deprecate NewFromEncodedCG and add MakeFromEncodedCG

SkCodecImageGenerator:
- Move code elsewhere for sharing
- Apply origin for incomplete decodes

SkPixmap.cpp/SkPixmapPriv.h:
- Now has the shared code for generators to apply origin

DMSrcSink.cpp:
- Call MakeFromEncodedCG

SkCGUtils.h:
- Add a version of SkCopyPixelsFromCGImage that takes an SkPixmap

Bug: skia:7138
Bug: skia:3834
Change-Id: Ic6dbc76360c6a84913b67373582f328d3946d637
Reviewed-on: https://skia-review.googlesource.com/63740
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 6af90c3..fc535dc 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -942,7 +942,7 @@
             break;
         case kPlatform_Mode: {
 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
-            gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded.get()));
+            gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
 #elif defined(SK_BUILD_FOR_WIN)
             gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get()));
 #endif
diff --git a/include/utils/mac/SkCGUtils.h b/include/utils/mac/SkCGUtils.h
index 2dcbb96..06995c3 100644
--- a/include/utils/mac/SkCGUtils.h
+++ b/include/utils/mac/SkCGUtils.h
@@ -11,6 +11,7 @@
 #include "SkSize.h"
 #include "SkImageInfo.h"
 #include "SkImage.h"
+#include "SkPixmap.h"
 
 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
 
@@ -46,6 +47,9 @@
  */
 SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels,
                                     CGImageRef src);
+static inline bool SkCopyPixelsFromCGImage(const SkPixmap& dst, CGImageRef src) {
+    return SkCopyPixelsFromCGImage(dst.info(), dst.rowBytes(), dst.writable_addr(), src);
+}
 
 /**
  *  Create an imageref from the specified bitmap using the specified colorspace.
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index 741c8e3..3f03b2f 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -5,42 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "SkAutoPixmapStorage.h"
 #include "SkCodecImageGenerator.h"
 #include "SkMakeUnique.h"
 #include "SkPixmapPriv.h"
 
-#define kMirrorX    SkPixmapPriv::kMirrorX
-#define kMirrorY    SkPixmapPriv::kMirrorY
-#define kSwapXY     SkPixmapPriv::kSwapXY
-
-const uint8_t gOrientationFlags[] = {
-    0,                              // kTopLeft_SkEncodedOrigin
-    kMirrorX,                       // kTopRight_SkEncodedOrigin
-    kMirrorX | kMirrorY,            // kBottomRight_SkEncodedOrigin
-               kMirrorY,            // kBottomLeft_SkEncodedOrigin
-                          kSwapXY,  // kLeftTop_SkEncodedOrigin
-    kMirrorX            | kSwapXY,  // kRightTop_SkEncodedOrigin
-    kMirrorX | kMirrorY | kSwapXY,  // kRightBottom_SkEncodedOrigin
-               kMirrorY | kSwapXY,  // kLeftBottom_SkEncodedOrigin
-};
-
-SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
-    unsigned io = static_cast<int>(o) - 1;
-    SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
-    return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
-}
-
-static bool should_swap_width_height(SkEncodedOrigin o) {
-    return SkToBool(SkPixmapPriv::OriginToOrient(o) & kSwapXY);
-}
-
-static SkImageInfo swap_width_height(SkImageInfo info) {
-    return info.makeWH(info.height(), info.width());
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
 std::unique_ptr<SkImageGenerator> SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp<SkData> data) {
     auto codec = SkCodec::MakeFromData(data);
     if (nullptr == codec) {
@@ -55,8 +23,8 @@
     if (kUnpremul_SkAlphaType == info.alphaType()) {
         info = info.makeAlphaType(kPremul_SkAlphaType);
     }
-    if (should_swap_width_height(codec->getOrigin())) {
-        info = swap_width_height(info);
+    if (SkPixmapPriv::ShouldSwapWidthHeight(codec->getOrigin())) {
+        info = SkPixmapPriv::SwapWidthHeight(info);
     }
     return info;
 }
@@ -73,39 +41,23 @@
 
 bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& requestInfo, void* requestPixels,
                                         size_t requestRowBytes, const Options& opts) {
-    const auto origin = fCodec->getOrigin();
-    const SkPixmap request(requestInfo, requestPixels, requestRowBytes);
-    const SkPixmap* codecMap = &request;
-    SkAutoPixmapStorage storage;    // used if we have to post-orient the output from the codec
+    SkPixmap dst(requestInfo, requestPixels, requestRowBytes);
 
-    if (origin != kTopLeft_SkEncodedOrigin) {
-        SkImageInfo info = requestInfo;
-        if (should_swap_width_height(origin)) {
-            info = swap_width_height(info);
+    auto decode = [this, &opts](const SkPixmap& pm) {
+        SkCodec::Options codecOpts;
+        codecOpts.fPremulBehavior = opts.fBehavior;
+        SkCodec::Result result = fCodec->getPixels(pm, &codecOpts);
+        switch (result) {
+            case SkCodec::kSuccess:
+            case SkCodec::kIncompleteInput:
+            case SkCodec::kErrorInInput:
+                return true;
+            default:
+                return false;
         }
-        // need a tmp buffer to receive the pixels, so we can post-orient them
-        if (!storage.tryAlloc(info)) {
-            return false;
-        }
-        codecMap = &storage;
-    }
+    };
 
-    SkCodec::Options codecOpts;
-    codecOpts.fPremulBehavior = opts.fBehavior;
-    SkCodec::Result result = fCodec->getPixels(*codecMap, &codecOpts);
-    switch (result) {
-        case SkCodec::kSuccess:
-            if (codecMap != &request) {
-                return SkPixmapPriv::Orient(request, *codecMap,
-                                            SkPixmapPriv::OriginToOrient(origin));
-            }
-            // fall through
-        case SkCodec::kIncompleteInput:
-        case SkCodec::kErrorInInput:
-            return true;
-        default:
-            return false;
-    }
+    return SkPixmapPriv::Orient(dst, fCodec->getOrigin(), decode);
 }
 
 bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 7e394b4..bd6436e 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -446,3 +446,32 @@
     return draw_orientation(dst, src, flags);
 }
 
+#define kMirrorX    SkPixmapPriv::kMirrorX
+#define kMirrorY    SkPixmapPriv::kMirrorY
+#define kSwapXY     SkPixmapPriv::kSwapXY
+
+static constexpr uint8_t gOrientationFlags[] = {
+    0,                              // kTopLeft_SkEncodedOrigin
+    kMirrorX,                       // kTopRight_SkEncodedOrigin
+    kMirrorX | kMirrorY,            // kBottomRight_SkEncodedOrigin
+               kMirrorY,            // kBottomLeft_SkEncodedOrigin
+                          kSwapXY,  // kLeftTop_SkEncodedOrigin
+    kMirrorX            | kSwapXY,  // kRightTop_SkEncodedOrigin
+    kMirrorX | kMirrorY | kSwapXY,  // kRightBottom_SkEncodedOrigin
+               kMirrorY | kSwapXY,  // kLeftBottom_SkEncodedOrigin
+};
+
+SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
+    unsigned io = static_cast<int>(o) - 1;
+    SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
+    return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
+}
+
+bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) {
+    return SkToBool(OriginToOrient(o) & kSwapXY);
+}
+
+SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) {
+    return info.makeWH(info.height(), info.width());
+}
+
diff --git a/src/core/SkPixmapPriv.h b/src/core/SkPixmapPriv.h
index 1d677fd..9941862 100644
--- a/src/core/SkPixmapPriv.h
+++ b/src/core/SkPixmapPriv.h
@@ -10,6 +10,7 @@
 
 #include "SkPixmap.h"
 #include "SkEncodedOrigin.h"
+#include "SkAutoPixmapStorage.h"
 
 class SkPixmapPriv {
 public:
@@ -27,6 +28,41 @@
      *  by the flags. If the inputs are invalid, this returns false and no copy is made.
      */
     static bool Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags);
+
+    static bool ShouldSwapWidthHeight(SkEncodedOrigin o);
+    static SkImageInfo SwapWidthHeight(const SkImageInfo& info);
+
+    /**
+     *  Decode an image and then copy into dst, applying origin.
+     *
+     *  @param dst SkPixmap to write the final image, after
+     *      applying the origin.
+     *  @param origin SkEncodedOrigin to apply to the raw pixels.
+     *  @param decode Function for decoding into a pixmap without
+     *      applying the origin.
+     */
+    static bool Orient(const SkPixmap& dst, SkEncodedOrigin origin,
+            std::function<bool(const SkPixmap&)> decode) {
+        SkAutoPixmapStorage storage;
+        const SkPixmap* tmp = &dst;
+        if (origin != kTopLeft_SkEncodedOrigin) {
+            auto info = dst.info();
+            if (ShouldSwapWidthHeight(origin)) {
+                info = SwapWidthHeight(info);
+            }
+            if (!storage.tryAlloc(info)) {
+                return false;
+            }
+            tmp = &storage;
+        }
+        if (!decode(*tmp)) {
+            return false;
+        }
+        if (tmp != &dst) {
+            return Orient(dst, *tmp, OriginToOrient(origin));
+        }
+        return true;
+    }
 };
 
 #endif
diff --git a/src/ports/SkImageGeneratorCG.cpp b/src/ports/SkImageGeneratorCG.cpp
index a2fe6a4..2d2c3d3 100644
--- a/src/ports/SkImageGeneratorCG.cpp
+++ b/src/ports/SkImageGeneratorCG.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkImageGeneratorCG.h"
+#include "SkPixmapPriv.h"
 
 #ifdef SK_BUILD_FOR_MAC
 #include <ApplicationServices/ApplicationServices.h>
@@ -28,8 +29,14 @@
     return imageSrc;
 }
 
+#ifdef SK_LEGACY_NEW_FROM_ENCODED_CG
 SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
-    CGImageSourceRef imageSrc = data_to_CGImageSrc(data);
+    return MakeFromEncodedCG(sk_ref_sp(data)).release();
+}
+#endif
+
+std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
+    CGImageSourceRef imageSrc = data_to_CGImageSrc(data.get());
     if (!imageSrc) {
         return nullptr;
     }
@@ -50,8 +57,6 @@
     if (nullptr == widthRef || nullptr == heightRef) {
         return nullptr;
     }
-    bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
-            kCGImagePropertyHasAlpha));
 
     int width, height;
     if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
@@ -59,20 +64,37 @@
         return nullptr;
     }
 
+    bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
+            kCGImagePropertyHasAlpha));
     SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
     SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
 
+    auto origin = kDefault_SkEncodedOrigin;
+    auto orientationRef = (CFNumberRef) (CFDictionaryGetValue(properties,
+            kCGImagePropertyOrientation));
+    int originInt;
+    if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
+        origin = (SkEncodedOrigin) originInt;
+    }
+
+    if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
+        info = SkPixmapPriv::SwapWidthHeight(info);
+    }
+
     // FIXME: We have the opportunity to extract color space information here,
     //        though I think it makes sense to wait until we understand how
     //        we want to communicate it to the generator.
 
-    return new SkImageGeneratorCG(info, autoImageSrc.release(), data);
+    return std::unique_ptr<SkImageGenerator>(new SkImageGeneratorCG(info, autoImageSrc.release(),
+                                                                    std::move(data), origin));
 }
 
-SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data)
+SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc,
+                                       sk_sp<SkData> data, SkEncodedOrigin origin)
     : INHERITED(info)
     , fImageSrc(imageSrc)
-    , fData(SkRef(data))
+    , fData(std::move(data))
+    , fOrigin(origin)
 {}
 
 SkData* SkImageGeneratorCG::onRefEncodedData() {
@@ -105,18 +127,17 @@
     }
     SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);
 
-    // FIXME: Using this function (as opposed to swizzling ourselves) greatly
-    //        restricts the color and alpha types that we support.  If we
-    //        swizzle ourselves, we can add support for:
-    //            kUnpremul_SkAlphaType
-    //            16-bit per component RGBA
-    //            kGray_8_SkColorType
-    //            kIndex_8_SkColorType
-    //        Additionally, it would be interesting to compare the performance
-    //        of SkSwizzler with CG's built in swizzler.
-    if (!SkCopyPixelsFromCGImage(info, rowBytes, pixels, image)) {
-        return false;
-    }
-
-    return true;
+    SkPixmap dst(info, pixels, rowBytes);
+    auto decode = [&image](const SkPixmap& pm) {
+        // FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
+        // ourselves) greatly restricts the color and alpha types that we
+        // support.  If we swizzle ourselves, we can add support for:
+        //     kUnpremul_SkAlphaType
+        //     16-bit per component RGBA
+        //     kGray_8_SkColorType
+        // Additionally, it would be interesting to compare the performance
+        // of SkSwizzler with CG's built in swizzler.
+        return SkCopyPixelsFromCGImage(pm, image);
+    };
+    return SkPixmapPriv::Orient(dst, fOrigin, decode);
 }
diff --git a/src/ports/SkImageGeneratorCG.h b/src/ports/SkImageGeneratorCG.h
index 65300a6..58aac4f 100644
--- a/src/ports/SkImageGeneratorCG.h
+++ b/src/ports/SkImageGeneratorCG.h
@@ -10,16 +10,21 @@
 
 #include "SkCGUtils.h"
 #include "SkData.h"
+#include "SkEncodedOrigin.h"
 #include "SkImageGenerator.h"
 #include "SkTemplates.h"
 
 class SkImageGeneratorCG : public SkImageGenerator {
 public:
+#ifdef SK_LEGACY_NEW_FROM_ENCODED_CG
     /*
      * Refs the data if an image generator can be returned.  Otherwise does
      * not affect the data.
      */
     static SkImageGenerator* NewFromEncodedCG(SkData* data);
+#endif
+
+    static std::unique_ptr<SkImageGenerator> MakeFromEncodedCG(sk_sp<SkData>);
 
 protected:
     SkData* onRefEncodedData() override;
@@ -30,12 +35,13 @@
 private:
     /*
      * Takes ownership of the imageSrc
-     * Refs the data
      */
-    SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data);
+    SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, sk_sp<SkData> data,
+                       SkEncodedOrigin origin);
 
     SkAutoTCallVProc<const void, CFRelease> fImageSrc;
     sk_sp<SkData>                           fData;
+    const SkEncodedOrigin                   fOrigin;
 
     typedef SkImageGenerator INHERITED;
 };