<commit_before>/* 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/. */

template <bool COMPOSITE, typename P>
static inline void copy_row(P* dst, const P* src, int span) {
  // No scaling, so just do a fast copy.
  memcpy(dst, src, span * sizeof(P));
}

template <>
void copy_row<true, uint32_t>(uint32_t* dst, const uint32_t* src, int span) {
  // No scaling, so just do a fast composite.
  auto* end = dst + span;
  while (dst + 4 <= end) {
    WideRGBA8 srcpx = unpack(unaligned_load<PackedRGBA8>(src));
    WideRGBA8 dstpx = unpack(unaligned_load<PackedRGBA8>(dst));
    PackedRGBA8 r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    unaligned_store(dst, r);
    src += 4;
    dst += 4;
  }
  if (dst < end) {
    WideRGBA8 srcpx = unpack(partial_load_span<PackedRGBA8>(src, end - dst));
    WideRGBA8 dstpx = unpack(partial_load_span<PackedRGBA8>(dst, end - dst));
    auto r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    partial_store_span(dst, r, end - dst);
  }
}

template <bool COMPOSITE, typename P>
static inline void scale_row(P* dst, int dstWidth, const P* src, int srcWidth,
                             int span, int frac) {
  // Do scaling with different source and dest widths.
  for (P* end = dst + span; dst < end; dst++) {
    *dst = *src;
    // Step source according to width ratio.
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
  }
}

template <>
void scale_row<true, uint32_t>(uint32_t* dst, int dstWidth, const uint32_t* src,
                               int srcWidth, int span, int frac) {
  // Do scaling with different source and dest widths.
  // Gather source pixels four at a time for better packing.
  auto* end = dst + span;
  for (; dst + 4 <= end; dst += 4) {
    U32 srcn;
    srcn.x = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.y = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.z = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.w = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    WideRGBA8 srcpx = unpack(bit_cast<PackedRGBA8>(srcn));
    WideRGBA8 dstpx = unpack(unaligned_load<PackedRGBA8>(dst));
    PackedRGBA8 r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    unaligned_store(dst, r);
  }
  if (dst < end) {
    // Process any remaining pixels. Try to gather as many pixels as possible
    // into a single source chunk for compositing.
    U32 srcn = {*src, 0, 0, 0};
    if (end - dst > 1) {
      for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
        src++;
      }
      srcn.y = *src;
      if (end - dst > 2) {
        for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
          src++;
        }
        srcn.z = *src;
      }
    }
    WideRGBA8 srcpx = unpack(bit_cast<PackedRGBA8>(srcn));
    WideRGBA8 dstpx = unpack(partial_load_span<PackedRGBA8>(dst, end - dst));
    auto r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    partial_store_span(dst, r, end - dst);
  }
}

template <bool COMPOSITE = false>
static NO_INLINE void scale_blit(Texture& srctex, const IntRect& srcReq,
                                 Texture& dsttex, const IntRect& dstReq,
                                 bool invertY, const IntRect& clipRect) {
  assert(!COMPOSITE || (srctex.internal_format == GL_RGBA8 &&
                        dsttex.internal_format == GL_RGBA8));
  // Cache scaling ratios
  int srcWidth = srcReq.width();
  int srcHeight = srcReq.height();
  int dstWidth = dstReq.width();
  int dstHeight = dstReq.height();
  // Compute valid dest bounds
  IntRect dstBounds = dsttex.sample_bounds(dstReq);
  // Compute valid source bounds
  // Scale source to dest, rounding inward to avoid sampling outside source
  IntRect srcBounds =
      srctex.sample_bounds(srcReq, invertY)
          .scale(srcWidth, srcHeight, dstWidth, dstHeight, true);
  // Limit dest sampling bounds to overlap source bounds
  dstBounds.intersect(srcBounds);
  // Compute the clipped bounds, relative to dstBounds.
  IntRect clippedDest = dstBounds.intersection(clipRect) - dstBounds.origin();
  // Check if clipped sampling bounds are empty
  if (clippedDest.is_empty()) {
    return;
  }
  // Compute final source bounds from clamped dest sampling bounds
  srcBounds =
      IntRect(dstBounds).scale(dstWidth, dstHeight, srcWidth, srcHeight);
  // Calculate source and dest pointers from clamped offsets
  int bpp = srctex.bpp();
  int srcStride = srctex.stride();
  int destStride = dsttex.stride();
  char* dest = dsttex.sample_ptr(dstReq, dstBounds);
  char* src = srctex.sample_ptr(srcReq, srcBounds, invertY);
  // Inverted Y must step downward along source rows
  if (invertY) {
    srcStride = -srcStride;
  }
  int span = clippedDest.width();
  int fracX = srcWidth * clippedDest.x0;
  int fracY = srcHeight * clippedDest.y0;
  dest += destStride * clippedDest.y0;
  dest += bpp * clippedDest.x0;
  src += srcStride * (fracY / dstHeight);
  src += bpp * (fracX / dstWidth);
  fracY %= dstHeight;
  fracX %= dstWidth;
  for (int rows = clippedDest.height(); rows > 0; rows--) {
    switch (bpp) {
      case 1:
        if (srcWidth == dstWidth)
          copy_row<COMPOSITE>((uint8_t*)dest, (uint8_t*)src, span);
        else
          scale_row<COMPOSITE>((uint8_t*)dest, dstWidth, (uint8_t*)src,
                               srcWidth, span, fracX);
        break;
      case 2:<commit_msg>Bug 1706198 - Avoid source-to-dest-to-source conversions during clipping of blit rects. r=mattwoodrow<commit_after>/* 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/. */

template <bool COMPOSITE, typename P>
static inline void copy_row(P* dst, const P* src, int span) {
  // No scaling, so just do a fast copy.
  memcpy(dst, src, span * sizeof(P));
}

template <>
void copy_row<true, uint32_t>(uint32_t* dst, const uint32_t* src, int span) {
  // No scaling, so just do a fast composite.
  auto* end = dst + span;
  while (dst + 4 <= end) {
    WideRGBA8 srcpx = unpack(unaligned_load<PackedRGBA8>(src));
    WideRGBA8 dstpx = unpack(unaligned_load<PackedRGBA8>(dst));
    PackedRGBA8 r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    unaligned_store(dst, r);
    src += 4;
    dst += 4;
  }
  if (dst < end) {
    WideRGBA8 srcpx = unpack(partial_load_span<PackedRGBA8>(src, end - dst));
    WideRGBA8 dstpx = unpack(partial_load_span<PackedRGBA8>(dst, end - dst));
    auto r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    partial_store_span(dst, r, end - dst);
  }
}

template <bool COMPOSITE, typename P>
static inline void scale_row(P* dst, int dstWidth, const P* src, int srcWidth,
                             int span, int frac) {
  // Do scaling with different source and dest widths.
  for (P* end = dst + span; dst < end; dst++) {
    *dst = *src;
    // Step source according to width ratio.
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
  }
}

template <>
void scale_row<true, uint32_t>(uint32_t* dst, int dstWidth, const uint32_t* src,
                               int srcWidth, int span, int frac) {
  // Do scaling with different source and dest widths.
  // Gather source pixels four at a time for better packing.
  auto* end = dst + span;
  for (; dst + 4 <= end; dst += 4) {
    U32 srcn;
    srcn.x = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.y = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.z = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    srcn.w = *src;
    for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
      src++;
    }
    WideRGBA8 srcpx = unpack(bit_cast<PackedRGBA8>(srcn));
    WideRGBA8 dstpx = unpack(unaligned_load<PackedRGBA8>(dst));
    PackedRGBA8 r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    unaligned_store(dst, r);
  }
  if (dst < end) {
    // Process any remaining pixels. Try to gather as many pixels as possible
    // into a single source chunk for compositing.
    U32 srcn = {*src, 0, 0, 0};
    if (end - dst > 1) {
      for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
        src++;
      }
      srcn.y = *src;
      if (end - dst > 2) {
        for (frac += srcWidth; frac >= dstWidth; frac -= dstWidth) {
          src++;
        }
        srcn.z = *src;
      }
    }
    WideRGBA8 srcpx = unpack(bit_cast<PackedRGBA8>(srcn));
    WideRGBA8 dstpx = unpack(partial_load_span<PackedRGBA8>(dst, end - dst));
    auto r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx)));
    partial_store_span(dst, r, end - dst);
  }
}

template <bool COMPOSITE = false>
static NO_INLINE void scale_blit(Texture& srctex, const IntRect& srcReq,
                                 Texture& dsttex, const IntRect& dstReq,
                                 bool invertY, const IntRect& clipRect) {
  assert(!COMPOSITE || (srctex.internal_format == GL_RGBA8 &&
                        dsttex.internal_format == GL_RGBA8));
  // Cache scaling ratios
  int srcWidth = srcReq.width();
  int srcHeight = srcReq.height();
  int dstWidth = dstReq.width();
  int dstHeight = dstReq.height();
  // Compute valid dest bounds
  IntRect dstBounds = dsttex.sample_bounds(dstReq).intersect(clipRect);
  // Compute valid source bounds
  IntRect srcBounds = srctex.sample_bounds(srcReq, invertY);
  // If srcReq is outside the source texture, we need to clip the sampling
  // bounds so that we never sample outside valid source bounds. Get texture
  // bounds relative to srcReq and scale to dest-space rounding inward, using
  // this rect to limit the dest bounds further.
  IntRect srcClip = srctex.bounds() - srcReq.origin();
  if (invertY) {
    srcClip.invert_y(srcReq.height());
  }
  srcClip.scale(srcWidth, srcHeight, dstWidth, dstHeight, true);
  dstBounds.intersect(srcClip);
  // Check if clipped sampling bounds are empty
  if (dstBounds.is_empty()) {
    return;
  }

  // Calculate source and dest pointers from clamped offsets
  int bpp = srctex.bpp();
  int srcStride = srctex.stride();
  int destStride = dsttex.stride();
  char* dest = dsttex.sample_ptr(dstReq, dstBounds);
  // Clip the source bounds by the destination offset.
  int fracX = srcWidth * dstBounds.x0;
  int fracY = srcHeight * dstBounds.y0;
  srcBounds.x0 = max(fracX / dstWidth, srcBounds.x0);
  srcBounds.y0 = max(fracY / dstHeight, srcBounds.y0);
  fracX %= dstWidth;
  fracY %= dstHeight;
  char* src = srctex.sample_ptr(srcReq, srcBounds, invertY);
  // Inverted Y must step downward along source rows
  if (invertY) {
    srcStride = -srcStride;
  }
  int span = dstBounds.width();
  for (int rows = dstBounds.height(); rows > 0; rows--) {
    switch (bpp) {
      case 1:
        if (srcWidth == dstWidth)
          copy_row<COMPOSITE>((uint8_t*)dest, (uint8_t*)src, span);
        else
          scale_row<COMPOSITE>((uint8_t*)dest, dstWidth, (uint8_t*)src,
                               srcWidth, span, fracX);
        break;
      case 2:
{'fraction_non_alphanumeric': 0.12419382952762768, 'fraction_numerical': 0.01350880251002266, 'mean_word_length': 2.7659993436166723, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4399999', 'n_tokens_mistral': 4023, 'n_tokens_neox': 3879, 'n_words': 1152}