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()); }
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(); }
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; }
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(); }
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()); } }
void FEConvolveMatrix::setKernelSize(const IntSize& kernelSize) { ASSERT(kernelSize.width() > 0); ASSERT(kernelSize.height() > 0); m_kernelSize = kernelSize; }
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); }
unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation)); return frameSize.width() * frameSize.height() * 4; }
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; }
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); }
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()); }
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; }
static double area(WebFrame* frame) { IntSize size = frame->visibleContentBoundsExcludingScrollbars().size(); return static_cast<double>(size.height()) * size.width(); }
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); }
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); }
explicit ImageSize(IntSize size) { area = static_cast<uint64_t>(size.width()) * size.height(); }
void ChromeClientQt::delegatedScrollRequested(const IntSize& delta) { emit m_webPage->scrollRequested(delta.width(), delta.height(), QRect(QPoint(0, 0), m_webPage->viewportSize())); }
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; }
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; }