static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace) { CGFloat components[4]; color.getRGBA(components[0], components[1], components[2], components[3]); return CGColorCreate(cachedCGColorSpace(colorSpace), components); }
ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_logicalSize(size) , m_resolutionScale(resolutionScale) { float scaledWidth = ceilf(resolutionScale * size.width()); float scaledHeight = ceilf(resolutionScale * size.height()); // FIXME: Should we automatically use a lower resolution? if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize()) return; m_size = IntSize(scaledWidth, scaledHeight); m_data.backingStoreSize = m_size; success = false; // Make early return mean failure. bool accelerateRendering = renderingMode == Accelerated; if (m_size.width() <= 0 || m_size.height() <= 0) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) Checked<int, RecordOverflow> width = m_size.width(); Checked<int, RecordOverflow> height = m_size.height(); #endif // Prevent integer overflows m_data.bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.width()); Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.height()) * m_data.bytesPerRow; if (numBytes.hasOverflowed()) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) IntSize maxSize = IOSurface::maximumSize(); if (width.unsafeGet() > maxSize.width() || height.unsafeGet() > maxSize.height()) accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); #endif m_data.colorSpace = cachedCGColorSpace(imageColorSpace); RetainPtr<CGContextRef> cgContext; if (accelerateRendering) { #if USE(IOSURFACE_CANVAS_BACKING_STORE) FloatSize userBounds = scaleSizeToUserSpace(FloatSize(width.unsafeGet(), height.unsafeGet()), m_data.backingStoreSize, m_size); m_data.surface = IOSurface::create(m_data.backingStoreSize, IntSize(userBounds), imageColorSpace); cgContext = m_data.surface->ensurePlatformContext(); if (cgContext) CGContextClearRect(cgContext.get(), FloatRect(FloatPoint(), userBounds)); #endif if (!cgContext) accelerateRendering = false; // If allocation fails, fall back to non-accelerated path. } if (!accelerateRendering) { if (!tryFastCalloc(m_data.backingStoreSize.height(), m_data.bytesPerRow.unsafeGet()).getValue(m_data.data)) return; ASSERT(!(reinterpret_cast<intptr_t>(m_data.data) & 3)); #if USE_ARGB32 m_data.bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; #else m_data.bitmapInfo = kCGImageAlphaPremultipliedLast; #endif cgContext = adoptCF(CGBitmapContextCreate(m_data.data, m_data.backingStoreSize.width(), m_data.backingStoreSize.height(), 8, m_data.bytesPerRow.unsafeGet(), m_data.colorSpace, m_data.bitmapInfo)); // Create a live image that wraps the data. m_data.dataProvider = adoptCF(CGDataProviderCreateWithData(0, m_data.data, numBytes.unsafeGet(), releaseImageData)); if (!cgContext) return; m_data.context = std::make_unique<GraphicsContext>(cgContext.get()); } context().scale(FloatSize(1, -1)); context().translate(0, -m_data.backingStoreSize.height()); context().applyDeviceScaleFactor(m_resolutionScale); success = true; }