tor-browser

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

blending.cc (6288B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "lib/jxl/blending.h"
      7 
      8 #include <jxl/memory_manager.h>
      9 
     10 #include <cstddef>
     11 #include <cstring>
     12 #include <vector>
     13 
     14 #include "lib/jxl/alpha.h"
     15 #include "lib/jxl/base/status.h"
     16 #include "lib/jxl/dec_patch_dictionary.h"
     17 #include "lib/jxl/frame_header.h"
     18 #include "lib/jxl/image.h"
     19 #include "lib/jxl/image_metadata.h"
     20 
     21 namespace jxl {
     22 
     23 bool NeedsBlending(const FrameHeader& frame_header) {
     24  if (!(frame_header.frame_type == FrameType::kRegularFrame ||
     25        frame_header.frame_type == FrameType::kSkipProgressive)) {
     26    return false;
     27  }
     28  const auto& info = frame_header.blending_info;
     29  bool replace_all = (info.mode == BlendMode::kReplace);
     30  for (const auto& ec_i : frame_header.extra_channel_blending_info) {
     31    if (ec_i.mode != BlendMode::kReplace) {
     32      replace_all = false;
     33    }
     34  }
     35  // Replace the full frame: nothing to do.
     36  if (!frame_header.custom_size_or_origin && replace_all) {
     37    return false;
     38  }
     39  return true;
     40 }
     41 
     42 Status PerformBlending(
     43    JxlMemoryManager* memory_manager, const float* const* bg,
     44    const float* const* fg, float* const* out, size_t x0, size_t xsize,
     45    const PatchBlending& color_blending, const PatchBlending* ec_blending,
     46    const std::vector<ExtraChannelInfo>& extra_channel_info) {
     47  bool has_alpha = false;
     48  size_t num_ec = extra_channel_info.size();
     49  for (size_t i = 0; i < num_ec; i++) {
     50    if (extra_channel_info[i].type == jxl::ExtraChannel::kAlpha) {
     51      has_alpha = true;
     52      break;
     53    }
     54  }
     55  JXL_ASSIGN_OR_RETURN(ImageF tmp,
     56                       ImageF::Create(memory_manager, xsize, 3 + num_ec));
     57  // Blend extra channels first so that we use the pre-blending alpha.
     58  for (size_t i = 0; i < num_ec; i++) {
     59    switch (ec_blending[i].mode) {
     60      case PatchBlendMode::kAdd:
     61        for (size_t x = 0; x < xsize; x++) {
     62          tmp.Row(3 + i)[x] = bg[3 + i][x + x0] + fg[3 + i][x + x0];
     63        }
     64        continue;
     65 
     66      case PatchBlendMode::kBlendAbove: {
     67        size_t alpha = ec_blending[i].alpha_channel;
     68        bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
     69        PerformAlphaBlending(bg[3 + i] + x0, bg[3 + alpha] + x0, fg[3 + i] + x0,
     70                             fg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     71                             is_premultiplied, ec_blending[i].clamp);
     72        continue;
     73      }
     74 
     75      case PatchBlendMode::kBlendBelow: {
     76        size_t alpha = ec_blending[i].alpha_channel;
     77        bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
     78        PerformAlphaBlending(fg[3 + i] + x0, fg[3 + alpha] + x0, bg[3 + i] + x0,
     79                             bg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     80                             is_premultiplied, ec_blending[i].clamp);
     81        continue;
     82      }
     83 
     84      case PatchBlendMode::kAlphaWeightedAddAbove: {
     85        size_t alpha = ec_blending[i].alpha_channel;
     86        PerformAlphaWeightedAdd(bg[3 + i] + x0, fg[3 + i] + x0,
     87                                fg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     88                                ec_blending[i].clamp);
     89        continue;
     90      }
     91 
     92      case PatchBlendMode::kAlphaWeightedAddBelow: {
     93        size_t alpha = ec_blending[i].alpha_channel;
     94        PerformAlphaWeightedAdd(fg[3 + i] + x0, bg[3 + i] + x0,
     95                                bg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     96                                ec_blending[i].clamp);
     97        continue;
     98      }
     99 
    100      case PatchBlendMode::kMul:
    101        PerformMulBlending(bg[3 + i] + x0, fg[3 + i] + x0, tmp.Row(3 + i),
    102                           xsize, ec_blending[i].clamp);
    103        continue;
    104 
    105      case PatchBlendMode::kReplace:
    106        if (xsize) memcpy(tmp.Row(3 + i), fg[3 + i] + x0, xsize * sizeof(**fg));
    107        continue;
    108 
    109      case PatchBlendMode::kNone:
    110        if (xsize) memcpy(tmp.Row(3 + i), bg[3 + i] + x0, xsize * sizeof(**fg));
    111        continue;
    112    }
    113  }
    114  size_t alpha = color_blending.alpha_channel;
    115 
    116  const auto add = [&]() {
    117    for (int p = 0; p < 3; p++) {
    118      float* out = tmp.Row(p);
    119      for (size_t x = 0; x < xsize; x++) {
    120        out[x] = bg[p][x + x0] + fg[p][x + x0];
    121      }
    122    }
    123  };
    124 
    125  const auto blend_weighted = [&](const float* const* bottom,
    126                                  const float* const* top) {
    127    bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
    128    PerformAlphaBlending(
    129        {bottom[0] + x0, bottom[1] + x0, bottom[2] + x0,
    130         bottom[3 + alpha] + x0},
    131        {top[0] + x0, top[1] + x0, top[2] + x0, top[3 + alpha] + x0},
    132        {tmp.Row(0), tmp.Row(1), tmp.Row(2), tmp.Row(3 + alpha)}, xsize,
    133        is_premultiplied, color_blending.clamp);
    134  };
    135 
    136  const auto add_weighted = [&](const float* const* bottom,
    137                                const float* const* top) {
    138    for (size_t c = 0; c < 3; c++) {
    139      PerformAlphaWeightedAdd(bottom[c] + x0, top[c] + x0, top[3 + alpha] + x0,
    140                              tmp.Row(c), xsize, color_blending.clamp);
    141    }
    142  };
    143 
    144  const auto copy = [&](const float* const* src) {
    145    for (size_t p = 0; p < 3; p++) {
    146      memcpy(tmp.Row(p), src[p] + x0, xsize * sizeof(**src));
    147    }
    148  };
    149 
    150  switch (color_blending.mode) {
    151    case PatchBlendMode::kAdd:
    152      add();
    153      break;
    154 
    155    case PatchBlendMode::kAlphaWeightedAddAbove:
    156      has_alpha ? add_weighted(bg, fg) : add();
    157      break;
    158 
    159    case PatchBlendMode::kAlphaWeightedAddBelow:
    160      has_alpha ? add_weighted(fg, bg) : add();
    161      break;
    162 
    163    case PatchBlendMode::kBlendAbove:
    164      has_alpha ? blend_weighted(bg, fg) : copy(fg);
    165      break;
    166 
    167    case PatchBlendMode::kBlendBelow:
    168      has_alpha ? blend_weighted(fg, bg) : copy(fg);
    169      break;
    170 
    171    case PatchBlendMode::kMul:
    172      for (int p = 0; p < 3; p++) {
    173        PerformMulBlending(bg[p] + x0, fg[p] + x0, tmp.Row(p), xsize,
    174                           color_blending.clamp);
    175      }
    176      break;
    177 
    178    case PatchBlendMode::kReplace:
    179      copy(fg);
    180      break;
    181 
    182    case PatchBlendMode::kNone:
    183      copy(bg);
    184  }
    185 
    186  for (size_t i = 0; i < 3 + num_ec; i++) {
    187    if (xsize != 0) memcpy(out[i] + x0, tmp.Row(i), xsize * sizeof(**out));
    188  }
    189  return true;
    190 }
    191 
    192 }  // namespace jxl