gfx/skia/trunk/src/ports/SkImageDecoder_CG.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2008 The Android Open Source Project
     3  *
     4  * Use of this source code is governed by a BSD-style license that can be
     5  * found in the LICENSE file.
     6  */
     8 #include "SkCGUtils.h"
     9 #include "SkColorPriv.h"
    10 #include "SkImageDecoder.h"
    11 #include "SkImageEncoder.h"
    12 #include "SkMovie.h"
    13 #include "SkStream.h"
    14 #include "SkStreamHelpers.h"
    15 #include "SkTemplates.h"
    16 #include "SkUnPreMultiply.h"
    18 #ifdef SK_BUILD_FOR_MAC
    19 #include <ApplicationServices/ApplicationServices.h>
    20 #endif
    22 #ifdef SK_BUILD_FOR_IOS
    23 #include <CoreGraphics/CoreGraphics.h>
    24 #include <ImageIO/ImageIO.h>
    25 #include <MobileCoreServices/MobileCoreServices.h>
    26 #endif
    28 static void malloc_release_proc(void* info, const void* data, size_t size) {
    29     sk_free(info);
    30 }
    32 static CGDataProviderRef SkStreamToDataProvider(SkStream* stream) {
    33     // TODO: use callbacks, so we don't have to load all the data into RAM
    34     SkAutoMalloc storage;
    35     const size_t len = CopyStreamToStorage(&storage, stream);
    36     void* data = storage.detach();
    38     return CGDataProviderCreateWithData(data, data, len, malloc_release_proc);
    39 }
    41 static CGImageSourceRef SkStreamToCGImageSource(SkStream* stream) {
    42     CGDataProviderRef data = SkStreamToDataProvider(stream);
    43     CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(data, 0);
    44     CGDataProviderRelease(data);
    45     return imageSrc;
    46 }
    48 class SkImageDecoder_CG : public SkImageDecoder {
    49 protected:
    50     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
    51 };
    53 #define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
    55 bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
    56     CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
    58     if (NULL == imageSrc) {
    59         return false;
    60     }
    61     SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
    63     CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL);
    64     if (NULL == image) {
    65         return false;
    66     }
    67     SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image);
    69     const int width = SkToInt(CGImageGetWidth(image));
    70     const int height = SkToInt(CGImageGetHeight(image));
    71     bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
    72     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    73         return true;
    74     }
    76     if (!this->allocPixelRef(bm, NULL)) {
    77         return false;
    78     }
    80     bm->lockPixels();
    81     bm->eraseColor(SK_ColorTRANSPARENT);
    83     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
    84     CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO);
    85     CFRelease(cs);
    87     CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image);
    88     CGContextRelease(cg);
    90     CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
    91     switch (info) {
    92         case kCGImageAlphaNone:
    93         case kCGImageAlphaNoneSkipLast:
    94         case kCGImageAlphaNoneSkipFirst:
    95             SkASSERT(SkBitmap::ComputeIsOpaque(*bm));
    96             bm->setAlphaType(kOpaque_SkAlphaType);
    97             break;
    98         default:
    99             // we don't know if we're opaque or not, so compute it.
   100             if (SkBitmap::ComputeIsOpaque(*bm)) {
   101                 bm->setAlphaType(kOpaque_SkAlphaType);
   102             }
   103     }
   104     if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) {
   105         // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied.
   106         // Convert to unpremultiplied.
   107         for (int i = 0; i < width; ++i) {
   108             for (int j = 0; j < height; ++j) {
   109                 uint32_t* addr = bm->getAddr32(i, j);
   110                 *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr);
   111             }
   112         }
   113         bm->setAlphaType(kUnpremul_SkAlphaType);
   114     }
   115     bm->unlockPixels();
   116     return true;
   117 }
   119 ///////////////////////////////////////////////////////////////////////////////
   121 extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
   123 SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
   124     SkImageDecoder* decoder = image_decoder_from_stream(stream);
   125     if (NULL == decoder) {
   126         // If no image decoder specific to the stream exists, use SkImageDecoder_CG.
   127         return SkNEW(SkImageDecoder_CG);
   128     } else {
   129         return decoder;
   130     }
   131 }
   133 /////////////////////////////////////////////////////////////////////////
   135 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
   136     return NULL;
   137 }
   139 /////////////////////////////////////////////////////////////////////////
   141 static size_t consumer_put(void* info, const void* buffer, size_t count) {
   142     SkWStream* stream = reinterpret_cast<SkWStream*>(info);
   143     return stream->write(buffer, count) ? count : 0;
   144 }
   146 static void consumer_release(void* info) {
   147     // we do nothing, since by design we don't "own" the stream (i.e. info)
   148 }
   150 static CGDataConsumerRef SkStreamToCGDataConsumer(SkWStream* stream) {
   151     CGDataConsumerCallbacks procs;
   152     procs.putBytes = consumer_put;
   153     procs.releaseConsumer = consumer_release;
   154     // we don't own/reference the stream, so it our consumer must not live
   155     // longer that our caller's ownership of the stream
   156     return CGDataConsumerCreate(stream, &procs);
   157 }
   159 static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream,
   160                                                         CFStringRef type) {
   161     CGDataConsumerRef consumer = SkStreamToCGDataConsumer(stream);
   162     if (NULL == consumer) {
   163         return NULL;
   164     }
   165     SkAutoTCallVProc<const void, CFRelease> arconsumer(consumer);
   167     return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, NULL);
   168 }
   170 class SkImageEncoder_CG : public SkImageEncoder {
   171 public:
   172     SkImageEncoder_CG(Type t) : fType(t) {}
   174 protected:
   175     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
   177 private:
   178     Type fType;
   179 };
   181 /*  Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes
   182     to our SkWStream. Since we don't reference/own the SkWStream, our consumer
   183     must only live for the duration of the onEncode() method.
   184  */
   185 bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm,
   186                                  int quality) {
   187     // Used for converting a bitmap to 8888.
   188     const SkBitmap* bmPtr = &bm;
   189     SkBitmap bitmap8888;
   191     CFStringRef type;
   192     switch (fType) {
   193         case kICO_Type:
   194             type = kUTTypeICO;
   195             break;
   196         case kBMP_Type:
   197             type = kUTTypeBMP;
   198             break;
   199         case kGIF_Type:
   200             type = kUTTypeGIF;
   201             break;
   202         case kJPEG_Type:
   203             type = kUTTypeJPEG;
   204             break;
   205         case kPNG_Type:
   206             // PNG encoding an ARGB_4444 bitmap gives the following errors in GM:
   207             // <Error>: CGImageDestinationAddImage image could not be converted to destination
   208             // format.
   209             // <Error>: CGImageDestinationFinalize image destination does not have enough images
   210             // So instead we copy to 8888.
   211             if (bm.colorType() == kARGB_4444_SkColorType) {
   212                 bm.copyTo(&bitmap8888, kPMColor_SkColorType);
   213                 bmPtr = &bitmap8888;
   214             }
   215             type = kUTTypePNG;
   216             break;
   217         default:
   218             return false;
   219     }
   221     CGImageDestinationRef dst = SkStreamToImageDestination(stream, type);
   222     if (NULL == dst) {
   223         return false;
   224     }
   225     SkAutoTCallVProc<const void, CFRelease> ardst(dst);
   227     CGImageRef image = SkCreateCGImageRef(*bmPtr);
   228     if (NULL == image) {
   229         return false;
   230     }
   231     SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image);
   233     CGImageDestinationAddImage(dst, image, NULL);
   234     return CGImageDestinationFinalize(dst);
   235 }
   237 ///////////////////////////////////////////////////////////////////////////////
   239 static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) {
   240     switch (t) {
   241         case SkImageEncoder::kICO_Type:
   242         case SkImageEncoder::kBMP_Type:
   243         case SkImageEncoder::kGIF_Type:
   244         case SkImageEncoder::kJPEG_Type:
   245         case SkImageEncoder::kPNG_Type:
   246             break;
   247         default:
   248             return NULL;
   249     }
   250     return SkNEW_ARGS(SkImageEncoder_CG, (t));
   251 }
   253 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory);
   255 struct FormatConversion {
   256     CFStringRef             fUTType;
   257     SkImageDecoder::Format  fFormat;
   258 };
   260 // Array of the types supported by the decoder.
   261 static const FormatConversion gFormatConversions[] = {
   262     { kUTTypeBMP, SkImageDecoder::kBMP_Format },
   263     { kUTTypeGIF, SkImageDecoder::kGIF_Format },
   264     { kUTTypeICO, SkImageDecoder::kICO_Format },
   265     { kUTTypeJPEG, SkImageDecoder::kJPEG_Format },
   266     // Also include JPEG2000
   267     { kUTTypeJPEG2000, SkImageDecoder::kJPEG_Format },
   268     { kUTTypePNG, SkImageDecoder::kPNG_Format },
   269 };
   271 static SkImageDecoder::Format UTType_to_Format(const CFStringRef uttype) {
   272     for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
   273         if (CFStringCompare(uttype, gFormatConversions[i].fUTType, 0) == kCFCompareEqualTo) {
   274             return gFormatConversions[i].fFormat;
   275         }
   276     }
   277     return SkImageDecoder::kUnknown_Format;
   278 }
   280 static SkImageDecoder::Format get_format_cg(SkStreamRewindable* stream) {
   281     CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
   283     if (NULL == imageSrc) {
   284         return SkImageDecoder::kUnknown_Format;
   285     }
   287     SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
   288     const CFStringRef name = CGImageSourceGetType(imageSrc);
   289     if (NULL == name) {
   290         return SkImageDecoder::kUnknown_Format;
   291     }
   292     return UTType_to_Format(name);
   293 }
   295 static SkImageDecoder_FormatReg gFormatReg(get_format_cg);

mercurial