Ejemplo n.º 1
0
PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode)
{
    PatternData* currentData = m_patternMap.get(object);
    if (currentData && currentData->pattern)
        return currentData;

    if (m_shouldCollectPatternAttributes) {
        patternElement().synchronizeAnimatedSVGAttribute(anyQName());

        m_attributes = PatternAttributes();
        patternElement().collectPatternAttributes(m_attributes);
        m_shouldCollectPatternAttributes = false;
    }

    // If we couldn't determine the pattern content element root, stop here.
    if (!m_attributes.patternContentElement())
        return 0;

    // An empty viewBox disables rendering.
    if (m_attributes.hasViewBox() && m_attributes.viewBox().isEmpty())
        return 0;

    // Compute all necessary transformations to build the tile image & the pattern.
    FloatRect tileBoundaries;
    AffineTransform tileImageTransform;
    if (!buildTileImageTransform(object, m_attributes, patternElement(), tileBoundaries, tileImageTransform))
        return 0;

    AffineTransform absoluteTransformIgnoringRotation;
    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation);

    // Ignore 2D rotation, as it doesn't affect the size of the tile.
    SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
    FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries);
    FloatRect clampedAbsoluteTileBoundaries;

    // Scale the tile size to match the scale level of the patternTransform.
    absoluteTileBoundaries.scale(static_cast<float>(m_attributes.patternTransform().xScale()),
        static_cast<float>(m_attributes.patternTransform().yScale()));

    // Build tile image.
    std::unique_ptr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries);
    if (!tileImage)
        return 0;

    RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore);
    if (!copiedImage)
        return 0;

    // Build pattern.
    OwnPtr<PatternData> patternData = adoptPtr(new PatternData);
    patternData->pattern = Pattern::create(copiedImage, true, true);

    // Compute pattern space transformation.
    const IntSize tileImageSize = tileImage->logicalSize();
    patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
    patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height());

    AffineTransform patternTransform = m_attributes.patternTransform();
    if (!patternTransform.isIdentity())
        patternData->transform = patternTransform * patternData->transform;

    // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows.
    if (resourceMode & ApplyToTextMode) {
        AffineTransform additionalTextTransformation;
        if (shouldTransformOnTextPainting(object, additionalTextTransformation))
            patternData->transform *= additionalTextTransformation;
    }
    patternData->pattern->setPatternSpaceTransform(patternData->transform);

    // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation
    // failures in the SVG image cache for example). To avoid having our PatternData deleted by
    // removeAllClientsFromCache(), we only make it visible in the cache at the very end.
    return m_patternMap.set(object, patternData.release()).iterator->value.get();
}
static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText)
{
    if (to < 0)
        to = run.length();

    QPainter *p = ctx->platformContext();

    QPen textFillPen;
    if (ctx->textDrawingMode() & cTextFill) {
        if (ctx->fillGradient()) {
            QBrush brush(*ctx->fillGradient()->platformGradient());
            brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
            textFillPen = QPen(brush, 0);
        } else if (ctx->fillPattern()) {
            AffineTransform affine;
            textFillPen = QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0);
        } else
            textFillPen = QPen(QColor(ctx->fillColor()));
    }

    QPen textStrokePen;
    if (ctx->textDrawingMode() & cTextStroke) {
        if (ctx->strokeGradient()) {
            QBrush brush(*ctx->strokeGradient()->platformGradient());
            brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
            textStrokePen = QPen(brush, ctx->strokeThickness());
        } else if (ctx->strokePattern()) {
            AffineTransform affine;
            QBrush brush(ctx->strokePattern()->createPlatformPattern(affine));
            textStrokePen = QPen(brush, ctx->strokeThickness());
        } else
            textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness());
    }

    String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
    QString string = fromRawDataWithoutRef(sanitized);
    QPointF pt(point.x(), point.y());

    // text shadow
    IntSize shadowSize;
    int shadowBlur;
    Color shadowColor;
    bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor);

    if (from > 0 || to < run.length()) {
        if (isComplexText) {
            QTextLayout layout(string, font);
            QTextLine line = setupLayout(&layout, run);
            float x1 = line.cursorToX(from);
            float x2 = line.cursorToX(to);
            if (x2 < x1)
                qSwap(x1, x2);

            QFontMetrics fm(font);
            int ascent = fm.ascent();
            QRectF clip(fm.boundingRect(string));

            if (hasShadow) {
                // TODO: when blur support is added, the clip will need to account
                // for the blur radius
                qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
                if (shadowSize.width() > 0)
                    dx2 = shadowSize.width();
                else
                    dx1 = -shadowSize.width();
                if (shadowSize.height() > 0)
                    dy2 = shadowSize.height();
                else
                    dy1 = -shadowSize.height();
                // expand the clip rect to include the text shadow as well
                clip.adjust(dx1, dx2, dy1, dy2);
            }
            p->save();
            //p->setClipRect(clip.toRect(), Qt::IntersectClip);
            pt.setY(pt.y() - ascent);
            if (hasShadow) {
                p->save();
                p->setPen(QColor(shadowColor));
                p->translate(shadowSize.width(), shadowSize.height());
                line.draw(p, pt);
                p->restore();
            }
            p->setPen(textFillPen);
            line.draw(p, pt);
            p->restore();
            return;
        }
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
        int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping);
        pt.setX(pt.x() + skipWidth);
        string = fromRawDataWithoutRef(sanitized, from, to - from);
#endif
    }

    p->setFont(font);

    int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier.
    if (!isComplexText)
        flags |= Qt::TextBypassShaping;
#endif

    QFontMetrics fm(font);
    QRectF clip(pt.x(), pt.y()-fm.ascent(), fm.width(string, -1, flags), fm.height());

    if (hasShadow) {
        // TODO: text shadow blur support
        p->save();
        p->translate(shadowSize.width(), shadowSize.height());
        //p->setClipRect(clip, Qt::IntersectClip);
        p->setPen(QColor(shadowColor));
        p->drawText(pt, string, flags, run.padding());
        p->restore();
    }
    if (ctx->textDrawingMode() & cTextStroke) {
        QPainterPath path;
        path.addText(pt, font, string);
        p->save();
        //p->setClipRect(clip, Qt::IntersectClip);
        p->setPen(textStrokePen);
        p->strokePath(path, p->pen());
        p->restore();
    }
    if (ctx->textDrawingMode() & cTextFill) {
        p->save();
        //p->setClipRect(clip, Qt::IntersectClip);
        p->setPen(textFillPen);
        p->drawText(pt, string, flags, run.padding());
        p->restore();
    }
}
void RenderTheme::paintSliderTicks(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& rect)
{
    Node* node = o.node();
    if (!node)
        return;

    HTMLInputElement* input = node->toInputElement();
    if (!input)
        return;

    HTMLDataListElement* dataList = downcast<HTMLDataListElement>(input->list());
    if (!dataList)
        return;

    double min = input->minimum();
    double max = input->maximum();
    ControlPart part = o.style().appearance();
    // We don't support ticks on alternate sliders like MediaVolumeSliders.
    if (part !=  SliderHorizontalPart && part != SliderVerticalPart)
        return;
    bool isHorizontal = part ==  SliderHorizontalPart;

    IntSize thumbSize;
    const RenderObject* thumbRenderer = input->sliderThumbElement()->renderer();
    if (thumbRenderer) {
        const RenderStyle& thumbStyle = thumbRenderer->style();
        int thumbWidth = thumbStyle.width().intValue();
        int thumbHeight = thumbStyle.height().intValue();
        thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight);
        thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth);
    }

    IntSize tickSize = sliderTickSize();
    float zoomFactor = o.style().effectiveZoom();
    FloatRect tickRect;
    int tickRegionSideMargin = 0;
    int tickRegionWidth = 0;
    IntRect trackBounds;
    RenderObject* trackRenderer = input->sliderTrackElement()->renderer();
    // We can ignoring transforms because transform is handled by the graphics context.
    if (trackRenderer)
        trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms();
    IntRect sliderBounds = o.absoluteBoundingBoxRectIgnoringTransforms();

    // Make position relative to the transformed ancestor element.
    trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x());
    trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y());

    if (isHorizontal) {
        tickRect.setWidth(floor(tickSize.width() * zoomFactor));
        tickRect.setHeight(floor(tickSize.height() * zoomFactor));
        tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
        tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
        tickRegionWidth = trackBounds.width() - thumbSize.width();
    } else {
        tickRect.setWidth(floor(tickSize.height() * zoomFactor));
        tickRect.setHeight(floor(tickSize.width() * zoomFactor));
        tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
        tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
        tickRegionWidth = trackBounds.height() - thumbSize.width();
    }
    RefPtr<HTMLCollection> options = dataList->options();
    GraphicsContextStateSaver stateSaver(*paintInfo.context);
    paintInfo.context->setFillColor(o.style().visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
    for (unsigned i = 0; Node* node = options->item(i); i++) {
        ASSERT(is<HTMLOptionElement>(node));
        HTMLOptionElement& optionElement = downcast<HTMLOptionElement>(*node);
        String value = optionElement.value();
        if (!input->isValidValue(value))
            continue;
        double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value));
        double tickFraction = (parsedValue - min) / (max - min);
        double tickRatio = isHorizontal && o.style().isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction;
        double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio);
        if (isHorizontal)
            tickRect.setX(tickPosition);
        else
            tickRect.setY(tickPosition);
        paintInfo.context->fillRect(tickRect);
    }
}
// Recursively walks the layer tree starting at the given node and computes all the
// necessary transformations, scissor rectangles, render surfaces, etc.
void LayerRendererChromium::updatePropertiesAndRenderSurfaces(CCLayerImpl* layer, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layerList)
{
    // Compute the new matrix transformation that will be applied to this layer and
    // all its children. It's important to remember that the layer's position
    // is the position of the layer's anchor point. Also, the coordinate system used
    // assumes that the origin is at the lower left even though the coordinates the browser
    // gives us for the layers are for the upper left corner. The Y flip happens via
    // the orthographic projection applied at render time.
    // The transformation chain for the layer is (using the Matrix x Vector order):
    // M = M[p] * Tr[l] * M[l] * Tr[c]
    // Where M[p] is the parent matrix passed down to the function
    //       Tr[l] is the translation matrix locating the layer's anchor point
    //       Tr[c] is the translation offset between the anchor point and the center of the layer
    //       M[l] is the layer's matrix (applied at the anchor point)
    // This transform creates a coordinate system whose origin is the center of the layer.
    // Note that the final matrix used by the shader for the layer is P * M * S . This final product
    // is computed in drawTexturedQuad().
    // Where: P is the projection matrix
    //        M is the layer's matrix computed above
    //        S is the scale adjustment (to scale up to the layer size)
    IntSize bounds = layer->bounds();
    FloatPoint anchorPoint = layer->anchorPoint();
    FloatPoint position = layer->position();

    // Offset between anchor point and the center of the quad.
    float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
    float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();

    TransformationMatrix layerLocalTransform;
    // LT = Tr[l]
    layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
    // LT = Tr[l] * M[l]
    layerLocalTransform.multiply(layer->transform());
    // LT = Tr[l] * M[l] * Tr[c]
    layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());

    TransformationMatrix combinedTransform = parentMatrix;
    combinedTransform = combinedTransform.multiply(layerLocalTransform);

    FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
    IntRect transformedLayerRect;

    // The layer and its descendants render on a new RenderSurface if any of
    // these conditions hold:
    // 1. The layer clips its descendants and its transform is not a simple translation.
    // 2. If the layer has opacity != 1 and does not have a preserves-3d transform style.
    // 3. The layer uses a mask
    // 4. The layer has a replica (used for reflections)
    // 5. The layer doesn't preserve-3d but is the child of a layer which does.
    // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening
    // out its children. The opacity value of the children layers is multiplied by the opacity
    // of their parent.
    bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform);
    bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D();
    bool useSurfaceForMasking = layer->maskLayer();
    bool useSurfaceForReflection = layer->replicaLayer();
    bool useSurfaceForFlatDescendants = layer->parent() && layer->parent()->preserves3D() && !layer->preserves3D() && layer->descendantsDrawsContent();
    if (useSurfaceForMasking || useSurfaceForReflection || useSurfaceForFlatDescendants || ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawsContent())) {
        RenderSurfaceChromium* renderSurface = layer->renderSurface();
        if (!renderSurface)
            renderSurface = layer->createRenderSurface();

        // The origin of the new surface is the upper left corner of the layer.
        TransformationMatrix drawTransform;
        drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
        layer->setDrawTransform(drawTransform);

        transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height());

        // Layer's opacity will be applied when drawing the render surface.
        renderSurface->m_drawOpacity = layer->opacity();
        if (layer->parent() && layer->parent()->preserves3D())
            renderSurface->m_drawOpacity *= layer->parent()->drawOpacity();
        layer->setDrawOpacity(1);

        TransformationMatrix layerOriginTransform = combinedTransform;
        layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
        renderSurface->m_originTransform = layerOriginTransform;
        layer->setScissorRect(IntRect());

        // The render surface scissor rect is the scissor rect that needs to
        // be applied before drawing the render surface onto its containing
        // surface and is therefore expressed in the parent's coordinate system.
        renderSurface->m_scissorRect = layer->parent() ? layer->parent()->scissorRect() : layer->scissorRect();

        renderSurface->m_layerList.clear();

        if (layer->maskLayer()) {
            renderSurface->m_maskLayer = layer->maskLayer();
            layer->maskLayer()->setTargetRenderSurface(renderSurface);
        } else
            renderSurface->m_maskLayer = 0;

        if (layer->replicaLayer() && layer->replicaLayer()->maskLayer())
            layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface);

        renderSurfaceLayerList.append(layer);
    } else {
        // DT = M[p] * LT
        layer->setDrawTransform(combinedTransform);
        transformedLayerRect = enclosingIntRect(layer->drawTransform().mapRect(layerRect));

        layer->setDrawOpacity(layer->opacity());

        if (layer->parent()) {
            if (layer->parent()->preserves3D())
               layer->setDrawOpacity(layer->drawOpacity() * layer->parent()->drawOpacity());

            // Layers inherit the scissor rect from their parent.
            layer->setScissorRect(layer->parent()->scissorRect());

            layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
        }

        if (layer != m_rootCCLayerImpl.get())
            layer->clearRenderSurface();

        if (layer->masksToBounds()) {
            IntRect scissor = transformedLayerRect;
            if (!layer->scissorRect().isEmpty())
                scissor.intersect(layer->scissorRect());
            layer->setScissorRect(scissor);
        }
    }

    if (layer->renderSurface())
        layer->setTargetRenderSurface(layer->renderSurface());
    else {
        ASSERT(layer->parent());
        layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
    }

    // drawableContentRect() is always stored in the coordinate system of the
    // RenderSurface the layer draws into.
    if (layer->drawsContent())
        layer->setDrawableContentRect(transformedLayerRect);
    else
        layer->setDrawableContentRect(IntRect());

    TransformationMatrix sublayerMatrix = layer->drawTransform();

    // Flatten to 2D if the layer doesn't preserve 3D.
    if (!layer->preserves3D()) {
        sublayerMatrix.setM13(0);
        sublayerMatrix.setM23(0);
        sublayerMatrix.setM31(0);
        sublayerMatrix.setM32(0);
        sublayerMatrix.setM33(1);
        sublayerMatrix.setM34(0);
        sublayerMatrix.setM43(0);
    }

    // Apply the sublayer transform at the center of the layer.
    sublayerMatrix.multiply(layer->sublayerTransform());

    // The origin of the children is the top left corner of the layer, not the
    // center. The matrix passed down to the children is therefore:
    // M[s] = M * Tr[-center]
    sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);

    LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->m_layerList : layerList);
    descendants.append(layer);

    unsigned thisLayerIndex = descendants.size() - 1;

    for (size_t i = 0; i < layer->children().size(); ++i) {
        CCLayerImpl* child = layer->children()[i].get();
        updatePropertiesAndRenderSurfaces(child, sublayerMatrix, renderSurfaceLayerList, descendants);

        if (child->renderSurface()) {
            RenderSurfaceChromium* childRenderSurface = child->renderSurface();
            IntRect drawableContentRect = layer->drawableContentRect();
            drawableContentRect.unite(enclosingIntRect(childRenderSurface->drawableContentRect()));
            layer->setDrawableContentRect(drawableContentRect);
            descendants.append(child);
        } else {
            IntRect drawableContentRect = layer->drawableContentRect();
            drawableContentRect.unite(child->drawableContentRect());
            layer->setDrawableContentRect(drawableContentRect);
        }
    }

    if (layer->masksToBounds() || useSurfaceForMasking) {
        IntRect drawableContentRect = layer->drawableContentRect();
        drawableContentRect.intersect(transformedLayerRect);
        layer->setDrawableContentRect(drawableContentRect);
    }

    if (layer->renderSurface() && layer != m_rootCCLayerImpl.get()) {
        RenderSurfaceChromium* renderSurface = layer->renderSurface();
        renderSurface->m_contentRect = layer->drawableContentRect();
        FloatPoint surfaceCenter = renderSurface->contentRectCenter();

        // Restrict the RenderSurface size to the portion that's visible.
        FloatSize centerOffsetDueToClipping;

        // Don't clip if the layer is reflected as the reflection shouldn't be
        // clipped.
        if (!layer->replicaLayer()) {
            if (!layer->scissorRect().isEmpty())
                renderSurface->m_contentRect.intersect(layer->scissorRect());
            FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter();
            centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
        }

        // The RenderSurface backing texture cannot exceed the maximum supported
        // texture size.
        renderSurface->m_contentRect.setWidth(std::min(renderSurface->m_contentRect.width(), m_maxTextureSize));
        renderSurface->m_contentRect.setHeight(std::min(renderSurface->m_contentRect.height(), m_maxTextureSize));

        if (renderSurface->m_contentRect.isEmpty())
            renderSurface->m_layerList.clear();

        // Since the layer starts a new render surface we need to adjust its
        // scissor rect to be expressed in the new surface's coordinate system.
        layer->setScissorRect(layer->drawableContentRect());

        // Adjust the origin of the transform to be the center of the render surface.
        renderSurface->m_drawTransform = renderSurface->m_originTransform;
        renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);

        // Compute the transformation matrix used to draw the replica of the render
        // surface.
        if (layer->replicaLayer()) {
            renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform;
            renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0);
            renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform());
            renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0);
        }
    }

    // If preserves-3d then sort all the descendants in 3D so that they can be 
    // drawn from back to front. If the preserves-3d property is also set on the parent then
    // skip the sorting as the parent will sort all the descendants anyway.
    if (layer->preserves3D() && (!layer->parent() || !layer->parent()->preserves3D()))
        m_layerSorter.sort(&descendants.at(thisLayerIndex), descendants.end());
}
Ejemplo n.º 5
0
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatPoint& srcPoint,
    const FloatSize& tileSize, CompositeOperator op)
{
    if (!m_source.initialized())
        return;

    cairo_surface_t* image = frameAtIndex(m_currentFrame);
    if (!image) // If it's too early we won't have an image yet.
        return;

    IntSize intrinsicImageSize = size();                       
    FloatRect srcRect(srcPoint, intrinsicImageSize);
    FloatPoint point = srcPoint;

    // Check and see if a single draw of the image can cover the entire area we are supposed to tile.
    float tileWidth = size().width();
    float tileHeight = size().height();
    
    // If the scale is not equal to the intrinsic size of the image, set transform matrix
    // to the appropriate scalar matrix, scale the source point, and set the size of the
    // scaled tile. 
    float scaleX = 1.0;
    float scaleY = 1.0;
    cairo_matrix_t mat;
    cairo_matrix_init_identity(&mat);
    if (tileSize.width() != intrinsicImageSize.width() || tileSize.height() != intrinsicImageSize.height()) {
        scaleX = intrinsicImageSize.width() / tileSize.width();
        scaleY = intrinsicImageSize.height() / tileSize.height();
        cairo_matrix_init_scale(&mat, scaleX, scaleY);
        
        tileWidth = tileSize.width();
        tileHeight = tileSize.height();
    }
   
    // We could get interesting source offsets (negative ones or positive ones.  Deal with both
    // out of bounds cases.
    float dstTileX = dstRect.x() + fmodf(fmodf(-point.x(), tileWidth) - tileWidth, tileWidth);
    float dstTileY = dstRect.y() + fmodf(fmodf(-point.y(), tileHeight) - tileHeight, tileHeight);
    FloatRect dstTileRect(dstTileX, dstTileY, tileWidth, tileHeight);
    
    float srcX = dstRect.x() - dstTileRect.x();
    float srcY = dstRect.y() - dstTileRect.y();

    // If the single image draw covers the whole area, then just draw once.
    if (dstTileRect.contains(dstRect)) {
        draw(ctxt, dstRect,
             FloatRect(srcX * scaleX, srcY * scaleY, dstRect.width() * scaleX, dstRect.height() * scaleY), op);
        return;
    }

    // We have to tile.
    cairo_t* context = ctxt->platformContext();

    cairo_save(context);

    // Set the compositing operation.
    setCompositingOperation(context, op, frameHasAlphaAtIndex(m_currentFrame));

    cairo_translate(context, dstTileRect.x(), dstTileRect.y());
    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
    cairo_pattern_set_matrix(pattern, &mat);
    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);

    // Draw the image.
    cairo_set_source(context, pattern);
    cairo_rectangle(context, srcX, srcY, dstRect.width(), dstRect.height());
    cairo_fill(context);
    cairo_restore(context);

    startAnimation();
}
Ejemplo n.º 6
0
static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight)
{
    if (platformContext->hasImageResamplingHint()) {
        IntSize srcSize;
        FloatSize dstSize;
        platformContext->getImageResamplingHint(&srcSize, &dstSize);
        srcWidth = srcSize.width();
        srcHeight = srcSize.height();
        destWidth = dstSize.width();
        destHeight = dstSize.height();
    }

    int destIWidth = static_cast<int>(destWidth);
    int destIHeight = static_cast<int>(destHeight);

    // The percent change below which we will not resample. This usually means
    // an off-by-one error on the web page, and just doing nearest neighbor
    // sampling is usually good enough.
    const float kFractionalChangeThreshold = 0.025f;

    // Images smaller than this in either direction are considered "small" and
    // are not resampled ever (see below).
    const int kSmallImageSizeThreshold = 8;

    // The amount an image can be stretched in a single direction before we
    // say that it is being stretched so much that it must be a line or
    // background that doesn't need resampling.
    const float kLargeStretch = 3.0f;

    // Figure out if we should resample this image. We try to prune out some
    // common cases where resampling won't give us anything, since it is much
    // slower than drawing stretched.
    if (srcWidth == destIWidth && srcHeight == destIHeight) {
        // We don't need to resample if the source and destination are the same.
        return RESAMPLE_NONE;
    }

    if (srcWidth <= kSmallImageSizeThreshold
        || srcHeight <= kSmallImageSizeThreshold
        || destWidth <= kSmallImageSizeThreshold
        || destHeight <= kSmallImageSizeThreshold) {
        // Never resample small images. These are often used for borders and
        // rules (think 1x1 images used to make lines).
        return RESAMPLE_NONE;
    }

    if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
        // Large image detected.

        // Don't resample if it is being stretched a lot in only one direction.
        // This is trying to catch cases where somebody has created a border
        // (which might be large) and then is stretching it to fill some part
        // of the page.
        if (srcWidth == destWidth || srcHeight == destHeight)
            return RESAMPLE_NONE;

        // The image is growing a lot and in more than one direction. Resampling
        // is slow and doesn't give us very much when growing a lot.
        return RESAMPLE_LINEAR;
    }

    if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold)
        && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) {
        // It is disappointingly common on the web for image sizes to be off by
        // one or two pixels. We don't bother resampling if the size difference
        // is a small fraction of the original size.
        return RESAMPLE_NONE;
    }

    // When the image is not yet done loading, use linear. We don't cache the
    // partially resampled images, and as they come in incrementally, it causes
    // us to have to resample the whole thing every time.
    if (!bitmap.isDataComplete())
        return RESAMPLE_LINEAR;

    // Everything else gets resampled.
    // If the platform context permits high quality interpolation, use it.
    if (platformContext->interpolationQuality() == InterpolationHigh)
        return RESAMPLE_AWESOME;
    
    return RESAMPLE_LINEAR;
}
Ejemplo n.º 7
0
bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile)
{
    if (!m_image)
        return false;
    // We need this to stay in scope because the native image is just a shallow copy of the data.
    m_decoder = new ImageSource(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
    if (!m_decoder)
        return false;
    ImageSource& decoder = *m_decoder;

    m_alphaOp = AlphaDoNothing;
    if (m_image->data()) {
        decoder.setData(m_image->data(), true);
        if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0))
            return false;
        m_imageSurface = decoder.createFrameAtIndex(0);
    } else {
        m_imageSurface = m_image->nativeImageForCurrentFrame();
        // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel,
        // which is true at present and may be changed in the future and needs adjustment accordingly.
        // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, 
        // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false.
        if (!premultiplyAlpha && m_imageHtmlDomSource != HtmlDomVideo)
            m_alphaOp = AlphaDoUnmultiply;

        // if m_imageSurface is not an image, extract a copy of the surface
        if (m_imageSurface && cairo_surface_get_type(m_imageSurface.get()) != CAIRO_SURFACE_TYPE_IMAGE) {
            RefPtr<cairo_surface_t> tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_imageWidth, m_imageHeight));
            copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(0, 0, m_imageWidth, m_imageHeight), IntSize(), CAIRO_OPERATOR_SOURCE);
            m_imageSurface = tmpSurface.release();
        }
    }

    if (!m_imageSurface)
        return false;

    ASSERT(cairo_surface_get_type(m_imageSurface.get()) == CAIRO_SURFACE_TYPE_IMAGE);

    IntSize imageSize = cairoSurfaceSize(m_imageSurface.get());
    m_imageWidth = imageSize.width();
    m_imageHeight = imageSize.height();
    if (!m_imageWidth || !m_imageHeight)
        return false;

    if (cairo_image_surface_get_format(m_imageSurface.get()) != CAIRO_FORMAT_ARGB32)
        return false;

    unsigned int srcUnpackAlignment = 1;
    size_t bytesPerRow = cairo_image_surface_get_stride(m_imageSurface.get());
    size_t bitsPerPixel = 32;
    unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth;
    if (padding) {
        srcUnpackAlignment = padding + 1;
        while (bytesPerRow % srcUnpackAlignment)
            ++srcUnpackAlignment;
    }

    m_imagePixelData = cairo_image_surface_get_data(m_imageSurface.get());
    m_imageSourceFormat = DataFormatBGRA8;
    m_imageSourceUnpackAlignment = srcUnpackAlignment;
    return true;
}
static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
{
    PassRefPtr<ImageData> data = ImageData::create(size.width(), size.height());
    memset(data->data()->data().data(), 0, data->data()->length());
    return data;
}
void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size)
{
    LOG(Media, "MediaPlayerPrivateAVFoundation:setNaturalSize(%p) - size = %d x %d", this, size.width(), size.height());

    IntSize oldSize = m_cachedNaturalSize;
    m_cachedNaturalSize = size;
    if (oldSize != m_cachedNaturalSize)
        m_player->sizeChanged();
}
Ejemplo n.º 10
0
void FEConvolveMatrix::platformApplySoftware()
{
    FilterEffect* in = inputEffect(0);

    Uint8ClampedArray* resultImage;
    if (m_preserveAlpha)
        resultImage = createUnmultipliedImageResult();
    else
        resultImage = createPremultipliedImageResult();
    if (!resultImage)
        return;

    IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());

    RefPtr<Uint8ClampedArray> srcPixelArray;
    if (m_preserveAlpha)
        srcPixelArray = in->asUnmultipliedImage(effectDrawingRect);
    else
        srcPixelArray = in->asPremultipliedImage(effectDrawingRect);

    IntSize paintSize = absolutePaintRect().size();
    PaintingData paintingData;
    paintingData.srcPixelArray = srcPixelArray.get();
    paintingData.dstPixelArray = resultImage;
    paintingData.width = paintSize.width();
    paintingData.height = paintSize.height();
    paintingData.bias = m_bias * 255;

    // Drawing fully covered pixels
    int clipRight = paintSize.width() - m_kernelSize.width();
    int clipBottom = paintSize.height() - m_kernelSize.height();

    if (clipRight >= 0 && clipBottom >= 0) {

        int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
        if (optimalThreadNumber > 1) {
            WTF::ParallelJobs<InteriorPixelParameters> parallelJobs(&WebCore::FEConvolveMatrix::setInteriorPixelsWorker, optimalThreadNumber);
            const int numOfThreads = parallelJobs.numberOfJobs();

            // Split the job into "heightPerThread" jobs but there a few jobs that need to be slightly larger since
            // heightPerThread * jobs < total size. These extras are handled by the remainder "jobsWithExtra".
            const int heightPerThread = clipBottom / numOfThreads;
            const int jobsWithExtra = clipBottom % numOfThreads;

            int startY = 0;
            for (int job = 0; job < numOfThreads; ++job) {
                InteriorPixelParameters& param = parallelJobs.parameter(job);
                param.filter = this;
                param.paintingData = &paintingData;
                param.clipRight = clipRight;
                param.clipBottom = clipBottom;
                param.yStart = startY;
                startY += job < jobsWithExtra ? heightPerThread + 1 : heightPerThread;
                param.yEnd = startY;
            }

            parallelJobs.execute();
        } else {
            // Fallback to single threaded mode.
            setInteriorPixels(paintingData, clipRight, clipBottom, 0, clipBottom);
        }

        clipRight += m_targetOffset.x() + 1;
        clipBottom += m_targetOffset.y() + 1;
        if (m_targetOffset.y() > 0)
            setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y());
        if (clipBottom < paintSize.height())
            setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height());
        if (m_targetOffset.x() > 0)
            setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom);
        if (clipRight < paintSize.width())
            setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom);
    } else {
        // Rare situation, not optimizied for speed
        setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height());
    }
}
Ejemplo n.º 11
0
void FEConvolveMatrix::setKernelSize(const IntSize& kernelSize)
{
    ASSERT(kernelSize.width() > 0);
    ASSERT(kernelSize.height() > 0);
    m_kernelSize = kernelSize;
}
Ejemplo n.º 12
0
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);
    cairo_translate(cr, point.x(), point.y());

    PangoLayout* layout = pango_cairo_create_layout(cr);
    setPangoAttributes(this, run, layout);

    gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
    pango_layout_set_text(layout, utf8, -1);

    // Our layouts are single line
    PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);

    GdkRegion* partialRegion = NULL;
    if (to - from != run.length()) {
        // Clip the region of the run to be rendered
        char* start = g_utf8_offset_to_pointer(utf8, from);
        char* end = g_utf8_offset_to_pointer(start, to - from);
        int ranges[] = {start - utf8, end - utf8};
        partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
        gdk_region_shrink(partialRegion, 0, -pixelSize());
    }

    Color fillColor = context->fillColor();
    float red, green, blue, alpha;

    // Text shadow, inspired by FontMac
    IntSize shadowSize;
    int shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() == cTextFill &&
        context->getShadow(shadowSize, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

        cairo_translate(cr, shadowSize.width(), shadowSize.height());

        if (partialRegion) {
            gdk_cairo_region(cr, partialRegion);
            cairo_clip(cr);
        }

        pango_cairo_show_layout_line(cr, layoutLine);

        cairo_restore(cr);
    }

    fillColor.getRGBA(red, green, blue, alpha);
    cairo_set_source_rgba(cr, red, green, blue, alpha);

    if (partialRegion) {
        gdk_cairo_region(cr, partialRegion);
        cairo_clip(cr);
    }

    pango_cairo_show_layout_line(cr, layoutLine);

    if (context->textDrawingMode() & cTextStroke) {
        Color strokeColor = context->strokeColor();
        strokeColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);
        pango_cairo_layout_line_path(cr, layoutLine);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowSize, shadowBlur, shadowColor);

    // Pango sometimes leaves behind paths we don't want
    cairo_new_path(cr);

    if (partialRegion)
        gdk_region_destroy(partialRegion);

    g_free(utf8);
    g_object_unref(layout);

    cairo_restore(cr);
}
Ejemplo n.º 13
0
unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
    IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation));
    return frameSize.width() * frameSize.height() * 4;
}
Ejemplo n.º 14
0
void FEConvolveMatrix::platformApplySoftware()
{
    FilterEffect* in = inputEffect(0);

    Uint8ClampedArray* resultImage;
    if (m_preserveAlpha)
        resultImage = createUnmultipliedImageResult();
    else
        resultImage = createPremultipliedImageResult();
    if (!resultImage)
        return;

    IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());

    RefPtr<Uint8ClampedArray> srcPixelArray;
    if (m_preserveAlpha)
        srcPixelArray = in->asUnmultipliedImage(effectDrawingRect);
    else
        srcPixelArray = in->asPremultipliedImage(effectDrawingRect);

    IntSize paintSize = absolutePaintRect().size();
    PaintingData paintingData;
    paintingData.srcPixelArray = srcPixelArray.get();
    paintingData.dstPixelArray = resultImage;
    paintingData.width = paintSize.width();
    paintingData.height = paintSize.height();
    paintingData.bias = m_bias * 255;

    // Drawing fully covered pixels
    int clipRight = paintSize.width() - m_kernelSize.width();
    int clipBottom = paintSize.height() - m_kernelSize.height();

    if (clipRight < 0 || clipBottom < 0) {
        // Rare situation, not optimizied for speed
        setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height());
        return;
    }

    int iterations = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
    if (!iterations) {
        setInteriorPixels(paintingData, clipRight, clipBottom, 0, clipBottom);
        return;
    }

    int stride = clipBottom / iterations;
    int chunkCount = (clipBottom + stride - 1) / stride;

    WorkQueue::concurrentApply(chunkCount, [&](size_t index) {
        int yStart = (stride * index);
        int yEnd = std::min<int>(stride * (index + 1), clipBottom);

        setInteriorPixels(paintingData, clipRight, clipBottom, yStart, yEnd);
    });

    clipRight += m_targetOffset.x() + 1;
    clipBottom += m_targetOffset.y() + 1;
    if (m_targetOffset.y() > 0)
        setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y());
    if (clipBottom < paintSize.height())
        setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height());
    if (m_targetOffset.x() > 0)
        setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom);
    if (clipRight < paintSize.width())
        setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom);
}
IntPoint ScrollView::maximumScrollPosition() const
{
    IntSize maximumOffset = contentsSize() - visibleContentRect().size();
    maximumOffset.clampNegativeToZero();
    return IntPoint(maximumOffset.width(), maximumOffset.height());
}
void WebPage::findZoomableAreaForPoint(const IntPoint& point, const IntSize& area)
{
    Node* node = 0;
    IntRect zoomableArea;
    bool foundAreaForTouchPoint = m_mainFrame->coreFrame()->eventHandler()->bestZoomableAreaForTouchPoint(point, IntSize(area.width() / 2, area.height() / 2), zoomableArea, node);

    if (!foundAreaForTouchPoint)
        return;

    ASSERT(node);

    if (node->document() && node->document()->view())
        zoomableArea = node->document()->view()->contentsToWindow(zoomableArea);

    send(Messages::WebPageProxy::DidFindZoomableArea(point, zoomableArea));
}
void ScrollView::updateScrollbars(const IntSize& desiredOffset)
{
    if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
        return;

    // If we came in here with the view already needing a layout, then go ahead and do that
    // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
    // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
    if (!m_scrollbarsSuppressed) {
        m_inUpdateScrollbars = true;
        visibleContentsResized();
        m_inUpdateScrollbars = false;
    }

    bool hasHorizontalScrollbar = m_horizontalScrollbar;
    bool hasVerticalScrollbar = m_verticalScrollbar;
    
    bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
    bool newHasVerticalScrollbar = hasVerticalScrollbar;
   
    ScrollbarMode hScroll = m_horizontalScrollbarMode;
    ScrollbarMode vScroll = m_verticalScrollbarMode;

    if (hScroll != ScrollbarAuto)
        newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
    if (vScroll != ScrollbarAuto)
        newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);

    if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
        if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
            setHasHorizontalScrollbar(newHasHorizontalScrollbar);
        if (hasVerticalScrollbar != newHasVerticalScrollbar)
            setHasVerticalScrollbar(newHasVerticalScrollbar);
    } else {
        bool sendContentResizedNotification = false;
        
        IntSize docSize = contentsSize();
        IntSize frameSize = frameRect().size();

        if (hScroll == ScrollbarAuto) {
            newHasHorizontalScrollbar = docSize.width() > visibleWidth();
            if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
                newHasHorizontalScrollbar = false;
        }
        if (vScroll == ScrollbarAuto) {
            newHasVerticalScrollbar = docSize.height() > visibleHeight();
            if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
                newHasVerticalScrollbar = false;
        }

        // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
        // try to both gain/lose a scrollbar in the same pass.
        if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
            newHasVerticalScrollbar = false;
        if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
            newHasHorizontalScrollbar = false;

        if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
            setHasHorizontalScrollbar(newHasHorizontalScrollbar);
            sendContentResizedNotification = true;
        }

        if (hasVerticalScrollbar != newHasVerticalScrollbar) {
            setHasVerticalScrollbar(newHasVerticalScrollbar);
            sendContentResizedNotification = true;
        }

        if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
            m_updateScrollbarsPass++;
            contentsResized();
            visibleContentsResized();
            IntSize newDocSize = contentsSize();
            if (newDocSize == docSize) {
                // The layout with the new scroll state had no impact on
                // the document's overall size, so updateScrollbars didn't get called.
                // Recur manually.
                updateScrollbars(desiredOffset);
            }
            m_updateScrollbarsPass--;
        }
    }
    
    // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
    // doing it multiple times).
    if (m_updateScrollbarsPass)
        return;

    m_inUpdateScrollbars = true;
    IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
    IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
    scroll.clampNegativeToZero();
 
    if (m_horizontalScrollbar) {
        int clientWidth = visibleWidth();
        m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
        int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
        IntRect oldRect(m_horizontalScrollbar->frameRect());
        IntRect hBarRect = IntRect(0,
                                   height() - m_horizontalScrollbar->height(),
                                   width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
                                   m_horizontalScrollbar->height());
        m_horizontalScrollbar->setFrameRect(hBarRect);
        if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
            m_horizontalScrollbar->invalidate();

        if (m_scrollbarsSuppressed)
            m_horizontalScrollbar->setSuppressInvalidation(true);
        m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
        m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
        m_horizontalScrollbar->setValue(scroll.width());
        if (m_scrollbarsSuppressed)
            m_horizontalScrollbar->setSuppressInvalidation(false); 
    } 

    if (m_verticalScrollbar) {
        int clientHeight = visibleHeight();
        m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
        int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
        if (pageStep < 0)
            pageStep = clientHeight;
        IntRect oldRect(m_verticalScrollbar->frameRect());
        IntRect vBarRect = IntRect(width() - m_verticalScrollbar->width(), 
                                   0,
                                   m_verticalScrollbar->width(),
                                   height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
        m_verticalScrollbar->setFrameRect(vBarRect);
        if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
            m_verticalScrollbar->invalidate();

        if (m_scrollbarsSuppressed)
            m_verticalScrollbar->setSuppressInvalidation(true);
        m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
        m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
        m_verticalScrollbar->setValue(scroll.height());
        if (m_scrollbarsSuppressed)
            m_verticalScrollbar->setSuppressInvalidation(false);
    }

    if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) {
        frameRectsChanged();
        updateScrollCorner();
    }

    // See if our offset has changed in a situation where we might not have scrollbars.
    // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
    // It can also happen when maximizing a window that has scrollbars (but the new maximized result
    // does not).
    IntSize scrollDelta = scroll - m_scrollOffset;
    if (scrollDelta != IntSize()) {
       m_scrollOffset = scroll;
       scrollContents(scrollDelta);
    }

    m_inUpdateScrollbars = false;
}
Ejemplo n.º 18
0
BitmapInfo BitmapInfo::createBottomUp(const IntSize& size, BitCount bitCount)
{
    return bitmapInfoForSize(size.width(), -size.height(), bitCount);
}
void PageScaleConstraintsSet::adjustFinalConstraintsToContentsSize(IntSize viewSize, IntSize contentsSize, int nonOverlayScrollbarWidth)
{
    m_finalConstraints.fitToContentsWidth(contentsSize.width(), viewSize.width() - nonOverlayScrollbarWidth);
}
Ejemplo n.º 20
0
void ScrollView::updateScrollbars(const IntSize& desiredOffset)
{
    // Don't allow re-entrancy into this function.
    if (m_data->m_inUpdateScrollbars)
        return;

    // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
    // In the end, FrameView should just merge with ScrollView.
    if (static_cast<const FrameView*>(this)->frame()->prohibitsScrolling())
        return;

    m_data->m_inUpdateScrollbars = true;

    bool hasVerticalScrollbar = m_data->m_vBar;
    bool hasHorizontalScrollbar = m_data->m_hBar;
    bool oldHasVertical = hasVerticalScrollbar;
    bool oldHasHorizontal = hasHorizontalScrollbar;
    ScrollbarMode hScroll = m_data->m_hScrollbarMode;
    ScrollbarMode vScroll = m_data->m_vScrollbarMode;
    
    const int cVerticalWidth = PlatformScrollbar::verticalScrollbarWidth();
    const int cHorizontalHeight = PlatformScrollbar::horizontalScrollbarHeight();

    for (int pass = 0; pass < 2; pass++) {
        bool scrollsVertically;
        bool scrollsHorizontally;

        if (!m_data->m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
            // Do a layout if pending before checking if scrollbars are needed.
            if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
                static_cast<FrameView*>(this)->layout();

            scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
            if (scrollsVertically)
                scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + cVerticalWidth > width());
            else {
                scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
                if (scrollsHorizontally)
                    scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + cHorizontalHeight > height());
            }
        }
        else {
            scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
            scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
        }
        
        if (hasVerticalScrollbar != scrollsVertically) {
            m_data->setHasVerticalScrollbar(scrollsVertically);
            hasVerticalScrollbar = scrollsVertically;
        }

        if (hasHorizontalScrollbar != scrollsHorizontally) {
            m_data->setHasHorizontalScrollbar(scrollsHorizontally);
            hasHorizontalScrollbar = scrollsHorizontally;
        }
    }
    
    // Set up the range (and page step/line step).
    IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
    IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
    scroll.clampNegativeToZero();
 
    if (m_data->m_hBar) {
        int clientWidth = visibleWidth();
        m_data->m_hBar->setEnabled(contentsWidth() > clientWidth);
        int pageStep = (clientWidth - PAGE_KEEP);
        if (pageStep < 0) pageStep = clientWidth;
        IntRect oldRect(m_data->m_hBar->frameGeometry());
        IntRect hBarRect = IntRect(0,
                                   height() - m_data->m_hBar->height(),
                                   width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0),
                                   m_data->m_hBar->height());
        m_data->m_hBar->setRect(hBarRect);
        if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_hBar->frameGeometry())
            m_data->m_hBar->invalidate();

        if (m_data->m_scrollbarsSuppressed)
            m_data->m_hBar->setSuppressInvalidation(true);
        m_data->m_hBar->setSteps(LINE_STEP, pageStep);
        m_data->m_hBar->setProportion(clientWidth, contentsWidth());
        m_data->m_hBar->setValue(scroll.width());
        if (m_data->m_scrollbarsSuppressed)
            m_data->m_hBar->setSuppressInvalidation(false); 
    } 

    if (m_data->m_vBar) {
        int clientHeight = visibleHeight();
        m_data->m_vBar->setEnabled(contentsHeight() > clientHeight);
        int pageStep = (clientHeight - PAGE_KEEP);
        if (pageStep < 0) pageStep = clientHeight;
        IntRect oldRect(m_data->m_vBar->frameGeometry());
        IntRect vBarRect = IntRect(width() - m_data->m_vBar->width(), 
                                   0,
                                   m_data->m_vBar->width(),
                                   height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
        m_data->m_vBar->setRect(vBarRect);
        if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_vBar->frameGeometry())
            m_data->m_vBar->invalidate();

        if (m_data->m_scrollbarsSuppressed)
            m_data->m_vBar->setSuppressInvalidation(true);
        m_data->m_vBar->setSteps(LINE_STEP, pageStep);
        m_data->m_vBar->setProportion(clientHeight, contentsHeight());
        m_data->m_vBar->setValue(scroll.height());
        if (m_data->m_scrollbarsSuppressed)
            m_data->m_vBar->setSuppressInvalidation(false);
    }

    if (oldHasVertical != (m_data->m_vBar != 0) || oldHasHorizontal != (m_data->m_hBar != 0))
        geometryChanged();

    // See if our offset has changed in a situation where we might not have scrollbars.
    // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
    // It can also happen when maximizing a window that has scrollbars (but the new maximized result
    // does not).
    IntSize scrollDelta = scroll - m_data->m_scrollOffset;
    if (scrollDelta != IntSize()) {
       m_data->m_scrollOffset = scroll;
       m_data->scrollBackingStore(scrollDelta);
    }

    m_data->m_inUpdateScrollbars = false;
}
void LayerRendererChromium::resizeOnscreenContent(const IntSize& size)
{
    if (m_context)
        m_context->reshape(size.width(), size.height());
}
Ejemplo n.º 22
0
bool FECustomFilter::resizeContext(const IntSize& newContextSize)
{
    bool multisample = resizeMultisampleBuffers(newContextSize);

    m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_frameBuffer);
    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_destTexture);
    // We are going to clear the output buffer anyway, so we can safely initialize the destination texture with garbage data.
    m_context->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, newContextSize.width(), newContextSize.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
    m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_destTexture, 0);

    // We don't need the depth buffer for the texture framebuffer, if we already
    // have a multisample buffer.
    if (!multisample) {
        m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
        m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
        m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
    }

    if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
        return false;

    if (multisample) {
        // Clear the framebuffer first, otherwise the first blit will fail.
        m_context->clearColor(0, 0, 0, 0);
        m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
    }

    m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);

    m_contextSize = newContextSize;
    return true;
}
// Checks whether a given size is within the maximum allowed texture size range.
bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize)
{
    if (textureSize.width() > m_maxTextureSize || textureSize.height() > m_maxTextureSize)
        return false;
    return true;
}
Ejemplo n.º 24
0
static double area(WebFrame* frame)
{
    IntSize size = frame->visibleContentBoundsExcludingScrollbars().size();
    return static_cast<double>(size.height()) * size.width();
}
Ejemplo n.º 25
0
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);

    cairo_set_scaled_font(cr, font->platformData().scaledFont());

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

    float offset = 0.0f;
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = 0.0f;
        offset += glyphBuffer.advanceAt(from + i);
    }

    Color fillColor = context->fillColor();

    // Synthetic Oblique
    if(font->platformData().syntheticOblique()) {
        cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()};
        cairo_transform(cr, &mat);
    } else {
        cairo_translate(cr, point.x(), point.y());
    }

    // Text shadow, inspired by FontMac
    IntSize shadowSize;
    int shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() == cTextFill &&
        context->getShadow(shadowSize, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        float red, green, blue, alpha;
        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

#if ENABLE(FILTERS)
        cairo_text_extents_t extents;
        cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);

        FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
        IntSize shadowBufferSize;
        FloatRect shadowRect;
        float kernelSize = 0.f;
        GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);

        // Draw shadow into a new ImageBuffer
        OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
        GraphicsContext* shadowContext = shadowBuffer->context();
        cairo_t* shadowCr = shadowContext->platformContext();

        cairo_translate(shadowCr, kernelSize, extents.height + kernelSize);

        cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
        cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(shadowCr);
            cairo_translate(shadowCr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
            cairo_restore(shadowCr);
        }
        cairo_translate(cr, 0.0, -extents.height);
        context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
#else
        cairo_translate(cr, shadowSize.width(), shadowSize.height());
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
#endif

        cairo_restore(cr);
    }

    if (context->textDrawingMode() & cTextFill) {
        if (context->fillGradient()) {
            cairo_set_source(cr, context->fillGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->fillPattern()) {
            AffineTransform affine;
            cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            float red, green, blue, alpha;
            fillColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
    }

    if (context->textDrawingMode() & cTextStroke) {
        if (context->strokeGradient()) {
            cairo_set_source(cr, context->strokeGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->strokePattern()) {
            AffineTransform affine;
            cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            Color strokeColor = context->strokeColor();
            float red, green, blue, alpha;
            strokeColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        } 
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace);

    cairo_restore(cr);
}
Ejemplo n.º 26
0
void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&)
{
    if (platformPageClient())
        platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect);
    emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect);
}
Ejemplo n.º 27
0
 explicit ImageSize(IntSize size) {
   area = static_cast<uint64_t>(size.width()) * size.height();
 }
Ejemplo n.º 28
0
void ChromeClientQt::delegatedScrollRequested(const IntSize& delta)
{
    emit m_webPage->scrollRequested(delta.width(), delta.height(), QRect(QPoint(0, 0), m_webPage->viewportSize()));
}
Ejemplo n.º 29
0
bool FECustomFilter::resizeMultisampleBuffers(const IntSize& newContextSize)
{
    if (!m_triedMultisampleBuffer && !createMultisampleBuffer())
        return false;

    if (!canUseMultisampleBuffers())
        return false;

    static const int kMaxSampleCount = 4;
    int maxSupportedSampleCount = 0;
    m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSupportedSampleCount);
    int sampleCount = std::min(kMaxSampleCount, maxSupportedSampleCount);
    if (!sampleCount) {
        deleteMultisampleRenderBuffers();
        return false;
    }

    Extensions3D* extensions = m_context->getExtensions();
    ASSERT(extensions);

    m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFrameBuffer);

    m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer);
    extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, Extensions3D::RGBA8_OES, newContextSize.width(), newContextSize.height());
    m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer);

    m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer);
    extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, GraphicsContext3D::DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
    m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer);

    m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);

    if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
        deleteMultisampleRenderBuffers();
        return false;
    }

    return true;
}
Ejemplo n.º 30
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());

                if (m_context->getError() == GraphicsContext3D::OUT_OF_MEMORY) {
                    adjustedSize.scale(s_resourceAdjustedRatio);
                    continue;
                }

                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) {
                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());

        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;
}