gfx/skia/trunk/src/ports/SkImageDecoder_WIC.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.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2011 Google Inc.
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9 #include "SkTypes.h"
michael@0 10
michael@0 11 // Workaround for:
michael@0 12 // http://connect.microsoft.com/VisualStudio/feedback/details/621653/
michael@0 13 // http://crbug.com/225822
michael@0 14 // In VS2010 both intsafe.h and stdint.h define the following without guards.
michael@0 15 // SkTypes brought in windows.h and stdint.h and the following defines are
michael@0 16 // not used by this file. However, they may be re-introduced by wincodec.h.
michael@0 17 #undef INT8_MIN
michael@0 18 #undef INT16_MIN
michael@0 19 #undef INT32_MIN
michael@0 20 #undef INT64_MIN
michael@0 21 #undef INT8_MAX
michael@0 22 #undef UINT8_MAX
michael@0 23 #undef INT16_MAX
michael@0 24 #undef UINT16_MAX
michael@0 25 #undef INT32_MAX
michael@0 26 #undef UINT32_MAX
michael@0 27 #undef INT64_MAX
michael@0 28 #undef UINT64_MAX
michael@0 29
michael@0 30 #include <wincodec.h>
michael@0 31 #include "SkAutoCoInitialize.h"
michael@0 32 #include "SkImageDecoder.h"
michael@0 33 #include "SkImageEncoder.h"
michael@0 34 #include "SkIStream.h"
michael@0 35 #include "SkMovie.h"
michael@0 36 #include "SkStream.h"
michael@0 37 #include "SkTScopedComPtr.h"
michael@0 38 #include "SkUnPreMultiply.h"
michael@0 39
michael@0 40 //All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
michael@0 41 //In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
michael@0 42 //but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
michael@0 43 //Undo this #define if it has been done so that we link against the symbols
michael@0 44 //we intended to link against on all SDKs.
michael@0 45 #if defined(CLSID_WICImagingFactory)
michael@0 46 #undef CLSID_WICImagingFactory
michael@0 47 #endif
michael@0 48
michael@0 49 class SkImageDecoder_WIC : public SkImageDecoder {
michael@0 50 public:
michael@0 51 // Decoding modes corresponding to SkImageDecoder::Mode, plus an extra mode for decoding
michael@0 52 // only the format.
michael@0 53 enum WICModes {
michael@0 54 kDecodeFormat_WICMode,
michael@0 55 kDecodeBounds_WICMode,
michael@0 56 kDecodePixels_WICMode,
michael@0 57 };
michael@0 58
michael@0 59 /**
michael@0 60 * Helper function to decode an SkStream.
michael@0 61 * @param stream SkStream to decode. Must be at the beginning.
michael@0 62 * @param bm SkBitmap to decode into. Only used if wicMode is kDecodeBounds_WICMode or
michael@0 63 * kDecodePixels_WICMode, in which case it must not be NULL.
michael@0 64 * @param format Out parameter for the SkImageDecoder::Format of the SkStream. Only used if
michael@0 65 * wicMode is kDecodeFormat_WICMode.
michael@0 66 */
michael@0 67 bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
michael@0 68
michael@0 69 protected:
michael@0 70 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
michael@0 71 };
michael@0 72
michael@0 73 struct FormatConversion {
michael@0 74 GUID fGuidFormat;
michael@0 75 SkImageDecoder::Format fFormat;
michael@0 76 };
michael@0 77
michael@0 78 static const FormatConversion gFormatConversions[] = {
michael@0 79 { GUID_ContainerFormatBmp, SkImageDecoder::kBMP_Format },
michael@0 80 { GUID_ContainerFormatGif, SkImageDecoder::kGIF_Format },
michael@0 81 { GUID_ContainerFormatIco, SkImageDecoder::kICO_Format },
michael@0 82 { GUID_ContainerFormatJpeg, SkImageDecoder::kJPEG_Format },
michael@0 83 { GUID_ContainerFormatPng, SkImageDecoder::kPNG_Format },
michael@0 84 };
michael@0 85
michael@0 86 static SkImageDecoder::Format GuidContainerFormat_to_Format(REFGUID guid) {
michael@0 87 for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
michael@0 88 if (IsEqualGUID(guid, gFormatConversions[i].fGuidFormat)) {
michael@0 89 return gFormatConversions[i].fFormat;
michael@0 90 }
michael@0 91 }
michael@0 92 return SkImageDecoder::kUnknown_Format;
michael@0 93 }
michael@0 94
michael@0 95 bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
michael@0 96 WICModes wicMode;
michael@0 97 switch (mode) {
michael@0 98 case SkImageDecoder::kDecodeBounds_Mode:
michael@0 99 wicMode = kDecodeBounds_WICMode;
michael@0 100 break;
michael@0 101 case SkImageDecoder::kDecodePixels_Mode:
michael@0 102 wicMode = kDecodePixels_WICMode;
michael@0 103 break;
michael@0 104 }
michael@0 105 return this->decodeStream(stream, bm, wicMode, NULL);
michael@0 106 }
michael@0 107
michael@0 108 bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
michael@0 109 Format* format) const {
michael@0 110 //Initialize COM.
michael@0 111 SkAutoCoInitialize scopedCo;
michael@0 112 if (!scopedCo.succeeded()) {
michael@0 113 return false;
michael@0 114 }
michael@0 115
michael@0 116 HRESULT hr = S_OK;
michael@0 117
michael@0 118 //Create Windows Imaging Component ImagingFactory.
michael@0 119 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
michael@0 120 if (SUCCEEDED(hr)) {
michael@0 121 hr = CoCreateInstance(
michael@0 122 CLSID_WICImagingFactory
michael@0 123 , NULL
michael@0 124 , CLSCTX_INPROC_SERVER
michael@0 125 , IID_PPV_ARGS(&piImagingFactory)
michael@0 126 );
michael@0 127 }
michael@0 128
michael@0 129 //Convert SkStream to IStream.
michael@0 130 SkTScopedComPtr<IStream> piStream;
michael@0 131 if (SUCCEEDED(hr)) {
michael@0 132 hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
michael@0 133 }
michael@0 134
michael@0 135 //Make sure we're at the beginning of the stream.
michael@0 136 if (SUCCEEDED(hr)) {
michael@0 137 LARGE_INTEGER liBeginning = { 0 };
michael@0 138 hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
michael@0 139 }
michael@0 140
michael@0 141 //Create the decoder from the stream content.
michael@0 142 SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
michael@0 143 if (SUCCEEDED(hr)) {
michael@0 144 hr = piImagingFactory->CreateDecoderFromStream(
michael@0 145 piStream.get() //Image to be decoded
michael@0 146 , NULL //No particular vendor
michael@0 147 , WICDecodeMetadataCacheOnDemand //Cache metadata when needed
michael@0 148 , &piBitmapDecoder //Pointer to the decoder
michael@0 149 );
michael@0 150 }
michael@0 151
michael@0 152 if (kDecodeFormat_WICMode == wicMode) {
michael@0 153 SkASSERT(format != NULL);
michael@0 154 //Get the format
michael@0 155 if (SUCCEEDED(hr)) {
michael@0 156 GUID guidFormat;
michael@0 157 hr = piBitmapDecoder->GetContainerFormat(&guidFormat);
michael@0 158 if (SUCCEEDED(hr)) {
michael@0 159 *format = GuidContainerFormat_to_Format(guidFormat);
michael@0 160 return true;
michael@0 161 }
michael@0 162 }
michael@0 163 return false;
michael@0 164 }
michael@0 165
michael@0 166 //Get the first frame from the decoder.
michael@0 167 SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
michael@0 168 if (SUCCEEDED(hr)) {
michael@0 169 hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
michael@0 170 }
michael@0 171
michael@0 172 //Get the BitmapSource interface of the frame.
michael@0 173 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
michael@0 174 if (SUCCEEDED(hr)) {
michael@0 175 hr = piBitmapFrameDecode->QueryInterface(
michael@0 176 IID_PPV_ARGS(&piBitmapSourceOriginal)
michael@0 177 );
michael@0 178 }
michael@0 179
michael@0 180 //Get the size of the bitmap.
michael@0 181 UINT width;
michael@0 182 UINT height;
michael@0 183 if (SUCCEEDED(hr)) {
michael@0 184 hr = piBitmapSourceOriginal->GetSize(&width, &height);
michael@0 185 }
michael@0 186
michael@0 187 //Exit early if we're only looking for the bitmap bounds.
michael@0 188 if (SUCCEEDED(hr)) {
michael@0 189 bm->setConfig(SkImageInfo::MakeN32Premul(width, height));
michael@0 190 if (kDecodeBounds_WICMode == wicMode) {
michael@0 191 return true;
michael@0 192 }
michael@0 193 if (!this->allocPixelRef(bm, NULL)) {
michael@0 194 return false;
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 //Create a format converter.
michael@0 199 SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
michael@0 200 if (SUCCEEDED(hr)) {
michael@0 201 hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
michael@0 202 }
michael@0 203
michael@0 204 GUID destinationPixelFormat;
michael@0 205 if (this->getRequireUnpremultipliedColors()) {
michael@0 206 destinationPixelFormat = GUID_WICPixelFormat32bppBGRA;
michael@0 207 } else {
michael@0 208 destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA;
michael@0 209 }
michael@0 210
michael@0 211 if (SUCCEEDED(hr)) {
michael@0 212 hr = piFormatConverter->Initialize(
michael@0 213 piBitmapSourceOriginal.get() //Input bitmap to convert
michael@0 214 , destinationPixelFormat //Destination pixel format
michael@0 215 , WICBitmapDitherTypeNone //Specified dither patterm
michael@0 216 , NULL //Specify a particular palette
michael@0 217 , 0.f //Alpha threshold
michael@0 218 , WICBitmapPaletteTypeCustom //Palette translation type
michael@0 219 );
michael@0 220 }
michael@0 221
michael@0 222 //Get the BitmapSource interface of the format converter.
michael@0 223 SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
michael@0 224 if (SUCCEEDED(hr)) {
michael@0 225 hr = piFormatConverter->QueryInterface(
michael@0 226 IID_PPV_ARGS(&piBitmapSourceConverted)
michael@0 227 );
michael@0 228 }
michael@0 229
michael@0 230 //Copy the pixels into the bitmap.
michael@0 231 if (SUCCEEDED(hr)) {
michael@0 232 SkAutoLockPixels alp(*bm);
michael@0 233 bm->eraseColor(SK_ColorTRANSPARENT);
michael@0 234 const UINT stride = (UINT) bm->rowBytes();
michael@0 235 hr = piBitmapSourceConverted->CopyPixels(
michael@0 236 NULL, //Get all the pixels
michael@0 237 stride,
michael@0 238 stride * height,
michael@0 239 reinterpret_cast<BYTE *>(bm->getPixels())
michael@0 240 );
michael@0 241
michael@0 242 // Note: we don't need to premultiply here since we specified PBGRA
michael@0 243 if (SkBitmap::ComputeIsOpaque(*bm)) {
michael@0 244 bm->setAlphaType(kOpaque_SkAlphaType);
michael@0 245 }
michael@0 246 }
michael@0 247
michael@0 248 return SUCCEEDED(hr);
michael@0 249 }
michael@0 250
michael@0 251 /////////////////////////////////////////////////////////////////////////
michael@0 252
michael@0 253 extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
michael@0 254
michael@0 255 SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
michael@0 256 SkImageDecoder* decoder = image_decoder_from_stream(stream);
michael@0 257 if (NULL == decoder) {
michael@0 258 // If no image decoder specific to the stream exists, use SkImageDecoder_WIC.
michael@0 259 return SkNEW(SkImageDecoder_WIC);
michael@0 260 } else {
michael@0 261 return decoder;
michael@0 262 }
michael@0 263 }
michael@0 264
michael@0 265 /////////////////////////////////////////////////////////////////////////
michael@0 266
michael@0 267 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
michael@0 268 return NULL;
michael@0 269 }
michael@0 270
michael@0 271 /////////////////////////////////////////////////////////////////////////
michael@0 272
michael@0 273 class SkImageEncoder_WIC : public SkImageEncoder {
michael@0 274 public:
michael@0 275 SkImageEncoder_WIC(Type t) : fType(t) {}
michael@0 276
michael@0 277 protected:
michael@0 278 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
michael@0 279
michael@0 280 private:
michael@0 281 Type fType;
michael@0 282 };
michael@0 283
michael@0 284 bool SkImageEncoder_WIC::onEncode(SkWStream* stream
michael@0 285 , const SkBitmap& bitmapOrig
michael@0 286 , int quality)
michael@0 287 {
michael@0 288 GUID type;
michael@0 289 switch (fType) {
michael@0 290 case kBMP_Type:
michael@0 291 type = GUID_ContainerFormatBmp;
michael@0 292 break;
michael@0 293 case kICO_Type:
michael@0 294 type = GUID_ContainerFormatIco;
michael@0 295 break;
michael@0 296 case kJPEG_Type:
michael@0 297 type = GUID_ContainerFormatJpeg;
michael@0 298 break;
michael@0 299 case kPNG_Type:
michael@0 300 type = GUID_ContainerFormatPng;
michael@0 301 break;
michael@0 302 default:
michael@0 303 return false;
michael@0 304 }
michael@0 305
michael@0 306 //Convert to 8888 if needed.
michael@0 307 const SkBitmap* bitmap;
michael@0 308 SkBitmap bitmapCopy;
michael@0 309 if (kPMColor_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) {
michael@0 310 bitmap = &bitmapOrig;
michael@0 311 } else {
michael@0 312 if (!bitmapOrig.copyTo(&bitmapCopy, kPMColor_SkColorType)) {
michael@0 313 return false;
michael@0 314 }
michael@0 315 bitmap = &bitmapCopy;
michael@0 316 }
michael@0 317
michael@0 318 // We cannot use PBGRA so we need to unpremultiply ourselves
michael@0 319 if (!bitmap->isOpaque()) {
michael@0 320 SkAutoLockPixels alp(*bitmap);
michael@0 321
michael@0 322 uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels());
michael@0 323 for (int y = 0; y < bitmap->height(); ++y) {
michael@0 324 for (int x = 0; x < bitmap->width(); ++x) {
michael@0 325 uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel();
michael@0 326
michael@0 327 SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
michael@0 328 SkColor* dst = reinterpret_cast<SkColor*>(bytes);
michael@0 329
michael@0 330 *dst = SkUnPreMultiply::PMColorToColor(*src);
michael@0 331 }
michael@0 332 }
michael@0 333 }
michael@0 334
michael@0 335 //Initialize COM.
michael@0 336 SkAutoCoInitialize scopedCo;
michael@0 337 if (!scopedCo.succeeded()) {
michael@0 338 return false;
michael@0 339 }
michael@0 340
michael@0 341 HRESULT hr = S_OK;
michael@0 342
michael@0 343 //Create Windows Imaging Component ImagingFactory.
michael@0 344 SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
michael@0 345 if (SUCCEEDED(hr)) {
michael@0 346 hr = CoCreateInstance(
michael@0 347 CLSID_WICImagingFactory
michael@0 348 , NULL
michael@0 349 , CLSCTX_INPROC_SERVER
michael@0 350 , IID_PPV_ARGS(&piImagingFactory)
michael@0 351 );
michael@0 352 }
michael@0 353
michael@0 354 //Convert the SkWStream to an IStream.
michael@0 355 SkTScopedComPtr<IStream> piStream;
michael@0 356 if (SUCCEEDED(hr)) {
michael@0 357 hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
michael@0 358 }
michael@0 359
michael@0 360 //Create an encode of the appropriate type.
michael@0 361 SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
michael@0 362 if (SUCCEEDED(hr)) {
michael@0 363 hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
michael@0 364 }
michael@0 365
michael@0 366 if (SUCCEEDED(hr)) {
michael@0 367 hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
michael@0 368 }
michael@0 369
michael@0 370 //Create a the frame.
michael@0 371 SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
michael@0 372 SkTScopedComPtr<IPropertyBag2> piPropertybag;
michael@0 373 if (SUCCEEDED(hr)) {
michael@0 374 hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
michael@0 375 }
michael@0 376
michael@0 377 if (SUCCEEDED(hr)) {
michael@0 378 PROPBAG2 name = { 0 };
michael@0 379 name.dwType = PROPBAG2_TYPE_DATA;
michael@0 380 name.vt = VT_R4;
michael@0 381 name.pstrName = L"ImageQuality";
michael@0 382
michael@0 383 VARIANT value;
michael@0 384 VariantInit(&value);
michael@0 385 value.vt = VT_R4;
michael@0 386 value.fltVal = (FLOAT)(quality / 100.0);
michael@0 387
michael@0 388 //Ignore result code.
michael@0 389 // This returns E_FAIL if the named property is not in the bag.
michael@0 390 //TODO(bungeman) enumerate the properties,
michael@0 391 // write and set hr iff property exists.
michael@0 392 piPropertybag->Write(1, &name, &value);
michael@0 393 }
michael@0 394 if (SUCCEEDED(hr)) {
michael@0 395 hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
michael@0 396 }
michael@0 397
michael@0 398 //Set the size of the frame.
michael@0 399 const UINT width = bitmap->width();
michael@0 400 const UINT height = bitmap->height();
michael@0 401 if (SUCCEEDED(hr)) {
michael@0 402 hr = piBitmapFrameEncode->SetSize(width, height);
michael@0 403 }
michael@0 404
michael@0 405 //Set the pixel format of the frame.
michael@0 406 const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
michael@0 407 WICPixelFormatGUID formatGUID = formatDesired;
michael@0 408 if (SUCCEEDED(hr)) {
michael@0 409 hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
michael@0 410 }
michael@0 411 if (SUCCEEDED(hr)) {
michael@0 412 //Be sure the image format is the one requested.
michael@0 413 hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
michael@0 414 }
michael@0 415
michael@0 416 //Write the pixels into the frame.
michael@0 417 if (SUCCEEDED(hr)) {
michael@0 418 SkAutoLockPixels alp(*bitmap);
michael@0 419 const UINT stride = (UINT) bitmap->rowBytes();
michael@0 420 hr = piBitmapFrameEncode->WritePixels(
michael@0 421 height
michael@0 422 , stride
michael@0 423 , stride * height
michael@0 424 , reinterpret_cast<BYTE*>(bitmap->getPixels()));
michael@0 425 }
michael@0 426
michael@0 427 if (SUCCEEDED(hr)) {
michael@0 428 hr = piBitmapFrameEncode->Commit();
michael@0 429 }
michael@0 430
michael@0 431 if (SUCCEEDED(hr)) {
michael@0 432 hr = piEncoder->Commit();
michael@0 433 }
michael@0 434
michael@0 435 return SUCCEEDED(hr);
michael@0 436 }
michael@0 437
michael@0 438 ///////////////////////////////////////////////////////////////////////////////
michael@0 439
michael@0 440 static SkImageEncoder* sk_imageencoder_wic_factory(SkImageEncoder::Type t) {
michael@0 441 switch (t) {
michael@0 442 case SkImageEncoder::kBMP_Type:
michael@0 443 case SkImageEncoder::kICO_Type:
michael@0 444 case SkImageEncoder::kJPEG_Type:
michael@0 445 case SkImageEncoder::kPNG_Type:
michael@0 446 break;
michael@0 447 default:
michael@0 448 return NULL;
michael@0 449 }
michael@0 450 return SkNEW_ARGS(SkImageEncoder_WIC, (t));
michael@0 451 }
michael@0 452
michael@0 453 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_wic_factory);
michael@0 454
michael@0 455 static SkImageDecoder::Format get_format_wic(SkStreamRewindable* stream) {
michael@0 456 SkImageDecoder::Format format;
michael@0 457 SkImageDecoder_WIC codec;
michael@0 458 if (!codec.decodeStream(stream, NULL, SkImageDecoder_WIC::kDecodeFormat_WICMode, &format)) {
michael@0 459 format = SkImageDecoder::kUnknown_Format;
michael@0 460 }
michael@0 461 return format;
michael@0 462 }
michael@0 463
michael@0 464 static SkImageDecoder_FormatReg gFormatReg(get_format_wic);

mercurial