FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) { FloatRect result; double x = frect.x(); double y = frect.y(); cairo_t* cr = m_data->cr; cairo_user_to_device(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user(cr, &x, &y); result.setX(static_cast<float>(x)); result.setY(static_cast<float>(y)); x = frect.width(); y = frect.height(); cairo_user_to_device_distance(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user_distance(cr, &x, &y); result.setWidth(static_cast<float>(x)); result.setHeight(static_cast<float>(y)); return result; }
bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, const LayoutObject& layoutObject, const FloatRect& targetBoundingBox, const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTransform) { if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, layoutObject, DisplayItem::SVGClip)) return true; SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &context); GraphicsContext& maskContext = maskPictureBuilder.context(); { TransformRecorder recorder(maskContext, layoutObject, localTransform); // Create a clipPathClipper if this clipPath is clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip); LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : nullptr; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !SVGClipPainter(*clipPathClipper).prepareEffect(m_clip, targetBoundingBox, targetPaintInvalidationRect, maskContext, clipPathClipperState)) return false; { AffineTransform contentTransform; if (m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransform.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransform.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } SubtreeContentTransformScope contentTransformScope(contentTransform); TransformRecorder contentTransformRecorder(maskContext, layoutObject, contentTransform); RefPtr<const SkPicture> clipContentPicture = m_clip.createContentPicture(); maskContext.getPaintController().createAndAppend<DrawingDisplayItem>(layoutObject, DisplayItem::SVGClip, clipContentPicture.get()); } if (clipPathClipper) SVGClipPainter(*clipPathClipper).finishEffect(m_clip, maskContext, clipPathClipperState); } LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayItem::SVGClip, targetPaintInvalidationRect); RefPtr<SkPicture> maskPicture = maskPictureBuilder.endRecording(); context.drawPicture(maskPicture.get()); return true; }
bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, RenderObject* object) { GraphicsContext* maskImageContext = maskerData->maskImage->context(); ASSERT(maskImageContext); // Eventually adjust the mask image context according to the target objectBoundingBox. AffineTransform maskContentTransformation; if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { FloatRect objectBoundingBox = object->objectBoundingBox(); maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskImageContext->concatCTM(maskContentTransformation); } // Draw the content into the ImageBuffer. for (auto& child : childrenOfType<SVGElement>(maskElement())) { auto renderer = child.renderer(); if (!renderer) continue; if (renderer->needsLayout()) return false; const RenderStyle& style = renderer->style(); if (style.display() == NONE || style.visibility() != VISIBLE) continue; SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), *renderer, maskContentTransformation); } #if !USE(CG) maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace); #else UNUSED_PARAM(colorSpace); #endif // Create the luminance mask. if (style().svgStyle().maskType() == MT_LUMINANCE) maskerData->maskImage->convertToLuminanceMask(); return true; }
bool SVGImageBufferTools::createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) { IntSize imageSize(roundedImageBufferSize(clampedAbsoluteTargetRect.size())); IntSize unclampedImageSize(SVGImageBufferTools::roundedImageBufferSize(absoluteTargetRect.size())); // Don't create empty ImageBuffers. if (imageSize.isEmpty()) return false; OwnPtr<ImageBuffer> image = ImageBuffer::create(imageSize, colorSpace, renderingMode); if (!image) return false; GraphicsContext* imageContext = image->context(); ASSERT(imageContext); // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height())); imageBuffer = image.release(); return true; }
bool LayoutSVGResourceClipper::asPath( const AffineTransform& animatedLocalTransform, const FloatRect& referenceBox, Path& clipPath) { if (!calculateClipContentPathIfNeeded()) return false; clipPath = m_clipContentPath; // We are able to represent the clip as a path. Continue with direct clipping, // and transform the content to userspace if necessary. if (clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { AffineTransform transform; transform.translate(referenceBox.x(), referenceBox.y()); transform.scaleNonUniform(referenceBox.width(), referenceBox.height()); clipPath.transform(transform); } // Transform path by animatedLocalTransform. clipPath.transform(animatedLocalTransform); return true; }
PassRefPtr<const SkPicture> LayoutSVGResourceMasker::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox, GraphicsContext& context) { SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } if (m_maskContentPicture) return m_maskContentPicture; SubtreeContentTransformScope contentTransformScope(contentTransformation); // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and // userSpaceOnUse units (http://crbug.com/294900). FloatRect bounds = strokeBoundingBox(); SkPictureBuilder pictureBuilder(bounds, nullptr, &context); ColorFilter maskContentFilter = style()->svgStyle().colorInterpolation() == CI_LINEARRGB ? ColorFilterSRGBToLinearRGB : ColorFilterNone; pictureBuilder.context().setColorFilter(maskContentFilter); for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { LayoutObject* layoutObject = childElement->layoutObject(); if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; SVGPaintContext::paintSubtree(pictureBuilder.context(), layoutObject); } m_maskContentPicture = pictureBuilder.endRecording(); return m_maskContentPicture; }
void RenderPath::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { childPaintInfo.context->save(); childPaintInfo.applyTransform(m_localTransform); if (childPaintInfo.phase == PaintPhaseForeground) { PaintInfo savedInfo(childPaintInfo); if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) { const SVGRenderStyle* svgStyle = style()->svgStyle(); if (svgStyle->shapeRendering() == SR_CRISPEDGES) childPaintInfo.context->setShouldAntialias(false); fillAndStrokePath(childPaintInfo.context); if (svgStyle->hasMarkers()) m_markerLayoutInfo.drawMarkers(childPaintInfo); } SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context); } if (drawsOutline) paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height())); childPaintInfo.context->restore(); } }
void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth) { int printedCharacters = 0; printPrefix(printedCharacters, depth); fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout); ++depth; auto resolver = runResolver(flow, layout); for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { const auto& run = *it; FloatRect rect = run.rect(); printPrefix(printedCharacters, depth); if (run.start() < run.end()) { fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(), rect.x(), rect.y(), rect.width(), rect.height(), run.text().toStringWithoutCopying().utf8().data()); } else { ASSERT(run.start() == run.end()); fprintf(stderr, "line break %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f)\n", run.lineIndex(), run.start(), run.end(), rect.x(), rect.y(), rect.width(), rect.height()); } } }
void PlatformContextCairo::clipForPatternFilling(const GraphicsContextState& state) { ASSERT(state.fillPattern); // Hold current cairo path in a variable for restoring it after configuring the pattern clip rectangle. auto currentPath = cairo_copy_path(m_cr.get()); cairo_new_path(m_cr.get()); // Initialize clipping extent from current cairo clip extents, then shrink if needed according to pattern. // Inspired by GraphicsContextQt::drawRepeatPattern. double x1, y1, x2, y2; cairo_clip_extents(m_cr.get(), &x1, &y1, &x2, &y2); FloatRect clipRect(x1, y1, x2 - x1, y2 - y1); Image* patternImage = state.fillPattern->tileImage(); ASSERT(patternImage); const AffineTransform& patternTransform = state.fillPattern->getPatternSpaceTransform(); FloatRect patternRect = patternTransform.mapRect(FloatRect(0, 0, patternImage->width(), patternImage->height())); bool repeatX = state.fillPattern->repeatX(); bool repeatY = state.fillPattern->repeatY(); if (!repeatX) { clipRect.setX(patternRect.x()); clipRect.setWidth(patternRect.width()); } if (!repeatY) { clipRect.setY(patternRect.y()); clipRect.setHeight(patternRect.height()); } if (!repeatX || !repeatY) { cairo_rectangle(m_cr.get(), clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()); cairo_clip(m_cr.get()); } // Restoring cairo path. cairo_append_path(m_cr.get(), currentPath); cairo_path_destroy(currentPath); }
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) { if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), op); return; } FloatSize intrinsicTileSize = size(); if (hasRelativeWidth()) intrinsicTileSize.setWidth(scaledTileSize.width()); if (hasRelativeHeight()) intrinsicTileSize.setHeight(scaledTileSize.height()); FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); draw(ctxt, destRect, visibleSrcRect, op); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); startAnimation(); }
LayoutRect RenderMathMLOperator::paintCharacter(PaintInfo& info, UChar character, const LayoutPoint& origin, CharacterPaintTrimming trim) { GlyphData data = style()->font().glyphDataForCharacter(character, false); FloatRect glyphBounds = data.fontData->boundsForGlyph(data.glyph); LayoutRect glyphPaintRect(origin, LayoutSize(glyphBounds.x() + glyphBounds.width(), glyphBounds.height())); glyphPaintRect.setY(origin.y() + glyphBounds.y()); // In order to have glyphs fit snugly with one another we snap the connecting edges to pixel boundaries // and trim off one pixel. The pixel trim is to account for fonts that have edge pixels that have less // than full coverage. These edge pixels can introduce small seams between connected glyphs FloatRect clipBounds = info.rect; switch (trim) { case TrimTop: glyphPaintRect.shiftYEdgeTo(glyphPaintRect.y().ceil() + 1); clipBounds.shiftYEdgeTo(glyphPaintRect.y()); break; case TrimBottom: glyphPaintRect.shiftMaxYEdgeTo(glyphPaintRect.maxY().floor() - 1); clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY()); break; case TrimTopAndBottom: LayoutUnit temp = glyphPaintRect.y() + 1; glyphPaintRect.shiftYEdgeTo(temp.ceil()); glyphPaintRect.shiftMaxYEdgeTo(glyphPaintRect.maxY().floor() - 1); clipBounds.shiftYEdgeTo(glyphPaintRect.y()); clipBounds.shiftMaxYEdgeTo(glyphPaintRect.maxY()); break; } // Clipping the enclosing IntRect avoids any potential issues at joined edges. GraphicsContextStateSaver stateSaver(*info.context); info.context->clip(clipBounds); info.context->drawText(style()->font(), TextRun(&character, 1), origin); return glyphPaintRect; }
void RenderPath::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); FloatRect nonLocalBoundingBox = m_localTransform.mapRect(boundingBox); // FIXME: The empty rect check is to deal with incorrect initial clip in renderSubtreeToImage // unfortunately fixing that problem is fairly complex unless we were willing to just futz the // rect to something "close enough" if (!nonLocalBoundingBox.intersects(paintInfo.rect) && !paintInfo.rect.isEmpty()) return; PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); applyTransformToPaintInfo(childPaintInfo, m_localTransform); SVGResourceFilter* filter = 0; if (childPaintInfo.phase == PaintPhaseForeground) { PaintInfo savedInfo(childPaintInfo); if (prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter)) { if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) childPaintInfo.context->setShouldAntialias(false); fillAndStrokePath(m_path, childPaintInfo.context, style(), this); if (static_cast<SVGStyledElement*>(node())->supportsMarkers()) m_markerLayoutInfo.drawMarkers(childPaintInfo); } finishRenderSVGContent(this, childPaintInfo, filter, savedInfo.context); } if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style()); childPaintInfo.context->restore(); }
FloatRect FilterEffect::determineFilterPrimitiveSubregion() { ASSERT(filter()); // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect. FloatRect subregion; if (unsigned numberOfInputEffects = inputEffects().size()) { subregion = inputEffect(0)->determineFilterPrimitiveSubregion(); for (unsigned i = 1; i < numberOfInputEffects; ++i) subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion()); } else subregion = filter()->filterRegion(); // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>. if (filterEffectType() == FilterEffectTypeTile) subregion = filter()->filterRegion(); subregion = mapRect(subregion); FloatRect boundaries = effectBoundaries(); if (hasX()) subregion.setX(boundaries.x()); if (hasY()) subregion.setY(boundaries.y()); if (hasWidth()) subregion.setWidth(boundaries.width()); if (hasHeight()) subregion.setHeight(boundaries.height()); setFilterPrimitiveSubregion(subregion); FloatRect absoluteSubregion = filter()->absoluteTransform().mapRect(subregion); FloatSize filterResolution = filter()->filterResolution(); absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); setMaxEffectRect(absoluteSubregion); return subregion; }
FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject& object) { FloatRect objectBoundingBox = object.objectBoundingBox(); FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(&maskElement(), maskElement().maskUnits(), objectBoundingBox); // Resource was not layouted yet. Give back clipping rect of the mask. if (selfNeedsLayout()) return maskBoundaries; if (m_maskContentBoundaries.isEmpty()) calculateMaskContentRepaintRect(); FloatRect maskRect = m_maskContentBoundaries; if (maskElement().maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskRect = transform.mapRect(maskRect); } maskRect.intersect(maskBoundaries); return maskRect; }
bool RenderThemeWinCE::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { bool rc = paintButton(o, paintInfo, r); FloatRect imRect = r; imRect.inflate(-3); paintInfo.context->save(); paintInfo.context->setStrokeColor(Color::black); paintInfo.context->setFillColor(Color::black); HTMLMediaElement* mediaElement = mediaElementParent(o->node()); bool paused = !mediaElement || mediaElement->paused(); if (paused) { float width = imRect.width(); imRect.setWidth(width / 3.0); paintInfo.context->fillRect(imRect); imRect.move(2.0 * width / 3.0, 0); paintInfo.context->fillRect(imRect); } else { FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint(imRect.maxX(), (imRect.y() + imRect.maxY()) / 2.0), FloatPoint(imRect.x(), imRect.maxY()) }; paintInfo.context->drawConvexPolygon(3, pts); } paintInfo.context->restore(); return rc; }
bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object) { GraphicsContext* maskImageContext = maskerData->maskImage->context(); ASSERT(maskImageContext); // Eventually adjust the mask image context according to the target objectBoundingBox. AffineTransform maskContentTransformation; if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { FloatRect objectBoundingBox = object->objectBoundingBox(); maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskImageContext->concatCTM(maskContentTransformation); } // Draw the content into the ImageBuffer. for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { RenderObject* renderer = node->renderer(); if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) continue; if (renderer->needsLayout()) return false; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; SVGImageBufferTools::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation); } #if !USE(CG) maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace); #else UNUSED_PARAM(colorSpace); #endif // Create the luminance mask. maskerData->maskImage->convertToLuminanceMask(); return true; }
FloatRect findInPageRectFromAbsoluteRect(const FloatRect& inputRect, const RenderObject* renderer) { if (!renderer || inputRect.isEmpty()) return FloatRect(); // Normalize the input rect to its container, saving the container bounding box for the incoming loop. FloatRect rendererBoundingBox; FloatRect normalizedRect = toNormalizedRect(inputRect, renderer, rendererBoundingBox); renderer = renderer->container(); // Go up across frames. while (renderer) { // Go up the render tree until we reach the root of the current frame (the RenderView). for (const RenderObject* container = renderer->container(); container; renderer = container, container = container->container()) { // Compose the normalized rects. The absolute bounding box of the container is calculated in toNormalizedRect // and can be reused for the next iteration of the loop. FloatRect normalizedBoxRect = toNormalizedRect(rendererBoundingBox, renderer, rendererBoundingBox); normalizedRect.scale(normalizedBoxRect.width(), normalizedBoxRect.height()); normalizedRect.moveBy(normalizedBoxRect.location()); if (normalizedRect.isEmpty()) return normalizedRect; } // Jump to the renderer owning the frame, if any. ASSERT(renderer->isRenderView()); renderer = renderer->frame() ? renderer->frame()->ownerRenderer() : 0; // Update the absolute coordinates to the new frame. if (renderer) rendererBoundingBox = renderer->absoluteBoundingBoxRect(); } return normalizedRect; }
void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect) { // Avoid NaN if (!isfinite(phase.x()) || !isfinite(phase.y())) return; cairo_save(cr); RefPtr<cairo_surface_t> clippedImageSurface = 0; if (tileRect.size() != imageSize) { IntRect imageRect = enclosingIntRect(tileRect); clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height())); RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get())); cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y()); cairo_paint(clippedImageContext.get()); image = clippedImageSurface.get(); } cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform); cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; cairo_matrix_t combined; cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix); cairo_matrix_invert(&combined); cairo_pattern_set_matrix(pattern, &combined); cairo_set_operator(cr, op); cairo_set_source(cr, pattern); cairo_pattern_destroy(pattern); cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height()); cairo_fill(cr); cairo_restore(cr); }
void PrintContext::computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) { m_pageRects.clear(); outPageHeight = 0; if (!m_frame->document() || !m_frame->view() || m_frame->document()->layoutViewItem().isNull()) return; if (userScaleFactor <= 0) { DLOG(ERROR) << "userScaleFactor has bad value " << userScaleFactor; return; } LayoutViewItem view = m_frame->document()->layoutViewItem(); const IntRect& documentRect = view.documentRect(); FloatSize pageSize = m_frame->resizePageRectsKeepingRatio( FloatSize(printRect.width(), printRect.height()), FloatSize(documentRect.width(), documentRect.height())); float pageWidth = pageSize.width(); float pageHeight = pageSize.height(); outPageHeight = pageHeight; // this is the height of the page adjusted by margins pageHeight -= headerHeight + footerHeight; if (pageHeight <= 0) { DLOG(ERROR) << "pageHeight has bad value " << pageHeight; return; } computePageRectsWithPageSizeInternal( FloatSize(pageWidth / userScaleFactor, pageHeight / userScaleFactor)); }
void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& dstRect) { if (m_data.m_tiledImage && context != m_context.get()) { FloatRect src = srcRect; if (src.width() == -1) src.setWidth(m_data.m_tiledImage->size().width()); if (src.height() == -1) src.setHeight(m_data.m_tiledImage->size().height()); ASSERT(context->platformContext()->activePainter()); AffineTransform phasedPatternTransform; phasedPatternTransform.translate(phase.x(), phase.y()); phasedPatternTransform.multLeft(patternTransform); PatternOpenVG pattern(m_data.m_tiledImage, src); pattern.setTransformation(phasedPatternTransform); PainterOpenVG* painter = context->platformContext()->activePainter(); PaintOpenVG currentPaint = painter->fillPaint(); CompositeOperator currentOp = painter->compositeOperation(); painter->setCompositeOperation(op); painter->setFillPattern(pattern); painter->drawRect(dstRect, VG_FILL_PATH); painter->setFillPaint(currentPaint); painter->setCompositeOperation(currentOp); return; } RefPtr<Image> imageCopy = copyImage(); imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, dstRect); }
void GraphicsContext::clip(const FloatRect& r) { wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context); wxPoint pos(0, 0); if (windc) { #if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) wxWindow* window = windc->GetWindow(); #else wxWindow* window = windc->m_owner; #endif if (window) { wxWindow* parent = window->GetParent(); // we need to convert from WebView "global" to WebFrame "local" coords. // FIXME: We only want to go to the top WebView. while (parent) { pos += window->GetPosition(); parent = parent->GetParent(); } } } m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y); }
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; double x = frect.x(); double y = frect.y(); cairo_t* cr = platformContext()->cr(); cairo_user_to_device(cr, &x, &y); x = round(x); y = round(y); cairo_device_to_user(cr, &x, &y); result.setX(narrowPrecisionToFloat(x)); result.setY(narrowPrecisionToFloat(y)); // We must ensure width and height are at least 1 (or -1) when // we're given float values in the range between 0 and 1 (or -1 and 0). double width = frect.width(); double height = frect.height(); cairo_user_to_device_distance(cr, &width, &height); if (width > -1 && width < 0) width = -1; else if (width > 0 && width < 1) width = 1; else width = round(width); if (height > -1 && width < 0) height = -1; else if (height > 0 && height < 1) height = 1; else height = round(height); cairo_device_to_user_distance(cr, &width, &height); result.setWidth(narrowPrecisionToFloat(width)); result.setHeight(narrowPrecisionToFloat(height)); return result; }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRectIn, ColorSpace styleColorSpace, CompositeOperator compositeOp) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, compositeOp); else { IntRect intSrcRect(srcRectIn); RefPtr<SharedBitmap> bmp = frameAtIndex(m_currentFrame); if (bmp->width() != m_source.size().width()) { double scaleFactor = static_cast<double>(bmp->width()) / m_source.size().width(); intSrcRect.setX(stableRound(srcRectIn.x() * scaleFactor)); intSrcRect.setWidth(stableRound(srcRectIn.width() * scaleFactor)); intSrcRect.setY(stableRound(srcRectIn.y() * scaleFactor)); intSrcRect.setHeight(stableRound(srcRectIn.height() * scaleFactor)); } bmp->draw(ctxt, enclosingIntRect(dstRect), intSrcRect, styleColorSpace, compositeOp); } startAnimation(); }
TextStream& SVGResourceFilter::externalRepresentation(TextStream& ts) const { ts << "[type=FILTER] "; FloatRect bbox = filterRect(); static FloatRect defaultFilterRect(0, 0, 1, 1); if (!filterBoundingBoxMode() || bbox != defaultFilterRect) { ts << " [bounding box="; if (filterBoundingBoxMode()) { bbox.scale(100.f); ts << "at (" << bbox.x() << "%," << bbox.y() << "%) size " << bbox.width() << "%x" << bbox.height() << "%"; } else ts << filterRect(); ts << "]"; } if (!filterBoundingBoxMode()) // default is true ts << " [bounding box mode=" << filterBoundingBoxMode() << "]"; if (effectBoundingBoxMode()) // default is false ts << " [effect bounding box mode=" << effectBoundingBoxMode() << "]"; return ts; }
void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target) { QPainter* painter = context->platformContext(); QTransform worldTransform = painter->worldTransform(); qreal scaleX = worldTransform.m11(); qreal scaleY = worldTransform.m22(); QRect targetViewRect = QRectF(target.x() * scaleX, target.y() * scaleY, target.width() * scaleX, target.height() * scaleY).toAlignedRect(); QTransform adjustedTransform(1., worldTransform.m12(), worldTransform.m13(), worldTransform.m21(), 1., worldTransform.m23(), worldTransform.m31(), worldTransform.m32(), worldTransform.m33()); painter->setWorldTransform(adjustedTransform); painter->drawTiledPixmap(targetViewRect, checkeredPixmap(), QPoint(targetViewRect.left() % checkerSize, targetViewRect.top() % checkerSize)); painter->setWorldTransform(worldTransform); }
void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect) { RenderSVGText& parentBlock = renderSVGText(); // Finally, assign the root block position, now that all content is laid out. LayoutRect boundingRect = enclosingLayoutRect(childRect); parentBlock.setLocation(boundingRect.location()); parentBlock.setSize(boundingRect.size()); // Position all children relative to the parent block. for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { // Skip generated content. if (!child->renderer().node()) continue; child->adjustPosition(-childRect.x(), -childRect.y()); } // Position ourselves. setX(0); setY(0); setLogicalWidth(childRect.width()); setLogicalHeight(childRect.height()); setLineTopBottomPositions(0, boundingRect.height(), 0, boundingRect.height()); }
IntRect::IntRect(const FloatRect &r) : m_location(IntPoint(static_cast<int>(r.x()), static_cast<int>(r.y()))) , m_size(IntSize(static_cast<int>(r.width()), static_cast<int>(r.height()))) { }
void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object) { FloatRect objectBoundingBox = object->objectBoundingBox(); // Mask rect clipped with clippingBoundingBox and filterBoundingBox as long as they are present. maskerData->maskRect = object->repaintRectInLocalCoordinates(); if (maskerData->maskRect.isEmpty()) { maskerData->emptyMask = true; return; } if (m_maskBoundaries.isEmpty()) calculateMaskContentRepaintRect(); FloatRect repaintRect = m_maskBoundaries; AffineTransform contextTransform; // We need to scale repaintRect for objectBoundingBox to get the drawing area. if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contextTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); FloatPoint contextAdjustment = repaintRect.location(); repaintRect = contextTransform.mapRect(repaintRect); repaintRect.move(objectBoundingBox.x(), objectBoundingBox.y()); contextTransform.translate(-contextAdjustment.x(), -contextAdjustment.y()); } repaintRect.intersect(maskerData->maskRect); maskerData->maskRect = repaintRect; IntRect maskImageRect = enclosingIntRect(maskerData->maskRect); maskImageRect.setLocation(IntPoint()); // Don't create ImageBuffers with image size of 0 if (maskImageRect.isEmpty()) { maskerData->emptyMask = true; return; } // FIXME: This changes color space to linearRGB, the default color space // for masking operations in SVG. We need a switch for the other color-space // attribute values sRGB, inherit and auto. maskerData->maskImage = ImageBuffer::create(maskImageRect.size(), LinearRGB); if (!maskerData->maskImage) return; GraphicsContext* maskImageContext = maskerData->maskImage->context(); ASSERT(maskImageContext); maskImageContext->save(); if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) maskImageContext->translate(-maskerData->maskRect.x(), -maskerData->maskRect.y()); maskImageContext->concatCTM(contextTransform); // draw the content into the ImageBuffer for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { RenderObject* renderer = node->renderer(); if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; renderSubtreeToImage(maskerData->maskImage.get(), renderer); } maskImageContext->restore(); // create the luminance mask RefPtr<ImageData> imageData(maskerData->maskImage->getUnmultipliedImageData(maskImageRect)); CanvasPixelArray* srcPixelArray(imageData->data()); for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) { unsigned char a = srcPixelArray->get(pixelOffset + 3); if (!a) continue; unsigned char r = srcPixelArray->get(pixelOffset); unsigned char g = srcPixelArray->get(pixelOffset + 1); unsigned char b = srcPixelArray->get(pixelOffset + 2); double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0); srcPixelArray->set(pixelOffset + 3, luma); } maskerData->maskImage->putUnmultipliedImageData(imageData.get(), maskImageRect, IntPoint()); }
FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect, SVGFilter* filter) { FloatRect uniteRect; FloatRect subregionBoundingBox = effect->effectBoundaries(); FloatRect subregion = subregionBoundingBox; if (effect->filterEffectType() != FilterEffectTypeTile) { // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. if (unsigned numberOfInputEffects = effect->inputEffects().size()) { for (unsigned i = 0; i < numberOfInputEffects; ++i) uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i), filter)); } else uniteRect = filter->filterRegionInUserSpace(); } else { determineFilterPrimitiveSubregion(effect->inputEffect(0), filter); uniteRect = filter->filterRegionInUserSpace(); } if (filter->effectBoundingBoxMode()) { subregion = uniteRect; // Avoid the calling of a virtual method several times. FloatRect targetBoundingBox = filter->targetBoundingBox(); if (effect->hasX()) subregion.setX(targetBoundingBox.x() + subregionBoundingBox.x() * targetBoundingBox.width()); if (effect->hasY()) subregion.setY(targetBoundingBox.y() + subregionBoundingBox.y() * targetBoundingBox.height()); if (effect->hasWidth()) subregion.setWidth(subregionBoundingBox.width() * targetBoundingBox.width()); if (effect->hasHeight()) subregion.setHeight(subregionBoundingBox.height() * targetBoundingBox.height()); } else { if (!effect->hasX()) subregion.setX(uniteRect.x()); if (!effect->hasY()) subregion.setY(uniteRect.y()); if (!effect->hasWidth()) subregion.setWidth(uniteRect.width()); if (!effect->hasHeight()) subregion.setHeight(uniteRect.height()); } effect->setFilterPrimitiveSubregion(subregion); FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion); FloatSize filterResolution = filter->filterResolution(); absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); // FEImage needs the unclipped subregion in absolute coordinates to determine the correct // destination rect in combination with preserveAspectRatio. if (effect->filterEffectType() == FilterEffectTypeImage) reinterpret_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); // Clip every filter effect to the filter region. FloatRect absoluteScaledFilterRegion = filter->filterRegion(); absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); absoluteSubregion.intersect(absoluteScaledFilterRegion); effect->setMaxEffectRect(enclosingIntRect(absoluteSubregion)); return subregion; }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription description) { #if PLATFORM(IOS) startAnimation(DoNotCatchUp); #else startAnimation(); #endif RetainPtr<CGImageRef> image; // Never use subsampled images for drawing into PDF contexts. if (wkCGContextIsPDFContext(ctxt->platformContext())) image = adoptCF(copyUnscaledFrameAtIndex(m_currentFrame)); else { CGRect transformedDestinationRect = CGRectApplyAffineTransform(destRect, CGContextGetCTM(ctxt->platformContext())); float subsamplingScale = std::min<float>(1, std::max(transformedDestinationRect.size.width / srcRect.width(), transformedDestinationRect.size.height / srcRect.height())); image = frameAtIndex(m_currentFrame, subsamplingScale); } if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } // Subsampling may have given us an image that is smaller than size(). IntSize imageSize(CGImageGetWidth(image.get()), CGImageGetHeight(image.get())); // srcRect is in the coordinates of the unsubsampled image, so we have to map it to the subsampled image. FloatRect scaledSrcRect = srcRect; if (imageSize != m_size) { FloatRect originalImageBounds(FloatPoint(), m_size); FloatRect subsampledImageBounds(FloatPoint(), imageSize); scaledSrcRect = mapRect(srcRect, originalImageBounds, subsampledImageBounds); } ImageOrientation orientation; if (description.respectImageOrientation() == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); ctxt->drawNativeImage(image.get(), imageSize, styleColorSpace, destRect, scaledSrcRect, compositeOp, blendMode, orientation); if (imageObserver()) imageObserver()->didDraw(this); }