Function.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /*
  2. * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/NonnullOwnPtr.h>
  7. #include <LibPDF/CommonNames.h>
  8. #include <LibPDF/Document.h>
  9. #include <LibPDF/Function.h>
  10. #include <LibPDF/ObjectDerivatives.h>
  11. // PDF 1.7 spec, 3.9 Functions
  12. namespace PDF {
  13. struct Bound {
  14. float lower;
  15. float upper;
  16. };
  17. // 3.9.1 Type 0 (Sampled) Functions
  18. class SampledFunction final : public Function {
  19. public:
  20. static PDFErrorOr<NonnullRefPtr<SampledFunction>> create(Document*, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<StreamObject>);
  21. virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
  22. private:
  23. SampledFunction(NonnullRefPtr<StreamObject>);
  24. Vector<Bound> m_domain;
  25. Vector<Bound> m_range;
  26. Vector<unsigned> m_sizes;
  27. int m_bits_per_sample { 0 };
  28. enum class Order {
  29. Linear = 1,
  30. Cubic = 3,
  31. };
  32. Order m_order { Order::Linear };
  33. Vector<Bound> m_encode;
  34. Vector<Bound> m_decode;
  35. NonnullRefPtr<StreamObject> m_stream;
  36. ReadonlyBytes m_sample_data;
  37. Vector<float> mutable m_outputs;
  38. };
  39. SampledFunction::SampledFunction(NonnullRefPtr<StreamObject> stream)
  40. : m_stream(move(stream))
  41. , m_sample_data(m_stream->bytes())
  42. {
  43. }
  44. PDFErrorOr<NonnullRefPtr<SampledFunction>>
  45. SampledFunction::create(Document* document, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<StreamObject> stream)
  46. {
  47. if (!range.has_value())
  48. return Error { Error::Type::MalformedPDF, "Function type 0 requires range" };
  49. // "TABLE 3.36 Additional entries specific to a type 0 function dictionary"
  50. auto const& dict = stream->dict();
  51. if (!dict->contains(CommonNames::Size))
  52. return Error { Error::Type::MalformedPDF, "Function type 0 requires /Size" };
  53. auto size_array = TRY(dict->get_array(document, CommonNames::Size));
  54. Vector<unsigned> sizes;
  55. for (auto const& size_value : *size_array) {
  56. if (size_value.to_int() <= 0)
  57. return Error { Error::Type::MalformedPDF, "Function type 0 /Size entry not positive" };
  58. sizes.append(static_cast<unsigned>(size_value.to_int()));
  59. }
  60. if (sizes.size() != domain.size())
  61. return Error { Error::Type::MalformedPDF, "Function type 0 /Size array has invalid size" };
  62. if (!dict->contains(CommonNames::BitsPerSample))
  63. return Error { Error::Type::MalformedPDF, "Function type 0 requires /BitsPerSample" };
  64. auto bits_per_sample = TRY(document->resolve_to<int>(dict->get_value(CommonNames::BitsPerSample)));
  65. switch (bits_per_sample) {
  66. case 1:
  67. case 2:
  68. case 4:
  69. case 8:
  70. case 12:
  71. case 16:
  72. case 24:
  73. case 32:
  74. // Ok!
  75. break;
  76. default:
  77. dbgln("invalid /BitsPerSample {}", bits_per_sample);
  78. return Error { Error::Type::MalformedPDF, "Function type 0 has invalid /BitsPerSample" };
  79. }
  80. Order order = Order::Linear;
  81. if (dict->contains(CommonNames::Order))
  82. order = static_cast<Order>(TRY(document->resolve_to<int>(dict->get_value(CommonNames::Order))));
  83. if (order != Order::Linear && order != Order::Cubic)
  84. return Error { Error::Type::MalformedPDF, "Function type 0 has invalid /Order" };
  85. Vector<Bound> encode;
  86. if (dict->contains(CommonNames::Encode)) {
  87. auto encode_array = TRY(dict->get_array(document, CommonNames::Encode));
  88. if (encode_array->size() % 2 != 0)
  89. return Error { Error::Type::MalformedPDF, "Function type 0 /Encode size not multiple of 2" };
  90. for (size_t i = 0; i < encode_array->size(); i += 2)
  91. encode.append({ encode_array->at(i).to_float(), encode_array->at(i + 1).to_float() });
  92. } else {
  93. for (unsigned const size : sizes)
  94. encode.append({ 0, static_cast<float>(size - 1) });
  95. }
  96. if (encode.size() != sizes.size())
  97. return Error { Error::Type::MalformedPDF, "Function type 0 /Encode array has invalid size" };
  98. Vector<Bound> decode;
  99. if (dict->contains(CommonNames::Decode)) {
  100. auto decode_array = TRY(dict->get_array(document, CommonNames::Decode));
  101. if (decode_array->size() % 2 != 0)
  102. return Error { Error::Type::MalformedPDF, "Function type 0 /Decode size not multiple of 2" };
  103. for (size_t i = 0; i < decode_array->size(); i += 2)
  104. decode.append({ decode_array->at(i).to_float(), decode_array->at(i + 1).to_float() });
  105. } else {
  106. decode = range.value();
  107. }
  108. if (decode.size() != range.value().size())
  109. return Error { Error::Type::MalformedPDF, "Function type 0 /Decode array has invalid size" };
  110. size_t size_product = 1;
  111. for (unsigned const size : sizes)
  112. size_product *= size;
  113. size_t bits_per_plane = size_product * bits_per_sample;
  114. size_t total_bits = bits_per_plane * decode.size();
  115. if (stream->bytes().size() < ceil_div(total_bits, 8ull))
  116. return Error { Error::Type::MalformedPDF, "Function type 0 stream too small" };
  117. auto function = adopt_ref(*new SampledFunction(stream));
  118. function->m_domain = move(domain);
  119. function->m_range = move(range.value());
  120. function->m_sizes = move(sizes);
  121. function->m_bits_per_sample = bits_per_sample;
  122. function->m_order = order;
  123. function->m_encode = move(encode);
  124. function->m_decode = move(decode);
  125. function->m_outputs.resize(function->m_range.size());
  126. return function;
  127. }
  128. PDFErrorOr<ReadonlySpan<float>> SampledFunction::evaluate(ReadonlySpan<float> x) const
  129. {
  130. if (x.size() != m_domain.size())
  131. return Error { Error::Type::MalformedPDF, "Function argument size does not match domain size" };
  132. if (m_order != Order::Linear)
  133. return Error { Error::Type::RenderingUnsupported, "Sample function with cubic order not yet implemented" };
  134. if (m_domain.size() != 1)
  135. return Error { Error::Type::RenderingUnsupported, "Sample function with m > 1 not yet implemented" };
  136. if (m_bits_per_sample != 8)
  137. return Error { Error::Type::RenderingUnsupported, "Sample function with bits per sample != 8 not yet implemented" };
  138. auto interpolate = [](float x, float x_min, float x_max, float y_min, float y_max) {
  139. return y_min + (x - x_min) * (y_max - y_min) / (x_max - x_min);
  140. };
  141. float xc = clamp(x[0], m_domain[0].lower, m_domain[0].upper);
  142. float e = interpolate(xc, m_domain[0].lower, m_domain[0].upper, m_encode[0].lower, m_encode[0].upper);
  143. float ec = clamp(e, 0.0f, static_cast<float>(m_sizes[0] - 1));
  144. float e0 = floor(ec);
  145. float e1 = ceil(ec);
  146. if (e0 == e1) {
  147. if (e0 == 0.0f)
  148. e1 = 1.0f;
  149. else
  150. e0 = e1 - 1.0f;
  151. }
  152. size_t plane_size = m_sizes[0];
  153. for (size_t i = 0; i < m_range.size(); ++i) {
  154. float s0 = m_sample_data[(size_t)e0 + i * plane_size];
  155. float s1 = m_sample_data[(size_t)e1 + i * plane_size];
  156. float r0 = interpolate(ec, e0, e1, s0, s1);
  157. r0 = interpolate(r0, 0.0f, 255.0f, m_decode[i].lower, m_decode[i].upper);
  158. m_outputs[i] = clamp(r0, m_range[i].lower, m_range[i].upper);
  159. }
  160. return m_outputs;
  161. }
  162. // 3.9.2 Type 2 (Exponential Interpolation) Functions
  163. class ExponentialInterpolationFunction final : public Function {
  164. public:
  165. static PDFErrorOr<NonnullRefPtr<ExponentialInterpolationFunction>> create(Document*, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject>);
  166. virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
  167. private:
  168. Bound m_domain;
  169. Optional<Vector<Bound>> m_range;
  170. Vector<float> m_c0;
  171. Vector<float> m_c1;
  172. float m_n;
  173. Vector<float> mutable m_values;
  174. };
  175. PDFErrorOr<NonnullRefPtr<ExponentialInterpolationFunction>>
  176. ExponentialInterpolationFunction::create(Document* document, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject> function_dict)
  177. {
  178. if (domain.size() != 1)
  179. return Error { Error::Type::MalformedPDF, "Function exponential requires domain with 1 entry" };
  180. // "TABLE 3.37 Additional entries specific to a type 2 function dictionary"
  181. if (!function_dict->contains(CommonNames::N))
  182. return Error { Error::Type::MalformedPDF, "Function exponential requires /N" };
  183. auto n = TRY(document->resolve(function_dict->get_value(CommonNames::N))).to_float();
  184. Vector<float> c0;
  185. if (function_dict->contains(CommonNames::C0)) {
  186. auto c0_array = TRY(function_dict->get_array(document, CommonNames::C0));
  187. for (size_t i = 0; i < c0_array->size(); i++)
  188. c0.append(c0_array->at(i).to_float());
  189. } else {
  190. c0.append(0.0f);
  191. }
  192. Vector<float> c1;
  193. if (function_dict->contains(CommonNames::C1)) {
  194. auto c1_array = TRY(function_dict->get_array(document, CommonNames::C1));
  195. for (size_t i = 0; i < c1_array->size(); i++)
  196. c1.append(c1_array->at(i).to_float());
  197. } else {
  198. c1.append(1.0f);
  199. }
  200. if (c0.size() != c1.size())
  201. return Error { Error::Type::MalformedPDF, "Function exponential mismatching C0 and C1 arrays" };
  202. if (range.has_value()) {
  203. if (range->size() != c0.size())
  204. return Error { Error::Type::MalformedPDF, "Function exponential mismatching Range and C arrays" };
  205. }
  206. // "Values of Domain must constrain x in such a way that if N is not an integer,
  207. // all values of x must be non-negative, and if N is negative, no value of x may be zero."
  208. if (n != (int)n && domain[0].lower < 0)
  209. return Error { Error::Type::MalformedPDF, "Function exponential requires non-negative bound for non-integer N" };
  210. if (n < 0 && (domain[0].lower <= 0 && domain[0].upper >= 0))
  211. return Error { Error::Type::MalformedPDF, "Function exponential with negative N requires non-zero domain" };
  212. auto function = adopt_ref(*new ExponentialInterpolationFunction());
  213. function->m_domain = domain[0];
  214. function->m_range = move(range);
  215. function->m_c0 = move(c0);
  216. function->m_c1 = move(c1);
  217. function->m_n = n;
  218. function->m_values.resize(function->m_c0.size());
  219. return function;
  220. }
  221. PDFErrorOr<ReadonlySpan<float>> ExponentialInterpolationFunction::evaluate(ReadonlySpan<float> xs) const
  222. {
  223. if (xs.size() != 1)
  224. return Error { Error::Type::MalformedPDF, "Function argument size does not match domain size" };
  225. float const x = clamp(xs[0], m_domain.lower, m_domain.upper);
  226. for (size_t i = 0; i < m_c0.size(); ++i)
  227. m_values[i] = m_c0[i] + pow(x, m_n) * (m_c1[i] - m_c0[i]);
  228. if (m_range.has_value()) {
  229. for (size_t i = 0; i < m_c0.size(); ++i)
  230. m_values[i] = clamp(m_values[i], m_range.value()[i].lower, m_range.value()[i].upper);
  231. }
  232. return m_values;
  233. }
  234. class StitchingFunction final : public Function {
  235. public:
  236. static PDFErrorOr<NonnullRefPtr<StitchingFunction>> create(Document*, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject>);
  237. virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
  238. private:
  239. StitchingFunction(Vector<NonnullRefPtr<Function>>);
  240. Bound m_domain;
  241. Optional<Vector<Bound>> m_range;
  242. Vector<NonnullRefPtr<Function>> m_functions;
  243. Vector<float> m_bounds;
  244. Vector<Bound> m_encode;
  245. Vector<float> mutable m_result;
  246. };
  247. StitchingFunction::StitchingFunction(Vector<NonnullRefPtr<Function>> functions)
  248. : m_functions(move(functions))
  249. {
  250. }
  251. PDFErrorOr<NonnullRefPtr<StitchingFunction>>
  252. StitchingFunction::create(Document* document, Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<DictObject> dict)
  253. {
  254. if (domain.size() != 1)
  255. return Error { Error::Type::MalformedPDF, "Function stitching requires domain with 1 entry" };
  256. // "TABLE 3.38 Additional entries specific to a type 3 function dictionary"
  257. if (!dict->contains(CommonNames::Functions))
  258. return Error { Error::Type::MalformedPDF, "Function stitching requires /Functions" };
  259. auto functions_array = TRY(dict->get_array(document, CommonNames::Functions));
  260. Vector<NonnullRefPtr<Function>> functions;
  261. for (size_t i = 0; i < functions_array->size(); i++) {
  262. auto function = TRY(Function::create(document, functions_array->get_object_at(i)));
  263. functions.append(move(function));
  264. }
  265. if (functions.is_empty())
  266. return Error { Error::Type::MalformedPDF, "Function stitching requires at least one function" };
  267. if (!dict->contains(CommonNames::Bounds))
  268. return Error { Error::Type::MalformedPDF, "Function stitching requires /Bounds" };
  269. auto bounds_array = TRY(dict->get_array(document, CommonNames::Bounds));
  270. if (bounds_array->size() != functions.size() - 1)
  271. return Error { Error::Type::MalformedPDF, "Function stitching /Bounds size does not match /Functions size" };
  272. Vector<float> bounds;
  273. for (size_t i = 0; i < bounds_array->size(); i++) {
  274. bounds.append(bounds_array->at(i).to_float());
  275. if (i > 0 && bounds[i - 1] >= bounds[i])
  276. return Error { Error::Type::MalformedPDF, "Function stitching /Bounds not strictly increasing" };
  277. }
  278. if (!bounds.is_empty()) {
  279. if (domain[0].lower == domain[0].upper)
  280. return Error { Error::Type::MalformedPDF, "Function stitching /Bounds requires non-zero domain" };
  281. if (domain[0].lower >= bounds[0] || bounds.last() >= domain[0].upper)
  282. return Error { Error::Type::MalformedPDF, "Function stitching /Bounds out of domain" };
  283. }
  284. if (!dict->contains(CommonNames::Encode))
  285. return Error { Error::Type::MalformedPDF, "Function stitching requires /Encode" };
  286. auto encode_array = TRY(dict->get_array(document, CommonNames::Encode));
  287. if (encode_array->size() != functions.size() * 2)
  288. return Error { Error::Type::MalformedPDF, "Function stitching /Encode size does not match /Functions size" };
  289. Vector<Bound> encode;
  290. for (size_t i = 0; i < encode_array->size(); i += 2) {
  291. encode.append({ encode_array->at(i).to_float(), encode_array->at(i + 1).to_float() });
  292. if (encode.last().lower > encode.last().upper)
  293. return Error { Error::Type::MalformedPDF, "Function stitching /Encode lower bound > upper bound" };
  294. }
  295. auto function = adopt_ref(*new StitchingFunction(move(functions)));
  296. function->m_domain = domain[0];
  297. function->m_range = move(range);
  298. function->m_bounds = move(bounds);
  299. function->m_encode = move(encode);
  300. if (function->m_range.has_value())
  301. function->m_result.resize(function->m_range.value().size());
  302. return function;
  303. }
  304. PDFErrorOr<ReadonlySpan<float>> StitchingFunction::evaluate(ReadonlySpan<float> xs) const
  305. {
  306. if (xs.size() != 1)
  307. return Error { Error::Type::MalformedPDF, "Function argument size does not match domain size" };
  308. float x = clamp(xs[0], m_domain.lower, m_domain.upper);
  309. // FIXME: binary search
  310. size_t i = 0;
  311. for (; i < m_bounds.size(); ++i) {
  312. if (x < m_bounds[i])
  313. break;
  314. }
  315. float left_bound = i == 0 ? m_domain.lower : m_bounds[i - 1];
  316. float right_bound = i == m_bounds.size() ? m_domain.upper : m_bounds[i];
  317. auto interpolate = [](float x, float x_min, float x_max, float y_min, float y_max) {
  318. return y_min + (x - x_min) * (y_max - y_min) / (x_max - x_min);
  319. };
  320. x = interpolate(x, left_bound, right_bound, m_encode[i].lower, m_encode[i].upper);
  321. auto result = TRY(m_functions[i]->evaluate({ &x, 1 }));
  322. if (!m_range.has_value())
  323. return result;
  324. if (result.size() != m_range.value().size())
  325. return Error { Error::Type::MalformedPDF, "Function stitching result size does not match range size" };
  326. for (size_t i = 0; i < result.size(); ++i)
  327. m_result[i] = clamp(result[i], m_range.value()[i].lower, m_range.value()[i].upper);
  328. return m_result;
  329. }
  330. class PostScriptCalculatorFunction final : public Function {
  331. public:
  332. static PDFErrorOr<NonnullRefPtr<PostScriptCalculatorFunction>> create(Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<StreamObject>);
  333. virtual PDFErrorOr<ReadonlySpan<float>> evaluate(ReadonlySpan<float>) const override;
  334. private:
  335. // TABLE 3.39 Operators in type 4 functions
  336. enum class OperatorType {
  337. Operand,
  338. // Arithmetic operators
  339. Abs,
  340. Add,
  341. Atan,
  342. Ceiling,
  343. Cos,
  344. Cvi,
  345. Cvr,
  346. Div,
  347. Exp,
  348. Floor,
  349. Idiv,
  350. Ln,
  351. Log,
  352. Mod,
  353. Mul,
  354. Neg,
  355. Round,
  356. Sin,
  357. Sqrt,
  358. Sub,
  359. Truncate,
  360. // Relational, boolean, and bitwise operators
  361. And,
  362. Bitshift,
  363. Eq,
  364. False,
  365. Ge,
  366. Gt,
  367. Le,
  368. Lt,
  369. Ne,
  370. Not,
  371. Or,
  372. True,
  373. Xor,
  374. // Conditional operators
  375. If,
  376. IfElse,
  377. // Stack operators
  378. Copy,
  379. Dup,
  380. Exch,
  381. Index,
  382. Pop,
  383. Roll,
  384. };
  385. static Optional<OperatorType> parse_operator(Reader&);
  386. struct IfElse;
  387. struct Token {
  388. // FIXME: Could nan-box this.
  389. OperatorType type;
  390. Variant<Empty, float, int> value {};
  391. };
  392. struct IfElse {
  393. Vector<Token> if_true;
  394. Vector<Token> if_false;
  395. };
  396. static PDFErrorOr<Vector<Token>> parse_postscript_calculator_function(Reader&, Vector<NonnullOwnPtr<IfElse>>&);
  397. struct Stack {
  398. Array<float, 100> stack;
  399. size_t top { 0 };
  400. PDFErrorOr<void> push(float value)
  401. {
  402. if (top == stack.size())
  403. return Error { Error::Type::RenderingUnsupported, "PostScript stack overflow"_string };
  404. stack[top++] = value;
  405. return {};
  406. }
  407. PDFErrorOr<float> pop()
  408. {
  409. if (top == 0)
  410. return Error { Error::Type::RenderingUnsupported, "PostScript stack underflow"_string };
  411. return stack[--top];
  412. }
  413. };
  414. PDFErrorOr<void> execute(Vector<Token> const&, Stack&) const;
  415. Vector<Bound> m_domain;
  416. Vector<Bound> m_range;
  417. Vector<Token> m_tokens;
  418. Vector<NonnullOwnPtr<IfElse>> m_if_elses;
  419. Vector<float> mutable m_result;
  420. };
  421. Optional<PostScriptCalculatorFunction::OperatorType> PostScriptCalculatorFunction::parse_operator(Reader& reader)
  422. {
  423. auto match_keyword = [&](char const* keyword) {
  424. if (reader.matches(keyword)) {
  425. reader.consume((int)strlen(keyword));
  426. return true;
  427. }
  428. return false;
  429. };
  430. if (match_keyword("abs"))
  431. return OperatorType::Abs;
  432. if (match_keyword("add"))
  433. return OperatorType::Add;
  434. if (match_keyword("atan"))
  435. return OperatorType::Atan;
  436. if (match_keyword("ceiling"))
  437. return OperatorType::Ceiling;
  438. if (match_keyword("cos"))
  439. return OperatorType::Cos;
  440. if (match_keyword("cvi"))
  441. return OperatorType::Cvi;
  442. if (match_keyword("cvr"))
  443. return OperatorType::Cvr;
  444. if (match_keyword("div"))
  445. return OperatorType::Div;
  446. if (match_keyword("exp"))
  447. return OperatorType::Exp;
  448. if (match_keyword("floor"))
  449. return OperatorType::Floor;
  450. if (match_keyword("idiv"))
  451. return OperatorType::Idiv;
  452. if (match_keyword("ln"))
  453. return OperatorType::Ln;
  454. if (match_keyword("log"))
  455. return OperatorType::Log;
  456. if (match_keyword("mod"))
  457. return OperatorType::Mod;
  458. if (match_keyword("mul"))
  459. return OperatorType::Mul;
  460. if (match_keyword("neg"))
  461. return OperatorType::Neg;
  462. if (match_keyword("round"))
  463. return OperatorType::Round;
  464. if (match_keyword("sin"))
  465. return OperatorType::Sin;
  466. if (match_keyword("sqrt"))
  467. return OperatorType::Sqrt;
  468. if (match_keyword("sub"))
  469. return OperatorType::Sub;
  470. if (match_keyword("truncate"))
  471. return OperatorType::Truncate;
  472. if (match_keyword("and"))
  473. return OperatorType::And;
  474. if (match_keyword("bitshift"))
  475. return OperatorType::Bitshift;
  476. if (match_keyword("eq"))
  477. return OperatorType::Eq;
  478. if (match_keyword("false"))
  479. return OperatorType::False;
  480. if (match_keyword("ge"))
  481. return OperatorType::Ge;
  482. if (match_keyword("gt"))
  483. return OperatorType::Gt;
  484. if (match_keyword("le"))
  485. return OperatorType::Le;
  486. if (match_keyword("lt"))
  487. return OperatorType::Lt;
  488. if (match_keyword("ne"))
  489. return OperatorType::Ne;
  490. if (match_keyword("not"))
  491. return OperatorType::Not;
  492. if (match_keyword("or"))
  493. return OperatorType::Or;
  494. if (match_keyword("true"))
  495. return OperatorType::True;
  496. if (match_keyword("xor"))
  497. return OperatorType::Xor;
  498. // If and Ifelse handled elsewhere.
  499. if (match_keyword("copy"))
  500. return OperatorType::Copy;
  501. if (match_keyword("dup"))
  502. return OperatorType::Dup;
  503. if (match_keyword("exch"))
  504. return OperatorType::Exch;
  505. if (match_keyword("index"))
  506. return OperatorType::Index;
  507. if (match_keyword("pop"))
  508. return OperatorType::Pop;
  509. if (match_keyword("roll"))
  510. return OperatorType::Roll;
  511. return {};
  512. }
  513. PDFErrorOr<Vector<PostScriptCalculatorFunction::Token>>
  514. PostScriptCalculatorFunction::parse_postscript_calculator_function(Reader& reader, Vector<NonnullOwnPtr<IfElse>>& if_elses)
  515. {
  516. // Assumes valid syntax.
  517. reader.consume_whitespace();
  518. if (!reader.consume('{'))
  519. return Error { Error::Type::MalformedPDF, "PostScript expected '{'" };
  520. Vector<PostScriptCalculatorFunction::Token> tokens;
  521. while (!reader.matches('}')) {
  522. if (reader.consume_whitespace())
  523. continue;
  524. if (reader.matches('{')) {
  525. auto if_true = TRY(parse_postscript_calculator_function(reader, if_elses));
  526. reader.consume_whitespace();
  527. if (reader.matches("if")) {
  528. reader.consume(2);
  529. tokens.append({ OperatorType::If, (int)if_elses.size() });
  530. if_elses.append(adopt_own(*new IfElse { move(if_true), {} }));
  531. continue;
  532. }
  533. VERIFY(reader.matches('{'));
  534. auto if_false = TRY(parse_postscript_calculator_function(reader, if_elses));
  535. reader.consume_whitespace();
  536. if (reader.matches("ifelse")) {
  537. reader.consume(6);
  538. tokens.append({ OperatorType::IfElse, (int)if_elses.size() });
  539. if_elses.append(adopt_own(*new IfElse { move(if_true), move(if_false) }));
  540. continue;
  541. }
  542. return Error { Error::Type::MalformedPDF, "PostScript confused parsing {}-delimited expressions"_string };
  543. }
  544. if (reader.matches_number()) {
  545. // FIXME: Nicer float conversion.
  546. char const* start = reinterpret_cast<char const*>(reader.bytes().slice(reader.offset()).data());
  547. char* endptr;
  548. float value = strtof(start, &endptr);
  549. reader.move_by(endptr - start);
  550. tokens.append({ OperatorType::Operand, value });
  551. continue;
  552. }
  553. if (Optional<OperatorType> op = parse_operator(reader); op.has_value()) {
  554. tokens.append({ op.value() });
  555. continue;
  556. }
  557. return Error { Error::Type::MalformedPDF, "PostScript unknown operator"_string };
  558. }
  559. VERIFY(reader.consume('}'));
  560. return tokens;
  561. }
  562. PDFErrorOr<NonnullRefPtr<PostScriptCalculatorFunction>>
  563. PostScriptCalculatorFunction::create(Vector<Bound> domain, Optional<Vector<Bound>> range, NonnullRefPtr<StreamObject> stream)
  564. {
  565. if (!range.has_value())
  566. return Error { Error::Type::MalformedPDF, "Function type 4 requires /Range" };
  567. Vector<NonnullOwnPtr<IfElse>> if_elses;
  568. Reader reader { stream->bytes() };
  569. auto tokens = TRY(parse_postscript_calculator_function(reader, if_elses));
  570. auto function = adopt_ref(*new PostScriptCalculatorFunction());
  571. function->m_domain = move(domain);
  572. function->m_range = move(range.value());
  573. function->m_tokens = move(tokens);
  574. function->m_if_elses = move(if_elses);
  575. return function;
  576. }
  577. PDFErrorOr<void> PostScriptCalculatorFunction::execute(Vector<Token> const& tokens, Stack& stack) const
  578. {
  579. for (auto const& token : tokens) {
  580. switch (token.type) {
  581. case OperatorType::Operand:
  582. TRY(stack.push(token.value.get<float>()));
  583. break;
  584. case OperatorType::Abs:
  585. TRY(stack.push(fabsf(TRY(stack.pop()))));
  586. break;
  587. case OperatorType::Add: {
  588. float b = TRY(stack.pop());
  589. float a = TRY(stack.pop());
  590. TRY(stack.push(a + b));
  591. break;
  592. }
  593. case OperatorType::Atan: {
  594. float b = TRY(stack.pop());
  595. float a = TRY(stack.pop());
  596. TRY(stack.push(AK::to_degrees(atan2f(b, a))));
  597. break;
  598. }
  599. case OperatorType::Ceiling:
  600. TRY(stack.push(ceilf(TRY(stack.pop()))));
  601. break;
  602. case OperatorType::Cos:
  603. TRY(stack.push(cosf(AK::to_radians(TRY(stack.pop())))));
  604. break;
  605. case OperatorType::Cvi:
  606. TRY(stack.push((int)TRY(stack.pop())));
  607. break;
  608. case OperatorType::Cvr:
  609. TRY(stack.push(TRY(stack.pop())));
  610. break;
  611. case OperatorType::Div: {
  612. float b = TRY(stack.pop());
  613. float a = TRY(stack.pop());
  614. TRY(stack.push(a / b));
  615. break;
  616. }
  617. case OperatorType::Exp:
  618. TRY(stack.push(expf(TRY(stack.pop()))));
  619. break;
  620. case OperatorType::Floor:
  621. TRY(stack.push(floorf(TRY(stack.pop()))));
  622. break;
  623. case OperatorType::Idiv: {
  624. int b = (int)TRY(stack.pop());
  625. int a = (int)TRY(stack.pop());
  626. TRY(stack.push(a / b));
  627. break;
  628. }
  629. case OperatorType::Ln:
  630. TRY(stack.push(logf(TRY(stack.pop()))));
  631. break;
  632. case OperatorType::Log:
  633. TRY(stack.push(log10f(TRY(stack.pop()))));
  634. break;
  635. case OperatorType::Mod: {
  636. float b = TRY(stack.pop());
  637. float a = TRY(stack.pop());
  638. TRY(stack.push(fmodf(a, b)));
  639. break;
  640. }
  641. case OperatorType::Mul: {
  642. float b = TRY(stack.pop());
  643. float a = TRY(stack.pop());
  644. TRY(stack.push(a * b));
  645. break;
  646. }
  647. case OperatorType::Neg:
  648. TRY(stack.push(-TRY(stack.pop())));
  649. break;
  650. case OperatorType::Round:
  651. TRY(stack.push(roundf(TRY(stack.pop()))));
  652. break;
  653. case OperatorType::Sin:
  654. TRY(stack.push(sinf(AK::to_radians(TRY(stack.pop())))));
  655. break;
  656. case OperatorType::Sqrt:
  657. TRY(stack.push(sqrtf(TRY(stack.pop()))));
  658. break;
  659. case OperatorType::Sub: {
  660. float b = TRY(stack.pop());
  661. float a = TRY(stack.pop());
  662. TRY(stack.push(a - b));
  663. break;
  664. }
  665. case OperatorType::Truncate:
  666. TRY(stack.push(truncf(TRY(stack.pop()))));
  667. break;
  668. case OperatorType::And: {
  669. int b = (int)TRY(stack.pop());
  670. int a = (int)TRY(stack.pop());
  671. TRY(stack.push(a & b));
  672. break;
  673. }
  674. case OperatorType::Bitshift: {
  675. int b = (int)TRY(stack.pop());
  676. int a = (int)TRY(stack.pop());
  677. if (b >= 0)
  678. TRY(stack.push(a << b));
  679. else
  680. TRY(stack.push(a >> -b));
  681. break;
  682. }
  683. case OperatorType::Eq: {
  684. float b = TRY(stack.pop());
  685. float a = TRY(stack.pop());
  686. TRY(stack.push(a == b ? 1.0f : 0.0f));
  687. break;
  688. }
  689. case OperatorType::False:
  690. TRY(stack.push(0.0f));
  691. break;
  692. case OperatorType::Ge: {
  693. float b = TRY(stack.pop());
  694. float a = TRY(stack.pop());
  695. TRY(stack.push(a >= b ? 1.0f : 0.0f));
  696. break;
  697. }
  698. case OperatorType::Gt: {
  699. float b = TRY(stack.pop());
  700. float a = TRY(stack.pop());
  701. TRY(stack.push(a > b ? 1.0f : 0.0f));
  702. break;
  703. }
  704. case OperatorType::Le: {
  705. float b = TRY(stack.pop());
  706. float a = TRY(stack.pop());
  707. TRY(stack.push(a <= b ? 1.0f : 0.0f));
  708. break;
  709. }
  710. case OperatorType::Lt: {
  711. float b = TRY(stack.pop());
  712. float a = TRY(stack.pop());
  713. TRY(stack.push(a < b ? 1.0f : 0.0f));
  714. break;
  715. }
  716. case OperatorType::Ne: {
  717. float b = TRY(stack.pop());
  718. float a = TRY(stack.pop());
  719. TRY(stack.push(a != b ? 1.0f : 0.0f));
  720. break;
  721. }
  722. case OperatorType::Not: {
  723. TRY(stack.push(TRY(stack.pop()) == 0.0f ? 1.0f : 0.0f));
  724. break;
  725. }
  726. case OperatorType::Or: {
  727. int b = (int)TRY(stack.pop());
  728. int a = (int)TRY(stack.pop());
  729. TRY(stack.push(a | b));
  730. break;
  731. }
  732. case OperatorType::True:
  733. TRY(stack.push(1.0f));
  734. break;
  735. case OperatorType::Xor: {
  736. int b = (int)TRY(stack.pop());
  737. int a = (int)TRY(stack.pop());
  738. TRY(stack.push(a ^ b));
  739. break;
  740. }
  741. case OperatorType::If: {
  742. auto const& if_else = m_if_elses[token.value.get<int>()];
  743. VERIFY(if_else->if_false.is_empty());
  744. if (TRY(stack.pop()) != 0.0f)
  745. TRY(execute(if_else->if_true, stack));
  746. break;
  747. }
  748. case OperatorType::IfElse: {
  749. auto const& if_else = m_if_elses[token.value.get<int>()];
  750. if (TRY(stack.pop()) != 0.0f)
  751. TRY(execute(if_else->if_true, stack));
  752. else
  753. TRY(execute(if_else->if_false, stack));
  754. break;
  755. }
  756. case OperatorType::Copy: {
  757. int n = (int)TRY(stack.pop());
  758. if (n < 0)
  759. return Error { Error::Type::RenderingUnsupported, "PostScript copy with negative argument"_string };
  760. if ((size_t)n > stack.top)
  761. return Error { Error::Type::RenderingUnsupported, "PostScript copy with argument larger than stack"_string };
  762. for (int i = 0; i < n; ++i)
  763. TRY(stack.push(stack.stack[stack.top - n]));
  764. break;
  765. }
  766. case OperatorType::Dup:
  767. TRY(stack.push(stack.stack[stack.top - 1]));
  768. break;
  769. case OperatorType::Exch: {
  770. float b = TRY(stack.pop());
  771. float a = TRY(stack.pop());
  772. TRY(stack.push(b));
  773. TRY(stack.push(a));
  774. break;
  775. }
  776. case OperatorType::Index: {
  777. int i = (int)TRY(stack.pop());
  778. if (i < 0)
  779. return Error { Error::Type::RenderingUnsupported, "PostScript index with negative argument"_string };
  780. if ((size_t)i >= stack.top)
  781. return Error { Error::Type::RenderingUnsupported, "PostScript index with argument larger than stack"_string };
  782. TRY(stack.push(stack.stack[stack.top - 1 - i]));
  783. break;
  784. }
  785. case OperatorType::Pop:
  786. TRY(stack.pop());
  787. break;
  788. case OperatorType::Roll: {
  789. int j = (int)TRY(stack.pop());
  790. int n = (int)TRY(stack.pop());
  791. if (n < 0)
  792. return Error { Error::Type::RenderingUnsupported, "PostScript roll with negative argument"_string };
  793. if ((size_t)n > stack.top)
  794. return Error { Error::Type::RenderingUnsupported, "PostScript roll with argument larger than stack"_string };
  795. if (j < 0)
  796. j += n;
  797. if (j < 0)
  798. return Error { Error::Type::RenderingUnsupported, "PostScript roll with negative argument"_string };
  799. if (j > n)
  800. return Error { Error::Type::RenderingUnsupported, "PostScript roll with argument larger than stack"_string };
  801. // http://pointer-overloading.blogspot.com/2013/09/algorithms-rotating-one-dimensional.html
  802. auto elements = stack.stack.span().slice(stack.top - n, n);
  803. elements.reverse();
  804. elements.slice(0, j).reverse();
  805. elements.slice(j).reverse();
  806. break;
  807. }
  808. }
  809. }
  810. return {};
  811. }
  812. PDFErrorOr<ReadonlySpan<float>> PostScriptCalculatorFunction::evaluate(ReadonlySpan<float> xs) const
  813. {
  814. if (xs.size() != m_domain.size())
  815. return Error { Error::Type::MalformedPDF, "Function argument size does not match domain size" };
  816. Stack stack;
  817. for (size_t i = 0; i < xs.size(); ++i)
  818. TRY(stack.push(clamp(xs[i], m_domain[i].lower, m_domain[i].upper)));
  819. TRY(execute(m_tokens, stack));
  820. if (stack.top != m_range.size())
  821. return Error { Error::Type::MalformedPDF, "Postscript result size does not match range size"_string };
  822. // FIXME: Does this need reversing?
  823. m_result.resize(stack.top);
  824. for (size_t i = 0; i < stack.top; ++i)
  825. m_result[i] = clamp(stack.stack[i], m_range[i].lower, m_range[i].upper);
  826. return m_result;
  827. }
  828. PDFErrorOr<NonnullRefPtr<Function>> Function::create(Document* document, NonnullRefPtr<Object> object)
  829. {
  830. if (!object->is<DictObject>() && !object->is<StreamObject>())
  831. return Error { Error::Type::MalformedPDF, "Function object must be dict or stream" };
  832. auto function_dict = object->is<DictObject>() ? object->cast<DictObject>() : object->cast<StreamObject>()->dict();
  833. // "TABLE 3.35 Entries common to all function dictionaries"
  834. if (!function_dict->contains(CommonNames::FunctionType))
  835. return Error { Error::Type::MalformedPDF, "Function requires /FunctionType" };
  836. auto function_type = TRY(document->resolve_to<int>(function_dict->get_value(CommonNames::FunctionType)));
  837. if (!function_dict->contains(CommonNames::Domain))
  838. return Error { Error::Type::MalformedPDF, "Function requires /Domain" };
  839. auto domain_array = TRY(function_dict->get_array(document, CommonNames::Domain));
  840. if (domain_array->size() % 2 != 0)
  841. return Error { Error::Type::MalformedPDF, "Function /Domain size not multiple of 2" };
  842. Vector<Bound> domain;
  843. for (size_t i = 0; i < domain_array->size(); i += 2) {
  844. domain.append({ domain_array->at(i).to_float(), domain_array->at(i + 1).to_float() });
  845. if (domain.last().lower > domain.last().upper)
  846. return Error { Error::Type::MalformedPDF, "Function /Domain lower bound > upper bound" };
  847. }
  848. // Can't use PDFErrorOr with Optional::map()
  849. Optional<Vector<Bound>> optional_range;
  850. if (function_dict->contains(CommonNames::Range)) {
  851. auto range_array = TRY(function_dict->get_array(document, CommonNames::Range));
  852. if (range_array->size() % 2 != 0)
  853. return Error { Error::Type::MalformedPDF, "Function /Range size not multiple of 2" };
  854. Vector<Bound> range;
  855. for (size_t i = 0; i < range_array->size(); i += 2) {
  856. range.append({ range_array->at(i).to_float(), range_array->at(i + 1).to_float() });
  857. if (range.last().lower > range.last().upper)
  858. return Error { Error::Type::MalformedPDF, "Function /Range lower bound > upper bound" };
  859. }
  860. optional_range = move(range);
  861. }
  862. switch (function_type) {
  863. case 0:
  864. if (!object->is<StreamObject>())
  865. return Error { Error::Type::MalformedPDF, "Function type 0 requires stream object" };
  866. return SampledFunction::create(document, move(domain), move(optional_range), object->cast<StreamObject>());
  867. // The spec has no entry for `1`.
  868. case 2:
  869. // FIXME: spec is not clear on if this should work with a StreamObject.
  870. return ExponentialInterpolationFunction::create(document, move(domain), move(optional_range), function_dict);
  871. case 3:
  872. // FIXME: spec is not clear on if this should work with a StreamObject.
  873. return StitchingFunction::create(document, move(domain), move(optional_range), function_dict);
  874. case 4:
  875. if (!object->is<StreamObject>())
  876. return Error { Error::Type::MalformedPDF, "Function type 4 requires stream object" };
  877. return PostScriptCalculatorFunction::create(move(domain), move(optional_range), object->cast<StreamObject>());
  878. default:
  879. dbgln("invalid function type {}", function_type);
  880. return Error(Error::Type::MalformedPDF, "Function has unkonwn type"_string);
  881. }
  882. }
  883. }