void CSSImageGeneratorValue::addClient(RenderObject* renderer, const IntSize& size) { ref(); ASSERT(renderer); if (!size.isEmpty()) m_sizes.add(size); RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); if (it == m_clients.end()) m_clients.add(renderer, SizeAndCount(size, 1)); else { SizeAndCount& sizeCount = it->value; ++sizeCount.count; } }
void RenderVideo::updateIntrinsicSize() { IntSize size = calculateIntrinsicSize(); size.scale(style()->effectiveZoom()); // Never set the element size to zero when in a media document. if (size.isEmpty() && node()->ownerDocument() && node()->ownerDocument()->isMediaDocument()) return; if (size == intrinsicSize()) return; setIntrinsicSize(size); setPreferredLogicalWidthsDirty(true); setNeedsLayout(true); }
void ImageBySizeCache::removeClient(const RenderObject* renderer) { RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); ASSERT(it != m_clients.end()); SizeCountPair& sizeCount = it->second; IntSize size = sizeCount.first; if (!size.isEmpty()) { m_sizes.remove(size); if (!m_sizes.contains(size)) m_images.remove(size); } if (!--sizeCount.second) m_clients.remove(renderer); }
static inline TransformationMatrix contentToScreenSpaceTransform(const LayerType* layer) { ASSERT(layerTransformsToScreenKnown(layer)); IntSize boundsInLayerSpace = layer->bounds(); IntSize boundsInContentSpace = layer->contentBounds(); TransformationMatrix transform = layer->screenSpaceTransform(); if (boundsInContentSpace.isEmpty()) return transform; // Scale from content space to layer space transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()), boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height())); return transform; }
void ImageResource::setContainerSizeForLayoutObject(const ImageResourceClient* layoutObject, const IntSize& containerSize, float containerZoom) { if (containerSize.isEmpty()) return; ASSERT(layoutObject); ASSERT(containerZoom); if (!m_image) return; if (!m_image->isSVGImage()) { m_image->setContainerSize(containerSize); return; } FloatSize containerSizeWithoutZoom(containerSize); containerSizeWithoutZoom.scale(1 / containerZoom); m_imageForContainerMap->set(layoutObject, SVGImageForContainer::create(toSVGImage(m_image.get()), containerSizeWithoutZoom, containerZoom)); }
Image* SVGImageCache::lookupOrCreateBitmapImageForClient(const CachedImageClient* client) { ASSERT(client); // The cache needs to know the size of the client before querying an image for it. SizeAndScalesMap::iterator sizeIt = m_sizeAndScalesMap.find(client); if (sizeIt == m_sizeAndScalesMap.end()) return Image::nullImage(); IntSize size = sizeIt->second.size; float zoom = sizeIt->second.zoom; float scale = sizeIt->second.scale; ASSERT(!size.isEmpty()); // Lookup image for client in cache and eventually update it. ImageDataMap::iterator it = m_imageDataMap.find(client); if (it != m_imageDataMap.end()) { ImageData& data = it->second; // Common case: image size & zoom remained the same. if (data.sizeAndScales.size == size && data.sizeAndScales.zoom == zoom && data.sizeAndScales.scale == scale) return data.image.get(); // If the image size for the client changed, we have to delete the buffer, remove the item from the cache and recreate it. delete data.buffer; m_imageDataMap.remove(it); } FloatSize scaledSize(size); scaledSize.scale(scale); // Create and cache new image and image buffer at requested size. OwnPtr<ImageBuffer> newBuffer = ImageBuffer::create(expandedIntSize(scaledSize), 1); if (!newBuffer) return Image::nullImage(); m_svgImage->drawSVGToImageBuffer(newBuffer.get(), size, zoom, scale, SVGImage::DontClearImageBuffer); RefPtr<Image> newImage = newBuffer->copyImage(CopyBackingStore); Image* newImagePtr = newImage.get(); ASSERT(newImagePtr); m_imageDataMap.add(client, ImageData(newBuffer.leakPtr(), newImage.release(), sizeIt->second)); return newImagePtr; }
void LayerGLES2::setNeedsDisplay(PassRefPtr<ImageData> contents, const FloatRect& dirtyRect, const IntSize& requiredTextureSize) { if (!isCompositingThread()) { dispatchCompositingMessage(Olympia::Platform::createMessage3(&LayerGLES2::invokeSetNeedsDisplay, this, contents, dirtyRect, requiredTextureSize)); return; } // Handle the case where we need display because we no longer need to be displayed, // due to texture size becoming 0 x 0 if (requiredTextureSize.isEmpty()) { m_dirtyRect = IntRect(); m_contents = 0; m_contentsDirty = false; m_requiredTextureSize = requiredTextureSize; return; } // If the dirty area is empty, there's nothing to do if (dirtyRect.isEmpty()) return; // In order to display, we will need a texture. ASSERT(contents); // Detect if we missed an updateTextureContents(). // If the contents are still dirty, and this is is not an update of the whole texture // we need to draw the new contents into the old if (m_contentsDirty && (dirtyRect != IntRect(IntPoint(), requiredTextureSize))) { ASSERT(m_contents); // if there's no layer renderer yet, we have never been rendered, and // we have no choice but to drop this update if (!m_layerRenderer) return; updateTextureContents(m_layerRenderer->context()); } m_dirtyRect = dirtyRect; m_contents = contents; m_contentsDirty = true; m_requiredTextureSize = requiredTextureSize; }
static inline TransformationMatrix contentToTargetSurfaceTransform(const LayerType* layer) { IntSize boundsInLayerSpace = layer->bounds(); IntSize boundsInContentSpace = layer->contentBounds(); TransformationMatrix transform = layer->drawTransform(); if (boundsInContentSpace.isEmpty()) return transform; // Scale from content space to layer space transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()), boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height())); // The draw transform expects the origin to be in the middle of the layer. transform.translate(-boundsInContentSpace.width() / 2.0, -boundsInContentSpace.height() / 2.0); return transform; }
unsigned DrawingBuffer::createColorTexture(const IntSize& size) { if (!m_context) return 0; unsigned offscreenColorTexture = m_context->createTexture(); if (!offscreenColorTexture) return 0; m_context->bindTexture(GL_TEXTURE_2D, offscreenColorTexture); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (!size.isEmpty()) texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); return offscreenColorTexture; }
void CSSImageGeneratorValue::addClient(const LayoutObject* layoutObject, const IntSize& size) { ASSERT(layoutObject); if (m_clients.isEmpty()) { ASSERT(!m_keepAlive); m_keepAlive = this; } if (!size.isEmpty()) m_sizes.add(size); LayoutObjectSizeCountMap::iterator it = m_clients.find(layoutObject); if (it == m_clients.end()) { m_clients.add(layoutObject, SizeAndCount(size, 1)); } else { SizeAndCount& sizeCount = it->value; ++sizeCount.count; } }
void ChunkedUpdateDrawingAreaProxy::setSize(const IntSize& viewSize) { WebPageProxy* page = this->page(); if (!page->isValid()) return; if (viewSize.isEmpty()) return; m_viewSize = viewSize; m_lastSetViewSize = viewSize; if (m_isWaitingForDidSetFrameNotification) return; m_isWaitingForDidSetFrameNotification = true; page->process()->responsivenessTimer()->start(); page->process()->send(DrawingAreaMessage::SetSize, page->pageID(), CoreIPC::In(id(), viewSize)); }
IntSize SVGImage::containerSize() const { SVGSVGElement* rootElement = svgRootElement(m_page.get()); if (!rootElement) return IntSize(); LayoutSVGRoot* layoutObject = toLayoutSVGRoot(rootElement->layoutObject()); if (!layoutObject) return IntSize(); // If a container size is available it has precedence. IntSize containerSize = layoutObject->containerSize(); if (!containerSize.isEmpty()) return containerSize; // Assure that a container size is always given for a non-identity zoom level. ASSERT(layoutObject->style()->effectiveZoom() == 1); FloatSize intrinsicSize; double intrinsicRatio = 0; layoutObject->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); if (intrinsicSize.isEmpty() && intrinsicRatio) { if (!intrinsicSize.width() && intrinsicSize.height()) intrinsicSize.setWidth(intrinsicSize.height() * intrinsicRatio); else if (intrinsicSize.width() && !intrinsicSize.height()) intrinsicSize.setHeight(intrinsicSize.width() / intrinsicRatio); } // TODO(davve): In order to maintain aspect ratio the intrinsic // size is faked from the viewBox as a last resort. This may cause // unwanted side effects. Preferably we should be able to signal // the intrinsic ratio in another way. if (intrinsicSize.isEmpty()) intrinsicSize = rootElement->currentViewBoxRect().size(); if (!intrinsicSize.isEmpty()) return expandedIntSize(intrinsicSize); // As last resort, use CSS replaced element fallback size. return IntSize(300, 150); }
void LayerBackedDrawingArea::setSize(const IntSize& viewSize) { ASSERT(m_shouldPaint); ASSERT_ARG(viewSize, !viewSize.isEmpty()); m_hostingLayer->setSize(viewSize); m_backingLayer->setSize(viewSize); scheduleCompositingLayerSync(); // Laying out the page can cause the drawing area to change so we keep an extra reference. RefPtr<LayerBackedDrawingArea> protect(this); m_webPage->setSize(viewSize); m_webPage->layoutIfNeeded(); if (m_webPage->drawingArea() != this) return; WebProcess::shared().connection()->deprecatedSend(DrawingAreaProxyLegacyMessage::DidSetSize, m_webPage->pageID(), CoreIPC::In(viewSize)); }
void CSSImageGeneratorValue::removeClient(RenderObject* renderer) { ASSERT(renderer); RenderObjectSizeCountMap::iterator it = m_clients.find(renderer); ASSERT(it != m_clients.end()); IntSize removedImageSize; SizeAndCount& sizeCount = it->value; IntSize size = sizeCount.size; if (!size.isEmpty()) { m_sizes.remove(size); if (!m_sizes.contains(size)) m_images.remove(size); } if (!--sizeCount.count) m_clients.remove(renderer); deref(); }
std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace colorSpace, RenderingMode renderingMode) { IntSize clampedSize = roundedIntSize(clampedRect.size()); IntSize unclampedSize = roundedIntSize(targetRect.size()); // Don't create empty ImageBuffers. if (clampedSize.isEmpty()) return nullptr; auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, 1, colorSpace); if (!imageBuffer) return nullptr; GraphicsContext& imageContext = imageBuffer->context(); // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. imageContext.scale(FloatSize(unclampedSize.width() / targetRect.width(), unclampedSize.height() / targetRect.height())); return imageBuffer; }
void CSSImageGeneratorValue::removeClient(const LayoutObject* layoutObject) { ASSERT(layoutObject); LayoutObjectSizeCountMap::iterator it = m_clients.find(layoutObject); ASSERT_WITH_SECURITY_IMPLICATION(it != m_clients.end()); IntSize removedImageSize; SizeAndCount& sizeCount = it->value; IntSize size = sizeCount.size; if (!size.isEmpty()) { m_sizes.remove(size); if (!m_sizes.contains(size)) m_images.remove(size); } if (!--sizeCount.count) m_clients.remove(layoutObject); if (m_clients.isEmpty()) { ASSERT(m_keepAlive); m_keepAlive.clear(); } }
void SVGImagePainter::paintForeground(const PaintInfo& paintInfo) { const LayoutImageResource* imageResource = m_layoutSVGImage.imageResource(); IntSize imageViewportSize = expandedIntSize(computeImageViewportSize()); if (imageViewportSize.isEmpty()) return; RefPtr<Image> image = imageResource->image(imageViewportSize, m_layoutSVGImage.style()->effectiveZoom()); FloatRect destRect = m_layoutSVGImage.objectBoundingBox(); FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(m_layoutSVGImage.element()); imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); InterpolationQuality interpolationQuality = InterpolationDefault; interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(m_layoutSVGImage, image.get(), image.get(), LayoutSize(destRect.size())); InterpolationQuality previousInterpolationQuality = paintInfo.context.imageInterpolationQuality(); paintInfo.context.setImageInterpolationQuality(interpolationQuality); paintInfo.context.drawImage(image.get(), destRect, srcRect, SkXfermode::kSrcOver_Mode); paintInfo.context.setImageInterpolationQuality(previousInterpolationQuality); }
PassRefPtr<Image> CSSCrossfadeValue::image(LayoutObject* renderer, const IntSize& size) { if (size.isEmpty()) return nullptr; Document* document = &renderer->document(); ImageResource* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), document); ImageResource* cachedToImage = cachedImageForCSSValue(m_toValue.get(), document); if (!cachedFromImage || !cachedToImage) return Image::nullImage(); Image* fromImage = cachedFromImage->imageForLayoutObject(renderer); Image* toImage = cachedToImage->imageForLayoutObject(renderer); if (!fromImage || !toImage) return Image::nullImage(); m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); return m_generatedImage.release(); }
PassRefPtr<Image> CSSCrossfadeValue::image(RenderObject* renderer, const IntSize& size) { if (size.isEmpty()) return 0; CachedResourceLoader* cachedResourceLoader = renderer->document()->cachedResourceLoader(); CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); if (!cachedFromImage || !cachedToImage) return Image::nullImage(); Image* fromImage = cachedFromImage->imageForRenderer(renderer); Image* toImage = cachedToImage->imageForRenderer(renderer); if (!fromImage || !toImage) return Image::nullImage(); m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); return m_generatedImage.release(); }
PassOwnPtr<RenderThemeEfl::ThemePartCacheEntry> RenderThemeEfl::ThemePartCacheEntry::create(const String& themePath, FormType type, const IntSize& size) { ASSERT(!themePath.isEmpty()); if (isFormElementTooLargeToDisplay(size) || size.isEmpty()) { EINA_LOG_ERR("Cannot render an element of size %dx%d.", size.width(), size.height()); return nullptr; } OwnPtr<ThemePartCacheEntry> entry = adoptPtr(new ThemePartCacheEntry); entry->m_canvas = adoptPtr(ecore_evas_buffer_new(size.width(), size.height())); if (!entry->canvas()) { EINA_LOG_ERR("ecore_evas_buffer_new(%d, %d) failed.", size.width(), size.height()); return nullptr; } // By default EFL creates buffers without alpha. ecore_evas_alpha_set(entry->canvas(), EINA_TRUE); entry->m_edje = adoptRef(edje_object_add(ecore_evas_get(entry->canvas()))); ASSERT(entry->edje()); if (!setSourceGroupForEdjeObject(entry->edje(), themePath, toEdjeGroup(type))) return nullptr; entry->m_surface = createSurfaceForBackingStore(entry->canvas()); if (!entry->surface()) return nullptr; evas_object_resize(entry->edje(), size.width(), size.height()); evas_object_show(entry->edje()); entry->type = type; entry->size = size; return entry.release(); }
IntSize RenderVideo::calculateIntrinsicSize() { HTMLVideoElement* video = videoElement(); // Spec text from 4.8.6 // // The intrinsic width of a video element's playback area is the intrinsic width // of the video resource, if that is available; otherwise it is the intrinsic // width of the poster frame, if that is available; otherwise it is 300 CSS pixels. // // The intrinsic height of a video element's playback area is the intrinsic height // of the video resource, if that is available; otherwise it is the intrinsic // height of the poster frame, if that is available; otherwise it is 150 CSS pixels. MediaPlayer* player = mediaElement()->player(); if (player && video->readyState() >= HTMLVideoElement::HAVE_METADATA) { IntSize size = player->naturalSize(); if (!size.isEmpty()) return size; } if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred()) return m_cachedImageSize; // When the natural size of the video is unavailable, we use the provided // width and height attributes of the video element as the intrinsic size until // better values become available. if (video->hasAttribute(widthAttr) && video->hasAttribute(heightAttr)) return IntSize(video->width(), video->height()); // <video> in standalone media documents should not use the default 300x150 // size since they also have audio-only files. By setting the intrinsic // size to 300x1 the video will resize itself in these cases, and audio will // have the correct height (it needs to be > 0 for controls to render properly). if (video->ownerDocument() && video->ownerDocument()->isMediaDocument()) return IntSize(defaultSize().width(), 1); return defaultSize(); }
void DrawingBuffer::reset(const IntSize& newSize) { if (!m_context) return; IntSize adjustedSize; bool evictContext = false; bool isNewContext = m_size.isEmpty(); if (s_allowContextEvictionOnCreate && isNewContext) adjustedSize = adjustSizeWithContextEviction(newSize, evictContext); else adjustedSize = adjustSize(newSize); if (adjustedSize.isEmpty()) return; if (evictContext) m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost."); if (adjustedSize != m_size) { do { // resize multisample FBO if (!resizeMultisampleFramebuffer(adjustedSize) || !resizeFramebuffer(adjustedSize)) { adjustedSize.scale(s_resourceAdjustedRatio); continue; } #if OS(DARWIN) // FIXME: This can be removed once renderbufferStorageMultisample starts reporting GL_OUT_OF_MEMORY properly on OSX. if (!checkBufferIntegrity()) { adjustedSize.scale(s_resourceAdjustedRatio); continue; } #endif break; } while (!adjustedSize.isEmpty()); setSize(adjustedSize); if (adjustedSize.isEmpty()) return; } m_context->disable(GraphicsContext3D::SCISSOR_TEST); m_context->clearColor(0, 0, 0, 0); m_context->colorMask(true, true, true, true); GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; if (m_attributes.depth) { m_context->clearDepth(1.0f); clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; m_context->depthMask(true); } if (m_attributes.stencil) { m_context->clearStencil(0); clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF); } clearFramebuffers(clearMask); }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; int drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == cTextFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { IntSize size; int blur; Color color; graphicsContext->getShadow(size, blur, color); drawIntoBitmap = !size.isEmpty() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. int lineGap = font->lineGap(); textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing()); bitmap.set(graphicsContext->createWindowsBitmap(textRect.size())); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->m_font.hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == cTextFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->m_syntheticBoldOffset) { xform.eM21 = 0; xform.eDx = font->m_syntheticBoldOffset; xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { RetainPtr<CGMutablePathRef> path(AdoptCF, CGPathCreateMutable()); XFORM xform; GetWorldTransform(hdc, &xform); TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGAffineTransform glyphTranslation = CGAffineTransformIdentity; for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGAffineTransform glyphTransform = CGAffineTransformConcat(initialGlyphTransform, glyphTranslation); CGPathAddPath(path.get(), &glyphTransform, glyphPath.get()); glyphTranslation = CGAffineTransformTranslate(glyphTranslation, gdiAdvances[i], 0); } CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); if (drawingMode & cTextFill) { CGContextAddPath(cgContext, path.get()); CGContextFillPath(cgContext); if (font->m_syntheticBoldOffset) { CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); CGContextAddPath(cgContext, path.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); } } if (drawingMode & cTextStroke) { CGContextAddPath(cgContext, path.get()); CGContextStrokePath(cgContext); if (font->m_syntheticBoldOffset) { CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); CGContextAddPath(cgContext, path.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); } } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }
bool DrawingBuffer::reset(const IntSize& newSize) { if (!m_context) return false; m_context->makeContextCurrent(); int maxTextureSize = 0; m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); if (newSize.height() > maxTextureSize || newSize.width() > maxTextureSize) { clear(); return false; } int pixelDelta = newSize.width() * newSize.height(); int oldSize = 0; if (!m_size.isEmpty()) { oldSize = m_size.width() * m_size.height(); pixelDelta -= oldSize; } IntSize adjustedSize = newSize; if (s_maximumResourceUsePixels) { while ((s_currentResourceUsePixels + pixelDelta) > s_maximumResourceUsePixels) { adjustedSize.scale(s_resourceAdjustedRatio); if (adjustedSize.isEmpty()) { clear(); return false; } pixelDelta = adjustedSize.width() * adjustedSize.height(); pixelDelta -= oldSize; } } const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); if (adjustedSize != m_size) { unsigned internalColorFormat, colorFormat, internalRenderbufferFormat; if (attributes.alpha) { internalColorFormat = GraphicsContext3D::RGBA; colorFormat = GraphicsContext3D::RGBA; internalRenderbufferFormat = Extensions3D::RGBA8_OES; } else { internalColorFormat = GraphicsContext3D::RGB; colorFormat = GraphicsContext3D::RGB; internalRenderbufferFormat = Extensions3D::RGB8_OES; } do { m_size = adjustedSize; // resize multisample FBO if (multisample()) { int maxSampleCount = 0; m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); int sampleCount = std::min(4, maxSampleCount); m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); resizeDepthStencil(sampleCount); if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { adjustedSize.scale(s_resourceAdjustedRatio); continue; } } // resize regular FBO m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE, 0); m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); // resize the front color buffer if (m_separateFrontTexture) { m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_frontColorBuffer); m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE, 0); } m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); if (!multisample()) resizeDepthStencil(0); if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) == GraphicsContext3D::FRAMEBUFFER_COMPLETE) break; adjustedSize.scale(s_resourceAdjustedRatio); } while (!adjustedSize.isEmpty()); pixelDelta = m_size.width() * m_size.height(); pixelDelta -= oldSize; s_currentResourceUsePixels += pixelDelta; if (!newSize.isEmpty() && adjustedSize.isEmpty()) { clear(); return false; } } m_context->disable(GraphicsContext3D::SCISSOR_TEST); m_context->clearColor(0, 0, 0, 0); m_context->colorMask(true, true, true, true); GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; if (attributes.depth) { m_context->clearDepth(1.0f); clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; m_context->depthMask(true); } if (attributes.stencil) { m_context->clearStencil(0); clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF); } clearFramebuffers(clearMask); return true; }
void SVGImage::drawSVGToImageBuffer(ImageBuffer* buffer, const IntSize& size, float zoom, float scale, ShouldClearBuffer shouldClear) { // FIXME: This doesn't work correctly with animations. If an image contains animations, that say run for 2 seconds, // and we currently have one <img> that displays us. If we open another document referencing the same SVGImage it // will display the document at a time where animations already ran - even though it has its own ImageBuffer. // We currently don't implement SVGSVGElement::setCurrentTime, and can NOT go back in time, once animations started. // There's no way to fix this besides avoiding style/attribute mutations from SVGAnimationElement. ASSERT(buffer); ASSERT(!size.isEmpty()); if (!m_page) return; Frame* frame = m_page->mainFrame(); SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement(); if (!rootElement) return; RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer()); if (!renderer) return; // Draw image at requested size. ImageObserver* observer = imageObserver(); ASSERT(observer); // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout. setImageObserver(0); // Disable repainting; we don't want deferred repaints to schedule any timers due to this relayout. frame->view()->beginDisableRepaints(); renderer->setContainerSize(size); frame->view()->resize(this->size()); if (zoom != 1) frame->setPageZoomFactor(zoom); // Eventually clear image buffer. IntRect rect(IntPoint(), size); FloatRect scaledRect(rect); scaledRect.scale(scale); if (shouldClear == ClearImageBuffer) buffer->context()->clearRect(enclosingIntRect(scaledRect)); // Draw SVG on top of ImageBuffer. draw(buffer->context(), enclosingIntRect(scaledRect), rect, ColorSpaceDeviceRGB, CompositeSourceOver); // Reset container size & zoom to initial state. Otherwhise the size() of this // image would return whatever last size was set by drawSVGToImageBuffer(). if (zoom != 1) frame->setPageZoomFactor(1); renderer->setContainerSize(IntSize()); frame->view()->resize(this->size()); if (frame->view()->needsLayout()) frame->view()->layout(); setImageObserver(observer); frame->view()->endDisableRepaints(); }
void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper) { const int changeMask = graphicsLayer->changeMask(); initializeTextureMapper(textureMapper); const TextureMapperNode::ContentData& pendingContent = graphicsLayer->pendingContent(); if (changeMask == NoChanges && pendingContent.needsDisplayRect.isEmpty() && !pendingContent.needsDisplay) return; setNeedsDisplay(); if (m_parent) m_parent->m_state.dirty = true; if (m_currentContent.contentType == HTMLContentType && (changeMask & ParentChange)) { // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't // try to snatch that ownership. if (!graphicsLayer->parent()) m_parent = 0; else m_parent = toTextureMapperNode(graphicsLayer->parent()); if (!graphicsLayer->parent() && m_parent) { size_t index = m_parent->m_children.find(this); m_parent->m_children.remove(index); } } if (changeMask & ChildrenChange) { m_children.clear(); for (size_t i = 0; i < graphicsLayer->children().size(); ++i) { if (TextureMapperNode* child = toTextureMapperNode(graphicsLayer->children()[i])) { if (!child) continue; m_children.append(child); child->m_parent = this; } } m_state.dirty = true; } if (changeMask & (SizeChange | ContentsRectChange)) { IntSize wantedSize = IntSize(graphicsLayer->size().width(), graphicsLayer->size().height()); if (wantedSize.isEmpty() && pendingContent.contentType == HTMLContentType) wantedSize = IntSize(graphicsLayer->contentsRect().width(), graphicsLayer->contentsRect().height()); if (wantedSize != m_size) { m_size = IntSize(wantedSize.width(), wantedSize.height()); if (m_platformClient) m_platformClient->setSizeChanged(m_size); const bool needsTiling = m_size.width() > 2000 || m_size.height() > 2000; if (m_state.tiled != needsTiling) m_state.tiled = needsTiling; m_state.dirty = true; } } if (changeMask & MaskLayerChange) { if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->maskLayer())) layer->m_effectTarget = this; } if (changeMask & ReplicaLayerChange) { if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->replicaLayer())) layer->m_effectTarget = this; } if (changeMask & (TransformChange | SizeChange | AnchorPointChange | PositionChange)) m_transforms.localDirty = true; if (changeMask & (ChildrenTransformChange | SizeChange)) m_transforms.perspectiveDirty = true; if (changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | ContentsRectChange | BackfaceVisibilityChange | PositionChange | MaskLayerChange | DrawsContentChange | ContentChange | ReplicaLayerChange)) { // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms, // all these elements affect the transforms of all the descendants. invalidateTransform(); } if (changeMask & DisplayChange) m_state.dirty = true; m_state.maskLayer = toTextureMapperNode(graphicsLayer->maskLayer()); m_state.replicaLayer = toTextureMapperNode(graphicsLayer->replicaLayer()); m_state.pos = graphicsLayer->position(); m_state.anchorPoint = graphicsLayer->anchorPoint(); m_state.size = graphicsLayer->size(); m_state.transform = graphicsLayer->transform(); m_state.contentsRect = graphicsLayer->contentsRect(); m_state.opacity = graphicsLayer->opacity(); m_state.contentsRect = graphicsLayer->contentsRect(); m_state.preserves3D = graphicsLayer->preserves3D(); m_state.masksToBounds = graphicsLayer->masksToBounds(); m_state.drawsContent = graphicsLayer->drawsContent(); m_state.contentsOpaque = graphicsLayer->contentsOpaque(); m_state.backfaceVisibility = graphicsLayer->backfaceVisibility(); m_state.childrenTransform = graphicsLayer->childrenTransform(); m_currentContent.contentType = pendingContent.contentType; m_currentContent.image = pendingContent.image; m_currentContent.media = pendingContent.media; m_currentContent.backgroundColor = pendingContent.backgroundColor; m_currentContent.needsDisplay = m_currentContent.needsDisplay || pendingContent.needsDisplay; m_currentContent.needsDisplayRect.unite(pendingContent.needsDisplayRect); }