blob: 21c19ec63b54690fcc29cd806d3477da6964dc35 [file] [log] [blame]
/*
* Copyright (C) 2016-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "ImageDecoderDirect2D.h"
#if USE(DIRECT2D)
#include "GraphicsContext.h"
#include "ImageOrientation.h"
#include "IntPoint.h"
#include "IntSize.h"
#include "Logging.h"
#include "NotImplemented.h"
#include "SharedBuffer.h"
#include <WinCodec.h>
#include <d2d1.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/Optional.h>
namespace WebCore {
ImageDecoderDirect2D::ImageDecoderDirect2D()
{
}
IWICImagingFactory2* ImageDecoderDirect2D::systemImagingFactory()
{
static IWICImagingFactory2* wicImagingFactory = nullptr;
if (!wicImagingFactory) {
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory2, (LPVOID*)&wicImagingFactory);
RELEASE_ASSERT(SUCCEEDED(hr));
}
return wicImagingFactory;
}
size_t ImageDecoderDirect2D::bytesDecodedToDetermineProperties() const
{
// Set to match value used for CoreGraphics.
return 13088;
}
String ImageDecoderDirect2D::filenameExtension() const
{
notImplemented();
return String();
}
bool ImageDecoderDirect2D::isSizeAvailable() const
{
return m_nativeDecoder ? true : false;
}
EncodedDataStatus ImageDecoderDirect2D::encodedDataStatus() const
{
if (!m_nativeDecoder)
return EncodedDataStatus::Error;
// FIXME: Hook into WIC decoder (if async decode is even possible)
return EncodedDataStatus::Complete;
}
IntSize ImageDecoderDirect2D::size() const
{
if (!m_nativeDecoder)
return IntSize();
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(0, &frame);
if (!SUCCEEDED(hr))
return IntSize();
UINT width, height;
hr = frame->GetSize(&width, &height);
if (!SUCCEEDED(hr))
return IntSize();
return IntSize(width, height);
}
size_t ImageDecoderDirect2D::frameCount() const
{
if (!m_nativeDecoder)
return 0;
UINT count;
HRESULT hr = m_nativeDecoder->GetFrameCount(&count);
if (!SUCCEEDED(hr))
return 0;
return count;
}
RepetitionCount ImageDecoderDirect2D::repetitionCount() const
{
if (!m_nativeDecoder)
return RepetitionCountNone;
// FIXME: Identify image type, and determine proper repetition count.
return RepetitionCountNone;
}
Optional<IntPoint> ImageDecoderDirect2D::hotSpot() const
{
return WTF::nullopt;
}
IntSize ImageDecoderDirect2D::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
if (!m_nativeDecoder)
return IntSize();
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(index, &frame);
if (!SUCCEEDED(hr))
return IntSize();
UINT width, height;
hr = frame->GetSize(&width, &height);
if (!SUCCEEDED(hr))
return IntSize();
return IntSize(width, height);
}
bool ImageDecoderDirect2D::frameIsCompleteAtIndex(size_t index) const
{
if (!m_nativeDecoder)
return false;
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(index, &frame);
return SUCCEEDED(hr);
}
ImageOrientation ImageDecoderDirect2D::frameOrientationAtIndex(size_t index) const
{
if (!m_nativeDecoder)
return ImageOrientation::None;
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(index, &frame);
if (!SUCCEEDED(hr))
return ImageOrientation::None;
COMPtr<IWICMetadataQueryReader> metadata;
hr = frame->GetMetadataQueryReader(&metadata);
if (!SUCCEEDED(hr))
return ImageOrientation::None;
PROPVARIANT value;
PropVariantInit(&value);
hr = metadata->GetMetadataByName(L"System.Photo.Orientation", &value);
if (SUCCEEDED(hr))
return ImageOrientation(static_cast<ImageOrientation::Orientation>(value.uiVal));
return ImageOrientation::None;
}
Seconds ImageDecoderDirect2D::frameDurationAtIndex(size_t index) const
{
if (!m_nativeDecoder)
return Seconds(0);
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(index, &frame);
if (!SUCCEEDED(hr))
return Seconds(0);
// FIXME: Figure out correct image format-specific query for frame duration check.
notImplemented();
return Seconds(0);
}
bool ImageDecoderDirect2D::frameAllowSubsamplingAtIndex(size_t index) const
{
return true;
}
bool ImageDecoderDirect2D::frameHasAlphaAtIndex(size_t index) const
{
if (!m_nativeDecoder)
return false;
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(index, &frame);
if (!SUCCEEDED(hr))
return false;
COMPtr<IWICMetadataQueryReader> metadata;
hr = frame->GetMetadataQueryReader(&metadata);
if (!SUCCEEDED(hr))
return false;
GUID containerFormat;
hr = metadata->GetContainerFormat(&containerFormat);
if (!SUCCEEDED(hr))
return false;
if (::IsEqualGUID(GUID_ContainerFormatJpeg, containerFormat))
return false;
return true;
}
unsigned ImageDecoderDirect2D::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
if (!m_nativeDecoder)
return 0;
auto frameSize = frameSizeAtIndex(index, subsamplingLevel);
return (frameSize.area() * 4).unsafeGet();
}
void ImageDecoderDirect2D::setTargetContext(ID2D1RenderTarget* renderTarget)
{
m_renderTarget = renderTarget;
}
NativeImagePtr ImageDecoderDirect2D::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions&)
{
if (!m_nativeDecoder)
return nullptr;
if (!m_renderTarget)
return nullptr;
COMPtr<IWICBitmapFrameDecode> frame;
HRESULT hr = m_nativeDecoder->GetFrame(0, &frame);
if (!SUCCEEDED(hr))
return nullptr;
COMPtr<IWICFormatConverter> converter;
hr = systemImagingFactory()->CreateFormatConverter(&converter);
if (!SUCCEEDED(hr))
return nullptr;
hr = converter->Initialize(frame.get(), GUID_WICPixelFormat32bppPRGBA, WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom);
if (!SUCCEEDED(hr))
return nullptr;
COMPtr<IWICBitmap> wicBitmap;
hr = systemImagingFactory()->CreateBitmapFromSource(converter.get(), WICBitmapCacheOnDemand, &wicBitmap);
if (!SUCCEEDED(hr))
return nullptr;
COMPtr<ID2D1Bitmap> bitmap;
hr = m_renderTarget->CreateBitmapFromWicBitmap(wicBitmap.get(), &bitmap);
if (!SUCCEEDED(hr))
return nullptr;
return bitmap;
}
void ImageDecoderDirect2D::setData(SharedBuffer& data, bool allDataReceived)
{
if (!allDataReceived)
return;
COMPtr<IWICStream> stream;
HRESULT hr = systemImagingFactory()->CreateStream(&stream);
if (!SUCCEEDED(hr))
return;
char* dataPtr = const_cast<char*>(data.data());
hr = stream->InitializeFromMemory(reinterpret_cast<BYTE*>(dataPtr), data.size());
if (!SUCCEEDED(hr))
return;
m_nativeDecoder = nullptr;
hr = systemImagingFactory()->CreateDecoderFromStream(stream.get(), nullptr, WICDecodeMetadataCacheOnDemand, &m_nativeDecoder);
if (!SUCCEEDED(hr)) {
m_nativeDecoder = nullptr;
return;
}
// Image was valid.
}
}
#endif