예제 #1
0
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);
}
예제 #3
0
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);
}
예제 #4
0
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;
}
예제 #5
0
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));
}
예제 #6
0
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #9
0
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;
}
예제 #10
0
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;
    }
}
예제 #11
0
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));
}
예제 #12
0
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();
}
예제 #15
0
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;
}
예제 #16
0
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();
  }
}
예제 #17
0
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);
}
예제 #18
0
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();
}
예제 #19
0
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();
}
예제 #20
0
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();
}
예제 #21
0
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();
}
예제 #22
0
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);
}
예제 #23
0
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);
}
예제 #24
0
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;
}
예제 #25
0
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);

}