Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/gfx/2d/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  DrawTarget.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "2D.h"
#include "Blur.h"
#include "Logging.h"
#include "PathHelpers.h"
#include "SourceSurfaceRawData.h"
#include "Tools.h"

#include "BufferEdgePad.h"
#include "BufferUnrotate.h"

#ifdef USE_NEON
#  include "mozilla/arm.h"
#  include "LuminanceNEON.h"
#endif

namespace mozilla {
namespace gfx {

/**
 * Byte offsets of channels in a native packed gfxColor or cairo image surface.
 */

#ifdef IS_BIG_ENDIAN
#  define GFX_ARGB32_OFFSET_A 0
#  define GFX_ARGB32_OFFSET_R 1
#  define GFX_ARGB32_OFFSET_G 2
#  define GFX_ARGB32_OFFSET_B 3
#else
#  define GFX_ARGB32_OFFSET_A 3
#  define GFX_ARGB32_OFFSET_R 2
#  define GFX_ARGB32_OFFSET_G 1
#  define GFX_ARGB32_OFFSET_B 0
#endif

// c = n / 255
// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
static const uint8_t gsRGBToLinearRGBMap[256] = {
    0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,
    1,   1,   1,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,
    3,   3,   4,   4,   4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   6,
    7,   7,   7,   8,   8,   8,   8,   9,   9,   9,   10,  10,  10,  11,  11,
    12,  12,  12,  13,  13,  13,  14,  14,  15,  15,  16,  16,  17,  17,  17,
    18,  18,  19,  19,  20,  20,  21,  22,  22,  23,  23,  24,  24,  25,  25,
    26,  27,  27,  28,  29,  29,  30,  30,  31,  32,  32,  33,  34,  35,  35,
    36,  37,  37,  38,  39,  40,  41,  41,  42,  43,  44,  45,  45,  46,  47,
    48,  49,  50,  51,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,
    62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  76,  77,
    78,  79,  80,  81,  82,  84,  85,  86,  87,  88,  90,  91,  92,  93,  95,
    96,  97,  99,  100, 101, 103, 104, 105, 107, 108, 109, 111, 112, 114, 115,
    116, 118, 119, 121, 122, 124, 125, 127, 128, 130, 131, 133, 134, 136, 138,
    139, 141, 142, 144, 146, 147, 149, 151, 152, 154, 156, 157, 159, 161, 163,
    164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190,
    192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220,
    222, 224, 226, 229, 231, 233, 235, 237, 239, 242, 244, 246, 248, 250, 253,
    255};

static void ComputesRGBLuminanceMask(const uint8_t* aSourceData,
                                     int32_t aSourceStride, uint8_t* aDestData,
                                     int32_t aDestStride, const IntSize& aSize,
                                     float aOpacity) {
#ifdef USE_NEON
  if (mozilla::supports_neon()) {
    ComputesRGBLuminanceMask_NEON(aSourceData, aSourceStride, aDestData,
                                  aDestStride, aSize, aOpacity);
    return;
  }
#endif

  int32_t redFactor = 55 * aOpacity;     // 255 * 0.2125 * opacity
  int32_t greenFactor = 183 * aOpacity;  // 255 * 0.7154 * opacity
  int32_t blueFactor = 18 * aOpacity;    // 255 * 0.0721
  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
  const uint8_t* sourcePixel = aSourceData;
  int32_t destOffset = aDestStride - aSize.width;
  uint8_t* destPixel = aDestData;

  for (int32_t y = 0; y < aSize.height; y++) {
    for (int32_t x = 0; x < aSize.width; x++) {
      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];

      if (a) {
        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >>
                     8;
      } else {
        *destPixel = 0;
      }
      sourcePixel += 4;
      destPixel++;
    }
    sourcePixel += sourceOffset;
    destPixel += destOffset;
  }
}

static void ComputeLinearRGBLuminanceMask(
    const uint8_t* aSourceData, int32_t aSourceStride, uint8_t* aDestData,
    int32_t aDestStride, const IntSize& aSize, float aOpacity) {
  int32_t redFactor = 55 * aOpacity;     // 255 * 0.2125 * opacity
  int32_t greenFactor = 183 * aOpacity;  // 255 * 0.7154 * opacity
  int32_t blueFactor = 18 * aOpacity;    // 255 * 0.0721
  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
  const uint8_t* sourcePixel = aSourceData;
  int32_t destOffset = aDestStride - aSize.width;
  uint8_t* destPixel = aDestData;

  for (int32_t y = 0; y < aSize.height; y++) {
    for (int32_t x = 0; x < aSize.width; x++) {
      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];

      // unpremultiply
      if (a) {
        if (a == 255) {
          /* sRGB -> linearRGB -> intensity */
          *destPixel = static_cast<uint8_t>(
              (gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_R]] *
                   redFactor +
               gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_G]] *
                   greenFactor +
               gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_B]] *
                   blueFactor) >>
              8);
        } else {
          uint8_t tempPixel[4];
          tempPixel[GFX_ARGB32_OFFSET_B] =
              (255 * sourcePixel[GFX_ARGB32_OFFSET_B]) / a;
          tempPixel[GFX_ARGB32_OFFSET_G] =
              (255 * sourcePixel[GFX_ARGB32_OFFSET_G]) / a;
          tempPixel[GFX_ARGB32_OFFSET_R] =
              (255 * sourcePixel[GFX_ARGB32_OFFSET_R]) / a;

          /* sRGB -> linearRGB -> intensity */
          *destPixel = static_cast<uint8_t>(
              ((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
                    redFactor +
                gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
                    greenFactor +
                gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
                    blueFactor) >>
               8) *
              (a / 255.0f));
        }
      } else {
        *destPixel = 0;
      }
      sourcePixel += 4;
      destPixel++;
    }
    sourcePixel += sourceOffset;
    destPixel += destOffset;
  }
}

void DrawTarget::PushDeviceSpaceClipRects(const IntRect* aRects,
                                          uint32_t aCount) {
  Matrix oldTransform = GetTransform();
  SetTransform(Matrix());

  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
  for (uint32_t i = 0; i < aCount; i++) {
    AppendRectToPath(pathBuilder, Rect(aRects[i]));
  }
  RefPtr<Path> path = pathBuilder->Finish();
  PushClip(path);

  SetTransform(oldTransform);
}

void DrawTarget::FillRoundedRect(const RoundedRect& aRect,
                                 const Pattern& aPattern,
                                 const DrawOptions& aOptions) {
  RefPtr<Path> path = MakePathForRoundedRect(*this, aRect.rect, aRect.corners);
  Fill(path, aPattern, aOptions);
}

void DrawTarget::StrokeCircle(const Point& aOrigin, float radius,
                              const Pattern& aPattern,
                              const StrokeOptions& aStrokeOptions,
                              const DrawOptions& aOptions) {
  RefPtr<Path> path = MakePathForCircle(*this, aOrigin, radius);
  Stroke(path, aPattern, aStrokeOptions, aOptions);
}

void DrawTarget::FillCircle(const Point& aOrigin, float radius,
                            const Pattern& aPattern,
                            const DrawOptions& aOptions) {
  RefPtr<Path> path = MakePathForCircle(*this, aOrigin, radius);
  Fill(path, aPattern, aOptions);
}

void DrawTarget::StrokeGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
                              const Pattern& aPattern,
                              const StrokeOptions& aStrokeOptions,
                              const DrawOptions& aOptions) {
  if (RefPtr<Path> path = aFont->GetPathForGlyphs(aBuffer, this)) {
    Stroke(path, aPattern, aStrokeOptions, aOptions);
  }
}

already_AddRefed<SourceSurface> DrawTarget::IntoLuminanceSource(
    LuminanceType aMaskType, float aOpacity) {
  // The default IntoLuminanceSource implementation needs a format of B8G8R8A8.
  if (mFormat != SurfaceFormat::B8G8R8A8) {
    return nullptr;
  }

  RefPtr<SourceSurface> surface = Snapshot();
  if (!surface) {
    return nullptr;
  }

  IntSize size = surface->GetSize();

  RefPtr<DataSourceSurface> maskSurface = surface->GetDataSurface();
  if (!maskSurface) {
    return nullptr;
  }

  DataSourceSurface::MappedSurface map;
  if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
    return nullptr;
  }

  // Create alpha channel mask for output
  RefPtr<SourceSurfaceAlignedRawData> destMaskSurface =
      new SourceSurfaceAlignedRawData;
  if (!destMaskSurface->Init(size, SurfaceFormat::A8, false, 0)) {
    return nullptr;
  }
  DataSourceSurface::MappedSurface destMap;
  if (!destMaskSurface->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
    return nullptr;
  }

  switch (aMaskType) {
    case LuminanceType::LUMINANCE: {
      ComputesRGBLuminanceMask(map.mData, map.mStride, destMap.mData,
                               destMap.mStride, size, aOpacity);
      break;
    }
    case LuminanceType::LINEARRGB: {
      ComputeLinearRGBLuminanceMask(map.mData, map.mStride, destMap.mData,
                                    destMap.mStride, size, aOpacity);
      break;
    }
  }

  maskSurface->Unmap();
  destMaskSurface->Unmap();

  return destMaskSurface.forget();
}

void DrawTarget::Blur(const AlphaBoxBlur& aBlur) {
  uint8_t* data;
  IntSize size;
  int32_t stride;
  SurfaceFormat format;
  if (!LockBits(&data, &size, &stride, &format)) {
    gfxWarning() << "Cannot perform in-place blur on non-data DrawTarget";
    return;
  }

  // Sanity check that the blur size matches the draw target.
  MOZ_ASSERT(size == aBlur.GetSize());
  MOZ_ASSERT(stride == aBlur.GetStride());
  aBlur.Blur(data);

  ReleaseBits(data);
}

void DrawTarget::PadEdges(const IntRegion& aRegion) {
  PadDrawTargetOutFromRegion(this, aRegion);
}

bool DrawTarget::Unrotate(IntPoint aRotation) {
  unsigned char* data;
  IntSize size;
  int32_t stride;
  SurfaceFormat format;

  if (LockBits(&data, &size, &stride, &format)) {
    uint8_t bytesPerPixel = BytesPerPixel(format);
    BufferUnrotate(data, size.width * bytesPerPixel, size.height, stride,
                   aRotation.x * bytesPerPixel, aRotation.y);
    ReleaseBits(data);
    return true;
  }
  return false;
}

int32_t ShadowOptions::BlurRadius() const {
  return AlphaBoxBlur::CalculateBlurRadius(Point(mSigma, mSigma)).width;
}

void DrawTarget::DrawShadow(const Path* aPath, const Pattern& aPattern,
                            const ShadowOptions& aShadow,
                            const DrawOptions& aOptions,
                            const StrokeOptions* aStrokeOptions) {
  // Get the approximate bounds of the source path
  Rect bounds = aPath->GetFastBounds(GetTransform(), aStrokeOptions);
  if (bounds.IsEmpty()) {
    return;
  }
  // Inflate the bounds by the blur radius
  bounds += aShadow.mOffset;
  int32_t blurRadius = aShadow.BlurRadius();
  bounds.Inflate(blurRadius);
  bounds.RoundOut();
  // Check if the bounds intersect the viewport
  Rect viewport(GetRect());
  viewport.Inflate(blurRadius);
  bounds = bounds.Intersect(viewport);
  IntRect intBounds;
  if (bounds.IsEmpty() || !bounds.ToIntRect(&intBounds) ||
      !CanCreateSimilarDrawTarget(intBounds.Size(), SurfaceFormat::A8)) {
    return;
  }
  // Create a draw target for drawing the shadow mask with enough room for blur
  RefPtr<DrawTarget> shadowTarget = CreateShadowDrawTarget(
      intBounds.Size(), SurfaceFormat::A8, aShadow.mSigma);
  if (shadowTarget) {
    // See bug 1524554.
    shadowTarget->ClearRect(Rect());
  }
  if (!shadowTarget || !shadowTarget->IsValid()) {
    return;
  }
  // Draw the path into the target for the initial shadow mask
  Point offset = Point(intBounds.TopLeft()) - aShadow.mOffset;
  shadowTarget->SetTransform(GetTransform().PostTranslate(-offset));
  DrawOptions shadowDrawOptions(
      aOptions.mAlpha, CompositionOp::OP_OVER,
      blurRadius > 1 ? AntialiasMode::NONE : aOptions.mAntialiasMode);
  if (aStrokeOptions) {
    shadowTarget->Stroke(aPath, aPattern, *aStrokeOptions, shadowDrawOptions);
  } else {
    shadowTarget->Fill(aPath, aPattern, shadowDrawOptions);
  }
  RefPtr<SourceSurface> snapshot = shadowTarget->Snapshot();
  // Finally, hand a snapshot of the mask to DrawSurfaceWithShadow for the
  // final shadow blur
  if (snapshot) {
    DrawSurfaceWithShadow(snapshot, offset, aShadow, aOptions.mCompositionOp);
  }
}

}  // namespace gfx
}  // namespace mozilla

92%


¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.