blob: 499383351939ee4537a1b4ece454dd94263fff48 [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 "ImageBufferData.h"
#if USE(DIRECT2D)
#include "BitmapInfo.h"
#include "GraphicsContext.h"
#include "HWndDC.h"
#include "IntRect.h"
#include "NotImplemented.h"
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/TypedArrayInlines.h>
#include <JavaScriptCore/Uint8ClampedArray.h>
#include <d2d1.h>
#include <wtf/Assertions.h>
#include <wtf/UniqueArray.h>
namespace WebCore {
RefPtr<Uint8ClampedArray> ImageBufferData::getData(AlphaPremultiplication, const IntRect& rect, const IntSize& size, bool /* accelerateRendering */, float /* resolutionScale */) const
{
auto platformContext = context->platformContext();
auto numBytes = rect.area<RecordOverflow>() * 4;
if (numBytes.hasOverflowed())
return nullptr;
auto result = Uint8ClampedArray::tryCreateUninitialized(numBytes.unsafeGet());
unsigned char* resultData = result ? result->data() : nullptr;
if (!resultData)
return nullptr;
BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(size);
void* pixels = nullptr;
auto bitmap = adoptGDIObject(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
HWndDC windowDC(nullptr);
auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(windowDC));
HGDIOBJ oldBitmap = ::SelectObject(bitmapDC.get(), bitmap.get());
COMPtr<ID2D1GdiInteropRenderTarget> gdiRenderTarget;
HRESULT hr = platformContext->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&gdiRenderTarget);
if (FAILED(hr))
return nullptr;
HDC hdc = nullptr;
hr = gdiRenderTarget->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &hdc);
BOOL ok = ::BitBlt(bitmapDC.get(), 0, 0, rect.width(), rect.height(), hdc, rect.x(), rect.y(), SRCCOPY);
RECT updateRect = { 0, 0, 0, 0 };
hr = gdiRenderTarget->ReleaseDC(&updateRect);
if (!ok)
return nullptr;
memcpy(result->data(), pixels, numBytes.unsafeGet());
return result;
}
void ImageBufferData::putData(const Uint8ClampedArray& source, AlphaPremultiplication sourceFormat, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool /* accelerateRendering */, float resolutionScale)
{
auto platformContext = context->platformContext();
COMPtr<ID2D1BitmapRenderTarget> renderTarget(Query, platformContext);
if (!renderTarget)
return;
COMPtr<ID2D1Bitmap> bitmap;
HRESULT hr = renderTarget->GetBitmap(&bitmap);
ASSERT(SUCCEEDED(hr));
ASSERT(sourceRect.width() > 0);
ASSERT(sourceRect.height() > 0);
Checked<int> originx = sourceRect.x();
Checked<int> destx = (Checked<int>(destPoint.x()) + sourceRect.x());
destx *= resolutionScale;
ASSERT(destx.unsafeGet() >= 0);
ASSERT(destx.unsafeGet() < size.width());
ASSERT(originx.unsafeGet() >= 0);
ASSERT(originx.unsafeGet() <= sourceRect.maxX());
Checked<int> endx = (Checked<int>(destPoint.x()) + sourceRect.maxX());
endx *= resolutionScale;
ASSERT(endx.unsafeGet() <= size.width());
Checked<int> width = sourceRect.width();
Checked<int> destw = endx - destx;
Checked<int> originy = sourceRect.y();
Checked<int> desty = (Checked<int>(destPoint.y()) + sourceRect.y());
desty *= resolutionScale;
ASSERT(desty.unsafeGet() >= 0);
ASSERT(desty.unsafeGet() < size.height());
ASSERT(originy.unsafeGet() >= 0);
ASSERT(originy.unsafeGet() <= sourceRect.maxY());
Checked<int> endy = (Checked<int>(destPoint.y()) + sourceRect.maxY());
endy *= resolutionScale;
ASSERT(endy.unsafeGet() <= size.height());
Checked<int> height = sourceRect.height();
Checked<int> desth = endy - desty;
if (width <= 0 || height <= 0)
return;
unsigned srcBytesPerRow = 4 * sourceSize.width();
const uint8_t* srcRows = source.data() + (originy * srcBytesPerRow + originx * 4).unsafeGet();
auto row = makeUniqueArray<uint8_t>(srcBytesPerRow);
for (int y = 0; y < height.unsafeGet(); ++y) {
for (int x = 0; x < width.unsafeGet(); x++) {
int basex = x * 4;
uint8_t alpha = srcRows[basex + 3];
if (sourceFormat == AlphaPremultiplication::Unpremultiplied && alpha != 255) {
row[basex] = (srcRows[basex] * alpha + 254) / 255;
row[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
row[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255;
row[basex + 3] = alpha;
} else
reinterpret_cast<uint32_t*>(row.get() + basex)[0] = reinterpret_cast<const uint32_t*>(srcRows + basex)[0];
}
D2D1_RECT_U dstRect = D2D1::RectU(destPoint.x(), destPoint.y() + y, destPoint.x() + size.width(), destPoint.y() + y + 1);
hr = bitmap->CopyFromMemory(&dstRect, row.get(), srcBytesPerRow);
ASSERT(SUCCEEDED(hr));
srcRows += srcBytesPerRow;
}
}
} // namespace WebCore
#endif