LayoutRect SVGLayoutSupport::transformPaintInvalidationRect(const LayoutObject& object, const AffineTransform& rootTransform, const FloatRect& localRect) { FloatRect adjustedRect = rootTransform.mapRect(localRect); if (object.isSVGShape() && object.styleRef().svgStyle().hasStroke()) { if (float strokeWidthForHairlinePadding = toLayoutSVGShape(object).strokeWidth()) { // For hairline strokes (stroke-width < 1 in device space), Skia rasterizes up to 0.4(9) off // the stroke center. That means enclosingIntRect is not enough - we must also pad to 0.5. // This is still fragile as it misses out on CC/DSF CTM components. const FloatSize strokeSize = rootTransform.mapSize( FloatSize(strokeWidthForHairlinePadding, strokeWidthForHairlinePadding)); if (strokeSize.width() < 1 || strokeSize.height() < 1) { const float pad = 0.5f - std::min(strokeSize.width(), strokeSize.height()) / 2; ASSERT(pad > 0); adjustedRect.inflate(pad); } } } if (adjustedRect.isEmpty()) return LayoutRect(); return LayoutRect(enclosingIntRect(adjustedRect)); }
void SVGImage::drawPatternForContainer(GraphicsContext& context, const FloatSize containerSize, float zoom, const FloatRect& srcRect, const FloatSize& tileScale, const FloatPoint& phase, SkXfermode::Mode compositeOp, const FloatRect& dstRect, const FloatSize& repeatSpacing, const KURL& url) { // Tile adjusted for scaling/stretch. FloatRect tile(srcRect); tile.scale(tileScale.width(), tileScale.height()); // Expand the tile to account for repeat spacing. FloatRect spacedTile(tile); spacedTile.expand(FloatSize(repeatSpacing)); SkPictureBuilder patternPicture(spacedTile, nullptr, &context); if (!DrawingRecorder::useCachedDrawingIfPossible(patternPicture.context(), *this, DisplayItem::Type::SVGImage)) { DrawingRecorder patternPictureRecorder(patternPicture.context(), *this, DisplayItem::Type::SVGImage, spacedTile); // When generating an expanded tile, make sure we don't draw into the spacing area. if (tile != spacedTile) patternPicture.context().clip(tile); SkPaint paint; drawForContainer(patternPicture.context().canvas(), paint, containerSize, zoom, tile, srcRect, url); } RefPtr<const SkPicture> tilePicture = patternPicture.endRecording(); SkMatrix patternTransform; patternTransform.setTranslate(phase.x() + spacedTile.x(), phase.y() + spacedTile.y()); RefPtr<SkShader> patternShader = adoptRef(SkShader::CreatePictureShader( tilePicture.get(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &patternTransform, nullptr)); SkPaint paint; paint.setShader(patternShader.get()); paint.setXfermodeMode(compositeOp); paint.setColorFilter(context.colorFilter()); context.drawRect(dstRect, paint); }
void CSSMatrix::setMatrixValue(const String& string, ExceptionState& exceptionState) { if (string.isEmpty()) return; // FIXME: crbug.com/154722 - should this continue to use legacy style parsing? RefPtrWillBeRawPtr<MutableStylePropertySet> styleDeclaration = MutableStylePropertySet::create(); if (BisonCSSParser::parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true, HTMLStandardMode, 0)) { // Convert to TransformOperations. This can fail if a property // requires style (i.e., param uses 'ems' or 'exs') RefPtrWillBeRawPtr<CSSValue> value = styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform); // Check for a "none" or empty transform. In these cases we can use the default identity matrix. if (!value || (value->isPrimitiveValue() && (toCSSPrimitiveValue(value.get()))->getValueID() == CSSValueNone)) return; DEFINE_STATIC_REF(RenderStyle, defaultStyle, RenderStyle::createDefaultStyle()); TransformOperations operations; if (!TransformBuilder::createTransformOperations(value.get(), CSSToLengthConversionData(defaultStyle, defaultStyle, 0, 0, 1.0f), operations)) { exceptionState.throwDOMException(SyntaxError, "Failed to interpret '" + string + "' as a transformation operation."); return; } // Convert transform operations to a TransformationMatrix. This can fail // if a param has a percentage ('%') if (operations.dependsOnBoxSize()) exceptionState.throwDOMException(SyntaxError, "The transformation depends on the box size, which is not supported."); TransformationMatrix t; operations.apply(FloatSize(0, 0), t); // set the matrix m_matrix = t; } else { // There is something there but parsing failed. exceptionState.throwDOMException(SyntaxError, "Failed to parse '" + string + "'."); } }
static void drawCrossfadeSubimage(GraphicsContext* context, Image* image, CompositeOperator operation, float opacity, IntSize targetSize) { IntSize imageSize = image->size(); // SVGImage resets the opacity when painting, so we have to use transparency layers to accurately paint one at a given opacity. bool useTransparencyLayer = image->isSVGImage(); GraphicsContextStateSaver stateSaver(*context); context->setCompositeOperation(operation); if (useTransparencyLayer) context->beginTransparencyLayer(opacity); else context->setAlpha(opacity); if (targetSize != imageSize) context->scale(FloatSize(static_cast<float>(targetSize.width()) / imageSize.width(), static_cast<float>(targetSize.height()) / imageSize.height())); context->drawImage(image, ColorSpaceDeviceRGB, IntPoint()); if (useTransparencyLayer) context->endTransparencyLayer(); }
void EllipsisBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font) { Color textColor = m_renderer->resolveColor(style, CSSPropertyColor); Color c = m_renderer->selectionBackgroundColor(); if (!c.isValid() || !c.alpha()) return; // If the text color ends up being the same as the selection background, invert the selection // background. if (textColor == c) c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); GraphicsContextStateSaver stateSaver(*context); LayoutUnit selectionBottom = root()->selectionBottom(); LayoutUnit top = root()->selectionTop(); LayoutUnit h = root()->selectionHeight(); const int deltaY = roundToInt(renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - top); const FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, h)); alignSelectionRectToDevicePixels(clipRect); context->clip(clipRect); // FIXME: Why is this always LTR? Fix by passing correct text run flags below. context->drawHighlightForText(font, RenderBlockFlow::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), localOrigin, h, c); }
ScrollOffset VisualViewport::maximumScrollOffset() const { if (!mainFrame()) return ScrollOffset(); // TODO(bokan): We probably shouldn't be storing the bounds in a float. // crbug.com/470718. FloatSize frameViewSize(contentsSize()); if (m_browserControlsAdjustment) { float minScale = frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale; frameViewSize.expand(0, m_browserControlsAdjustment / minScale); } frameViewSize.scale(m_scale); frameViewSize = FloatSize(flooredIntSize(frameViewSize)); FloatSize viewportSize(m_size); viewportSize.expand(0, ceilf(m_browserControlsAdjustment)); FloatSize maxPosition = frameViewSize - viewportSize; maxPosition.scale(1 / m_scale); return ScrollOffset(maxPosition); }
static PassOwnPtr<Shape> createCircleShape(const FloatPoint& center, float radius) { ASSERT(radius >= 0); return adoptPtr(new RectangleShape(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius))); }
static FloatSize lineSize(float logicalLeft, float logicalRight, float height) { return FloatSize(logicalRight - logicalLeft, height); }
ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, DeferralMode, bool& success) : m_data(size) // NOTE: The input here isn't important as ImageBufferDataCG's constructor just ignores it. , m_size(size) { success = false; // Make early return mean failure. bool accelerateRendering = renderingMode == Accelerated; if (size.width() <= 0 || size.height() <= 0) return; Checked<int, RecordOverflow> width = size.width(); Checked<int, RecordOverflow> height = size.height(); // Prevent integer overflows m_data.m_bytesPerRow = 4 * width; Checked<size_t, RecordOverflow> numBytes = height * m_data.m_bytesPerRow; if (numBytes.hasOverflowed()) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) if (width.unsafeGet() >= maxIOSurfaceDimension || height.unsafeGet() >= maxIOSurfaceDimension || (width * height).unsafeGet() < minIOSurfaceArea) accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); #endif switch (imageColorSpace) { case ColorSpaceDeviceRGB: m_data.m_colorSpace = deviceRGBColorSpaceRef(); break; case ColorSpaceSRGB: m_data.m_colorSpace = sRGBColorSpaceRef(); break; case ColorSpaceLinearRGB: m_data.m_colorSpace = linearRGBColorSpaceRef(); break; } RetainPtr<CGContextRef> cgContext; if (accelerateRendering) { #if USE(IOSURFACE_CANVAS_BACKING_STORE) m_data.m_surface = createIOSurface(size); cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace)); #endif if (!cgContext) accelerateRendering = false; // If allocation fails, fall back to non-accelerated path. } if (!accelerateRendering) { if (!tryFastCalloc(height.unsafeGet(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data)) return; ASSERT(!(reinterpret_cast<size_t>(m_data.m_data) & 2)); m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; cgContext.adoptCF(CGBitmapContextCreate(m_data.m_data, width.unsafeGet(), height.unsafeGet(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo)); // Create a live image that wraps the data. m_data.m_dataProvider.adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, numBytes.unsafeGet(), releaseImageData)); } if (!cgContext) return; m_context = adoptPtr(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -height.unsafeGet()); m_context->setIsAcceleratedContext(accelerateRendering); #if defined(BUILDING_ON_LION) m_data.m_lastFlushTime = currentTimeMS(); #endif success = true; }
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) { if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextSetShouldAntialias(context, false); int x = rect.x(); int y = rect.y(); float w = (float)rect.width(); float h = (float)rect.height(); float scaleFactor = h / w; float reverseScaleFactor = w / h; if (w != h) scale(FloatSize(1, scaleFactor)); float hRadius = w / 2; float vRadius = h / 2; float fa = startAngle; float falen = fa + angleSpan; float start = -fa * piFloat / 180.0f; float end = -falen * piFloat / 180.0f; CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true); if (w != h) scale(FloatSize(1, reverseScaleFactor)); float width = strokeThickness(); int patWidth = 0; switch (strokeStyle()) { case DottedStroke: patWidth = (int)(width / 2); break; case DashedStroke: patWidth = 3 * (int)(width / 2); break; default: break; } if (patWidth) { // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint // will be 50 pixels. int distance; if (hRadius == vRadius) distance = static_cast<int>((piFloat * hRadius) / 2.0f); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f); int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; float patternOffset = 0.0f; // Special case 1px dotted borders for speed. if (patWidth == 1) patternOffset = 1.0f; else { bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; patternOffset += remainder / 2.0f; } else patternOffset = patWidth / 2.0f; } else { if (remainder) patternOffset = (patWidth - remainder) / 2.0f; } } const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } CGContextStrokePath(context); CGContextRestoreGState(context); }
PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(PatternData* patternData, const SVGPatternElement* patternElement, RenderObject* object) const { PatternAttributes attributes = patternElement->collectPatternProperties(); // If we couldn't determine the pattern content element root, stop here. if (!attributes.patternContentElement()) return 0; FloatRect objectBoundingBox = object->objectBoundingBox(); FloatRect patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); AffineTransform patternTransform = attributes.patternTransform(); AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(), patternElement->preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height()); FloatRect patternBoundariesIncludingOverflow = calculatePatternBoundariesIncludingOverflow(attributes, objectBoundingBox, viewBoxCTM, patternBoundaries); IntSize imageSize(lroundf(patternBoundariesIncludingOverflow.width()), lroundf(patternBoundariesIncludingOverflow.height())); // FIXME: We should be able to clip this more, needs investigation clampImageBufferSizeToViewport(object->document()->view(), imageSize); // Don't create ImageBuffers with image size of 0 if (imageSize.isEmpty()) return 0; OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(imageSize); GraphicsContext* context = tileImage->context(); ASSERT(context); context->save(); // Translate to pattern start origin if (patternBoundariesIncludingOverflow.location() != patternBoundaries.location()) { context->translate(patternBoundaries.x() - patternBoundariesIncludingOverflow.x(), patternBoundaries.y() - patternBoundariesIncludingOverflow.y()); patternBoundaries.setLocation(patternBoundariesIncludingOverflow.location()); } // Process viewBox or boundingBoxModeContent correction if (!viewBoxCTM.isIdentity()) context->concatCTM(viewBoxCTM); else if (attributes.boundingBoxModeContent()) { context->translate(objectBoundingBox.x(), objectBoundingBox.y()); context->scale(FloatSize(objectBoundingBox.width(), objectBoundingBox.height())); } // Render subtree into ImageBuffer for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer()) continue; renderSubtreeToImage(tileImage.get(), node->renderer()); } patternData->boundaries = patternBoundaries; // Compute pattern transformation patternData->transform.translate(patternBoundaries.x(), patternBoundaries.y()); patternData->transform.multiply(patternTransform); context->restore(); return tileImage.release(); }
void TextureMapperLayer::didCommitScrollOffset(const IntSize& offset) { m_userScrollOffset = FloatSize(m_userScrollOffset.width() - offset.width(), m_userScrollOffset.height() - offset.height()); m_currentTransform.setPosition(adjustedPosition()); }
void WebChromeClient::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& position, bool isVideo) { FrameView* frameView = m_page->mainFrame()->view(); FloatRect rect(frameView->contentsToRootView(frameView->windowToContents(position)), FloatSize()); m_page->send(Messages::WebPageProxy::ShowPlaybackTargetPicker(contextId, rect, isVideo)); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; CGContextRef context = ctxt->platformContext(); ctxt->save(); bool shouldUseSubimage = false; // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image // and then set a clip to the portion that we want to display. FloatRect adjustedDestRect = destRect; FloatSize selfSize = currentFrameSize(); if (srcRect.size() != selfSize) { CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context); // When the image is scaled using high-quality interpolation, we create a temporary CGImage // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { FloatRect subimageRect = srcRect; float leftPadding = srcRect.x() - floorf(srcRect.x()); float topPadding = srcRect.y() - floorf(srcRect.y()); subimageRect.move(-leftPadding, -topPadding); adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale); subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding)); adjustedDestRect.setWidth(subimageRect.width() / xScale); subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale)); } CGContextClipToRect(context, destRect); } // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. if (!shouldUseSubimage && currHeight < selfSize.height()) adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); ctxt->setCompositeOperation(compositeOp); // Flip the coords. CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); // Adjust the color space. image = imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); if (imageObserver()) imageObserver()->didDraw(this); }
void RenderSVGResourceFilter::postApplyResource(RenderElement& renderer, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*) { ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); FilterData* filterData = m_filter.get(&renderer); if (!filterData) return; switch (filterData->state) { case FilterData::MarkedForRemoval: m_filter.remove(&renderer); return; case FilterData::CycleDetected: case FilterData::Applying: // We have a cycle if we are already applying the data. // This can occur due to FeImage referencing a source that makes use of the FEImage itself. // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack // will continue correctly. filterData->state = FilterData::PaintingSource; return; case FilterData::PaintingSource: if (!filterData->savedContext) { removeClientFromCache(renderer); return; } context = filterData->savedContext; filterData->savedContext = 0; break; case FilterData::Built: { } // Empty } FilterEffect* lastEffect = filterData->builder->lastEffect(); if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) { // This is the real filtering of the object. It just needs to be called on the // initial filtering process. We just take the stored filter result on a // second drawing. if (filterData->state != FilterData::Built) filterData->filter->setSourceImage(WTF::move(filterData->sourceGraphicBuffer)); // Always true if filterData is just built (filterData->state == FilterData::Built). if (!lastEffect->hasResult()) { filterData->state = FilterData::Applying; lastEffect->applyAll(); lastEffect->correctFilterResultIfNeeded(); lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB); } filterData->state = FilterData::Built; ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); context->drawImageBuffer(resultImage, renderer.style().colorSpace(), lastEffect->absolutePaintRect()); context->scale(filterData->filter->filterResolution()); context->concatCTM(filterData->shearFreeAbsoluteTransform); } } filterData->sourceGraphicBuffer.reset(); }
PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); OwnPtr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeRectangleType: { const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape); FloatRect bounds( floatValueForLength(rectangle->x(), boxWidth), floatValueForLength(rectangle->y(), boxHeight), floatValueForLength(rectangle->width(), boxWidth), floatValueForLength(rectangle->height(), boxHeight)); FloatSize cornerRadii( floatValueForLength(rectangle->cornerRadiusX(), boxWidth), floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); ensureRadiiDoNotOverlap(bounds, cornerRadii); FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); break; } case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); float centerX = floatValueForLength(circle->centerX(), boxWidth); float centerY = floatValueForLength(circle->centerY(), boxHeight); float radius = floatValueForLength(circle->radius(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2)); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); shape = createShapeCircle(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); float centerX = floatValueForLength(ellipse->centerX(), boxWidth); float centerY = floatValueForLength(ellipse->centerY(), boxHeight); float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth); float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode); shape = createShapeEllipse(logicalCenter, logicalRadii); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape); const Vector<Length>& values = polygon->values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } case BasicShape::BasicShapeInsetRectangleType: { const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape); float left = floatValueForLength(rectangle->left(), boxWidth); float top = floatValueForLength(rectangle->top(), boxHeight); FloatRect bounds( left, top, boxWidth - left - floatValueForLength(rectangle->right(), boxWidth), boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight)); FloatSize cornerRadii( floatValueForLength(rectangle->cornerRadiusX(), boxWidth), floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); ensureRadiiDoNotOverlap(bounds, cornerRadii); FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = floatValueForLength(margin, 0); shape->m_padding = floatValueForLength(padding, 0); return shape.release(); }
void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) { if (!fontElement) return; SVGTextRunWalkerDrawTextData data; FloatPoint currentPoint = point; float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f); SVGPaintServer* activePaintServer = run.activePaintServer(); // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts. if (!run.referencingRenderObject()) { ASSERT(!activePaintServer); // TODO: We're only supporting simple filled HTML text so far. SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer(); solidPaintServer->setColor(context->fillColor()); activePaintServer = solidPaintServer; } ASSERT(activePaintServer); int charsConsumed; String glyphName; bool isVerticalText = false; float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName); FloatPoint glyphOrigin; String language; // TODO: language matching & svg glyphs should be possible for HTML text, too. if (run.referencingRenderObject()) { isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle()); if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element())) language = element->getAttribute(XMLNames::langAttr); } if (!isVerticalText) { glyphOrigin.setX(fontData->horizontalOriginX() * scale); glyphOrigin.setY(fontData->horizontalOriginY() * scale); } data.extraCharsAvailable = 0; data.charsConsumed = 0; SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback); runWalker.walk(run, isVerticalText, language, from, to); SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType; unsigned numGlyphs = data.glyphIdentifiers.size(); unsigned fallbackCharacterIndex = 0; for (unsigned i = 0; i < numGlyphs; ++i) { const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i]; if (identifier.isValid) { // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). if (!identifier.pathData.isEmpty()) { context->save(); if (isVerticalText) { glyphOrigin.setX(identifier.verticalOriginX * scale); glyphOrigin.setY(identifier.verticalOriginY * scale); } context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); context->scale(FloatSize(scale, -scale)); context->beginPath(); context->addPath(identifier.pathData); if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) { // Spec: Any properties specified on a text elements which represents a length, such as the // 'stroke-width' property, might produce surprising results since the length value will be // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?) if (targetType == ApplyToStrokeTargetType && scale != 0.0f) context->setStrokeThickness(context->strokeThickness() / scale); activePaintServer->renderPath(context, run.referencingRenderObject(), targetType); activePaintServer->teardown(context, run.referencingRenderObject(), targetType); } context->restore(); } if (isVerticalText) currentPoint.move(0.0f, identifier.verticalAdvanceY * scale); else currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f); } else { // Handle system font fallback FontDescription fontDescription(context->font().fontDescription()); fontDescription.setFamily(FontFamily()); Font font(fontDescription, 0, 0); // spacing handled by SVG text code. font.update(context->font().fontSelector()); TextRun fallbackCharacterRun(run); fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1); font.drawText(context, fallbackCharacterRun, currentPoint); if (isVerticalText) currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun)); else currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f); fallbackCharacterIndex++; } } } }
void CCDamageTracker::extendDamageForRenderSurface(CCLayerImpl* layer, FloatRect& targetDamageRect) { // There are two ways a "descendant surface" can damage regions of the "target surface": // 1. Property change: // - a surface's geometry can change because of // - changes to descendants (i.e. the subtree) that affect the surface's content rect // - changes to ancestor layers that propagate their property changes to their entire subtree. // - just like layers, both the old surface rect and new surface rect will // damage the target surface in this case. // // 2. Damage rect: This surface may have been damaged by its own layerList as well, and that damage // should propagate to the target surface. // CCRenderSurface* renderSurface = layer->renderSurface(); bool surfaceIsNew = false; FloatRect oldSurfaceRect = removeRectFromCurrentFrame(layer->id(), surfaceIsNew); FloatRect surfaceRectInTargetSpace = renderSurface->drawableContentRect(); // already includes replica if it exists. saveRectForNextFrame(layer->id(), surfaceRectInTargetSpace); FloatRect damageRectInLocalSpace; if (surfaceIsNew || renderSurface->surfacePropertyChanged() || layer->layerSurfacePropertyChanged()) { // The entire surface contributes damage. damageRectInLocalSpace = renderSurface->contentRect(); // The surface's old region is now exposed on the target surface, too. targetDamageRect.uniteIfNonZero(oldSurfaceRect); } else { // Only the surface's damageRect will damage the target surface. damageRectInLocalSpace = renderSurface->damageTracker()->currentDamageRect(); } // If there was damage, transform it to target space, and possibly contribute its reflection if needed. if (!damageRectInLocalSpace.isEmpty()) { const WebTransformationMatrix& drawTransform = renderSurface->drawTransform(); FloatRect damageRectInTargetSpace = CCMathUtil::mapClippedRect(drawTransform, damageRectInLocalSpace); targetDamageRect.uniteIfNonZero(damageRectInTargetSpace); if (layer->replicaLayer()) { const WebTransformationMatrix& replicaDrawTransform = renderSurface->replicaDrawTransform(); targetDamageRect.uniteIfNonZero(CCMathUtil::mapClippedRect(replicaDrawTransform, damageRectInLocalSpace)); } } // If there was damage on the replica's mask, then the target surface receives that damage as well. if (layer->replicaLayer() && layer->replicaLayer()->maskLayer()) { CCLayerImpl* replicaMaskLayer = layer->replicaLayer()->maskLayer(); bool replicaIsNew = false; removeRectFromCurrentFrame(replicaMaskLayer->id(), replicaIsNew); const WebTransformationMatrix& replicaDrawTransform = renderSurface->replicaDrawTransform(); FloatRect replicaMaskLayerRect = CCMathUtil::mapClippedRect(replicaDrawTransform, FloatRect(FloatPoint::zero(), FloatSize(replicaMaskLayer->bounds().width(), replicaMaskLayer->bounds().height()))); saveRectForNextFrame(replicaMaskLayer->id(), replicaMaskLayerRect); // In the current implementation, a change in the replica mask damages the entire replica region. if (replicaIsNew || replicaMaskLayer->layerPropertyChanged() || !replicaMaskLayer->updateRect().isEmpty()) targetDamageRect.uniteIfNonZero(replicaMaskLayerRect); } // If the layer has a background filter, this may cause pixels in our surface to be expanded, so we will need to expand any damage // at or below this layer. We expand the damage from this layer too, as we need to readback those pixels from the surface with only // the contents of layers below this one in them. This means we need to redraw any pixels in the surface being used for the blur in // this layer this frame. if (layer->backgroundFilters().hasFilterThatMovesPixels()) expandDamageRectInsideRectWithFilters(targetDamageRect, surfaceRectInTargetSpace, layer->backgroundFilters()); }
void toWebTransformOperations(const TransformOperations& transformOperations, WebTransformOperations* webTransformOperations) { // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects. for (size_t j = 0; j < transformOperations.size(); ++j) { switch (transformOperations.operations()[j]->type()) { case TransformOperation::ScaleX: case TransformOperation::ScaleY: case TransformOperation::ScaleZ: case TransformOperation::Scale3D: case TransformOperation::Scale: { ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendScale(transform->x(), transform->y(), transform->z()); break; } case TransformOperation::TranslateX: case TransformOperation::TranslateY: case TransformOperation::TranslateZ: case TransformOperation::Translate3D: case TransformOperation::Translate: { TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get()); ASSERT(transform->x().isFixed() && transform->y().isFixed()); webTransformOperations->appendTranslate(transform->x().value(), transform->y().value(), transform->z()); break; } case TransformOperation::RotateX: case TransformOperation::RotateY: case TransformOperation::Rotate3D: case TransformOperation::Rotate: { RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendRotate(transform->x(), transform->y(), transform->z(), transform->angle()); break; } case TransformOperation::SkewX: case TransformOperation::SkewY: case TransformOperation::Skew: { SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendSkew(transform->angleX(), transform->angleY()); break; } case TransformOperation::Matrix: { MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Matrix3D: { Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Perspective: { PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendPerspective(transform->perspective()); break; } case TransformOperation::Interpolated: { TransformationMatrix m; transformOperations.operations()[j]->apply(m, FloatSize()); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Identity: webTransformOperations->appendIdentity(); break; case TransformOperation::None: // Do nothing. break; } // switch } // for each operation }
void GraphicsContext::drawImageBuffer(ImageBuffer& image, const FloatRect& destination, const ImagePaintingOptions& imagePaintingOptions) { drawImageBuffer(image, destination, FloatRect(FloatPoint(), FloatSize(image.logicalSize())), imagePaintingOptions); }
PassOwnPtr<WebKit::WebAnimation> createWebAnimation(const KeyframeValueList& values, const CSSAnimationData* animation, int animationId, double timeOffset, const FloatSize& boxSize) { if (values.property() == AnimatedPropertyWebkitTransform) { OwnPtr<WebTransformAnimationCurve> curve = adoptPtr(Platform::current()->compositorSupport()->createTransformAnimationCurve()); return createWebAnimation<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(values, animation, animationId, timeOffset, curve.get(), WebKit::WebAnimation::TargetPropertyTransform, FloatSize(boxSize)); } if (values.property() == AnimatedPropertyOpacity) { OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(Platform::current()->compositorSupport()->createFloatAnimationCurve()); return createWebAnimation<FloatAnimationValue, WebFloatKeyframe, WebFloatAnimationCurve>(values, animation, animationId, timeOffset, curve.get(), WebKit::WebAnimation::TargetPropertyOpacity, FloatSize()); } return nullptr; }
void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor) { scale(FloatSize(deviceScaleFactor, deviceScaleFactor)); platformApplyDeviceScaleFactor(deviceScaleFactor); }
TEST(TransparencyWin, OpaqueCompositeLayer) { OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), 1)); // KeepTransform { TransparencyWin helper; helper.init(src->context(), TransparencyWin::OpaqueCompositeLayer, TransparencyWin::KeepTransform, IntRect(1, 1, 14, 12)); helper.composite(); EXPECT_TRUE(src->context() != helper.context()); EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); EXPECT_TRUE(IntRect(1, 1, 14, 12) == helper.drawRect()); } // KeepTransform with scroll applied. src->context()->save(); src->context()->translate(0, -1); { TransparencyWin helper; helper.init(src->context(), TransparencyWin::OpaqueCompositeLayer, TransparencyWin::KeepTransform, IntRect(1, 1, 14, 14)); helper.composite(); EXPECT_TRUE(src->context() != helper.context()); EXPECT_TRUE(IntSize(14, 14) == helper.m_layerSize); EXPECT_TRUE(IntRect(1, 1, 14, 14) == helper.drawRect()); } src->context()->restore(); // Untransform { TransparencyWin helper; helper.init(src->context(), TransparencyWin::OpaqueCompositeLayer, TransparencyWin::Untransform, IntRect(1, 1, 14, 12)); helper.composite(); EXPECT_TRUE(src->context() != helper.context()); EXPECT_TRUE(IntSize(14, 12) == helper.m_layerSize); EXPECT_TRUE(IntRect(0, 0, 14, 12) == helper.drawRect()); } // ScaleTransform src->context()->save(); src->context()->scale(FloatSize(2.0, 0.5)); { TransparencyWin helper; helper.init(src->context(), TransparencyWin::OpaqueCompositeLayer, TransparencyWin::ScaleTransform, IntRect(2, 2, 6, 6)); helper.composite(); // The coordinate system should be based in the upper left of our box. // It should be post-transformed. EXPECT_TRUE(src->context() != helper.context()); EXPECT_TRUE(IntSize(12, 3) == helper.m_layerSize); EXPECT_TRUE(IntRect(0, 0, 12, 3) == helper.drawRect()); } src->context()->restore(); }
FloatSize naturalSize() const override { return FloatSize(); }
void PDFDocumentImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { // FIXME: If we want size negotiation with PDF documents as-image, this is the place to implement it (https://bugs.webkit.org/show_bug.cgi?id=12095). Image::computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio); intrinsicRatio = FloatSize(); }
void ImagePainter::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = m_renderImage.contentWidth(); LayoutUnit cHeight = m_renderImage.contentHeight(); GraphicsContext* context = paintInfo.context; if (!m_renderImage.imageResource()->hasImage() || m_renderImage.imageResource()->errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { const int borderWidth = 1; LayoutUnit leftBorder = m_renderImage.borderLeft(); LayoutUnit topBorder = m_renderImage.borderTop(); LayoutUnit leftPad = m_renderImage.paddingLeft(); LayoutUnit topPad = m_renderImage.paddingTop(); // Draw an outline rect where the image should be. IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight)); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, paintRect); context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray); context->setFillColor(Color::transparent); context->drawRect(paintRect); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2 * borderWidth; LayoutUnit usableHeight = cHeight - 2 * borderWidth; RefPtr<Image> image = m_renderImage.imageResource()->image(); if (m_renderImage.imageResource()->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { float deviceScaleFactor = blink::deviceScaleFactor(m_renderImage.frame()); // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor); image = brokenImageAndImageScaleFactor.first; IntSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth); context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, m_renderImage.shouldRespectImageOrientation()); errorPictureDrawn = true; } if (!m_renderImage.altText().isEmpty()) { const Font& font = m_renderImage.style()->font(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint textRectOrigin = paintOffset; textRectOrigin.move(leftBorder + leftPad + (RenderImage::paddingWidth / 2) - borderWidth, topBorder + topPad + (RenderImage::paddingHeight / 2) - borderWidth); LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = constructTextRun(&m_renderImage, font, m_renderImage.altText(), m_renderImage.style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection); float textWidth = font.width(textRun); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height())); context->setFillColor(m_renderImage.resolveColor(CSSPropertyColor)); if (textRun.direction() == RTL) { int availableWidth = cWidth - static_cast<int>(RenderImage::paddingWidth); textOrigin.move(availableWidth - ceilf(textWidth), 0); } if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context->drawBidiText(font, textRunPaintInfo, textOrigin); } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) { context->drawBidiText(font, textRunPaintInfo, textOrigin); } } } } else if (m_renderImage.imageResource()->hasImage() && cWidth > 0 && cHeight > 0) { LayoutRect contentRect = m_renderImage.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = m_renderImage.replacedContentRect(); paintRect.moveBy(paintOffset); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, contentRect); bool clip = !contentRect.contains(paintRect); if (clip) { context->save(); context->clip(contentRect); } paintIntoRect(context, paintRect); if (clip) context->restore(); } }
PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width().toFloat() : logicalBoxSize.height().toFloat(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height().toFloat() : logicalBoxSize.width().toFloat(); OwnPtr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = toBasicShapeCircle(basicShape); FloatPoint center = floatPointForCenterCoordinate(circle->centerX(), circle->centerY(), FloatSize(boxWidth, boxHeight)); float radius = circle->floatValueForRadiusInBox(FloatSize(boxWidth, boxHeight)); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createCircleShape(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = toBasicShapeEllipse(basicShape); FloatPoint center = floatPointForCenterCoordinate(ellipse->centerX(), ellipse->centerY(), FloatSize(boxWidth, boxHeight)); float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), center.x(), boxWidth); float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), center.y(), boxHeight); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = toBasicShapePolygon(basicShape); const Vector<Length>& values = polygon->values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); OwnPtr<Vector<FloatPoint>> vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height().toFloat(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } case BasicShape::BasicShapeInsetType: { const BasicShapeInset& inset = *toBasicShapeInset(basicShape); float left = floatValueForLength(inset.left(), boxWidth); float top = floatValueForLength(inset.top(), boxHeight); float right = floatValueForLength(inset.right(), boxWidth); float bottom = floatValueForLength(inset.bottom(), boxHeight); FloatRect rect(left, top, std::max<float>(boxWidth - left - right, 0), std::max<float>(boxHeight - top - bottom, 0)); FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height().toFloat(), writingMode); FloatSize boxSize(boxWidth, boxHeight); FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); FloatRoundedRect finalRect(logicalRect, cornerRadii); finalRect.constrainRadii(); shape = createInsetShape(finalRect); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = margin; return shape.release(); }
void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { if (!m_glContext) return; ASSERT(m_renderStyle == GraphicsContext3D::RenderOffscreen); m_context->markLayerComposited(); // FIXME: We do not support mask for the moment with TextureMapperImageBuffer. if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { GraphicsContext* context = textureMapper->graphicsContext(); context->save(); context->platformContext()->setGlobalAlpha(opacity); const int height = m_context->m_currentHeight; const int width = m_context->m_currentWidth; int totalBytes = width * height * 4; auto pixels = std::make_unique<unsigned char[]>(totalBytes); if (!pixels) return; // OpenGL keeps the pixels stored bottom up, so we need to flip the image here. context->translate(0, height); context->scale(FloatSize(1, -1)); context->concatCTM(matrix.toAffineTransform()); m_context->readRenderingResults(pixels.get(), totalBytes); // Premultiply alpha. for (int i = 0; i < totalBytes; i += 4) if (pixels[i + 3] != 255) { pixels[i + 0] = min(255, pixels[i + 0] * pixels[i + 3] / 255); pixels[i + 1] = min(255, pixels[i + 1] * pixels[i + 3] / 255); pixels[i + 2] = min(255, pixels[i + 2] * pixels[i + 3] / 255); } RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data( const_cast<unsigned char*>(pixels.get()), CAIRO_FORMAT_ARGB32, width, height, width * 4)); context->platformContext()->drawSurfaceToContext(imageSurface.get(), targetRect, IntRect(0, 0, width, height), context); context->restore(); return; } #if USE(TEXTURE_MAPPER_GL) if (m_context->m_attrs.antialias && m_context->m_state.boundFBO == m_context->m_multisampleFBO) { GLContext* previousActiveContext = GLContext::getCurrent(); if (previousActiveContext != m_glContext) m_context->makeContextCurrent(); m_context->resolveMultisamplingIfNecessary(); ::glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO); if (previousActiveContext && previousActiveContext != m_glContext) previousActiveContext->makeContextCurrent(); } TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper); TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context->m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0); IntSize textureSize(m_context->m_currentWidth, m_context->m_currentHeight); texmapGL->drawTexture(m_context->m_texture, flags, textureSize, targetRect, matrix, opacity); #endif // USE(ACCELERATED_COMPOSITING_GL) }
PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e) { float scale = widgetInputEventsScaleFactor(widget); IntSize offset = widgetInputEventsOffset(widget); switch (e.type) { case WebInputEvent::GestureScrollBegin: m_type = PlatformEvent::GestureScrollBegin; break; case WebInputEvent::GestureScrollEnd: m_type = PlatformEvent::GestureScrollEnd; break; case WebInputEvent::GestureFlingStart: m_type = PlatformEvent::GestureFlingStart; break; case WebInputEvent::GestureScrollUpdate: m_type = PlatformEvent::GestureScrollUpdate; m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; break; case WebInputEvent::GestureScrollUpdateWithoutPropagation: m_type = PlatformEvent::GestureScrollUpdateWithoutPropagation; m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; break; case WebInputEvent::GestureTap: m_type = PlatformEvent::GestureTap; m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); m_data.m_tap.m_tapCount = e.data.tap.tapCount; break; case WebInputEvent::GestureTapUnconfirmed: m_type = PlatformEvent::GestureTapUnconfirmed; m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); break; case WebInputEvent::GestureTapDown: m_type = PlatformEvent::GestureTapDown; m_area = expandedIntSize(FloatSize(e.data.tapDown.width / scale, e.data.tapDown.height / scale)); break; case WebInputEvent::GestureShowPress: m_type = PlatformEvent::GestureShowPress; m_area = expandedIntSize(FloatSize(e.data.showPress.width / scale, e.data.showPress.height / scale)); break; case WebInputEvent::GestureTapCancel: m_type = PlatformEvent::GestureTapDownCancel; break; case WebInputEvent::GestureDoubleTap: // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType. m_type = PlatformEvent::NoType; break; case WebInputEvent::GestureTwoFingerTap: m_type = PlatformEvent::GestureTwoFingerTap; m_area = expandedIntSize(FloatSize(e.data.twoFingerTap.firstFingerWidth / scale, e.data.twoFingerTap.firstFingerHeight / scale)); break; case WebInputEvent::GestureLongPress: m_type = PlatformEvent::GestureLongPress; m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); break; case WebInputEvent::GestureLongTap: m_type = PlatformEvent::GestureLongTap; m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); break; case WebInputEvent::GesturePinchBegin: m_type = PlatformEvent::GesturePinchBegin; break; case WebInputEvent::GesturePinchEnd: m_type = PlatformEvent::GesturePinchEnd; break; case WebInputEvent::GesturePinchUpdate: m_type = PlatformEvent::GesturePinchUpdate; m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale; break; default: ASSERT_NOT_REACHED(); } m_position = widget->convertFromContainingWindow(IntPoint((e.x - offset.width()) / scale, (e.y - offset.height()) / scale)); m_globalPosition = IntPoint(e.globalX, e.globalY); m_timestamp = e.timeStampSeconds; m_modifiers = 0; if (e.modifiers & WebInputEvent::ShiftKey) m_modifiers |= PlatformEvent::ShiftKey; if (e.modifiers & WebInputEvent::ControlKey) m_modifiers |= PlatformEvent::CtrlKey; if (e.modifiers & WebInputEvent::AltKey) m_modifiers |= PlatformEvent::AltKey; if (e.modifiers & WebInputEvent::MetaKey) m_modifiers |= PlatformEvent::MetaKey; }
void GeneratedImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { Image::computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio); intrinsicRatio = FloatSize(); }