1d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Copyright 2017 PDFium Authors. All rights reserved.
2d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Use of this source code is governed by a BSD-style license that can be
3d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// found in the LICENSE file.
4d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
5d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
7d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fpdfapi/page/cpdf_sampledfunc.h"
8d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
9d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fpdfapi/parser/cpdf_array.h"
10d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fxcrt/cfx_fixedbufgrow.h"
11d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fxcrt/fx_extension.h"
12d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fxcrt/fx_safe_types.h"
13d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
14d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannnamespace {
15d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
16d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// See PDF Reference 1.7, page 170, table 3.36.
17d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannbool IsValidBitsPerSample(uint32_t x) {
18d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  switch (x) {
19d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 1:
20d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 2:
21d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 4:
22d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 8:
23d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 12:
24d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 16:
25d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 24:
26d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    case 32:
27d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return true;
28d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    default:
29d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return false;
30d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
31d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
32d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
33d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}  // namespace
34d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
35d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {}
36d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
37d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCPDF_SampledFunc::~CPDF_SampledFunc() {}
38d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
39d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannbool CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
40d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Stream* pStream = pObj->AsStream();
41d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pStream)
42d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
43d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
44d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Dictionary* pDict = pStream->GetDict();
45d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Array* pSize = pDict->GetArrayFor("Size");
46d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Array* pEncode = pDict->GetArrayFor("Encode");
47d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
48d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_nBitsPerSample = pDict->GetIntegerFor("BitsPerSample");
49d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!IsValidBitsPerSample(m_nBitsPerSample))
50d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
51d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
52d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
53d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
54d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_pSampleStream->LoadAllDataFiltered();
55d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_SAFE_UINT32 nTotalSampleBits = 1;
56d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_EncodeInfo.resize(m_nInputs);
57d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (uint32_t i = 0; i < m_nInputs; i++) {
58d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    m_EncodeInfo[i].sizes = pSize ? pSize->GetIntegerAt(i) : 0;
59d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (!pSize && i == 0)
60d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_EncodeInfo[i].sizes = pDict->GetIntegerFor("Size");
61d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    nTotalSampleBits *= m_EncodeInfo[i].sizes;
62d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (pEncode) {
63d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_EncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2);
64d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_EncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1);
65d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
66d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_EncodeInfo[i].encode_min = 0;
67d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_EncodeInfo[i].encode_max =
68d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          m_EncodeInfo[i].sizes == 1 ? 1 : (float)m_EncodeInfo[i].sizes - 1;
69d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
70d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
71d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  nTotalSampleBits *= m_nBitsPerSample;
72d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  nTotalSampleBits *= m_nOutputs;
73d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_SAFE_UINT32 nTotalSampleBytes = nTotalSampleBits;
74d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  nTotalSampleBytes += 7;
75d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  nTotalSampleBytes /= 8;
76d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
77d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
78d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
79d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
80d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  m_DecodeInfo.resize(m_nOutputs);
81d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (uint32_t i = 0; i < m_nOutputs; i++) {
82d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (pDecode) {
83d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_DecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i);
84d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_DecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1);
85d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    } else {
86d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_DecodeInfo[i].decode_min = m_pRanges[i * 2];
87d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_DecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
88d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
89d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
90d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return true;
91d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
92d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
93d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannbool CPDF_SampledFunc::v_Call(float* inputs, float* results) const {
94d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int pos = 0;
95d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs);
96d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  float* encoded_input = encoded_input_buf;
97d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2);
98d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  uint32_t* index = int_buf;
99d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  uint32_t* blocksize = index + m_nInputs;
100d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (uint32_t i = 0; i < m_nInputs; i++) {
101d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (i == 0)
102d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      blocksize[i] = 1;
103d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    else
104d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      blocksize[i] = blocksize[i - 1] * m_EncodeInfo[i - 1].sizes;
105d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    encoded_input[i] =
106d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        Interpolate(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
107d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                    m_EncodeInfo[i].encode_min, m_EncodeInfo[i].encode_max);
108d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    index[i] = pdfium::clamp(static_cast<uint32_t>(encoded_input[i]), 0U,
109d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                             m_EncodeInfo[i].sizes - 1);
110d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    pos += index[i] * blocksize[i];
111d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
112d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_SAFE_INT32 bits_to_output = m_nOutputs;
113d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bits_to_output *= m_nBitsPerSample;
114d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!bits_to_output.IsValid())
115d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
116d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
117d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_SAFE_INT32 bitpos = pos;
118d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bitpos *= bits_to_output.ValueOrDie();
119d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!bitpos.IsValid())
120d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
121d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
122d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  FX_SAFE_INT32 range_check = bitpos;
123d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  range_check += bits_to_output.ValueOrDie();
124d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!range_check.IsValid())
125d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
126d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
127d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  const uint8_t* pSampleData = m_pSampleStream->GetData();
128d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!pSampleData)
129d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return false;
130d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
131d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (uint32_t j = 0; j < m_nOutputs; j++, bitpos += m_nBitsPerSample) {
132d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    uint32_t sample =
133d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        GetBits32(pSampleData, bitpos.ValueOrDie(), m_nBitsPerSample);
134d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    float encoded = (float)sample;
135d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    for (uint32_t i = 0; i < m_nInputs; i++) {
136d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      if (index[i] == m_EncodeInfo[i].sizes - 1) {
137d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        if (index[i] == 0)
138d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          encoded = encoded_input[i] * (float)sample;
139d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      } else {
140d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        FX_SAFE_INT32 bitpos2 = blocksize[i];
141d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        bitpos2 += pos;
142d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        bitpos2 *= m_nOutputs;
143d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        bitpos2 += j;
144d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        bitpos2 *= m_nBitsPerSample;
145d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        if (!bitpos2.IsValid())
146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann          return false;
147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        uint32_t sample1 =
148d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
149d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        encoded +=
150d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            (encoded_input[i] - index[i]) * ((float)sample1 - (float)sample);
151d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      }
152d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    }
153d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    results[j] =
154d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        Interpolate(encoded, 0, (float)m_SampleMax, m_DecodeInfo[j].decode_min,
155d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann                    m_DecodeInfo[j].decode_max);
156d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
157d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return true;
158d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann}
159