tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CSSClipPathInstance.cpp (8829B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Main header first:
      8 #include "CSSClipPathInstance.h"
      9 
     10 #include "gfx2DGlue.h"
     11 #include "gfxContext.h"
     12 #include "gfxPlatform.h"
     13 #include "mozilla/SVGUtils.h"
     14 #include "mozilla/ShapeUtils.h"
     15 #include "mozilla/dom/SVGElement.h"
     16 #include "mozilla/dom/SVGPathData.h"
     17 #include "mozilla/gfx/2D.h"
     18 #include "mozilla/gfx/PathHelpers.h"
     19 #include "nsIFrame.h"
     20 #include "nsLayoutUtils.h"
     21 
     22 using namespace mozilla::dom;
     23 using namespace mozilla::gfx;
     24 
     25 namespace mozilla {
     26 
     27 /* static*/
     28 void CSSClipPathInstance::ApplyBasicShapeOrPathClip(
     29    gfxContext& aContext, nsIFrame* aFrame, const gfxMatrix& aTransform) {
     30  RefPtr<Path> path =
     31      CreateClipPathForFrame(aContext.GetDrawTarget(), aFrame, aTransform);
     32  if (!path) {
     33    // This behavior matches |SVGClipPathFrame::ApplyClipPath()|.
     34    // https://www.w3.org/TR/css-masking-1/#ClipPathElement:
     35    // "An empty clipping path will completely clip away the element that had
     36    // the clip-path property applied."
     37    aContext.Clip(Rect());
     38    return;
     39  }
     40  aContext.Clip(path);
     41 }
     42 
     43 /* static*/
     44 RefPtr<Path> CSSClipPathInstance::CreateClipPathForFrame(
     45    gfx::DrawTarget* aDt, nsIFrame* aFrame, const gfxMatrix& aTransform) {
     46  const auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
     47  MOZ_ASSERT(clipPathStyle.IsShape() || clipPathStyle.IsBox(),
     48             "This is used with basic-shape, and geometry-box only");
     49 
     50  CSSClipPathInstance instance(aFrame, clipPathStyle);
     51 
     52  return instance.CreateClipPath(aDt, aTransform);
     53 }
     54 
     55 /* static*/
     56 bool CSSClipPathInstance::HitTestBasicShapeOrPathClip(nsIFrame* aFrame,
     57                                                      const gfxPoint& aPoint) {
     58  const auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
     59  MOZ_ASSERT(!clipPathStyle.IsNone(), "unexpected none value");
     60  MOZ_ASSERT(!clipPathStyle.IsUrl(), "unexpected url value");
     61 
     62  CSSClipPathInstance instance(aFrame, clipPathStyle);
     63 
     64  RefPtr<DrawTarget> drawTarget =
     65      gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
     66  RefPtr<Path> path = instance.CreateClipPath(
     67      drawTarget, SVGUtils::GetCSSPxToDevPxMatrix(aFrame));
     68  float pixelRatio = float(AppUnitsPerCSSPixel()) /
     69                     float(aFrame->PresContext()->AppUnitsPerDevPixel());
     70  return path && path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
     71 }
     72 
     73 /* static */
     74 Maybe<Rect> CSSClipPathInstance::GetBoundingRectForBasicShapeOrPathClip(
     75    nsIFrame* aFrame, const StyleClipPath& aClipPathStyle) {
     76  MOZ_ASSERT(aClipPathStyle.IsShape() || aClipPathStyle.IsBox());
     77 
     78  CSSClipPathInstance instance(aFrame, aClipPathStyle);
     79 
     80  RefPtr<DrawTarget> drawTarget =
     81      gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
     82  RefPtr<Path> path = instance.CreateClipPath(
     83      drawTarget, SVGUtils::GetCSSPxToDevPxMatrix(aFrame));
     84  return path ? Some(path->GetBounds()) : Nothing();
     85 }
     86 
     87 already_AddRefed<Path> CSSClipPathInstance::CreateClipPath(
     88    DrawTarget* aDrawTarget, const gfxMatrix& aTransform) {
     89  nscoord appUnitsPerDevPixel =
     90      mTargetFrame->PresContext()->AppUnitsPerDevPixel();
     91 
     92  nsRect r = nsLayoutUtils::ComputeClipPathGeometryBox(
     93      mTargetFrame, mClipPathStyle.IsBox() ? mClipPathStyle.AsBox()
     94                                           : mClipPathStyle.AsShape()._1);
     95 
     96  gfxRect rr(r.x, r.y, r.width, r.height);
     97  rr.Scale(1.0 / AppUnitsPerCSSPixel());
     98  rr = aTransform.TransformRect(rr);
     99  rr.Scale(appUnitsPerDevPixel);
    100  rr.Round();
    101 
    102  r = nsRect(int(rr.x), int(rr.y), int(rr.width), int(rr.height));
    103 
    104  if (mClipPathStyle.IsBox()) {
    105    RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
    106    AppendRectToPath(builder, NSRectToRect(r, appUnitsPerDevPixel), true);
    107    return builder->Finish();
    108  }
    109 
    110  MOZ_ASSERT(mClipPathStyle.IsShape());
    111 
    112  r = ToAppUnits(r.ToNearestPixels(appUnitsPerDevPixel), appUnitsPerDevPixel);
    113 
    114  const auto& basicShape = *mClipPathStyle.AsShape()._0;
    115  switch (basicShape.tag) {
    116    case StyleBasicShape::Tag::Circle:
    117      return CreateClipPathCircle(aDrawTarget, r);
    118    case StyleBasicShape::Tag::Ellipse:
    119      return CreateClipPathEllipse(aDrawTarget, r);
    120    case StyleBasicShape::Tag::Polygon:
    121      return CreateClipPathPolygon(aDrawTarget, r);
    122    case StyleBasicShape::Tag::Rect:
    123      return CreateClipPathInset(aDrawTarget, r);
    124    case StyleBasicShape::Tag::PathOrShape:
    125      return basicShape.AsPathOrShape().IsPath()
    126                 ? CreateClipPathPath(aDrawTarget, r)
    127                 : CreateClipPathShape(aDrawTarget, r);
    128    default:
    129      MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected shape type");
    130  }
    131  // Return an empty Path:
    132  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
    133  return builder->Finish();
    134 }
    135 
    136 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathCircle(
    137    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    138  const StyleBasicShape& shape = *mClipPathStyle.AsShape()._0;
    139  const nsPoint& center =
    140      ShapeUtils::ComputeCircleOrEllipseCenter(shape, aRefBox);
    141  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
    142  return ShapeUtils::BuildCirclePath(
    143      shape, aRefBox, center,
    144      mTargetFrame->PresContext()->AppUnitsPerDevPixel(), builder);
    145 }
    146 
    147 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathEllipse(
    148    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    149  const StyleBasicShape& shape = *mClipPathStyle.AsShape()._0;
    150  const nsPoint& center =
    151      ShapeUtils::ComputeCircleOrEllipseCenter(shape, aRefBox);
    152  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
    153  return ShapeUtils::BuildEllipsePath(
    154      shape, aRefBox, center,
    155      mTargetFrame->PresContext()->AppUnitsPerDevPixel(), builder);
    156 }
    157 
    158 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathPolygon(
    159    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    160  const auto& basicShape = *mClipPathStyle.AsShape()._0;
    161  auto fillRule = basicShape.AsPolygon().fill == StyleFillRule::Nonzero
    162                      ? FillRule::FILL_WINDING
    163                      : FillRule::FILL_EVEN_ODD;
    164  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(fillRule);
    165  return ShapeUtils::BuildPolygonPath(
    166      basicShape, aRefBox, mTargetFrame->PresContext()->AppUnitsPerDevPixel(),
    167      builder);
    168 }
    169 
    170 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathInset(
    171    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    172  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
    173  return ShapeUtils::BuildInsetPath(
    174      *mClipPathStyle.AsShape()._0, aRefBox,
    175      mTargetFrame->PresContext()->AppUnitsPerDevPixel(), builder);
    176 }
    177 
    178 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathPath(
    179    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    180  const auto& path = mClipPathStyle.AsShape()._0->AsPathOrShape().AsPath();
    181 
    182  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(
    183      path.fill == StyleFillRule::Nonzero ? FillRule::FILL_WINDING
    184                                          : FillRule::FILL_EVEN_ODD);
    185  const nscoord appUnitsPerDevPixel =
    186      mTargetFrame->PresContext()->AppUnitsPerDevPixel();
    187  const Point offset =
    188      LayoutDevicePoint::FromAppUnits(aRefBox.TopLeft(), appUnitsPerDevPixel)
    189          .ToUnknownPoint();
    190  const float scale = mTargetFrame->Style()->EffectiveZoom().Zoom(
    191      float(AppUnitsPerCSSPixel()) / float(appUnitsPerDevPixel));
    192  return SVGPathData::BuildPath(path.path._0.AsSpan(), builder,
    193                                StyleStrokeLinecap::Butt, 0.0, {}, offset,
    194                                scale);
    195 }
    196 
    197 already_AddRefed<Path> CSSClipPathInstance::CreateClipPathShape(
    198    DrawTarget* aDrawTarget, const nsRect& aRefBox) {
    199  const auto& shape = mClipPathStyle.AsShape()._0->AsPathOrShape().AsShape();
    200 
    201  RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(
    202      shape.fill == StyleFillRule::Nonzero ? FillRule::FILL_WINDING
    203                                           : FillRule::FILL_EVEN_ODD);
    204  const nscoord appUnitsPerDevPixel =
    205      mTargetFrame->PresContext()->AppUnitsPerDevPixel();
    206  const CSSSize basis = CSSSize::FromAppUnits(aRefBox.Size());
    207  const Point offset =
    208      LayoutDevicePoint::FromAppUnits(aRefBox.TopLeft(), appUnitsPerDevPixel)
    209          .ToUnknownPoint();
    210  const float scale = mTargetFrame->Style()->EffectiveZoom().Zoom(
    211      float(AppUnitsPerCSSPixel()) / float(appUnitsPerDevPixel));
    212  return SVGPathData::BuildPath(shape.commands.AsSpan(), builder,
    213                                StyleStrokeLinecap::Butt, 0.0, basis, offset,
    214                                scale);
    215 }
    216 
    217 }  // namespace mozilla