Coverage Report

Created: 2022-08-24 06:33

/src/libjxl/lib/jxl/modular/encoding/encoding.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef LIB_JXL_MODULAR_ENCODING_ENCODING_H_
7
#define LIB_JXL_MODULAR_ENCODING_ENCODING_H_
8
9
#include <stddef.h>
10
#include <stdint.h>
11
12
#include <vector>
13
14
#include "lib/jxl/dec_ans.h"
15
#include "lib/jxl/image.h"
16
#include "lib/jxl/modular/encoding/context_predict.h"
17
#include "lib/jxl/modular/encoding/dec_ma.h"
18
#include "lib/jxl/modular/modular_image.h"
19
#include "lib/jxl/modular/options.h"
20
#include "lib/jxl/modular/transform/transform.h"
21
22
namespace jxl {
23
24
// Valid range of properties for using lookup tables instead of trees.
25
constexpr int32_t kPropRangeFast = 512;
26
27
struct GroupHeader : public Fields {
28
  GroupHeader();
29
30
  JXL_FIELDS_NAME(GroupHeader)
31
32
259k
  Status VisitFields(Visitor *JXL_RESTRICT visitor) override {
33
259k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &use_global_tree));
34
256k
    JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&wp_header));
35
254k
    uint32_t num_transforms = static_cast<uint32_t>(transforms.size());
36
254k
    JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), BitsOffset(4, 2),
37
254k
                                           BitsOffset(8, 18), 0,
38
254k
                                           &num_transforms));
39
254k
    if (visitor->IsReading()) transforms.resize(num_transforms);
40
309k
    for (size_t i = 0; i < num_transforms; i++) {
41
59.9k
      JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&transforms[i]));
42
59.9k
    }
43
249k
    return true;
44
254k
  }
45
46
  bool use_global_tree;
47
  weighted::Header wp_header;
48
49
  std::vector<Transform> transforms;
50
};
51
52
FlatTree FilterTree(const Tree &global_tree,
53
                    std::array<pixel_type, kNumStaticProperties> &static_props,
54
                    size_t *num_props, bool *use_wp, bool *wp_only,
55
                    bool *gradient_only);
56
57
template <typename T>
58
bool TreeToLookupTable(const FlatTree &tree,
59
                       T context_lookup[2 * kPropRangeFast],
60
                       int8_t offsets[2 * kPropRangeFast],
61
35.8k
                       int8_t multipliers[2 * kPropRangeFast] = nullptr) {
62
35.8k
  struct TreeRange {
63
    // Begin *excluded*, end *included*. This works best with > vs <= decision
64
    // nodes.
65
35.8k
    int begin, end;
66
35.8k
    size_t pos;
67
35.8k
  };
68
35.8k
  std::vector<TreeRange> ranges;
69
35.8k
  ranges.push_back(TreeRange{-kPropRangeFast - 1, kPropRangeFast - 1, 0});
70
126k
  while (!ranges.empty()) {
71
114k
    TreeRange cur = ranges.back();
72
114k
    ranges.pop_back();
73
114k
    if (cur.begin < -kPropRangeFast - 1 || cur.begin >= kPropRangeFast - 1 ||
74
114k
        cur.end > kPropRangeFast - 1) {
75
      // Tree is outside the allowed range, exit.
76
0
      return false;
77
0
    }
78
114k
    auto &node = tree[cur.pos];
79
    // Leaf.
80
114k
    if (node.property0 == -1) {
81
78.2k
      if (node.predictor_offset < std::numeric_limits<int8_t>::min() ||
82
78.2k
          node.predictor_offset > std::numeric_limits<int8_t>::max()) {
83
0
        return false;
84
0
      }
85
78.2k
      if (node.multiplier < std::numeric_limits<int8_t>::min() ||
86
78.2k
          node.multiplier > std::numeric_limits<int8_t>::max()) {
87
23.7k
        return false;
88
23.7k
      }
89
54.5k
      if (multipliers == nullptr && node.multiplier != 1) {
90
0
        return false;
91
0
      }
92
24.5M
      for (int i = cur.begin + 1; i < cur.end + 1; i++) {
93
24.4M
        context_lookup[i + kPropRangeFast] = node.childID;
94
24.4M
        if (multipliers) multipliers[i + kPropRangeFast] = node.multiplier;
95
24.4M
        offsets[i + kPropRangeFast] = node.predictor_offset;
96
24.4M
      }
97
54.5k
      continue;
98
54.5k
    }
99
    // > side of top node.
100
35.9k
    if (node.properties[0] >= kNumStaticProperties) {
101
28.5k
      ranges.push_back(TreeRange({node.splitvals[0], cur.end, node.childID}));
102
28.5k
      ranges.push_back(
103
28.5k
          TreeRange({node.splitval0, node.splitvals[0], node.childID + 1}));
104
28.5k
    } else {
105
7.44k
      ranges.push_back(TreeRange({node.splitval0, cur.end, node.childID}));
106
7.44k
    }
107
    // <= side
108
35.9k
    if (node.properties[1] >= kNumStaticProperties) {
109
1.74k
      ranges.push_back(
110
1.74k
          TreeRange({node.splitvals[1], node.splitval0, node.childID + 2}));
111
1.74k
      ranges.push_back(
112
1.74k
          TreeRange({cur.begin, node.splitvals[1], node.childID + 3}));
113
34.2k
    } else {
114
34.2k
      ranges.push_back(
115
34.2k
          TreeRange({cur.begin, node.splitval0, node.childID + 2}));
116
34.2k
    }
117
35.9k
  }
118
12.1k
  return true;
119
35.8k
}
bool jxl::TreeToLookupTable<unsigned char>(std::__1::vector<jxl::FlatDecisionNode, std::__1::allocator<jxl::FlatDecisionNode> > const&, unsigned char*, signed char*, signed char*)
Line
Count
Source
61
35.5k
                       int8_t multipliers[2 * kPropRangeFast] = nullptr) {
62
35.5k
  struct TreeRange {
63
    // Begin *excluded*, end *included*. This works best with > vs <= decision
64
    // nodes.
65
35.5k
    int begin, end;
66
35.5k
    size_t pos;
67
35.5k
  };
68
35.5k
  std::vector<TreeRange> ranges;
69
35.5k
  ranges.push_back(TreeRange{-kPropRangeFast - 1, kPropRangeFast - 1, 0});
70
125k
  while (!ranges.empty()) {
71
113k
    TreeRange cur = ranges.back();
72
113k
    ranges.pop_back();
73
113k
    if (cur.begin < -kPropRangeFast - 1 || cur.begin >= kPropRangeFast - 1 ||
74
113k
        cur.end > kPropRangeFast - 1) {
75
      // Tree is outside the allowed range, exit.
76
0
      return false;
77
0
    }
78
113k
    auto &node = tree[cur.pos];
79
    // Leaf.
80
113k
    if (node.property0 == -1) {
81
77.9k
      if (node.predictor_offset < std::numeric_limits<int8_t>::min() ||
82
77.9k
          node.predictor_offset > std::numeric_limits<int8_t>::max()) {
83
0
        return false;
84
0
      }
85
77.9k
      if (node.multiplier < std::numeric_limits<int8_t>::min() ||
86
77.9k
          node.multiplier > std::numeric_limits<int8_t>::max()) {
87
23.7k
        return false;
88
23.7k
      }
89
54.2k
      if (multipliers == nullptr && node.multiplier != 1) {
90
0
        return false;
91
0
      }
92
24.2M
      for (int i = cur.begin + 1; i < cur.end + 1; i++) {
93
24.1M
        context_lookup[i + kPropRangeFast] = node.childID;
94
24.1M
        if (multipliers) multipliers[i + kPropRangeFast] = node.multiplier;
95
24.1M
        offsets[i + kPropRangeFast] = node.predictor_offset;
96
24.1M
      }
97
54.2k
      continue;
98
54.2k
    }
99
    // > side of top node.
100
35.9k
    if (node.properties[0] >= kNumStaticProperties) {
101
28.5k
      ranges.push_back(TreeRange({node.splitvals[0], cur.end, node.childID}));
102
28.5k
      ranges.push_back(
103
28.5k
          TreeRange({node.splitval0, node.splitvals[0], node.childID + 1}));
104
28.5k
    } else {
105
7.44k
      ranges.push_back(TreeRange({node.splitval0, cur.end, node.childID}));
106
7.44k
    }
107
    // <= side
108
35.9k
    if (node.properties[1] >= kNumStaticProperties) {
109
1.74k
      ranges.push_back(
110
1.74k
          TreeRange({node.splitvals[1], node.splitval0, node.childID + 2}));
111
1.74k
      ranges.push_back(
112
1.74k
          TreeRange({cur.begin, node.splitvals[1], node.childID + 3}));
113
34.2k
    } else {
114
34.2k
      ranges.push_back(
115
34.2k
          TreeRange({cur.begin, node.splitval0, node.childID + 2}));
116
34.2k
    }
117
35.9k
  }
118
11.8k
  return true;
119
35.5k
}
bool jxl::TreeToLookupTable<unsigned short>(std::__1::vector<jxl::FlatDecisionNode, std::__1::allocator<jxl::FlatDecisionNode> > const&, unsigned short*, signed char*, signed char*)
Line
Count
Source
61
276
                       int8_t multipliers[2 * kPropRangeFast] = nullptr) {
62
276
  struct TreeRange {
63
    // Begin *excluded*, end *included*. This works best with > vs <= decision
64
    // nodes.
65
276
    int begin, end;
66
276
    size_t pos;
67
276
  };
68
276
  std::vector<TreeRange> ranges;
69
276
  ranges.push_back(TreeRange{-kPropRangeFast - 1, kPropRangeFast - 1, 0});
70
552
  while (!ranges.empty()) {
71
276
    TreeRange cur = ranges.back();
72
276
    ranges.pop_back();
73
276
    if (cur.begin < -kPropRangeFast - 1 || cur.begin >= kPropRangeFast - 1 ||
74
276
        cur.end > kPropRangeFast - 1) {
75
      // Tree is outside the allowed range, exit.
76
0
      return false;
77
0
    }
78
276
    auto &node = tree[cur.pos];
79
    // Leaf.
80
276
    if (node.property0 == -1) {
81
276
      if (node.predictor_offset < std::numeric_limits<int8_t>::min() ||
82
276
          node.predictor_offset > std::numeric_limits<int8_t>::max()) {
83
0
        return false;
84
0
      }
85
276
      if (node.multiplier < std::numeric_limits<int8_t>::min() ||
86
276
          node.multiplier > std::numeric_limits<int8_t>::max()) {
87
0
        return false;
88
0
      }
89
276
      if (multipliers == nullptr && node.multiplier != 1) {
90
0
        return false;
91
0
      }
92
282k
      for (int i = cur.begin + 1; i < cur.end + 1; i++) {
93
282k
        context_lookup[i + kPropRangeFast] = node.childID;
94
282k
        if (multipliers) multipliers[i + kPropRangeFast] = node.multiplier;
95
282k
        offsets[i + kPropRangeFast] = node.predictor_offset;
96
282k
      }
97
276
      continue;
98
276
    }
99
    // > side of top node.
100
0
    if (node.properties[0] >= kNumStaticProperties) {
101
0
      ranges.push_back(TreeRange({node.splitvals[0], cur.end, node.childID}));
102
0
      ranges.push_back(
103
0
          TreeRange({node.splitval0, node.splitvals[0], node.childID + 1}));
104
0
    } else {
105
0
      ranges.push_back(TreeRange({node.splitval0, cur.end, node.childID}));
106
0
    }
107
    // <= side
108
0
    if (node.properties[1] >= kNumStaticProperties) {
109
0
      ranges.push_back(
110
0
          TreeRange({node.splitvals[1], node.splitval0, node.childID + 2}));
111
0
      ranges.push_back(
112
0
          TreeRange({cur.begin, node.splitvals[1], node.childID + 3}));
113
0
    } else {
114
0
      ranges.push_back(
115
0
          TreeRange({cur.begin, node.splitval0, node.childID + 2}));
116
0
    }
117
0
  }
118
276
  return true;
119
276
}
120
// TODO(veluca): make cleaner interfaces.
121
122
Status ValidateChannelDimensions(const Image &image,
123
                                 const ModularOptions &options);
124
125
Status ModularGenericDecompress(BitReader *br, Image &image,
126
                                GroupHeader *header, size_t group_id,
127
                                ModularOptions *options,
128
                                bool undo_transforms = true,
129
                                const Tree *tree = nullptr,
130
                                const ANSCode *code = nullptr,
131
                                const std::vector<uint8_t> *ctx_map = nullptr,
132
                                bool allow_truncated_group = false);
133
}  // namespace jxl
134
135
#endif  // LIB_JXL_MODULAR_ENCODING_ENCODING_H_