CGGradientRef Gradient::platformGradient() { if (m_gradient) return m_gradient; sortStopsIfNecessary(); // FIXME: ExtendedColor - we should generate CGColorRefs here, so that // we can handle color spaces. const int cReservedStops = 3; Vector<CGFloat, 4 * cReservedStops> colorComponents; colorComponents.reserveInitialCapacity(m_stops.size() * 4); // RGBA components per stop Vector<CGFloat, cReservedStops> locations; locations.reserveInitialCapacity(m_stops.size()); for (size_t i = 0; i < m_stops.size(); ++i) { colorComponents.uncheckedAppend(m_stops[i].red); colorComponents.uncheckedAppend(m_stops[i].green); colorComponents.uncheckedAppend(m_stops[i].blue); colorComponents.uncheckedAppend(m_stops[i].alpha); locations.uncheckedAppend(m_stops[i].stop); } // FIXME: ExtendedColor - use CGGradientCreateWithColors so that we can have stops in different color spaces. m_gradient = CGGradientCreateWithColorComponents(sRGBColorSpaceRef(), colorComponents.data(), locations.data(), m_stops.size()); return m_gradient; }
ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_data(size) , m_size(size) , m_accelerateRendering(renderingMode == Accelerated) { #if !USE(IOSURFACE_CANVAS_BACKING_STORE) ASSERT(renderingMode == Unaccelerated); #endif success = false; // Make early return mean failure. if (size.width() < 0 || size.height() < 0) return; unsigned bytesPerRow = size.width(); if (bytesPerRow > 0x3FFFFFFF) // Protect against overflow return; bytesPerRow *= 4; m_data.m_bytesPerRow = bytesPerRow; size_t dataSize = size.height() * bytesPerRow; switch (imageColorSpace) { case ColorSpaceDeviceRGB: m_data.m_colorSpace = deviceRGBColorSpaceRef(); break; case ColorSpaceSRGB: m_data.m_colorSpace = sRGBColorSpaceRef(); break; case ColorSpaceLinearRGB: m_data.m_colorSpace = linearRGBColorSpaceRef(); break; } RetainPtr<CGContextRef> cgContext; if (!m_accelerateRendering) { if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data)) return; ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2)); m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, m_data.m_colorSpace, m_data.m_bitmapInfo)); // Create a live image that wraps the data. m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, dataSize, releaseImageData)); } else { #if USE(IOSURFACE_CANVAS_BACKING_STORE) m_data.m_surface = createIOSurface(size); cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), size.width(), size.height(), m_data.m_colorSpace)); #else m_accelerateRendering = false; // Force to false on older platforms #endif } if (!cgContext) return; m_context.set(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -size.height()); success = true; }
static inline CGColorSpaceRef cachedCGColorSpace(ColorSpace colorSpace) { switch (colorSpace) { case DeviceColorSpace: return deviceRGBColorSpaceRef(); case sRGBColorSpace: return sRGBColorSpaceRef(); } ASSERT_NOT_REACHED(); return deviceRGBColorSpaceRef(); }
static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, ColorSpace colorSpace) { CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalImage); // If the image already has a (non-device) color space, we don't want to // override it, so return. if (!originalColorSpace || !CFEqual(originalColorSpace, deviceRGBColorSpaceRef())) return originalImage; switch (colorSpace) { case DeviceColorSpace: return originalImage; case sRGBColorSpace: return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, sRGBColorSpaceRef())); } ASSERT_NOT_REACHED(); return originalImage; }
ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, DeferralMode, bool& success) : m_data(size) // NOTE: The input here isn't important as ImageBufferDataCG's constructor just ignores it. , m_size(size) { success = false; // Make early return mean failure. bool accelerateRendering = renderingMode == Accelerated; if (size.width() <= 0 || size.height() <= 0) return; Checked<int, RecordOverflow> width = size.width(); Checked<int, RecordOverflow> height = size.height(); // Prevent integer overflows m_data.m_bytesPerRow = 4 * width; Checked<size_t, RecordOverflow> numBytes = height * m_data.m_bytesPerRow; if (numBytes.hasOverflowed()) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) if (width.unsafeGet() >= maxIOSurfaceDimension || height.unsafeGet() >= maxIOSurfaceDimension || (width * height).unsafeGet() < minIOSurfaceArea) accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); #endif switch (imageColorSpace) { case ColorSpaceDeviceRGB: m_data.m_colorSpace = deviceRGBColorSpaceRef(); break; case ColorSpaceSRGB: m_data.m_colorSpace = sRGBColorSpaceRef(); break; case ColorSpaceLinearRGB: m_data.m_colorSpace = linearRGBColorSpaceRef(); break; } RetainPtr<CGContextRef> cgContext; if (accelerateRendering) { #if USE(IOSURFACE_CANVAS_BACKING_STORE) m_data.m_surface = createIOSurface(size); cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace)); #endif if (!cgContext) accelerateRendering = false; // If allocation fails, fall back to non-accelerated path. } if (!accelerateRendering) { if (!tryFastCalloc(height.unsafeGet(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data)) return; ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2)); m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, width.unsafeGet(), height.unsafeGet(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo)); // Create a live image that wraps the data. m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, numBytes.unsafeGet(), releaseImageData)); } if (!cgContext) return; m_context = adoptPtr(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -height.unsafeGet()); m_context->setIsAcceleratedContext(accelerateRendering); #if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); #endif success = true; }
static CGColorSpaceRef colorSpace(ShareableBitmap::Flags flags) { if (flags & ShareableBitmap::SupportsExtendedColor) return extendedSRGBColorSpaceRef(); return sRGBColorSpaceRef(); }
ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_data(size) , m_size(size) , m_accelerateRendering(renderingMode == Accelerated) { success = false; // Make early return mean failure. if (size.width() <= 0 || size.height() <= 0) return; Checked<int, RecordOverflow> width = size.width(); Checked<int, RecordOverflow> height = size.height(); // Prevent integer overflows m_data.m_bytesPerRow = 4 * width; Checked<size_t, RecordOverflow> dataSize = height * m_data.m_bytesPerRow; if (dataSize.hasOverflowed()) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) if (width.unsafeGet() >= maxIOSurfaceDimension || height.unsafeGet() >= maxIOSurfaceDimension || (width * height).unsafeGet() < minIOSurfaceArea) m_accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); #endif switch (imageColorSpace) { case ColorSpaceDeviceRGB: m_data.m_colorSpace = deviceRGBColorSpaceRef(); break; case ColorSpaceSRGB: m_data.m_colorSpace = sRGBColorSpaceRef(); break; case ColorSpaceLinearRGB: m_data.m_colorSpace = linearRGBColorSpaceRef(); break; } RetainPtr<CGContextRef> cgContext; if (m_accelerateRendering) { #if USE(IOSURFACE_CANVAS_BACKING_STORE) m_data.m_surface = createIOSurface(size); cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace)); #endif if (!cgContext) m_accelerateRendering = false; // If allocation fails, fall back to non-accelerated path. } if (!m_accelerateRendering) { if (!tryFastCalloc(height.unsafeGet(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data)) return; ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2)); #if USE_ARGB32 m_data.m_bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; #else m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; #endif cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, width.unsafeGet(), height.unsafeGet(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo)); // Create a live image that wraps the data. m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, dataSize.unsafeGet(), releaseImageData)); } if (!cgContext) return; m_context= adoptPtr(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -height.unsafeGet()); success = true; }
void BitmapImage::checkForSolidColor() { m_checkedForSolidColor = true; m_isSolidColor = false; if (frameCount() > 1) return; if (!haveFrameAtIndex(0)) { IntSize size = m_source.frameSizeAtIndex(0, 0); if (size.width() != 1 || size.height() != 1) return; if (!ensureFrameIsCached(0)) return; } CGImageRef image = nullptr; if (m_frames.size()) image = m_frames[0].m_frame; if (!image) return; // Currently we only check for solid color in the important special case of a 1x1 image. if (CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { unsigned char pixel[4]; // RGBA RetainPtr<CGContextRef> bitmapContext = adoptCF(CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), sRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big)); if (!bitmapContext) return; GraphicsContext(bitmapContext.get()).setCompositeOperation(CompositeCopy); CGRect destinationRect = CGRectMake(0, 0, 1, 1); CGContextDrawImage(bitmapContext.get(), destinationRect, image); if (!pixel[3]) m_solidColor = Color(0, 0, 0, 0); else m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); m_isSolidColor = true; } }